Customizing MarkLogic on AWS with Packer and Terraform
31 August 2020 10:05 AM
|
|
SummaryPacker from HashiCorp is an open source provisioning tool, allowing for the automated creation of machine images, extending the ability to manage infrastructure to machine images. Packer supports a number of different image types including AWS, Azure, Docker, VirtualBox and VMWare. These powerful tools can be used together to deploy a MarkLogic Cluster to AWS using the MarkLogic CloudFormation Template, using a customized Amazon Machine Image (AMI). The MarkLogic CloudFormation Template is the preferred method recommended by MarkLogic for building out MarkLogic clusters within AWS. By default the MarkLogic CloudFormation Template uses the official MarkLogic AMIs. While this guide will cover a some portions of Terraform, the primary focus will be using Packer to customize an official MarkLogic AMI. For more detailed information on Terraform, we recommend reading Deploying MarkLogic to AWS with Terraform, which includes more detailed information on using Terraform, as well as the example files referenced later in this article. Setting Up PackerFor the purpose of this example, I will assume that you have already installed the AWS CLI, with the correct credentials, and you have installed Packer. Packer TemplatesA Packer template is a JSON configuration file that is used to define the image that we want to build. Templates have a number of keys available for defining the machine image, but the most commonly used ones are builders, provisioners and post-processors.
Creating a TemplateFor our example, we are going to take the official MarkLogic AMI and apply some customizations before creating a new image. Defining VariablesVariables help make the build more flexible, so we will utilize a seperate variables file,
{ "vpc_region": "us-east-1", "vpc_id": "vpc-06d3506111cea30d0", "vpc_public_sn_id": "subnet-03343e69ae5bed127", "vpc_public_sg_id": "sg-07693eb077acb8635", "ami_filter": "release-MarkLogic-10*", "ami_owner": "679593333241", "instance_type": "t3.large", "ssh_username": "ec2-user" }
Creating Our TemplateNow that we have some of the specific build details defined, we can create our template,
{ "builders": [ { "type": "amazon-ebs", "region": "{{user `vpc_region`}}", "vpc_id": "{{user `vpc_id`}}", "subnet_id": "{{user `vpc_public_sn_id`}}", "associate_public_ip_address": true, "security_group_id": "{{user `vpc_public_sg_id`}}", "source_ami_filter": { "filters": { "virtualization-type": "hvm", "name": "{{user `ami_filter}}", "root-device-type": "ebs" }, "owners": ["{{user `ami_owner`}}"], "most_recent": true }, "instance_type": "{{user `instance_type`}}", "ssh_username": "{{user `ssh_username`}}", "ami_name": "ml-{{isotime \"2006-01-02-1504\"}}", "tags": { "Name": "ml-packer" } } ], "provisioners": [ { "type": "shell", "script": "./baseInit.sh" }, { "destination": "/tmp/", "source": "./marklogic.conf", "type": "file" }, { "type": "shell", "inline": [ "sudo mv /tmp/marklogic.conf /etc/marklogic.conf" ] } ] }
In the ProvisionersIn our example, we are using the Provisioning ScriptFor our custom image, we've determined that we need an additional piece of software installed, which we will do inside a script. We've named the script
echo "**** Starting setup.sh ****"
echo "Installing Git"
sudo yum install -y git
echo "**** Finishing setup.sh ****"
Executing Our BuildNow that we've completed setting up our build, it's time to use packer to create the image.
packer build -debug -var-file=vars.json base_ami.json
Here you can see that we are telling packer to do a build using The last part of the build output will print out the details of our new image:
==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:
us-east-1: ami-0100....
Terraform and the MarkLogic CloudFormation TemplateAt this point we have our image and want to use it when deploying the MarkLogic CloudFormation Template. Unfortunately there is no simple way to do this, as the MarkLogic CloudFormation Template does not have the option to specify a custom AMI. Fortunately Terraform has some functions available that we can use to make the changes to the Template. VariablesFirst we want to add a couple entries to our existing Terraform variables file.
variable "ami_tag" { type = string default = "ml-packer" } variable "search_string" { type = string default = "ImageId: " }
The first variable, Data SourceTo retrieve the AMI, we need to define a data source. In this case it will be an aws_ami data source. We are going to call the file
data "aws_ami" "ml_ami" { filter { name = "state" values = ["available"] } filter { name = "tag:Name" values = ["${var.ami_tag}"] } owners = ["self"] most_recent = true }
So we are filtering the available AMIs, only looking at ones that are owned by our own account ( Updates to Terraform Root ModuleNow we are ready to make a couple of updates to our Terraform root module file to integrate the new AMI into our deployment. In our last example, we used the MarkLogic CloudFormation template from its S3 bucket. For this deployment, we are going to use a local copy of the template, Replace the
template_body = replace(file("./mlcluster-template.yaml"), "/${var.search_string}.*/","${var.search_string} ${data.aws_ami.ml_ami.id}")
When we updated the variables in our Terraform variable file, we created the variable Deploying with TerraformNow we are ready to run Terraform to deploy our cluster. First we want to double check that the template looks correct before we attempt to create the CloudFormation stack. The output of terraform plan will show the CloudFormation template that will be deployed. Check the output to make sure that the value for ImageId shows our desired AMI Once we have confirmed our new AMI is being referenced, we can then run terraform apply to create a new stack using the template. This can be validated by opening a command line on one of the new hosts, and checking to see if Git is installed, and if Wrapping UpAt this point, we have now customized the official MarkLogic AMI to create our own AMI using Packer. We have then used Terraform to update the MarkLogic CloudFormation Template and to deploy a CloudFormation stack based on the updated template. | |
|