Blue and Green Deployments with Terraform Workspaces
This post showcases the simplicity of leveraging Terraform Workspaces for blue green deployments. Including the benefits this can bring to your projects and how to best structure your project repo when leveraging Jenkins, Terraform & Ansible together.
Blue and Green Deployments
Blue Green deployments is a deployment strategy that reduces downtime and risk by running two identical environments simultaneously. Only one environment is serving live production traffic. You can safely update and test the idle environment. If all tests pass you can then promote the idle updated version to serve the production load.
Blue Green deployments can eliminate deployment downtime. It also allows you to immediately rollback if unexpected issues rise with the latest update.
Terraform workspaces allow us to use the exact same terraform configuration to create multiple distinct environments. Each workspace has its own associated state file, this lends itself perfectly for blue green deployments.
You can create new workspaces with terraform workspace new <workspace_name> or select an existing workspace with terraform workspace select <workspace_name>
You can use Jenkins to leverage the CI pipeline. Input parameters is where we’ll define what action we want to take on which version of the infrastructure.
├── Ansible │ ├── playbook.yml │ └── roles │ └── nginx │ ├── tasks │ │ └── main.yml │ ├── templates │ │ └── index.html.j2 │ └── vars │ ├── blue.yml │ └── green.yml ├── Jenkinsfile ├── LICENSE ├── README.md └── Terraform ├── Demo │ ├── asg.tf │ ├── blue.tfvars │ ├── data.tf │ ├── green.tfvars │ ├── sg.tf │ ├── terraform.tf │ └── user_data.tpl └── Setup ├── main.tf ├── outputs.tf └── terraform.tf
You can define variables in various locations. The Colour input parameter specified in the pipeline will control which variable files are used in both Terraform and Ansible. This allows us to specify different configurations for each version independently. We can define additional variables within the Jenkinsfile and pass them down to Terraform & Ansible, or specify variables in Terraform and pass those down to Ansible. This gives us great flexibility when defining variables for projects at each layer.
After initialising terraform in the correct directory we select the workspace. However, if this fails due to not existing, it will be created for you.
We then use the same input parameter to specify the associated tfvars file when creating the terraform plan:
terraform plan '-var-file=blue.tfvars' -no-color '-out=tfout'
This allows us to define version specific variables in the associated blue.tfvars & green.tfvars files.
Our EC2 user_data generates via the template_file data block. This allows us to inject variables into user data and pass them to Ansible via the ansible-pull command. We use the –extra-vars flag pass in the colour variable. This then uses Ansible to include the correct variables for the infrastructure we’re deploying by using include_vars.
This allows us to define variables at the start of the pipeline and efficiently pass them down into the Infrastructure as Code and the Configuration Management layers. Structuring a project like this provides multiple benefits, the main one being a clear demarcation between Infrastructure as Code and Configuration Management whilst leveraging the same codebase to create both blue and green environments.
Each directory in the main Terraform directory represents a Layer, each layer will have its own state file. The pipeline parameter defines which layer is deploying. The benefit here is that we can split our project into logical layers. We can then structure this in various ways depending on the project. This gives us fine grained control and flexibility, if we have global resources used by multiple sub environments we can create a global layer, we can then use these resources in other layers as needed. A great example of this is an RDS instance in a global RDS layer with both blue and green deployments accessing this database.
Terraform workspaces are used to solve various problems when we’re building projects that require identical sub environments. Depending on the requirements of the project you may prefer to leverage workspaces for another purpose. Maybe for each sub-environment (si1, sit2..) instead of the blue green deployment aspect of the project. In this scenario the workspaces would reflect a single sub environment. We can then have another pipeline parameter controlling which leg of the sub environment gets deployed if blue-green deployments are required at this level.
You can implement blue-green deployments in various ways depending on your tech stack. However if you are looking to implement it in Terraform, workspaces are definitely the logical approach, at least for most project requirements.