terraform { required_version = ">= 1.6" required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 4.0" } } backend "azurerm" {} } provider "azurerm" { features {} } # --- Variablen -------------------------------------------------------- variable "location" { type = string default = "germanywestcentral" } variable "prefix" { type = string default = "iaclab" } variable "environment" { type = string default = "lab" } variable "image_version" { type = string description = "Image-Version aus der Compute Gallery – der Rollout-Schalter" } variable "instance_count" { type = number default = 3 } variable "vm_size" { type = string default = "Standard_B2s" } variable "ssh_public_key_path" { type = string default = "~/.ssh/id_ed25519.pub" } locals { tags = { managed_by = "terraform" project = "iac-lab" layer = "workload" } } # --- Verweise auf die Base-Schicht ------------------------------------ data "azurerm_subnet" "app" { name = "snet-app" virtual_network_name = "vnet-${var.prefix}" resource_group_name = "rg-${var.prefix}-base" } data "azurerm_shared_image_version" "web" { name = var.image_version image_name = "img-web-ubuntu2404" gallery_name = "gal_${var.prefix}" resource_group_name = "rg-${var.prefix}-base" } resource "azurerm_resource_group" "web" { name = "rg-${var.prefix}-web" location = var.location tags = local.tags } # --- Load Balancer ---------------------------------------------------- resource "azurerm_public_ip" "lb" { name = "pip-${var.prefix}-lb" location = azurerm_resource_group.web.location resource_group_name = azurerm_resource_group.web.name allocation_method = "Static" sku = "Standard" zones = ["1", "2", "3"] tags = local.tags } resource "azurerm_lb" "web" { name = "lb-${var.prefix}-web" location = azurerm_resource_group.web.location resource_group_name = azurerm_resource_group.web.name sku = "Standard" tags = local.tags frontend_ip_configuration { name = "fe" public_ip_address_id = azurerm_public_ip.lb.id } } resource "azurerm_lb_backend_address_pool" "web" { name = "be-web" loadbalancer_id = azurerm_lb.web.id } resource "azurerm_lb_probe" "http" { name = "probe-http" loadbalancer_id = azurerm_lb.web.id protocol = "Http" port = 80 request_path = "/health" } resource "azurerm_lb_rule" "http" { name = "http" loadbalancer_id = azurerm_lb.web.id protocol = "Tcp" frontend_port = 80 backend_port = 80 frontend_ip_configuration_name = "fe" backend_address_pool_ids = [azurerm_lb_backend_address_pool.web.id] probe_id = azurerm_lb_probe.http.id disable_outbound_snat = true # Outbound regelt die Outbound Rule } resource "azurerm_lb_outbound_rule" "egress" { name = "egress" loadbalancer_id = azurerm_lb.web.id protocol = "All" backend_address_pool_id = azurerm_lb_backend_address_pool.web.id frontend_ip_configuration { name = "fe" } } # --- VM Scale Set: die Herde ------------------------------------------ resource "azurerm_linux_virtual_machine_scale_set" "web" { name = "vmss-${var.prefix}-web" location = azurerm_resource_group.web.location resource_group_name = azurerm_resource_group.web.name sku = var.vm_size instances = var.instance_count zones = ["1", "2", "3"] tags = local.tags source_image_id = data.azurerm_shared_image_version.web.id custom_data = base64encode(templatefile("${path.module}/cloud-init.yaml", { environment = var.environment })) # Von Azure verlangt; dient nur als Notfallzugang (NSG blockt SSH) admin_username = "azureadmin" disable_password_authentication = true admin_ssh_key { username = "azureadmin" public_key = file(pathexpand(var.ssh_public_key_path)) } # Neue Image-Version => batchweiser Austausch der Instanzen upgrade_mode = "Rolling" health_probe_id = azurerm_lb_probe.http.id rolling_upgrade_policy { max_batch_instance_percent = 34 max_unhealthy_instance_percent = 34 max_unhealthy_upgraded_instance_percent = 34 pause_time_between_batches = "PT30S" } # Kranke Instanz => wird ersetzt, nicht repariert automatic_instance_repair { enabled = true grace_period = "PT10M" } os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } network_interface { name = "nic" primary = true ip_configuration { name = "ipcfg" primary = true subnet_id = data.azurerm_subnet.app.id load_balancer_backend_address_pool_ids = [azurerm_lb_backend_address_pool.web.id] } } depends_on = [azurerm_lb_rule.http] } output "url" { value = "http://${azurerm_public_ip.lb.ip_address}" }