Introduction to Terraform and Infrastructure as Code

My journey from clicking through cloud consoles to declarative infrastructure management


Table of Contents


Introduction: The Friday Night Disaster

It was 5:47 PM on a Friday when my phone rang. My heart sank when I saw it was the junior developer on call.

"The staging environment is gone. All of it."

Gone. Not broken. Not misconfigured. Gone. Someone had accidentally deleted the wrong resource group in Azure while cleaning up a test environment. And because we managed everything through the cloud console, there was no code to redeploy. No version control. Just my memory of the dozens of resources I'd manually created over the past 3 months.

I spent the next 6 hours clicking through Azure Portal, AWS Console, and various other cloud interfaces, trying to recreate everything from memory and scattered screenshots. Security groups with 47 individual rules. Load balancers with specific health check configurations. Database instances with exact parameter settings. Tag after tag after tag.

I missed my daughter's 8th birthday dinner.

That Saturday morning, exhausted and frustrated, I searched for "how to automate cloud infrastructure." That's when I discovered Infrastructure as Code and Terraform. It would fundamentally change how I approached infrastructure management.

This article is the beginning of your Infrastructure as Code journey. I'll share everything I wish someone had told me on that frustrating Friday night.


What is Infrastructure as Code?

Infrastructure as Code (IaC) is the practice of managing and provisioning infrastructure through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.

Let me break that down with a simple analogy:

The Traditional Approach: The Recipe Card Method

Imagine you're teaching someone to bake a cake, but instead of giving them a recipe, you stand next to them and say:

  • "First, turn the oven to 350Β°F"

  • "Now add 2 cups of flour"

  • "Mix for 3 minutes"

  • "Wait, did I say 2 cups or 3 cups? Let me check my notes..."

Every time you bake the cake, you have to remember all the steps, in the right order, with the right quantities. If someone else tries to bake it, they might miss a step or use different ingredients.

The IaC Approach: The Written Recipe

With Infrastructure as Code, you write down the recipe once:

Now anyone can bake the same cake, consistently, every single time. That's Infrastructure as Code.

Why This Matters for Infrastructure

When you define infrastructure as code:

  • Version Control: Track every change in Git, like you do with application code

  • Reproducibility: Deploy identical environments consistently

  • Documentation: The code IS the documentation

  • Collaboration: Teams can review infrastructure changes like code reviews

  • Automation: Integrate with CI/CD pipelines

  • Disaster Recovery: Redeploy entire environments with one command


Why Not Just Use Cloud Consoles?

I spent 2 years managing infrastructure through cloud consoles before learning IaC. Here's what I learned the hard way:

The Console Clicking Nightmare

Problem 1: No Version History

Problem 2: Environment Drift

  • Dev environment has 2GB memory

  • Staging has 4GB (someone clicked "upgrade" last month)

  • Production has 8GB (because we had an incident)

  • Nobody knows which configuration is "correct"

Problem 3: Knowledge Silos

Problem 4: Human Error

  • Click the wrong button β†’ resources deleted

  • Forget a step β†’ broken deployments

  • Misconfigure settings β†’ security vulnerabilities

  • No way to catch mistakes before they hit production

Problem 5: Scaling Impossibility

  • Need 3 identical web servers? Click 3 times through 15-step wizard

  • Need to update all of them? Click 45 times

  • Need to add 10 more? Please, just... no.

My Console Clicking Horror Story

In 2018, I was managing infrastructure for a financial services application across three environments (dev, staging, production). Everything was done through the AWS Console.

One day, I needed to update a security group rule in production. Simple task, right?

What I intended to do:

  • Add rule allowing HTTPS from new load balancer IP

What I actually did:

  • Opened wrong security group (they had similar names)

  • Modified production database security group

  • Accidentally removed a rule while adding the new one

  • Didn't notice because Console doesn't show "diff" of changes

Result:

  • Production database became unreachable

  • Application down for 37 minutes

  • Lost ~$15,000 in revenue

  • Spent 2 hours in post-mortem meetings

  • Wrote "incident report" that basically said "I clicked wrong button"

With Infrastructure as Code, this would have been:

  1. Made change in code

  2. Reviewed diff: terraform plan shows exactly what will change

  3. Team member reviews pull request: "Hey, why are you touching the database security group?"

  4. Mistake caught before production impact


Understanding Infrastructure as Code Tools

Not all IaC tools are created equal. Let me break down the landscape:

Configuration Management vs Infrastructure Provisioning

Configuration Management Tools (Ansible, Chef, Puppet, SaltStack)

  • Focus: Configure and manage existing servers

  • Strength: Application deployment, software installation, configuration updates

  • Example: "Install Nginx on these 10 servers and configure them identically"

Infrastructure Provisioning Tools (Terraform, CloudFormation, Pulumi)

  • Focus: Create and manage infrastructure resources

  • Strength: Networks, servers, databases, cloud resources

  • Example: "Create 10 servers, a load balancer, and a VPC with specific subnets"

Declarative vs Imperative

Imperative Approach (Like cooking instructions)

Declarative Approach (Like a recipe's ingredient list)

The Major Players

Tool
Type
Strength
Weakness

Terraform

Declarative, Multi-cloud

Provider-agnostic, huge ecosystem

Learning curve, state management

CloudFormation

Declarative, AWS-only

Deep AWS integration, free

AWS-locked, verbose YAML

Pulumi

Declarative, Multi-cloud

Real programming languages

Newer, smaller community

Ansible

Imperative/Declarative

Simple, agentless

Not ideal for infrastructure


Why Terraform? My Choice Explained

After evaluating all major IaC tools, I chose Terraform. Here's why:

1. Provider-Agnostic Architecture

The Problem I Had:

  • AWS for compute

  • Azure for legacy applications

  • GCP for data analytics

  • Cloudflare for DNS

  • GitHub for code repositories

Terraform's Solution:

One configuration language. One workflow. One state file. Multiple clouds.

2. Massive Provider Ecosystem

Terraform has 3,000+ providers for everything imaginable:

  • Cloud Providers: AWS, Azure, GCP, Oracle Cloud, Alibaba Cloud

  • SaaS Platforms: GitHub, GitLab, Datadog, PagerDuty, Slack

  • Databases: MongoDB, PostgreSQL, MySQL

  • DNS/CDN: Cloudflare, Route53, Fastly

  • Monitoring: Datadog, New Relic, Splunk

  • And even: Spotify playlists, Home Assistant, your coffee maker (probably)

3. Declarative and Predictable

4. State Management

Terraform tracks what it created in a state file. This means:

  • Knows what exists vs what should exist

  • Can detect drift (manual changes)

  • Can update resources in place vs recreate

  • Prevents duplicate resource creation

5. Massive Community

  • 70,000+ modules in Terraform Registry

  • Active community on Reddit, Stack Overflow, HashiCorp forums

  • Extensive documentation

  • Regular updates and improvements

6. Free and Open Source

  • Core Terraform is 100% free

  • Optional paid features (Terraform Cloud) for teams

  • No vendor lock-in

When NOT to Use Terraform

Use Ansible instead if:

  • Primarily configuring existing servers

  • Need to run commands on remote systems

  • Focused on application deployment

Use CloudFormation instead if:

  • 100% AWS-only, forever

  • Need deep AWS-specific features

  • Want AWS support for the IaC tool itself

Use Pulumi instead if:

  • Want to write infrastructure in Python/TypeScript/Go

  • Need complex programmatic logic

  • Willing to trade ecosystem maturity for familiar languages


Installing Terraform

Let's get Terraform installed. I'll show you the best method for each operating system.

macOS Installation

Option 1: Homebrew (Recommended)

Option 2: Manual Download

Linux Installation

Ubuntu/Debian:

RHEL/CentOS/Fedora:

Windows Installation

Option 1: Chocolatey (Recommended)

Option 2: Manual Download

  1. Download from https://www.terraform.io/downloads

  2. Extract ZIP file

  3. Add to PATH environment variable

  4. Restart terminal

  5. Run terraform version

Verification

After installation, you should see output like:

Enable tab completion:


Terraform Architecture Overview

Before we write code, let's understand how Terraform works:

spinner

Key Components

1. Configuration Files (.tf files)

  • Where you define infrastructure in HCL

  • Human-readable and version-controllable

  • Contains resources, providers, variables, outputs

2. Terraform CLI

  • Command-line tool you run

  • Executes commands: init, plan, apply, destroy

  • Orchestrates everything

3. Providers

  • Plugins that talk to APIs (AWS, Azure, GCP, etc.)

  • Downloaded during terraform init

  • Each provider knows how to create/read/update/delete its resources

4. State File

  • Terraform's "database" of what it created

  • Maps configuration to real-world resources

  • Tracks metadata and resource dependencies

  • Critical: Lose this, lose Terraform's knowledge of your infrastructure

5. Execution Engine

  • Builds dependency graph

  • Determines order of operations

  • Executes create/update/delete operations

  • Handles errors and rollbacks


Your First Terraform Configuration

Let's start with the simplest possible example. We'll create a file on your local computer - no cloud accounts needed yet.

Step 1: Create a Project Directory

Step 2: Create Your First Configuration File

Create a file named main.tf:

Step 3: Initialize Terraform

What you'll see:

What just happened:

  • Terraform read your configuration

  • Detected you're using the local provider

  • Downloaded the provider plugin

  • Created a .terraform directory to store plugins

  • Ready to execute commands


Understanding the Terraform Workflow

Terraform has a standard workflow. Let's go through it step by step:

spinner

The Four Core Commands

1. terraform init - Initialize

  • Downloads provider plugins

  • Prepares backend for state storage

  • Initializes modules

  • Run this once per project (or when adding new providers)

2. terraform plan - Preview Changes

  • Shows what Terraform will do

  • Compares desired state (config) vs current state

  • No changes are made - it's a preview

  • Always run this before apply

3. terraform apply - Execute Changes

  • Actually creates/modifies/deletes resources

  • Shows plan and asks for confirmation

  • Updates state file

  • This makes real changes

4. terraform destroy - Clean Up

  • Deletes all resources Terraform created

  • Useful for testing and cleanup

  • Be very careful - this is destructive

Let's Execute Our First Plan

Output:

Reading the output:

  • + means "will be created"

  • ~ means "will be modified"

  • - means "will be destroyed"

  • (known after apply) - values determined during creation

Now Let's Actually Create

Terraform shows the plan again and asks:

Type yes and press Enter.

Output:

Verify It Worked

You should see both files with the exact content you defined!

Auto-Approve (Use Carefully)


Breaking Down What Just Happened

Let's examine our configuration in detail:

Resource Block Anatomy

Resource Type: local_file

  • Format: <provider>_<resource_type>

  • local = provider name

  • file = resource type within that provider

Resource Name: welcome

  • Your custom identifier for this resource

  • Used to reference it elsewhere in config

  • Must be unique within this resource type

Arguments: filename, content, file_permission

  • Configuration for this resource

  • Each resource type has different arguments

  • Some required, some optional

Special Functions and Expressions

${path.module} - Module Path

timestamp() - Current Time

Heredoc String (<<-EOT ... EOT)

The State File

After applying, check your directory:

You'll see:

  • terraform.tfstate - THE STATE FILE

  • terraform.tfstate.backup - Previous state version

Let's peek inside:

This is Terraform's memory of what it created. Guard it with your life (we'll learn proper state management in Article 6).


Common Mistakes and How to Avoid Them

Let me share the mistakes I made when starting with Terraform:

Mistake #1: Not Running terraform plan First

What I Did:

What I Should Have Done:

Lesson: Always plan before apply. Always.

Mistake #2: Editing Resources Manually

What I Did:

What Happened:

Lesson: Don't manually modify Terraform-managed resources. Change the configuration instead.

Mistake #3: Committing State Files to Git

What I Did:

What I Should Have Done:

Lesson: State files can contain secrets. Never commit them to Git (unless using encrypted remote state).

Mistake #4: Deleting State Files

What I Did:

What Happened:

Why: Terraform lost its memory of creating the file, so it tries to create it again.

Lesson: State files are sacred. Back them up, store them securely, but never delete them.

Mistake #5: Using Hardcoded Values Everywhere

What I Did:

What I Should Have Done (we'll learn this in Article 3):

Lesson: Use variables for reusability. Hardcoding doesn't scale.


Best Practices from Day One

Start with good habits immediately:

1. Always Use Version Control

2. Organize Your Files

Bad:

Good:

3. Use Meaningful Resource Names

Bad:

Good:

4. Add Comments

5. Start with Plan, End with Destroy

6. Keep State Files Safe

For now (learning):

  • Don't delete state files

  • Don't edit state files manually

  • Don't commit to Git

Later (production):

  • Use remote state (S3, Azure Storage, Terraform Cloud)

  • Enable state locking

  • Enable versioning/backups


What I Learned About Infrastructure as Code

Looking back at my journey from that Friday night disaster to confident IaC practices:

1. Infrastructure IS Code

The biggest mindset shift: Treat infrastructure with the same rigor as application code.

  • Version control everything

  • Code review infrastructure changes

  • Test before deploying

  • Document through code

2. Declarative Beats Imperative

Describing what you want is better than scripting how to create it.

Imperative (Bash script):

Declarative (Terraform):

3. State Management is Critical

The state file is Terraform's memory. Respect it:

  • Back it up

  • Secure it (contains secrets)

  • Use remote state for teams

  • Never edit manually

4. Start Simple, Grow Complexity

Don't try to terraform your entire infrastructure on day one:

Week 1: Local file resources (learning) Week 2: Simple cloud resources (VPC, subnets) Week 3: Add modules (networking, compute) Month 2: Multi-environment setup Month 3: CI/CD integration Month 6: Enterprise-scale patterns

5. The Community is Amazing

When stuck:

6. Errors are Learning Opportunities

Every Error: message taught me something:

Don't fear errors. Read them carefully. They're usually helpful.


Next Steps

Congratulations! You've taken your first steps into Infrastructure as Code. Here's what you've accomplished:

βœ… Understood what Infrastructure as Code is and why it matters βœ… Installed Terraform on your system βœ… Created your first Terraform configuration βœ… Learned the core Terraform workflow (init, plan, apply, destroy) βœ… Understood the role of state files βœ… Established best practices from day one

Practice Exercises

Before moving to Article 2, solidify your understanding:

Exercise 1: Create Multiple Files

Exercise 2: Modify and Reapply

Exercise 3: Destroy and Recreate

Exercise 4: Experiment with Functions

Coming Up Next

In Article 2: Providers, Resources, and the Magic of State Files, we'll dive deeper into:

  • How providers work and how to configure them

  • Resource block anatomy in detail

  • State file deep dive and management

  • Data sources for reading information

  • Multi-provider configurations

  • Real-world example: Building a simple multi-resource infrastructure

Your Infrastructure Journey

Remember that Friday night when I manually rebuilt an entire environment? That was my last Friday night spent clicking through cloud consoles.

With Terraform:

  • Lost environments can be rebuilt with terraform apply

  • Changes are reviewed before deployment

  • Documentation lives in the code

  • Teams can collaborate effectively

  • Sleep soundly knowing infrastructure is reproducible

You're on your way to the same confidence. Keep practicing, keep learning, and remember: every expert started exactly where you are now.


Practice Exercise for This Week: Create a Terraform configuration that creates 3 files representing different environments (dev, staging, prod). Each file should contain:

  • Environment name

  • Creation timestamp

  • A motivational message about IaC

Don't worry about making it perfect. Focus on running through the workflow (init, plan, apply) multiple times until it feels natural.

See you in Article 2! πŸš€


"Infrastructure as Code isn't about technology. It's about treating infrastructure with the same discipline and rigor we apply to application development. Once you understand that, everything else is just syntax." - Me, after rebuilding that staging environment for the last time

Last updated