Infrastructure as Code (IaC)

Contents

IaC Fundamentals

Core Concepts

  • Declarative vs Imperative
  • Idempotency
  • State Management
  • Version Control
  • Modularity

Benefits:

  • Consistency and Reproducibility
  • Version Control and History
  • Automated Deployment
  • Documentation as Code
  • Cost Efficiency

Terraform

Basic Configuration

# Provider Configuration provider "aws" { region = "us-west-2" } # Resource Definition resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" tags = { Name = "WebServer" } } # Output Values output "instance_ip" { value = aws_instance.web.public_ip }

Module Structure

# Variables variable "environment" { type = string default = "development" } # Module Definition module "vpc" { source = "./modules/vpc" name = "main-vpc" cidr = "10.0.0.0/16" private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] enable_nat_gateway = true }

Ansible

Playbook Example

# web-server.yml --- - name: Configure web server hosts: web_servers become: yes tasks: - name: Install nginx apt: name: nginx state: present update_cache: yes - name: Copy nginx configuration template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx handlers: - name: restart nginx service: name: nginx state: restarted

Role Structure

# roles/webserver/tasks/main.yml --- - name: Install required packages apt: name: "{{ item }}" state: present with_items: - nginx - php-fpm - mysql-client # roles/webserver/handlers/main.yml --- - name: restart services service: name: "{{ item }}" state: restarted with_items: - nginx - php-fpm

AWS CloudFormation

Template Structure

{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "Web Application Stack", "Parameters": { "InstanceType": { "Type": "String", "Default": "t2.micro", "AllowedValues": ["t2.micro", "t2.small", "t2.medium"] } }, "Resources": { "WebServerInstance": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType": {"Ref": "InstanceType"}, "ImageId": "ami-0c55b159cbfafe1f0", "SecurityGroups": [{"Ref": "WebServerSecurityGroup"}] } } }, "Outputs": { "WebsiteURL": { "Description": "URL for the website", "Value": {"Fn::GetAtt": ["WebServerInstance", "PublicDnsName"]} } } }

Stack Management

# Create Stack aws cloudformation create-stack \ --stack-name my-web-app \ --template-body file://template.json \ --parameters ParameterKey=InstanceType,ParameterValue=t2.small # Update Stack aws cloudformation update-stack \ --stack-name my-web-app \ --template-body file://template.json \ --parameters ParameterKey=InstanceType,ParameterValue=t2.medium

Azure ARM Templates

Template Structure

{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "metadata": { "description": "Storage Account Name" } } }, "resources": [ { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-04-01", "name": "[parameters('storageAccountName')]", "location": "[resourceGroup().location]", "sku": { "name": "Standard_LRS" }, "kind": "StorageV2" } ] }

Deployment

# Deploy Template az deployment group create \ --resource-group MyResourceGroup \ --template-file template.json \ --parameters storageAccountName=mystorageaccount # Export Template az group export \ --name MyResourceGroup \ > exported-template.json

Pulumi

TypeScript Configuration

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; const bucket = new aws.s3.Bucket("my-bucket", { acl: "private", tags: { Environment: "Dev", Name: "My bucket" } }); // Create an S3 object const object = new aws.s3.BucketObject("index.html", { bucket: bucket.id, source: new pulumi.asset.FileAsset("index.html"), acl: "public-read", contentType: "text/html" });

Python Configuration

from pulumi import export from pulumi_azure_native import storage from pulumi_azure_native import resources # Create a resource group resource_group = resources.ResourceGroup("my-group") # Create a storage account account = storage.StorageAccount("storage", resource_group_name=resource_group.name, sku=storage.SkuArgs( name=storage.SkuName.STANDARD_LRS, ), kind=storage.Kind.STORAGE_V2) # Export the connection string export("connection_string", account.name)

Testing Infrastructure

Terraform Testing

# Unit Test provider "test" {} resource "test_assertions" "my_test" { component = "vpc" equal "cidr_block" { description = "CIDR block should match" got = module.vpc.vpc_cidr_block want = "10.0.0.0/16" } }

Serverspec

require 'serverspec' describe 'Nginx Configuration' do describe package('nginx') do it { should be_installed } end describe service('nginx') do it { should be_enabled } it { should be_running } end describe port(80) do it { should be_listening } end end