Infrastructure as Code with Terraform & Jenkins ๐¶
This tutorial walks through a declarative Jenkins pipeline (45-Jenkinsfile-terraform) that orchestrates the provisioning and teardown of infrastructure using Terraform across different environments (dev, qa, prod).
๐ Pipeline Overview¶
Here is the high-level flow of our Terraform automation pipeline:
flowchart LR
Jenkins["<img src='https://upload.wikimedia.org/wikipedia/commons/e/e9/Jenkins_logo.svg' width='30' /> Jenkins"] --> P[Pipeline]
P --> Init["<img src='https://upload.wikimedia.org/wikipedia/commons/0/04/Terraform_Logo.svg' width='30' /> Terraform Init"]
Init -->|plan| Plan["<img src='https://upload.wikimedia.org/wikipedia/commons/0/04/Terraform_Logo.svg' width='30' /> Terraform Plan"]
Plan --> Approval{Manual Approval}
Approval -->|Approved| Apply["<img src='https://upload.wikimedia.org/wikipedia/commons/0/04/Terraform_Logo.svg' width='30' /> Terraform Apply/Destroy"]
[!TIP] Important: Always include a manual
Approvalstage before executingterraform applyordestroyin a CI/CD environment to prevent accidental infrastructure modifications or deletions!
๐ ๏ธ Step-by-Step Breakdown¶
1. Configuration & Parameters¶
The pipeline begins by defining global options and the parameters required to trigger the build.
pipeline {
agent any
options {
disableConcurrentBuilds()
disableResume()
buildDiscarder(logRotator(numToKeepStr: '10'))
timeout(time: 1, unit: 'HOURS')
}
parameters {
choice(name: 'ENVIRONMENT', choices: ['dev', 'qa', 'prod'], description: 'Choose Environment to deploy')
choice(name: 'ACTION', choices: ['plan', 'apply', 'destroy'], description: 'Terraform action to execute')
}
- Parameters:
ENVIRONMENTdetermines the target scope for the.tfvarsfile (e.g., development or production).ACTIONcontrols whether the pipeline will only generate a plan, apply it, or destroy the resources entirely.
2. Initialization & Plan Stages¶
environment {
TF_DIR = "deployment/terraform"
}
stages {
stage('Terraform Init') {
steps {
sh """
cd ${TF_DIR}
terraform init -reconfigure
"""
}
}
stage('Plan Dev') {
when { environment name: 'ENVIRONMENT', value: 'dev' }
steps {
sh """
cd ${TF_DIR}
terraform plan -var-file=dev.tfvars -out=tfplan
"""
}
}
init -reconfigure: Ensures the backend is safely initialized, preventing state locking issues across parallel jobs or when switching configurations.-out=tfplan: Exports the plan to a binary file. This guarantees that the exact changes reviewed during the plan phase will be identical to what is applied.
[!TIP] We always execute commands by first
cding into theTF_DIR(e.g.,cd ${TF_DIR}) since Jenkins starts executing from the root of the workspace.
3. Manual Approval Gateway¶
stage('Approval') {
when {
expression { params.ACTION in ['apply', 'destroy'] }
}
steps {
input message: "Approve Terraform ${params.ACTION} for ${params.ENVIRONMENT}?", ok: 'Proceed'
}
}
This acts as a safety barrier. The pipeline will pause here, waiting for a human administrator to click "Proceed" inside the Jenkins UI before any real infrastructure is fundamentally altered.
4. Apply / Destroy Stage¶
stage('Apply / Destroy Dev') {
when {
allOf {
environment name: 'ENVIRONMENT', value: 'dev'
expression { params.ACTION in ['apply', 'destroy'] }
}
}
steps {
sh """
cd ${TF_DIR}
if [ "${params.ACTION}" = "destroy" ]; then
terraform destroy -var-file=dev.tfvars -auto-approve
else
terraform apply tfplan
fi
"""
}
}
Based on the initial parameter provided, it will seamlessly pivot between completely removing the stack (destroy -auto-approve) or rolling out the changes (apply tfplan).
๐ง Knowledge Check¶
Why do we use the -out=tfplan flag during terraform plan?
What does the allOf { } block do in the declarative pipeline's when statement?
Which Terraform command is used to completely tear down all provisioned resources?
๐ฌ DevopsPilot Weekly โ Learn DevOps, Cloud & Gen AI the simple way.
๐ Subscribe here