Introduction to Infrastructure as Code (IaC)

Stanislav Lazarenko
10 min readMar 21, 2023

--

Infrastructure as Code (IaC) is the process of managing and provisioning computing resources, networks, and other infrastructure components through machine-readable definition files, rather than through manual processes or interactive configuration tools. By treating infrastructure like software, you can apply the same practices to infrastructure management as you do for software development, such as version control, code review, and continuous integration.

In the context of Python, there are a few popular tools and libraries that can be used to manage infrastructure as code. Some of these tools include:

  1. Terraform: Terraform is a widely-used IaC tool that allows you to define and manage infrastructure across multiple cloud providers using a declarative language called HCL. Though it is not Python-based, you can interact with Terraform using Python libraries like python-terraform.
  2. Ansible: Ansible is an open-source automation tool that can help you with configuration management, application deployment, and task automation. You can write Ansible playbooks using YAML, and since it’s Python-based, you can extend its functionality using Python modules.
  3. Pulumi: Pulumi is a modern IaC tool that allows you to write infrastructure code using general-purpose programming languages like Python, JavaScript, TypeScript, and Go. With Pulumi, you can define cloud resources using familiar Python constructs and libraries.
  4. Boto3: Boto3 is the official Amazon Web Services (AWS) SDK for Python. It allows you to interact with AWS services and manage infrastructure resources programmatically. Boto3 is particularly useful if you’re working with AWS resources and prefer to work with Python directly.

To get started with Infrastructure as Code using Python, you may want to explore one or more of these tools, depending on your needs and preferred cloud provider.

Infrastructure as Code (IaC) is an approach to managing and provisioning infrastructure components, such as virtual machines, networks, and storage, through machine-readable definition files instead of manual processes or interactive configuration tools. This approach enables you to apply software development principles and practices to infrastructure management.

Here are some key concepts and benefits associated with IaC:

  1. Version control: IaC allows you to maintain your infrastructure configurations in version control systems like Git. This provides a history of changes, enables collaboration among team members, and allows you to roll back to previous configurations if needed.
  2. Consistency: By defining infrastructure as code, you can ensure consistent environments across development, testing, and production stages. This consistency helps reduce potential issues caused by discrepancies between environments.
  3. Reusability: IaC makes it easy to create reusable templates for provisioning resources, which can be shared across different projects and teams, resulting in faster deployments and better consistency.
  4. Automation: IaC enables automation of infrastructure provisioning and management tasks, reducing manual intervention and potential for human error, which leads to more efficient and reliable infrastructure deployments.
  5. Self-documentation: Since infrastructure is defined as code, the code itself can serve as documentation. This makes it easier for team members to understand and maintain the infrastructure.

Overview of Terraform

Terraform is a popular Infrastructure as Code (IaC) tool that uses a declarative language called HashiCorp Configuration Language (HCL) to define and manage infrastructure resources. Although Terraform doesn’t use Python to write the infrastructure code directly, I can provide you with an example of how to create an AWS EC2 instance using Terraform.

First, you need to install Terraform on your machine. You can download it from the official website (https://www.terraform.io/downloads.html).

Create a new directory for your Terraform project and navigate to it in the terminal.

Create a file named main.tf in the directory, and add the following code:

provider "aws" {
region = "us-west-2"
}

resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Enable HTTP access"

ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "aws_instance" "web_server" {
ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 AMI (HVM), SSD Volume Type
instance_type = "t2.micro"

vpc_security_group_ids = [aws_security_group.web_sg.id]

user_data = <<-EOF
#!/bin/bash
echo "Hello, World!" > index.html
nohup python3 -m http.server 80 &
EOF

tags = {
Name = "web-server"
}
}

output "public_ip" {
value = aws_instance.web_server.public_ip
}

output "public_dns" {
value = aws_instance.web_server.public_dns
}

In this example, we define an AWS provider with the us-west-2 region. We create a security group that allows HTTP traffic and an EC2 instance using the Amazon Linux 2 AMI. The instance is associated with the security group and configured with a user data script to serve a "Hello, World!" message using Python's built-in HTTP server. Finally, we define outputs for the instance's public IP and DNS name.

To initialize your Terraform project, run:

terraform init

To preview the changes Terraform will apply, run:

terraform plan

To apply the changes and create the resources, run:

terraform apply

After you’re done with the resources, you can destroy them using:

terraform destroy

Remember that Terraform itself does not use Python, but you can interact with Terraform using Python libraries like python-terraform if you want to integrate it into a Python-based workflow.

Streamlining Your Workflow with python-terraform: Practical Examples

python-terraform is a Python wrapper for interacting with Terraform. It allows you to run Terraform commands from within your Python script or application.

First, you need to install the python-terraform library using pip:

pip install python-terraform

Next, let’s create a simple Python script that uses python-terraform to interact with the Terraform code we wrote earlier (the AWS EC2 instance example).

Create a new Python file named terraform_example.py in the same directory as your main.tf file and add the following code:

from python_terraform import Terraform

# Initialize Terraform
tf = Terraform()
tf.init()

# Run 'terraform plan'
return_code, stdout, stderr = tf.plan()
print("Terraform Plan Output:")
print(stdout)

# Prompt the user to confirm if they want to apply the changes
user_input = input("Do you want to apply the changes? (yes/no): ")

if user_input.lower() == "yes":
# Run 'terraform apply' with auto approval
return_code, stdout, stderr = tf.apply(auto_approve=True)
print("Terraform Apply Output:")
print(stdout)
else:
print("Cancelled.")

# Destroy resources when done (optional)
user_input = input("Do you want to destroy the resources? (yes/no): ")

if user_input.lower() == "yes":
# Run 'terraform destroy' with auto approval
return_code, stdout, stderr = tf.destroy(auto_approve=True)
print("Terraform Destroy Output:")
print(stdout)
else:
print("Resources not destroyed.")

This script initializes Terraform, runs terraform plan to preview the changes, prompts the user to apply the changes, and then optionally destroys the resources when done.

To run the script, simply execute the following command in your terminal:

python terraform_example.py

The python-terraform library provides an easy way to interact with Terraform from Python, which can be useful for integrating Terraform into Python-based applications, workflows, or automations. However, keep in mind that the actual infrastructure code is still written in HCL (Terraform language) and not in Python.

Streamlining Your Workflow with Ansible: Practical Example

Ansible is an automation tool that helps you with configuration management, application deployment, and task automation. It uses YAML to define “playbooks” that describe the desired state of your infrastructure.

First, you need to install Ansible on your machine. You can follow the official installation guide here: https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html

Next, let’s create an Ansible playbook to create an AWS EC2 instance, similar to the previous examples.

Create a new directory for your Ansible project and navigate to it in the terminal.

Create a file named requirements.yml in the directory, and add the following content:

---
- name: community.aws
src: https://github.com/ansible-collections/community.aws.git
version: main

This file specifies that we need the community.aws collection to work with AWS resources.

Install the required collections by running:

ansible-galaxy collection install -r requirements.yml

Create a file named ec2_playbook.yml in the directory, and add the following content:

---
- name: Create AWS EC2 instance
hosts: localhost
gather_facts: no
tasks:
- name: Launch EC2 instance
community.aws.ec2_instance:
name: "web-server"
region: "us-west-2"
instance_type: "t2.micro"
image_id: "ami-0c55b159cbfafe1f0" # Amazon Linux 2 AMI (HVM), SSD Volume Type
security_group: "web-sg"
key_name: "your-key-pair" # Replace with your own key pair name
user_data: |
#!/bin/bash
echo "Hello, World!" > index.html
nohup python3 -m http.server 80 &
wait: yes
wait_timeout: 300
state: present
register: ec2_instance

- name: Display instance information
debug:
var: ec2_instance

This playbook creates an EC2 instance using the community.aws.ec2_instance module. Replace "your-key-pair" with the name of your own AWS key pair.

To run the playbook, execute the following command in your terminal:

ansible-playbook ec2_playbook.yml

Ansible doesn’t have a built-in Python API to run playbooks like Terraform’s python-terraform wrapper. However, you can run Ansible playbooks from within your Python script using the subprocess module.

Here’s a simple example of how to run the Ansible playbook from a Python script:

import subprocess

# Run the Ansible playbook
command = ["ansible-playbook", "ec2_playbook.yml"]
process = subprocess.run(command, capture_output=True, text=True)

# Display the output
print("Ansible Playbook Output:")
print(process.stdout)

Save this script as ansible_example.py in the same directory as your ec2_playbook.yml file and execute it with the following command:

python ansible_example.py

Keep in mind that this approach runs the Ansible command as a subprocess, which means that you won’t have direct access to the Ansible API from within your Python script. If you need more advanced integration with Ansible, you might want to look into Ansible Runner (https://ansible-runner.readthedocs.io/), which provides a Python API for interacting with Ansible.

Unlocking the Power of AWS with Boto3: Python script implementation

Boto3 is the official AWS SDK for Python, which allows you to interact with AWS services and manage infrastructure resources programmatically. Here’s an example of how to create an EC2 instance using Boto3.

First, make sure you have installed Boto3:

pip install boto3
  1. Configure your AWS credentials. You can either set environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN if needed) or configure them in the AWS CLI configuration file (~/.aws/credentials).
  2. Create a Python script named boto3_example.py and add the following code:
import boto3

# Create a Boto3 session
session = boto3.Session(region_name="us-west-2")

# Create an EC2 client
ec2 = session.client("ec2")

# Create a security group
response = ec2.create_security_group(
GroupName="web-sg",
Description="Enable HTTP access",
)
security_group_id = response["GroupId"]

# Add an ingress rule to the security group
ec2.authorize_security_group_ingress(
GroupId=security_group_id,
IpProtocol="tcp",
FromPort=80,
ToPort=80,
CidrIp="0.0.0.0/0",
)

# Create an EC2 instance
user_data = """#!/bin/bash
echo "Hello, World!" > index.html
nohup python3 -m http.server 80 &
"""

response = ec2.run_instances(
ImageId="ami-0c55b159cbfafe1f0", # Amazon Linux 2 AMI (HVM), SSD Volume Type
InstanceType="t2.micro",
MinCount=1,
MaxCount=1,
SecurityGroupIds=[security_group_id],
UserData=user_data,
)

# Get the instance ID
instance_id = response["Instances"][0]["InstanceId"]

# Print the instance ID
print("Created EC2 instance with ID:", instance_id)

# Terminate the instance when done (optional)
terminate_input = input("Do you want to terminate the instance? (yes/no): ")

if terminate_input.lower() == "yes":
ec2.terminate_instances(InstanceIds=[instance_id])
print("Terminated EC2 instance with ID:", instance_id)
else:
print("Instance not terminated.")

This script creates an EC2 client using Boto3, creates a security group, adds an ingress rule to the security group, and then creates an EC2 instance associated with that security group. The instance is configured with a user data script to serve a “Hello, World!” message using Python’s built-in HTTP server. The script also prompts the user whether to terminate the instance when done.

Run the script with the following command:

python boto3_example.py

Boto3 allows you to manage AWS resources using Python directly, giving you a lot of flexibility and control over how you interact with AWS services.

Infrastructure as Code Made Easy: Building and Managing Cloud Resources with Pulumi (Python):

Creation example for the AWS EC2 instance using Pulumi with Python.

import pulumi
from pulumi_aws import ec2

# Create a security group that allows HTTP traffic
web_sg = ec2.SecurityGroup("web-sg",
description="Enable HTTP access",
ingress=[
ec2.SecurityGroupIngressArgs(
protocol="tcp",
from_port=80,
to_port=80,
cidr_blocks=["0.0.0.0/0"],
),
],
)

# Create an EC2 instance
web_server = ec2.Instance("web-server",
instance_type="t2.micro",
ami="ami-0c55b159cbfafe1f0", # Amazon Linux 2 AMI (HVM), SSD Volume Type
vpc_security_group_ids=[web_sg.id],
user_data="""#!/bin/bash
echo "Hello, World!" > index.html
nohup python3 -m http.server 80 &
""",
)

# Export the instance's public IP and DNS name
pulumi.export("public_ip", web_server.public_ip)
pulumi.export("public_dns", web_server.public_dns)

In this example, we first create a security group that allows HTTP traffic, and then create an EC2 instance using the Amazon Linux 2 AMI. The instance is configured with a simple user data script to serve a “Hello, World!” message using Python’s built-in HTTP server. Finally, we export the instance’s public IP and DNS name.

With this code, you can manage the EC2 instance using Pulumi commands, such as pulumi up to create or update the resources and pulumi destroy to delete the resources.

Conclusion

In conclusion, Infrastructure as Code (IaC) allows for the management and provisioning of infrastructure components through machine-readable definition files instead of manual processes or interactive configuration tools. Python has several popular tools and libraries for managing IaC, including Terraform, Ansible, Pulumi, and Boto3. By treating infrastructure like software, you can apply software development principles and practices to infrastructure management, including version control, consistency, reusability, automation, and self-documentation. Depending on your needs and preferred cloud provider, you can choose to explore one or more of these tools. While each of these tools has its strengths and weaknesses, they all aim to provide a simple and efficient way of creating and managing infrastructure resources in the cloud.

--

--