Managing Azure Container Instances with Terraform

Learn how to set up and manage Azure Container Instances using Terraform, including container groups, volumes, and monitoring

Managing Azure Container Instances with Terraform

Azure Container Instances (ACI) provides a serverless container hosting environment without the need to manage the underlying infrastructure. This guide demonstrates how to set up and manage ACI using Terraform.

Video Tutorial

Learn more about managing Azure Container Instances with Terraform in this comprehensive video tutorial:

Prerequisites

  • Azure CLI configured with appropriate permissions
  • Terraform installed (version 1.0.0 or later)
  • Resource group created
  • Understanding of container concepts

Project Structure

terraform-azure-aci/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│   └── aci/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── configs/
    └── container.json

Container Instance Configuration

Create modules/aci/main.tf:

# Container Group
resource "azurerm_container_group" "main" {
  name                = "${var.project_name}-aci"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_address_type     = "Public"
  dns_name_label      = "${var.project_name}-aci"
  os_type             = "Linux"

  container {
    name   = "app"
    image  = "mcr.microsoft.com/azuredocs/aci-helloworld:latest"
    cpu    = "0.5"
    memory = "1.5"

    ports {
      port     = 80
      protocol = "TCP"
    }

    environment_variables = {
      "NODE_ENV" = "production"
    }

    secure_environment_variables = {
      "API_KEY" = var.api_key
    }

    volume {
      name       = "config"
      mount_path = "/app/config"
      
      secret = {
        "config.json" = base64encode(jsonencode({
          "apiUrl": "https://api.example.com",
          "logLevel": "info"
        }))
      }
    }

    liveness_probe {
      http_get {
        path   = "/health"
        port   = 80
        scheme = "Http"
      }
      initial_delay_seconds = 30
      period_seconds       = 10
      failure_threshold    = 3
      success_threshold    = 1
      timeout_seconds      = 1
    }

    readiness_probe {
      http_get {
        path   = "/ready"
        port   = 80
        scheme = "Http"
      }
      initial_delay_seconds = 30
      period_seconds       = 10
      failure_threshold    = 3
      success_threshold    = 1
      timeout_seconds      = 1
    }
  }

  container {
    name   = "sidecar"
    image  = "mcr.microsoft.com/azuredocs/aci-tutorial-sidecar"
    cpu    = "0.5"
    memory = "0.5"

    ports {
      port     = 8080
      protocol = "TCP"
    }
  }

  identity {
    type = "SystemAssigned"
  }

  image_registry_credential {
    server   = var.acr_server
    username = var.acr_username
    password = var.acr_password
  }

  diagnostics {
    log_analytics {
      workspace_id  = var.log_analytics_workspace_id
      workspace_key = var.log_analytics_workspace_key
      log_type      = "ContainerInsights"
      metadata = {
        "Environment" = var.environment
      }
    }
  }

  tags = var.tags
}

# Network Profile
resource "azurerm_network_profile" "main" {
  name                = "${var.project_name}-network-profile"
  location            = var.location
  resource_group_name = var.resource_group_name

  container_network_interface {
    name = "aci-nic"

    ip_configuration {
      name      = "aci-ipconfig"
      subnet_id = var.subnet_id
    }
  }

  tags = var.tags
}

# Container Group with Virtual Network
resource "azurerm_container_group" "vnet" {
  name                = "${var.project_name}-aci-vnet"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_address_type     = "Private"
  network_profile_id  = azurerm_network_profile.main.id
  os_type             = "Linux"

  container {
    name   = "app"
    image  = "mcr.microsoft.com/azuredocs/aci-helloworld:latest"
    cpu    = "0.5"
    memory = "1.5"

    ports {
      port     = 80
      protocol = "TCP"
    }
  }

  tags = var.tags
}

# Storage Account for File Share
resource "azurerm_storage_account" "main" {
  name                     = "${var.project_name}storage"
  resource_group_name      = var.resource_group_name
  location                 = var.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  tags = var.tags
}

# File Share
resource "azurerm_storage_share" "main" {
  name                 = "acishare"
  storage_account_name = azurerm_storage_account.main.name
  quota                = 50
}

# Container Group with Storage
resource "azurerm_container_group" "storage" {
  name                = "${var.project_name}-aci-storage"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_address_type     = "Public"
  dns_name_label      = "${var.project_name}-aci-storage"
  os_type             = "Linux"

  container {
    name   = "app"
    image  = "mcr.microsoft.com/azuredocs/aci-hellofiles"
    cpu    = "0.5"
    memory = "1.5"

    ports {
      port     = 80
      protocol = "TCP"
    }

    volume {
      name       = "aci-storage"
      mount_path = "/aci/logs"
      share_name = azurerm_storage_share.main.name

      storage_account_name = azurerm_storage_account.main.name
      storage_account_key  = azurerm_storage_account.main.primary_access_key
    }
  }

  tags = var.tags
}

## Monitoring Configuration

1. **Diagnostic Settings**
```hcl
resource "azurerm_monitor_diagnostic_setting" "aci" {
  name                       = "${var.project_name}-diag"
  target_resource_id        = azurerm_container_group.main.id
  log_analytics_workspace_id = var.log_analytics_workspace_id

  log {
    category = "ContainerInstanceLog"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }

  metric {
    category = "AllMetrics"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }
}

# Container Alerts
resource "azurerm_monitor_metric_alert" "cpu" {
  name                = "${var.project_name}-cpu-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_container_group.main.id]
  description         = "Alert when CPU usage is high"

  criteria {
    metric_namespace = "Microsoft.ContainerInstance/containerGroups"
    metric_name      = "CpuUsage"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 80
  }

  action {
    action_group_id = var.action_group_id
  }
}

resource "azurerm_monitor_metric_alert" "memory" {
  name                = "${var.project_name}-memory-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_container_group.main.id]
  description         = "Alert when memory usage is high"

  criteria {
    metric_namespace = "Microsoft.ContainerInstance/containerGroups"
    metric_name      = "MemoryUsage"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 80
  }

  action {
    action_group_id = var.action_group_id
  }
}

Best Practices

  1. Security

    • Use managed identities
    • Secure environment variables
    • Network isolation
    • Access control
  2. Performance

    • Right-size resources
    • Monitor usage
    • Configure probes
    • Optimize images
  3. High Availability

    • Use multiple instances
    • Health monitoring
    • Auto-restart
    • Backup data
  4. Cost Optimization

    • Monitor usage
    • Clean up resources
    • Right-size containers
    • Use spot instances

Advanced Features

  1. GPU Support
resource "azurerm_container_group" "gpu" {
  name                = "${var.project_name}-aci-gpu"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_address_type     = "Public"
  os_type             = "Linux"

  container {
    name   = "gpu"
    image  = "tensorflow/tensorflow:latest-gpu"
    cpu    = "4.0"
    memory = "8.0"

    gpu {
      count = 1
      sku   = "K80"
    }
  }

  tags = var.tags
}

Conclusion

You’ve learned how to set up and manage Azure Container Instances using Terraform. This setup provides:

  • Container deployment
  • Volume management
  • Network integration
  • Monitoring configuration

Remember to:

  • Monitor resources
  • Update containers
  • Review security
  • Maintain backups