Packer Blue-Green Deployments

Let’s review a deployment scenario that utilizes Packer, Terraform, Ansible, and AWS Autoscaling.

The code is available at https://github.com/sdarwin/packer-blue-green-deployment-example

Part 1 – builder.sh

To begin with, all the parts of the puzzle will be tied together by a fairly simple bash script, here called builder.sh. The logic is as follows:

1. build a new AMI with Packer. (In other words, run “packer”)
2. deploy the AMI to a new Autoscaling group with Terraform. (In other words, run “terraform apply”)

That’s really all the script does, so it may practically be considered a “wrapper script”. builder.sh offers command-line flags to skip either step 1 or step 2. That’s helpful during debugging, or if the AMI has already been built.

Part 2 – Packer

The packer configuration files are located in the packer subdirectory of the project. They include app.json and variables.json. Customize variables.json for each particular deployment. app.json has one main provisioner:

"provisioners": [
{
      "type": "shell",
      "script": "script.sh"
}

It’s calling script.sh. And what does script.sh do? See https://github.com/sdarwin/packer-blue-green-deployment-example/blob/master/packer/script.sh

– Install Ansible
– Run Ansible, with these commands:

ansible-playbook -i $INVENTORY bootstrap.yml 
ansible-playbook -i $INVENTORY deploy.yml"

The example Ansible playbooks run a series of one-time setup tasks, which is bootstrap.yml, and then a series of deployment tasks, which is deploy.yml. Subsequent code deployments would typically only need to run deploy.yml, which checks out the app code from git, since setup is already done. However, because this is immutable infrastructure, and an AMI image is created completely from scratch when it is built, the distinctions are less relevant. Bootstrap will be run once. Deploy will be run once. Then the image is ready. In the future, a new AMI image will follow the whole process again (although if that becomes very time intensive, the base AMI could already have required packages pre-installed.)

Usually, the contents of the Ansible playbooks do not need to be especially modified to fit this deployment methodology.
script.sh sets the inventory file to only include localhost. When ansible runs, only one host will be deployed, which is localhost. This brings up the question: what about other various servers in the environment? If the DB server should be configured by Ansible also, how is that done? Probably a hybrid configuration makes sense. Have a standard Ansible control machine, which deploys many servers in the infrastructure. Then use this immutable methodology only for certain layers of the stack.

Part 3 – Terraform

The code is based on this forum post. That is the interesting step. The remainder of the example Terraform code is fairly boilerplate: Security Group, Load Balancer, etc.

Question: How does Terraform know which AMI to deploy?
Answer: The builder.sh wrapper script is dumping the id from packer into the file packer/ami.txt, which is then parsed and forwarded to Terraform in the next step as a command-line option. Reading the AMI from a file allows for the possibility of rerunning the script and redeploying the same AMI without a rebuild.

Leave a Reply

Your email address will not be published. Required fields are marked *