GitLab Review Apps are a convenient way of managing dynamic environments for the purpose of reviewing changes before merging into your main branch. GitLab has great Kubernetes support and can easily deploy to your clusters, but if your application is not nicely containerized or your team is not ready to take on Kubernetes, what do you do? You Terraform!
Terraform is an excellent cloud-agnostic tool for developing your infrastructure as code. By combining a couple features of Terraform, we can pretty easily build a system for deploying Review Apps.
Workspaces provide a way of provisioning and managing multiple sets of identical infrastructure without copying Terraform configuration files. If you are familiar with Terraform and its .tfstate
files, you can think of Workspaces as creating and managing new arbitrarily named .tfstate
files.
For example, terraform workspace new $BRANCH
creates a new Workspace which is named with the value of the environment variable $BRANCH
. This creates a new blank .tfstate
, meaning a terraform apply
will provision a new set of resources that are managed independently of any resources managed by any other workspace.
Remote State is a way to persist Terraform state across multiple machines by storing .tfstate
files in one of several supported remote storage mechanisms, such as Amazon S3. While this is most commonly used to allow people to collaboratively work on infrastructure, it can easily be used within GitLab jobs to provision and keep track of infrastructure managed by Terraform.
The key here is that Remote State persists Workspaces, allowing GitLab CI/CD to reference the Workspaces created for each branch across different jobs that will be ran at different times from different machines.
The .gitlab-ci.yml
configuration for this is pretty straightforward, but there are a few key points.
There are three important pieces of configuration here, all within the environment
block.
name
is the dynamically built name of the environment itself. In this case it is based on the the CI_COMMIT_REF_SLUG
variable which is the URL-friendly representation of the branch name.url
is the URL that GitLab associates to the environment. Note that GitLab does not create the DNS record for this, it is up to you to create it.on_stop
tells GitLab which job should be triggered when the branch is closed or the environment is manually stopped, thus finishing off what makes this a Review App and not just a dynamically named environment.The script
portion of the configuration is where Terraform comes in.
We need to store the Terraform configuration outside of this repository because we need the configuration files to be available after the branch is closed.
Referencing a particular Git tag when cloning this repository is necessary to ensure that the infrastructure used to provision these applications does not change without you knowing.
As mentioned earlier, Terraform Workspaces is one of the big features that makes Review Apps with Terraform possible. We can define the infrastructure required to run the application and then use Workspaces to manage isolated copies of this infrastructure.
terraform workspace select $CI_COMMIT_REF_SLUG || terraform workspace new $CI_COMMIT_REF_SLUG
Here we are selecting the Workspace named with the value of $CI_COMMIT_REF_SLUG
or we are creating it if it does not exist. This ensures that we can run the the StartReview
job multiple times from a single branch without having issues.
The rest of the script is a standard terraform apply
followed by some CodeDeploy specific stuff. I am not going into deployment specifics in this article since there are many tools for doing it, but if you are interested in setting up CodeDeploy I have written about it in the past.
The StopReview
job is very similar to StartReview
.
The GIT_STRATEGY
environment variable set to none
makes sure that GitLab does not try to clone the branch when running this job. This is necessary because this job may be ran after the branch is closed, and thus with nothing to clone.
The combination of action: stop
and the name
property is what tells GitLab which environment this job is meant to stop. The name
here needs to match the name
set in StartReview
.
Getting to the script, we again clone the Terraform repository with the same tag used earlier.
We select the Terraform Workspace corresponding to this branch (it will already be created if we are running this job) and run terraform destroy -auto-approve
to de-provision the infrastructure that was created for this branch’s Review App.
To clean everything up, we then switch the default
Workspace and delete the Workspace we created for this branch. Terraform does not let you delete the currently selected Workspace, which is why we need to switch back to default
.
At this point you should have infrastructure that can be provisioned at will dynamically based on branch name and then destroyed either at will or automatically when the branch is closed. Integrating your deployment tool of choice on top of this will give you fully functional Review Apps with their own infrastructure even if your application is not ready for Kubernetes.
Follow Jared Ready for more DevOps goodness!
👏 if you enjoyed the read!