MarzleyTech Learn

Home / Learn / DevOps & cloud: from zero to deploying and running real systems / Infrastructure as code: Terraform and Ansible (servers built from files, not clicks)

Infrastructure as code: Terraform and Ansible (servers built from files, not clicks)

Clicking around a cloud console is fine for learning. But for real systems you need to rebuild environments exactly, review changes and recover after disasters. Infrastructure as code (IaC) describes your servers, networks and databases in text files kept in Git.

Why IaC?

Without IaCWith IaC
"Who changed the firewall last week?"Every change is a reviewed Git commit
Staging and production slowly drift apartBoth built from the same code
Rebuilding after a disaster takes daysRun the code again
Knowledge lives in one person's headIt's written down and versioned

Two kinds of tools

ToolMain jobStyle
Terraform (or the open-source fork OpenTofu)Create cloud resources: networks, servers, databases, DNSDeclarative: describe the end state
AnsibleConfigure servers: install packages, edit files, deploy appsRuns tasks over SSH, no agent needed
Cloud-specificAWS CloudFormation / CDK, Azure Bicep, Google Cloud Deployment ManagerTied to one provider
PulumiIaC in general-purpose languages (Python, TypeScript)Declarative, code-based

Terraform example

HCL
# main.tf
terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" {
  region = var.region
}

variable "region" {
  default = "af-south-1"   # Cape Town; choose the region that fits your users and rules
}

resource "aws_s3_bucket" "backups" {
  bucket = "marzley-shop-backups-2026"
}

resource "aws_s3_bucket_public_access_block" "backups" {
  bucket                  = aws_s3_bucket.backups.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

output "bucket_name" {
  value = aws_s3_bucket.backups.bucket
}

The workflow:

Terminal
terraform init      # download providers
terraform fmt       # tidy the code
terraform plan      # preview what will change (read this carefully!)
terraform apply     # make the changes
terraform destroy   # delete everything (great for practice environments)

State: Terraform keeps a state file recording what it created. In teams, store state remotely (an S3 bucket, Azure Storage, Terraform Cloud) with locking, and never commit it to Git: it can contain secrets.

Modules package reusable pieces (e.g. a standard VPC) so every project builds networks the same way.

Ansible example

YAML
# playbook.yml: configure web servers
- hosts: web
  become: true
  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present
        update_cache: true

    - name: Copy site configuration
      template:
        src: shop.conf.j2
        dest: /etc/nginx/sites-available/shop.conf
      notify: Reload nginx

    - name: Enable the site
      file:
        src: /etc/nginx/sites-available/shop.conf
        dest: /etc/nginx/sites-enabled/shop.conf
        state: link
      notify: Reload nginx

  handlers:
    - name: Reload nginx
      service:
        name: nginx
        state: reloaded
Terminal
ansible-playbook -i inventory.ini playbook.yml

Ansible tasks are idempotent: running the playbook twice gives the same result, changing only what's needed.

Good IaC practices

  1. Everything in Git, changed through pull requests.
  2. **Always read terraform plan** before applying; look for unexpected deletions.
  3. Remote state with locking; never commit state or secrets.
  4. Separate environments (dev, staging, production) with variables or workspaces.
  5. Run IaC in CI/CD: plan on every PR, apply after approval.
  6. Tag resources (project, owner, environment) to track costs.
Think about it: A teammate fixes a production problem by changing a firewall rule by hand in the console. Next week, someone runs terraform apply. What happens, and what's the right process?Show answer

Terraform sees the manual change as drift and may revert it to what the code says, bringing the problem back. The right process: make the fix in the Terraform code through a pull request, review the plan, then apply, so code and reality stay the same.

Summary

  • IaC describes infrastructure in versioned files: reviewable, repeatable and recoverable.
  • Terraform (or OpenTofu) creates cloud resources declaratively: init, plan, apply, destroy.
  • Ansible configures servers with idempotent tasks over SSH.
  • Keep code in Git, read plans carefully, use remote state and run IaC through CI/CD.

Check yourself

  1. Which Terraform command previews changes before applying them? (write like terraform plan)

    Show answer

    terraform plan

  2. Running an Ansible playbook twice gives the same result. What is this property called? (one word)

    Show answer

    idempotent

  3. Should the Terraform state file be committed to Git? (yes or no)

    Show answer

    no

Lesson 8 of 14 in DevOps & cloud: from zero to deploying and running real systems · Written by · Course notes