How teams use GitLab and Terraform for infrastructure as code: A demo
This demo demonstrates how to follow good GitOps procedure to deploy infrastructure as code using Terraform for automation and GitLab as the single source of truth.
Infrastructure as Code (IaC) is the practice of managing and provisioning computing infrastructure—such as servers, databases, and networking—through machine-readable configuration files, rather than manual processes. By defining infrastructure in code, teams can version control, test, and automate deployments in a consistent and repeatable way, just like they do with application code.
IaC enables faster delivery, reduces configuration drift, and improves collaboration across development, operations, and security teams. When paired with Git-based workflows like GitOps, IaC becomes a foundation for scalable and secure cloud infrastructure automation.
When multiple teams use a Git repository as the single source of truth for all infrastructure and application deployment code, they’re performing a good GitOps procedure. Infrastructure teams can collaborate and deploy code to multiple cloud services using Terraform for automation. This article demonstrates how teams can create a Kubernetes cluster by collaborating with teammates within GitLab.
Getting started
This gitops-demo group illustrates the steps infra teams can follow.
Begin by logging into the group where the project lives within GitLab. The next step is to open the README.md file, which shows the underlying structure of the gitops-demo group. There are a few individual projects and two subgroups: infrastructure and applications.
There is a separate repository for each cloud: Azure, GCP, and AWS, and a repository for templates.
Similar files can be found in all three cloud repositories. All of the files are written in Terraform to automate the deployment process, while a gitlab-ci.yml
file is also stored in the repository to provide instructions for automation.
The backend file
Using HashiCorp's Terraform Cloud Service as a remote location for the state file keeps the state file safe and in a central location so it can be accessed by any process. One advantage of using Terraform Cloud is it has the ability to lock the state to ensure only one job can run at a time, preventing multiple jobs from making conflicting changes. The code stores the state files in the Terraform Cloud in an organization called gitops-demo
in a workspace called aws
. This keeps the running state in the cloud provider, so any team member has access at any time.
terraform {
backend "remote" {
hostname = "app.terraform.io"
organization = "gitops-demo"
workspaces {
name = "aws"
}
}
}
EKS.tf file
The EKS is another Terraform file that leverages the EKS module for the Terraform cluster. Teams can define parameters such as the type of subnets and the number of nodes in the EKS terraform file.
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_name = "gitops-demo-eks"
subnets = "${module.vpc.public_subnets}"
write_kubeconfig = "false"
tags = {
Terraform = "true"
Environment = "dev"
}
vpc_id = "${module.vpc.vpc_id}"
worker_groups = [
{
instance_type = "m4.large"
asg_max_size = 5
tags = [{
key = "Terraform"
value = "true"
propagate_at_launch = true
}]
}
]
}
Define the GitLab admin
The Kubernetes provider can be used to create a GitLab admin user and set up automatically as code and managed by Terraform.
Register the cluster with GitLab
Now that a Kubernetes cluster has been created, it's time to register it with GitLab in order to deploy more code to the cluster in the future. The first step is to use the GitLab provider to create a group cluster named AWS cluster.
data "gitlab_group" "gitops-demo-apps" {
full_path = "gitops-demo/apps"
}
provider "gitlab" {
alias = "use-pre-release-plugin"
version = "v2.99.0"
}
resource "gitlab_group_cluster" "aws_cluster" {
provider = "gitlab.use-pre-release-plugin"
group = "${data.gitlab_group.gitops-demo-apps.id}"
name = "${module.eks.cluster_id}"
domain = "eks.gitops-demo.com"
environment_scope = "eks/*"
kubernetes_api_url = "${module.eks.cluster_endpoint}"
kubernetes_token = "${data.kubernetes_secret.gitlab-admin-token.data.token}"
kubernetes_ca_cert = "${trimspace(base64decode(module.eks.cluster_certificate_authority_data))}"
}
The code contains the domain name, environment scope, and Kubernetes credentials.
After this runs, the cluster will be created in AWS and automatically registered to the gitops-demo/apps group.
Terraform template
Return to the infrastructure group and open the Templates folder. When looking at the terraform.gitlab-ci.yml file, it's possible to see how the CI works to deploy infrastructure code to the cloud using Terraform.
Inside the CI file, teams can see a few different stages: validate, plan, apply, and destroy. Using Hashicorp's Terraform base image, users can run different tasks.
The first step is to initialize Terraform.
before_script:
- terraform --version
- terraform init
- apk add --update curl
- curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.13.7/2019-06-11/bin/linux/amd64/kubectl
- install kubectl /usr/local/bin/ && rm kubectl
- curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.13.7/2019-06-11/bin/linux/amd64/aws-iam-authenticator
- install aws-iam-authenticator /usr/local/bin/ && rm aws-iam-authenticator
The next step is to validate that everything is correct.
validate:
stage: validate
script:
- terraform validate
- terraform fmt -check=true
only:
- branches
It's important to remember that good GitOps workflows incorporate creating a merge request for the changes.
merge review:
stage: plan
script:
- terraform plan -out=$PLAN
- echo \`\`\`diff > plan.txt
- terraform show -no-color ${PLAN} | tee -a plan.txt
- echo \`\`\` >> plan.txt
- sed -i -e 's/ +/+/g' plan.txt
- sed -i -e 's/ ~/~/g' plan.txt
- sed -i -e 's/ -/-/g' plan.txt
- MESSAGE=$(cat plan.txt)
- >-
curl -X POST -g -H "PRIVATE-TOKEN: ${GITLAB_TOKEN}"
--data-urlencode "body=${MESSAGE}"
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/discussions"
artifacts:
name: plan
paths:
- $PLAN
only:
- merge_requests
The merge request
The merge request (MR) is the most important step in GitOps. This is the process to review all changes and see the impact of those changes. The MR is also a collaboration tool where team members can discuss changes and stakeholders can approve changes before the final merge into the main branch.
The merge request defines what will happen when running the infrastructure as code. After the MR is created, the Terraform plan is uploaded to the MR. After all changes have been reviewed and approved, the code can be merged to the main branch. Once the code changes are merged, all the changes will be deployed into production.
Frequently Asked Questions
Frequently Asked Questions
Infrastructure as code automates IT infrastructure provisioning by using configuration files instead of manual server management. Teams use Terraform for automation while GitLab serves as the single source of truth for version control. This approach ensures the same infrastructure environment deploys each time, eliminating inconsistent configurations across machines.
Teams collaborate through merge requests where they can review, comment, and suggest changes to infrastructure code. Merge requests serve as the change mechanism for infrastructure updates, providing collaboration tools for discussion and stakeholder approval. Once approved, code merges to the main branch and acts as an audit log for all changes.
GitOps workflows increase efficiency, collaboration, and stability by replacing manual processes with automated configuration file deployment. Teams gain increased visibility into infrastructure changes, consistent deployments across environments, improved stability through version control, and better scalability compared to traditional manual server management approaches.
CI/CD pipelines automate infrastructure management using Git workflows with continuous integration and deployment. After code merges to the main branch, pipelines initiate changes in the environment using Terraform. The automation overwrites manual changes and prevents configuration drift, ensuring environments always deploy the consistent desired state defined in code.
Merge requests are the most important step in GitOps, serving as the process to review all infrastructure changes and see their impact. They provide collaboration tools where team members can discuss modifications and stakeholders can approve changes before final merge. Merge requests define what happens when running infrastructure as code and include built-in rollback features.
50%+ of the Fortune 100 trust GitLab
Start shipping better software faster
See what your team can do with the intelligent
DevSecOps platform.