Automating infrastructure provisioning with Terraform is nothing for many, but to truly harness IaC power, seamless integration with CI/CD pipelines is key. In this guide, we’ll walk you through the process of setting up and running your Terraform configurations within GitLab CI from a GitHub-imported Repo. This powerful combination not only ensures consistent deployments but also brings version-controlled infrastructure management to the forefront of your development workflow.
This is the first topic of my Terraform pipelines for dummies series that covers pipelined deployments in GitLab, GitHub Actions, AzureDevOps, AWS Catalyst, and GCP Cloud Build. A beautiful excuse to learn CI/CD for Infra bros while having fun.
If you have your source repo stored in GitHub (i.e github.com/brokedba/terraform-examples )
There are two ways to do it :
Option1: Import from GitHub using GitLab UI
In your GitLab Portal, click New Project and select the “Import Project” option
Once you select the import project option, hit “Repository by URL” and fill in the source/target repo details
Choose the visibility of the imported project (repo), and hit Create project.
Note: You could also import the repo by authorizing GitLab to access your GitHub in one click
Option2: Import using Git CLI
$ git clone https://github.com/brokedba/terraform-examples.git
Add an SSH public key to your GitLab under GitHub Profile> preference> SSH Key
Test your connection with your Gitlab from your terminal by specifying the SSH Private Key
brokedba@brokdba:~$ ssh -i ~/.ssh/id_rsa_gitlab -T git@gitlab.com
Welcome to GitLab, @brokedba!
Create a New GitLab Project in GitLab GUI same as the git repo name “terraform-examples”
Add GitLab as a Remote repo: adjust the below with your GitLab Namespace
$
cd terraform-examples $git remote add origin git@gitlab.com/{Namespace}/terraform-examples.git
$ GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_gitlab" git push -u origin main
remote: Resolving deltas: 100% (733/733), done.
To git@gitlab.com:brokedba/terraform-examples.git
* [new branch] main -> main
Branch main set up to track remote branch main from origin.
Now that our repo is imported we’ll set the necessary variables for our terraform pipeline. Our target platform will be Oracle Cloud.
Under the Project, Click Settings > CI/CD > Variables > Expand > Add Variable
Under “Variables”, Click “Expand” and Add your Authentication Variables
For our deployment, we’ll need to set the below variables. GitLab equivalent for secrets is masked variables
TF_VAR_Tenancy_OCID: Masked
TF_VAR_Private_Key_Path: Masked
TF_VAR_Fingerprint: Masked
TF_VAR_User_OCID: Masked
TF_VAR_Compartment_OCID: Masked (where to create the resource )
TF_VAR_Region
TF_VAR_SSH_Public_Key: variable of type file, for the vm to be deployed (to contain long text)
TF_VAR_gitlab_access_token: this token authorizes runners to interact with GitLab. Unlike GitHub, where authentication is automatic through GITHUB_TOKEN, GitLab requires manual setup.
The GitLab CI/CD pipeline config is controlled by a .gitlab-ci.yml file, similar to GitHub Workflow.
We need to create a CI file in the root directory of our repo based on a template called Terraform.latest.gitlab-ci.yml
Description of the GitLab-ci Content
Each GitLab-CI template allows the abstraction of actions depending on its type. In our case base. GitLab.CI extends all terraform workflow stages. This is different than GitHub actions, with a shorter code footprint.
1) The Generic section contains the include which loads templates and the variables
TF_ROOT
represents the working directory where our terraform config files reside in my repo.
I have many deployments, but the variable can take any subdirectory I want (Example: launch-instance). Note: the SAST template in the picture was removed later from my include please do the same.
After we declared the stage names and defined the same in a sequence as described below.
FMT – For formatting the Terraform config.
Validate
– Validation of Code
Build
– Run Terraform Plan
Deploy
– Executes Terraform apply command. Then save the state file as an artifact
Cleanup
– Load the artifact (state file) and destroy the resource
Each stage uses the keyword “extends” with .terraform:*
that references a function in the template
Now that we have both the project (repo), the variables, and the pipeline defined let’s run it and monitor the workflow.
Go to your Project> Build > Pipeline and Click Run Pipeline
DEPLOY: Both the validate and build (TF Plan) stages are now done, the pipeline waits for a manual deploy
Once run, you can check the logs while our web server is being deployed in the Oracle Cloud Platform
If we check the console, we’ll see that the web server is now up and running, ready to take requests
DESTROY: After a successful deployment, all looks good, we can now clean by tearing down our resources
Notice how the cleanup job reused the state file, loaded from the artifact to destroy the webserver
Final Pipeline Status
Once complete we can see the status and the time it took to finish the pipeline (FMT had just a minor warning)
There are pros and tread offs about using GitLab over GitHub actions, here’s a few to consider
The Advantages (Pros)
GitLab is Open source but still more secure than GitHub
I love how GitLab allows us to pause a pipeline stage using the manual job option that GitHub doesn’t have
GitLab has a lot of templates available for different frameworks unlike GitHub actions 3rd-party marketplace
GitLab CI offers better reporting and auditing capabilities, for tracking/analyzing workflow performance
Full of other features: child pipelines, dynamic pipeline generation, very flexible conditionals, composable pipeline definitions, security, merge trains, and code review
The Disadvantages (Cons)
GitLab lacks GitHub’s massive popularity/support in the community (fewer blogs/StackOverflow posts)
GitLab supports only one CI workflow file (gitlab-ci.yaml) per repository, whereas GitHub allows multiple
GitLab UI lacks Auto-refresh of the pipeline/job status forcing you to refresh the browser unlike in GitHub
We just showed a simple pipeline automating the whole workflow of a terraform deployment in OCI
We also leveraged GitLab’s unique manual job option for pausing pipeline stages which is rare elsewhere
GitLab’s singular approach relies on a rich built-in template library instead of a public Marketplace
I tried to share a few bits in terms of experience but there are tons of articles comparing GitLab and GitHub
My demo didn’t cover event triggers via rules(CI_PIPELINE_SOURCE), but you can learn more here
I also used artifacts to save a state file but it’s recommended to use GitLab managed remote state instead
Hope this helps! Next, I’ll dive into GitHub Actions terraform Multicloud pipelines using OIDC.