Skip to main content
Continuous Integration
CHAPTER 14

Infrastructure as Code in CI

Updated: May 15, 2026
30 min read

# CHAPTER 14

Infrastructure as Code in CI

1. Introduction

So far, our CI/CD pipelines have focused entirely on software: testing PHP code, compiling React apps, and pushing Docker images. However, deploying an application often requires changes to the underlying hardware. You might need a new database, an updated firewall rule, or a larger Load Balancer. Historically, a DevOps engineer would manually click buttons in the AWS Console to make these changes before running the CI pipeline. This breaks the automation loop. In this chapter, we will integrate Infrastructure as Code (IaC) tools like Terraform and Ansible directly into our CI/CD pipelines, allowing our automated workflows to provision and configure the very hardware they deploy software to.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define the role of Infrastructure as Code (IaC) within a CI/CD workflow.
  • Differentiate between the functions of Terraform (Provisioning) and Ansible (Configuration).
  • Integrate Terraform commands (fmt, plan, apply) into GitHub Actions.
  • Understand the "Plan on PR, Apply on Merge" workflow paradigm.
  • Securely manage Terraform state files within a CI environment.

3. Beginner-Friendly Explanation

Imagine producing a theatrical play.
  • The Software (Application Code): The script, the actors, and the costumes. (What we've automated so far).
  • The Hardware (Infrastructure): The stage, the lighting rigs, and the sound system.

If the script calls for a rainstorm in Act 2, but the stage crew manually forgot to install the sprinklers, the play fails. Infrastructure as Code (IaC) is writing a script for the stage crew. When the CI pipeline runs, it first reads the IaC script, builds the stage with the sprinklers perfectly (Terraform), and then brings out the actors (Software Deployment). The environment and the application are deployed together automatically.

4. Terraform vs. Ansible in CI

Both are IaC tools, but they serve different purposes in the pipeline.
  • Terraform (The Builder): A declarative tool. You write resource "awsdbinstance". The CI pipeline runs terraform apply, and Terraform builds the physical database server in AWS.
  • Ansible (The Configurer): A procedural tool. Once Terraform builds the blank server, the CI pipeline runs ansible-playbook, which logs into the server via SSH and installs Nginx and PHP.

5. The "Plan on PR, Apply on Merge" Workflow

Modifying infrastructure is dangerous. If a CI pipeline deletes a database, your company goes offline. Therefore, IaC pipelines use a strict, two-step safety workflow.

Step 1: The Pull Request (The Simulation) When a developer modifies a Terraform file and opens a Pull Request, the CI pipeline runs terraform plan. This simulates the changes without actually touching the cloud. The pipeline posts a comment on the PR: *"If you merge this, I will create 1 server and destroy 1 database."*

Step 2: The Merge (The Execution) Human reviewers read the simulation comment. If it looks correct, they click "Merge." The code enters the main branch. This triggers the second half of the CI pipeline, which runs terraform apply -auto-approve, making the physical changes to the live cloud.

6. Mini Project: Automate Infrastructure Deployment

Let's build the GitHub Actions workflow that executes the "Plan" phase when a Pull Request is opened.

Step-by-Step Architecture Concept:

yaml
1234567891011121314151617181920212223242526272829303132333435
name: Terraform Infrastructure Pipeline

on:
  pull_request: # Only run on PRs!

jobs:
  terraform-plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 1. Install Terraform on the runner
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3

      # 2. Authenticate securely with AWS
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      # 3. Initialize and check formatting
      - name: Terraform Init
        run: terraform init
        
      - name: Terraform Format Check
        run: terraform fmt -check

      # 4. Generate the execution plan!
      - name: Terraform Plan
        id: plan
        # The -no-color flag makes it readable for GitHub comments
        run: terraform plan -no-color -out=tfplan

*(In a full enterprise setup, the next step would use a GitHub Script to post the stdout of this plan directly as a comment on the Pull Request UI for the reviewers to see).*

7. Real-World Scenarios

A rapidly growing startup needed to deploy an identical copy of their entire application stack (Servers, Databases, Load Balancers) for every new enterprise client they signed. Doing this manually took an engineer 3 days of clicking through the AWS console, and they often made configuration mistakes. The team transitioned to Terraform and integrated it into GitLab CI. Now, when the sales team signs a new client, a developer simply adds the client's name to a list in a clients.tfvars file and merges the Pull Request. The CI pipeline triggers, reads the Terraform code, and automatically builds a flawless, identical infrastructure stack in the cloud in under 10 minutes.

8. Best Practices

  • Remote State Locking: Terraform uses a "State File" (terraform.tfstate) to remember what infrastructure it has built. If two developers merge code at the exact same time, two CI runners might try to run terraform apply simultaneously, corrupting the state file and destroying the cloud environment. You MUST configure a remote backend (like an S3 bucket) with state locking (like DynamoDB) to ensure CI runners form a queue and only execute one at a time.

9. Security Recommendations

  • Least Privilege for IaC: The AWS IAM user attached to a CI runner executing Terraform is incredibly powerful because it literally builds the cloud. It needs permission to create EC2 instances, VPCs, and databases. However, it should strictly be DENIED permission to manipulate core IAM permissions (so it can't create new admin users) or delete CloudTrail audit logs, ensuring a compromised pipeline cannot cover its tracks.

10. Troubleshooting Tips

  • Hanging Pipelines: If a pipeline running ansible-playbook hangs indefinitely until the 6-hour GitHub timeout cancels it, it is usually waiting for an interactive prompt. For example, SSH might be asking *"Are you sure you want to continue connecting (yes/no)?"*. Since there is no human to type "yes", the runner freezes. Always use flags like ANSIBLEHOSTKEY_CHECKING=False in automated environments.

11. Exercises

  1. 1. What is the operational purpose of running terraform plan during the Pull Request phase of a CI pipeline?
  1. 2. Explain the fundamental difference between the automation tasks handled by Terraform versus Ansible in a deployment pipeline.

12. FAQs

Q: Should I put my Terraform code and my Application code in the same Git repository? A: For small projects, yes (called a Monorepo). For enterprise projects, it is best practice to separate them. Put the Application code in app-repo (which triggers the build/test CI pipeline), and put the infrastructure code in infra-repo (which triggers the Terraform CI pipeline).

13. Interview Questions

  • Q: Describe the "Plan on PR, Apply on Merge" paradigm. How does this CI workflow mitigate the risks of applying declarative infrastructure changes to a production environment?
  • Q: Two automated Jenkins pipelines executing Terraform run simultaneously against the same environment. Explain the catastrophic risk this poses to the terraform.tfstate file and the architectural requirements necessary to prevent it.

14. Summary

In Chapter 14, we expanded the scope of our CI/CD pipelines from purely compiling software to physically architecting the cloud. By integrating Infrastructure as Code (IaC) tools like Terraform and Ansible, we empowered our automation to provision servers, configure firewalls, and deploy databases dynamically. We implemented the strict "Plan on PR, Apply on Merge" safety paradigm, transforming the Pull Request process into an interactive infrastructure review gateway. With IaC integrated into the pipeline, the deployment of identical, complex application stacks is now entirely automated, version-controlled, and seamlessly reproducible.

15. Next Chapter Recommendation

Our pipeline now builds the hardware and deploys the software perfectly. But what if we push a bad update to 1,000 live users? How do we swap the old code for the new code safely? Proceed to Chapter 15: Continuous Deployment Basics.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·