Explain the concept of Infrastructure as Code.
Quick Answer
Infrastructure as Code manages and provisions infrastructure (servers, networks, databases) through version-controlled, machine-readable configuration files instead of manual setup. It makes environments reproducible, auditable, and consistent, and enables review and automation. Declarative tools (Terraform, Bicep/ARM, CloudFormation) describe desired state, while imperative tools script the steps; IaC is a foundation of reliable CI/CD.
Detailed Answer
Infrastructure as Code (IaC) is the practice of managing and provisioning infrastructure through machine-readable configuration files rather than manual processes or interactive configuration tools.
Key Principles:
-
Declarative vs Imperative:
- Declarative: Define the desired end state (Terraform, ARM templates)
- Imperative: Define steps to achieve the state (scripts, Ansible)
-
Version Control: Infrastructure definitions stored in Git
-
Idempotency: Running the same code multiple times produces the same result
-
Reproducibility: Create identical environments reliably
Benefits of IaC:
- Consistency: Eliminates configuration drift between environments
- Speed: Infrastructure can be provisioned in minutes
- Documentation: Code serves as documentation
- Version Control: Track changes and rollback if needed
- Testing: Test infrastructure changes before production
- Disaster Recovery: Quickly rebuild infrastructure from code
- Cost Management: Easily create/destroy environments to save costs
Popular IaC Tools:
1. Terraform (Multi-Cloud)
# main.tf - Deploy .NET Core app to Azure
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = "myapp-rg"
location = "East US"
}
resource "azurerm_app_service_plan" "asp" {
name = "myapp-asp"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
kind = "Linux"
reserved = true
sku {
tier = "Standard"
size = "S1"
}
}
resource "azurerm_linux_web_app" "webapp" {
name = "myapi-webapp"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_app_service_plan.asp.id
site_config {
application_stack {
dotnet_version = "8.0"
}
}
app_settings = {
"ASPNETCORE_ENVIRONMENT" = "Production"
}
}
resource "azurerm_sql_server" "sql" {
name = "myapp-sqlserver"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
version = "12.0"
administrator_login = "sqladmin"
administrator_login_password = var.sql_password
}
resource "azurerm_sql_database" "db" {
name = "myapp-db"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
server_name = azurerm_sql_server.sql.name
edition = "Standard"
requested_service_objective_name = "S0"
}
output "webapp_url" {
value = azurerm_linux_web_app.webapp.default_hostname
}
2. ARM Templates (Azure-Specific)
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"webAppName": {
"type": "string",
"metadata": {
"description": "Name of the web app"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"resources": [
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('webAppName'), '-plan')]",
"location": "[parameters('location')]",
"sku": {
"name": "S1",
"tier": "Standard"
},
"kind": "linux",
"properties": {
"reserved": true
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('webAppName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', concat(parameters('webAppName'), '-plan'))]"
],
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', concat(parameters('webAppName'), '-plan'))]",
"siteConfig": {
"linuxFxVersion": "DOTNETCORE|8.0"
}
}
}
]
}
3. Bicep (Azure - ARM Template Alternative)
// main.bicep
param webAppName string
param location string = resourceGroup().location
param sqlAdminPassword string
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
name: '${webAppName}-plan'
location: location
sku: {
name: 'S1'
tier: 'Standard'
}
kind: 'linux'
properties: {
reserved: true
}
}
resource webApp 'Microsoft.Web/sites@2022-03-01' = {
name: webAppName
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOTNETCORE|8.0'
appSettings: [
{
name: 'ASPNETCORE_ENVIRONMENT'
value: 'Production'
}
]
}
}
}
output webAppUrl string = webApp.properties.defaultHostName
4. Pulumi (Code-Based IaC with C#)
using Pulumi;
using Pulumi.Azure.Core;
using Pulumi.Azure.AppService;
class MyStack : Stack
{
public MyStack()
{
var resourceGroup = new ResourceGroup("myapp-rg");
var appServicePlan = new Plan("myapp-asp", new PlanArgs
{
ResourceGroupName = resourceGroup.Name,
Kind = "Linux",
Reserved = true,
Sku = new PlanSkuArgs
{
Tier = "Standard",
Size = "S1",
},
});
var app = new AppService("myapp", new AppServiceArgs
{
ResourceGroupName = resourceGroup.Name,
AppServicePlanId = appServicePlan.Id,
SiteConfig = new AppServiceSiteConfigArgs
{
LinuxFxVersion = "DOTNETCORE|8.0",
},
});
this.Endpoint = app.DefaultSiteHostname;
}
[Output]
public Output Endpoint { get; set; }
}
Best Practices:
- Use Version Control: Store IaC in Git repositories
- Modularization: Break down into reusable modules
- Environment Separation: Use workspaces or separate state files
- Secret Management: Never hardcode secrets; use Azure Key Vault, AWS Secrets Manager
- State Management: Use remote state storage (Azure Storage, S3)
- Code Review: Treat infrastructure changes like application code
- Automated Testing: Test infrastructure before deploying
- Documentation: Comment complex configurations