ในบทความนี้
In this post
จากโพสต์ที่แล้วเราเรียนรู้ Networking พื้นฐาน — DNS, Firewall, Load Balancer, SSH
แต่ลองนึกภาพว่าต้อง setup server 50 เครื่อง... จะ SSH เข้าไปตั้งค่าทีละเครื่องจริงเหรอ? 😰
นี่คือที่มาของ Infrastructure as Code (IaC) — เขียน code เพื่อสร้างและจัดการ infrastructure ทั้งหมด แทนที่จะทำด้วยมือ เหมือนเขียนสูตรอาหารแทนที่จะจำในหัว 📝🐕
IaC คืออะไร?
Infrastructure as Code คือแนวคิดที่ว่า — infrastructure (server, network, database, firewall) ควรถูก กำหนดด้วย code ไม่ใช่การคลิกบน console หรือพิมพ์คำสั่งทีละบรรทัด
ข้อดีของ IaC: repeatable (ทำซ้ำได้เหมือนเดิมทุกครั้ง), version controlled (เก็บใน Git ดู history ได้), reviewable (review infrastructure changes เหมือน code review), testable (ทดสอบก่อน apply ได้) — เปรียบเทียบก่อนและหลัง IaC:
ก่อน IaC (Manual) 😩
- Login เข้า AWS Console
- คลิก "Create EC2 Instance"
- เลือก Ubuntu, t3.medium, 50GB disk...
- SSH เข้าไปติดตั้ง Nginx, Node.js, PostgreSQL...
- ทำ 50 ครั้ง ❌
หลัง IaC (Automated) 🚀
- เขียน Terraform → สร้าง 50 servers
- เขียน Ansible → ติดตั้ง software ทั้ง 50 เครื่อง
- รัน 1 คำสั่ง ✅
💡 หลักการสำคัญ:
✅ Repeatable — ทำซ้ำได้ผลเหมือนเดิมทุกครั้ง
✅ Version-controlled — เก็บใน Git, ดู history ได้
✅ Reviewable — ทีม review ก่อน apply
✅ Testable — ทดสอบก่อน deploy ได้
Terraform vs Ansible — ใช้ตัวไหน?
คำตอบคือ ใช้ทั้งคู่! เพราะทำหน้าที่ต่างกัน — Terraform "สร้าง" infrastructure (VMs, networks, databases, load balancers) ส่วน Ansible "ตั้งค่า" สิ่งที่สร้างมา (install software, configure services, deploy apps) Terraform เป็น declarative (บอกว่า "ต้องการอะไร") Ansible เป็น procedural (บอกว่า "ทำอะไรทีละขั้น"):
| Feature | Terraform | Ansible |
|---|---|---|
| หน้าที่หลัก | สร้าง/จัดการ infrastructure | ตั้งค่า/ติดตั้ง software |
| ประเภท | Provisioning tool | Configuration Management tool |
| ภาษา | HCL (HashiCorp Config Language) | YAML (Playbooks) |
| วิธีทำงาน | Declarative — บอก "ต้องการอะไร" | Procedural + Declarative |
| State | ✅ มี state file ติดตาม | ❌ Agentless, ไม่มี state |
| ตัวอย่าง | สร้าง EC2, VPC, RDS, S3 | ติดตั้ง Nginx, Deploy app |
| Cloud Support | AWS, GCP, Azure, DigitalOcean, +100 providers | SSH เข้าเครื่องไหนก็ได้ |
💡 จำง่ายๆ: Terraform = สร้างเครื่อง | Ansible = ตั้งค่าเครื่อง
Terraform — สร้าง Infrastructure ด้วย Code
Terraform โดย HashiCorp เป็น IaC tool ที่ได้รับความนิยมสูงสุด — รองรับ cloud providers ทุกเจ้า (AWS, Azure, GCP, DigitalOcean, etc.) ด้วย provider plugins ใช้ภาษา HCL (HashiCorp Configuration Language) ที่อ่านง่าย และจัดการ state ของ infrastructure ให้อัตโนมัติ
Terraform ทำงานยังไง?
Terraform workflow มี 3 ขั้นตอนหลัก: Write (เขียน .tf files), Plan (ดูว่าจะเปลี่ยนอะไร — เหมือน dry run), Apply (สร้าง/แก้ infrastructure จริง) สิ่งสำคัญคือ terraform plan แสดง diff ก่อน apply เสมอ — ไม่มีเซอร์ไพรส์!
ตัวอย่าง: สร้าง AWS EC2 Instance
ตัวอย่าง main.tf ด้านล่างสร้าง EC2 instance บน AWS — สังเกตว่า HCL อ่านง่ายมาก: กำหนด provider (AWS, region), resource (instance type, AMI, security group), และ output (IP address) ทุกอย่างเป็น declarative:
# กำหนด provider (Cloud ที่จะใช้)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-southeast-1" # Singapore
}
# สร้าง EC2 Instance
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0" # Ubuntu 22.04
instance_type = "t3.medium"
tags = {
Name = "web-server-01"
Environment = "production"
ManagedBy = "terraform"
}
# Security Group
vpc_security_group_ids = [aws_security_group.web_sg.id]
}
# สร้าง Security Group
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Allow HTTP and SSH"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # HTTP จากทุกที่
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"] # SSH จาก private network เท่านั้น
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Output — แสดง IP ที่ได้
output "server_ip" {
value = aws_instance.web_server.public_ip
}
# Terraform commands
terraform init # ดาวน์โหลด provider plugins
terraform plan # ดู preview ว่าจะสร้างอะไร
terraform apply # สร้างจริง! (ถาม yes/no)
terraform destroy # ลบทั้งหมด (ระวัง!)
# ตัวอย่าง output ของ terraform plan:
# + aws_instance.web_server
# ami: "ami-0c55b159cbfafe1f0"
# instance_type: "t3.medium"
#
# Plan: 2 to add, 0 to change, 0 to destroy.
Terraform สร้างหลายเครื่องพร้อมกัน
พลังของ IaC เห็นชัดเมื่อต้องสร้างหลายเครื่อง — แค่ใช้ count หรือ for_each ก็สร้าง 10, 50, 100 เครื่องได้ในคำสั่งเดียว ลองทำแบบ manual ดู!
# ใช้ count สร้าง 5 เครื่องรวด!
resource "aws_instance" "web_cluster" {
count = 5
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
tags = {
Name = "web-server-${count.index + 1}"
}
}
# Output ทุก IP
output "server_ips" {
value = aws_instance.web_cluster[*].public_ip
}
# → ["10.0.1.1", "10.0.1.2", "10.0.1.3", "10.0.1.4", "10.0.1.5"]
Ansible — ตั้งค่า Server อัตโนมัติ
Ansible โดย Red Hat เป็น configuration management tool ที่ใช้ง่ายที่สุด — เขียน playbooks ด้วย YAML ธรรมดา ไม่ต้องเรียนภาษาใหม่ เหมาะกับ: install packages, configure services, deploy applications, manage users/permissions
Ansible ทำงานยังไง?
Ansible เป็น agentless — ไม่ต้องติดตั้งอะไรบนเครื่องเป้าหมาย ใช้ SSH เข้าไปรันคำสั่งเลย! ต่างจาก Chef/Puppet ที่ต้องติดตั้ง agent บนทุกเครื่อง ทำให้ setup ง่ายและ maintain น้อยกว่า มี 2 ส่วนหลัก: Inventory (รายชื่อ servers) และ Playbook (สิ่งที่ต้องทำ):
Step 1: Inventory — บอกว่ามี server อะไรบ้าง
Inventory คือไฟล์ที่บอก Ansible ว่า "มี server อะไรบ้าง แบ่งเป็นกลุ่มอะไร" สามารถจัดกลุ่มเป็น webservers, databases, monitoring ได้ — แล้วรัน playbook เฉพาะกลุ่ม:
all:
children:
webservers:
hosts:
web1:
ansible_host: 10.0.1.1
web2:
ansible_host: 10.0.1.2
web3:
ansible_host: 10.0.1.3
databases:
hosts:
db1:
ansible_host: 10.0.2.1
vars:
ansible_user: deploy
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
Step 2: Playbook — บอกว่าต้องทำอะไร
Playbook คือ YAML file ที่อธิบาย "ต้องทำอะไรบ้าง" ทีละ task — Ansible จะรันตามลำดับ แต่ละ task ใช้ module (เช่น apt, copy, service, template) ที่เป็น idempotent คือรันกี่ครั้งก็ได้ผลเหมือนกัน ตัวอย่าง setup web server:
---
- name: Setup Web Servers
hosts: webservers
become: yes # ใช้ sudo
tasks:
# อัพเดท system
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
# ติดตั้ง Nginx
- name: Install Nginx
apt:
name: nginx
state: present
# ติดตั้ง Node.js 20
- name: Add NodeSource repository
shell: curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
- name: Install Node.js
apt:
name: nodejs
state: present
# Copy config file
- name: Deploy Nginx config
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/myapp
notify: Restart Nginx
# เปิด firewall
- name: Allow HTTP through firewall
ufw:
rule: allow
port: "80"
proto: tcp
# ตรวจสอบว่า Nginx ทำงาน
- name: Ensure Nginx is running
service:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
# รัน playbook
ansible-playbook -i inventory.yml setup-webserver.yml
# ดูผลลัพธ์:
# PLAY [Setup Web Servers] *************************************
# TASK [Install Nginx] *****************************************
# changed: [web1]
# changed: [web2]
# changed: [web3]
#
# PLAY RECAP ***************************************************
# web1: ok=7 changed=5 unreachable=0 failed=0
# web2: ok=7 changed=5 unreachable=0 failed=0
# web3: ok=7 changed=5 unreachable=0 failed=0
Ansible Ad-hoc Commands — ไม่ต้องเขียน playbook
สำหรับงานเร็วๆ ที่ไม่ต้องเขียน playbook — ใช้ ad-hoc commands รันคำสั่งเดียวบนหลายเครื่องพร้อมกัน เช่น check uptime ทุกเครื่อง, restart service, copy file:
# Ping ทุกเครื่อง
ansible all -i inventory.yml -m ping
# ดู disk space ทุก webserver
ansible webservers -i inventory.yml -a "df -h"
# ติดตั้ง package ด่วน
ansible webservers -i inventory.yml -m apt -a "name=htop state=present" --become
# Restart service
ansible webservers -i inventory.yml -m service -a "name=nginx state=restarted" --become
Terraform + Ansible ทำงานร่วมกัน
Workflow ที่ดีที่สุดคือใช้ ทั้งคู่ร่วมกัน — Terraform สร้าง infrastructure (VMs, VPC, Load Balancer) แล้วส่ง output (IP addresses) ให้ Ansible ไปตั้งค่า (install Docker, deploy app, configure monitoring) เหมือน Terraform "สร้างบ้าน" แล้ว Ansible "ตกแต่งภายใน":
# 1. Terraform สร้าง infrastructure
cd terraform/
terraform apply -auto-approve
# 2. Export IP ที่ได้ เป็น Ansible inventory
terraform output -json server_ips | \
jq -r '.[] | " " + . ' > ../ansible/hosts.txt
# 3. Ansible ตั้งค่าทุกเครื่อง
cd ../ansible/
ansible-playbook -i inventory.yml setup-all.yml
IaC Tools อื่นๆ ที่น่ารู้
นอกจาก Terraform + Ansible ยังมี IaC tools อื่นๆ ที่น่าสนใจ — แต่ละตัวมีจุดแข็งต่างกัน เลือกตามความเหมาะสมของทีมและ use case:
| Tool | ประเภท | จุดเด่น |
|---|---|---|
| Terraform | Provisioning | HCL, multi-cloud, state management |
| Ansible | Config Management | YAML, agentless, simple |
| Pulumi | Provisioning | เขียนด้วย Python/TypeScript/Go แทน HCL |
| CloudFormation | Provisioning | AWS native, JSON/YAML |
| Chef / Puppet | Config Management | Enterprise-grade, agent-based |
| OpenTofu | Provisioning | Terraform fork (open-source) |
Best Practices
IaC ทำให้ infrastructure เป็น code ดังนั้นต้อง treat เหมือน code จริงๆ — version control, code review, testing, modularization หลักการสำคัญที่ต้องทำ:
- เก็บ IaC ใน Git — ทุก infrastructure change ต้องผ่าน PR review
- ใช้ modules — แยก code เป็น module ที่ reuse ได้
- แยก environment — dev / staging / production ใช้ config คนละชุด
- อย่าเก็บ secrets ใน code — ใช้ Vault, AWS Secrets Manager, หรือ environment variables
- ใช้ remote state — Terraform state เก็บใน S3 + DynamoDB lock ไม่ใช่ local
- Plan ก่อน Apply เสมอ — อ่าน plan ให้ดีก่อนกด yes!
- Idempotent — รันกี่ครั้งก็ได้ผลเหมือนเดิม
# Terraform remote state (best practice)
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
🐕 กฎทอง: ถ้า infrastructure ไม่ได้อยู่ใน code = มันไม่มีอยู่จริง ทุกอย่างต้อง reproducible!
สรุป
Infrastructure as Code เปลี่ยนวิธีจัดการ infrastructure จาก "จำในหัว + ทำด้วยมือ" เป็น "เขียน code + automate ทั้งหมด" ผลลัพธ์คือ: สร้าง environment ใหม่ได้ในนาที, disaster recovery เร็วขึ้น 100 เท่า, ทุกการเปลี่ยนแปลงมี audit trail ใน Git:
- IaC = จัดการ infrastructure ด้วย code แทนการทำมือ
- Terraform = สร้าง infrastructure (EC2, VPC, RDS) ด้วย HCL →
plan→apply - Ansible = ตั้งค่า software (Nginx, Docker, app) ด้วย YAML Playbooks ผ่าน SSH
- ใช้ทั้งคู่ = Terraform สร้างเครื่อง → Ansible ตั้งค่าเครื่อง → Production ready!
- Best Practices = Git, modules, remote state, แยก env, ไม่เก็บ secrets ใน code
- เริ่มต้นง่ายๆ:
terraform init → plan → apply+ansible-playbook📝🐕
In the previous post we covered the networking fundamentals — DNS, firewalls, load balancers, SSH.
But picture having to set up 50 servers... are you really going to SSH into each one and configure it by hand? 😰
This is where Infrastructure as Code (IaC) comes in — writing code to create and manage your entire infrastructure instead of doing it by hand. Like writing the recipe down instead of keeping it in your head 📝🐕
What is IaC?
Infrastructure as Code is the idea that infrastructure — servers, networks, databases, firewalls — should be defined in code, not clicked together in a console or typed one command at a time.
The benefits of IaC: repeatable (the same result every time), version controlled (kept in Git, with a history you can read), reviewable (infrastructure changes go through review, just like code), testable (you can test before you apply) — compare life before and after IaC:
Before IaC (Manual) 😩
- Log in to the AWS Console
- Click "Create EC2 Instance"
- Pick Ubuntu, t3.medium, 50GB disk...
- SSH in and install Nginx, Node.js, PostgreSQL...
- Do it 50 times ❌
After IaC (Automated) 🚀
- Write Terraform → 50 servers created
- Write Ansible → software installed on all 50
- Run one command ✅
💡 The core principles:
✅ Repeatable — the same result on every run
✅ Version-controlled — kept in Git, with a readable history
✅ Reviewable — the team reviews before you apply
✅ Testable — test it before you deploy
Terraform vs Ansible — which one?
The answer is both! Because they do different jobs — Terraform "builds" infrastructure (VMs, networks, databases, load balancers) while Ansible "configures" what was built (install software, configure services, deploy apps). Terraform is declarative (you state "what you want"); Ansible is procedural (you state "what to do, step by step"):
| Feature | Terraform | Ansible |
|---|---|---|
| Primary job | Create/manage infrastructure | Configure/install software |
| Category | Provisioning tool | Configuration Management tool |
| Language | HCL (HashiCorp Config Language) | YAML (Playbooks) |
| How it works | Declarative — you state "what you want" | Procedural + Declarative |
| State | ✅ Tracks a state file | ❌ Agentless, no state |
| Examples | Create EC2, VPC, RDS, S3 | Install Nginx, deploy an app |
| Cloud Support | AWS, GCP, Azure, DigitalOcean, +100 providers | Any machine you can SSH into |
💡 An easy way to remember it: Terraform = build the machine | Ansible = configure the machine
Terraform — building infrastructure with code
Terraform, by HashiCorp, is the most widely adopted IaC tool — it supports every cloud provider (AWS, Azure, GCP, DigitalOcean, etc.) through provider plugins, uses the readable HCL (HashiCorp Configuration Language), and manages your infrastructure's state for you.
How does Terraform work?
The Terraform workflow has three main steps: Write (author your .tf files), Plan (see what will change — a dry run), Apply (actually create or modify the infrastructure). The important part is that terraform plan always shows you the diff before you apply — no surprises!
Example: creating an AWS EC2 instance
The main.tf below creates an EC2 instance on AWS — notice how readable HCL is: you declare the provider (AWS, region), the resource (instance type, AMI, security group), and an output (the IP address). Everything is declarative:
# Declare the provider (the cloud you will use)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-southeast-1" # Singapore
}
# Create an EC2 instance
resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0" # Ubuntu 22.04
instance_type = "t3.medium"
tags = {
Name = "web-server-01"
Environment = "production"
ManagedBy = "terraform"
}
# Security Group
vpc_security_group_ids = [aws_security_group.web_sg.id]
}
# Create the Security Group
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Allow HTTP and SSH"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # HTTP from anywhere
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"] # SSH from the private network only
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Output — show the IP we got
output "server_ip" {
value = aws_instance.web_server.public_ip
}
# Terraform commands
terraform init # download the provider plugins
terraform plan # preview what will be created
terraform apply # build it for real! (asks yes/no)
terraform destroy # tear it all down (careful!)
# Sample terraform plan output:
# + aws_instance.web_server
# ami: "ami-0c55b159cbfafe1f0"
# instance_type: "t3.medium"
#
# Plan: 2 to add, 0 to change, 0 to destroy.
Terraform builds many machines at once
The power of IaC becomes obvious the moment you need more than one machine — count or for_each will build 10, 50 or 100 servers from a single command. Try that by hand!
# Use count to build 5 machines in one go!
resource "aws_instance" "web_cluster" {
count = 5
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
tags = {
Name = "web-server-${count.index + 1}"
}
}
# Output every IP
output "server_ips" {
value = aws_instance.web_cluster[*].public_ip
}
# → ["10.0.1.1", "10.0.1.2", "10.0.1.3", "10.0.1.4", "10.0.1.5"]
Ansible — configuring servers automatically
Ansible, by Red Hat, is the easiest configuration management tool to pick up — you write playbooks in ordinary YAML, with no new language to learn. It is a good fit for installing packages, configuring services, deploying applications, and managing users and permissions.
How does Ansible work?
Ansible is agentless — nothing has to be installed on the target machine; it simply SSHes in and runs the commands. That is unlike Chef or Puppet, which need an agent on every host, and it makes setup easier and maintenance lighter. There are two main pieces: the Inventory (the list of servers) and the Playbook (what to do):
Step 1: Inventory — tell it which servers exist
The Inventory is the file that tells Ansible "these are the servers, and these are the groups they fall into". You can group them as webservers, databases, monitoring — then run a playbook against one group only:
all:
children:
webservers:
hosts:
web1:
ansible_host: 10.0.1.1
web2:
ansible_host: 10.0.1.2
web3:
ansible_host: 10.0.1.3
databases:
hosts:
db1:
ansible_host: 10.0.2.1
vars:
ansible_user: deploy
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
Step 2: Playbook — tell it what to do
A Playbook is a YAML file describing what has to happen, one task at a time — Ansible runs them in order. Each task uses a module (apt, copy, service, template, and so on) that is idempotent: run it any number of times and the result is the same. Here is a web server setup:
---
- name: Setup Web Servers
hosts: webservers
become: yes # use sudo
tasks:
# Update the system
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
# Install Nginx
- name: Install Nginx
apt:
name: nginx
state: present
# Install Node.js 20
- name: Add NodeSource repository
shell: curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
- name: Install Node.js
apt:
name: nodejs
state: present
# Copy config file
- name: Deploy Nginx config
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/myapp
notify: Restart Nginx
# Open the firewall
- name: Allow HTTP through firewall
ufw:
rule: allow
port: "80"
proto: tcp
# Check that Nginx is running
- name: Ensure Nginx is running
service:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
# Run the playbook
ansible-playbook -i inventory.yml setup-webserver.yml
# The output:
# PLAY [Setup Web Servers] *************************************
# TASK [Install Nginx] *****************************************
# changed: [web1]
# changed: [web2]
# changed: [web3]
#
# PLAY RECAP ***************************************************
# web1: ok=7 changed=5 unreachable=0 failed=0
# web2: ok=7 changed=5 unreachable=0 failed=0
# web3: ok=7 changed=5 unreachable=0 failed=0
Ansible ad-hoc commands — no playbook required
For quick jobs that do not deserve a playbook, use ad-hoc commands to run a single command across many machines at once — check uptime everywhere, restart a service, copy a file:
# Ping every machine
ansible all -i inventory.yml -m ping
# Check disk space on every webserver
ansible webservers -i inventory.yml -a "df -h"
# Install a package in a hurry
ansible webservers -i inventory.yml -m apt -a "name=htop state=present" --become
# Restart a service
ansible webservers -i inventory.yml -m service -a "name=nginx state=restarted" --become
Terraform + Ansible working together
The best workflow uses both together — Terraform creates the infrastructure (VMs, VPC, load balancer), then hands its output (the IP addresses) to Ansible, which configures it (install Docker, deploy the app, set up monitoring). Terraform "builds the house"; Ansible "furnishes the rooms":
# 1. Terraform builds the infrastructure
cd terraform/
terraform apply -auto-approve
# 2. Export the IPs it returned as an Ansible inventory
terraform output -json server_ips | \
jq -r '.[] | " " + . ' > ../ansible/hosts.txt
# 3. Ansible configures every machine
cd ../ansible/
ansible-playbook -i inventory.yml setup-all.yml
Other IaC tools worth knowing
Beyond Terraform + Ansible there are other IaC tools worth a look — each has a different strength, so pick the one that suits your team and your use case:
| Tool | Category | Strength |
|---|---|---|
| Terraform | Provisioning | HCL, multi-cloud, state management |
| Ansible | Config Management | YAML, agentless, simple |
| Pulumi | Provisioning | Written in Python/TypeScript/Go instead of HCL |
| CloudFormation | Provisioning | AWS native, JSON/YAML |
| Chef / Puppet | Config Management | Enterprise-grade, agent-based |
| OpenTofu | Provisioning | Terraform fork (open-source) |
Best Practices
IaC turns infrastructure into code, so you have to treat it like real code — version control, code review, testing, modularization. The principles that matter:
- Keep your IaC in Git — every infrastructure change goes through PR review
- Use modules — split the code into reusable modules
- Separate your environments — dev / staging / production each get their own config
- Never keep secrets in code — use Vault, AWS Secrets Manager, or environment variables
- Use remote state — keep Terraform state in S3 with a DynamoDB lock, not locally
- Always plan before you apply — read the plan carefully before pressing yes!
- Idempotent — run it any number of times, get the same result
# Terraform remote state (best practice)
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
🐕 The golden rule: if the infrastructure is not in code, it does not really exist. Everything has to be reproducible!
Summary
Infrastructure as Code changes how you manage infrastructure — from "remember it and do it by hand" to "write the code and automate all of it". The results: a new environment in minutes, disaster recovery 100 times faster, and an audit trail in Git for every change:
- IaC = manage infrastructure with code instead of by hand
- Terraform = build the infrastructure (EC2, VPC, RDS) in HCL →
plan→apply - Ansible = configure the software (Nginx, Docker, the app) with YAML playbooks over SSH
- Use both = Terraform builds the machine → Ansible configures it → production ready!
- Best Practices = Git, modules, remote state, separate environments, no secrets in code
- An easy place to start:
terraform init → plan → applyplusansible-playbook📝🐕