Skapa en Application Gateway ingress-kontrollant i Azure Kubernetes Service

Azure Kubernetes Service (AKS) hanterar din värdbaserade Kubernetes-miljö. AKS gör det snabbt och enkelt att distribuera och hantera containerbaserade program utan kunskaper om orkestrering av containrar. AKS eliminerar också arbetet med att ta program offline för drift- och underhållsaktiviteter. Med AKS kan dessa uppgifter , inklusive etablering, uppgradering och skalning av resurser, utföras på begäran.

En ingress-kontrollant innehåller olika funktioner för Kubernetes-tjänster. Dessa funktioner omfattar omvänd proxy, konfigurerbar trafikroutning och TLS-avslutning. Kubernetes-ingressresurser används för att konfigurera ingressreglerna för enskilda Kubernetes-tjänster. Med hjälp av en ingress-kontrollant och ingressregler kan en enda IP-adress dirigera trafik till flera tjänster i ett Kubernetes-kluster. Alla dessa funktioner tillhandahålls av Azure Application Gateway, vilket gör det till en perfekt ingress-kontrollant för Kubernetes på Azure.

I den här artikeln får du lära dig hur:

  • Skapa ett Kubernetes-kluster med AKS med Application Gateway som ingress-kontrollant
  • Definiera ett Kubernetes-kluster
  • Skapa en Application Gateway-resurs
  • Skapa ett Kubernetes-kluster
  • Testa tillgängligheten för ett Kubernetes-kluster

1. Konfigurera din miljö

  • Azure-prenumeration: Om du inte har någon Azure-prenumeration kan du skapa ett kostnadsfritt konto innan du börjar.
  • Azure-tjänstenshuvudnamn: Om du inte har ett huvudnamn för tjänsten skapar du ett huvudnamn för tjänsten. Anteckna värdena för appId , displayName , och passwordtenant .

  • Objekt-ID för tjänstenshuvudnamn: Kör följande kommando för att hämta objekt-ID:t för tjänstens huvudnamn:

2. Konfigurera Azure Storage för att lagra Terraform-tillstånd

Terraform spårar tillstånd lokalt via filen terraform.tfstate. Det här mönstret fungerar bra i en miljö med en enda person. I en miljö med flera personer behöver du dock spåra tillstånd på servern med Azure Storage. I det här avsnittet lär du dig att hämta nödvändig information om lagringskontot och skapa en lagringscontainer. Terraform-tillståndsinformationen lagras sedan i containern.

  1. Bläddra till Azure Portal.

  2. Under Azure-tjänsterväljer du Storage konton. (Om alternativet Storage konton inte visas på huvudsidan väljer du Fler tjänster för att hitta alternativet.)

  3. På sidan Storage väljer du namnet på det lagringskonto som Terraform ska lagra tillstånd i. Du kan till exempel använda lagringskontot som skapades när du öppnade Cloud Shell första gången. Lagringskontonamnet som skapades av Cloud Shell börjar vanligtvis med cs följt av en slumpmässig sträng med siffror och bokstäver.

  4. Anteckna det valda lagringskontonamnet.

  5. Välj Åtkomstnycklar på lagringskontosidan.

    Menyn Lagringskonto

  6. Notera nyckelvärdet key1. (Om du väljer ikonen till höger om nyckeln kopieras värdet till Urklipp.)

    Lagringskontots åtkomstnycklar

  7. Skapa en container i ditt Azure Storage-konto. Ersätt platshållarna med lämpliga värden för ditt Azure Storage-konto.

    az storage container create -n tfstate --account-name <storage_account_name> --account-key <storage_account_key>
    

3. Implementera Terraform-koden

  1. Skapa en katalog där du kan testa Terraform-exempelkoden och göra den till den aktuella katalogen.

  2. Skapa en fil med main.tf namnet och infoga följande kod:

    terraform {
    
      required_version = ">=0.12"
    
      required_providers {
        azurerm = {
          source = "hashicorp/azurerm"
          version = "~>2.0"
        }
      }
      backend "azurerm" {
        resource_group_name = var.resource_group_name
        storage_account_name = var.storage_account_name
        container_name = "tfstate"
        key = "codelab.microsoft.tfstate"
      }
      }
    
      provider "azurerm" {
      features {}
    }
    
  3. Skapa en fil med variables.tf namnet som ska innehålla projektvariablerna och infoga följande kod:

    variable "resource_group_name" {
        description = "Name of the resource group."
    }
    
    variable "location" {
        description = "Location of the cluster."
    }
    
    variable "aks_service_principal_app_id" {
        description = "Application ID/Client ID  of the service principal. Used by AKS to manage AKS related resources on Azure like vms, subnets."
    }
    
    variable "aks_service_principal_client_secret" {
        description = "Secret of the service principal. Used by AKS to manage Azure."
    }
    
    variable "aks_service_principal_object_id" {
        description = "Object ID of the service principal."
    }
    
    variable "virtual_network_name" {
        description = "Virtual network name"
        default     = "aksVirtualNetwork"
    }
    
    variable "virtual_network_address_prefix" {
        description = "VNET address prefix"
        default     = "15.0.0.0/8"
    }
    
    variable "aks_subnet_name" {
        description = "Subnet Name."
        default     = "kubesubnet"
    }
    
    variable "aks_subnet_address_prefix" {
        description = "Subnet address prefix."
        default     = "15.0.0.0/16"
    }
    
    variable "app_gateway_subnet_address_prefix" {
        description = "Subnet server IP address."
        default     = "15.1.0.0/16"
    }
    
    variable "app_gateway_name" {
        description = "Name of the Application Gateway"
        default = "ApplicationGateway1"
    }
    
    variable "app_gateway_sku" {
        description = "Name of the Application Gateway SKU"
        default = "Standard_v2"
    }
    
    variable "app_gateway_tier" {
        description = "Tier of the Application Gateway tier"
        default = "Standard_v2"
    }
    
    variable "aks_name" {
        description = "AKS cluster name"
        default     = "aks-cluster1"
    }
    variable "aks_dns_prefix" {
        description = "Optional DNS prefix to use with hosted Kubernetes API server FQDN."
        default     = "aks"
    }
    
    variable "aks_agent_os_disk_size" {
        description = "Disk size (in GB) to provision for each of the agent pool nodes. This value ranges from 0 to 1023. Specifying 0 applies the default disk size for that agentVMSize."
        default     = 40
    }
    
    variable "aks_agent_count" {
        description = "The number of agent nodes for the cluster."
        default     = 3
    }
    
    variable "aks_agent_vm_size" {
        description = "VM size"
        default     = "Standard_D3_v2"
    }
    
    variable "kubernetes_version" {
        description = "Kubernetes version"
        default     = "1.11.5"
    }
    
    variable "aks_service_cidr" {
        description = "CIDR notation IP range from which to assign service cluster IPs"
        default     = "10.0.0.0/16"
    }
    
    variable "aks_dns_service_ip" {
        description = "DNS server IP address"
        default     = "10.0.0.10"
    }
    
    variable "aks_docker_bridge_cidr" {
        description = "CIDR notation IP for Docker bridge."
        default     = "172.17.0.1/16"
    }
    
    variable "aks_enable_rbac" {
        description = "Enable RBAC on the AKS cluster. Defaults to false."
        default     = "false"
    }
    
    variable "vm_user_name" {
        description = "User name for the VM"
        default     = "vmuser1"
    }
    
    variable "public_ssh_key_path" {
        description = "Public key path for SSH."
        default     = "~/.ssh/id_rsa.pub"
    }
    
    variable "tags" {
        type = map(string)
    
        default = {
        source = "terraform"
        }
    }
    
    variable "storage_account_name" {
        description = "Name of storage account"
    }
    
  4. Skapa en fil med resources.tf namnet och infoga följande kod.

    # # Locals block for hardcoded names. 
    locals {
        backend_address_pool_name      = "${azurerm_virtual_network.test.name}-beap"
        frontend_port_name             = "${azurerm_virtual_network.test.name}-feport"
        frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip"
        http_setting_name              = "${azurerm_virtual_network.test.name}-be-htst"
        listener_name                  = "${azurerm_virtual_network.test.name}-httplstn"
        request_routing_rule_name      = "${azurerm_virtual_network.test.name}-rqrt"
        app_gateway_subnet_name = "appgwsubnet"
    }
    
    data "azurerm_resource_group" "rg" {
        name = var.resource_group_name
    }
    
    # User Assigned Identities 
    resource "azurerm_user_assigned_identity" "testIdentity" {
        resource_group_name = data.azurerm_resource_group.rg.name
        location            = data.azurerm_resource_group.rg.location
    
        name = "identity1"
    
        tags = var.tags
    }
    
    resource "azurerm_virtual_network" "test" {
        name                = var.virtual_network_name
        location            = data.azurerm_resource_group.rg.location
        resource_group_name = data.azurerm_resource_group.rg.name
        address_space       = [var.virtual_network_address_prefix]
    
        subnet {
        name           = var.aks_subnet_name
        address_prefix = var.aks_subnet_address_prefix
        }
    
        subnet {
        name           = "appgwsubnet"
        address_prefix = var.app_gateway_subnet_address_prefix
        }
    
        tags = var.tags
    }
    
    data "azurerm_subnet" "kubesubnet" {
        name                 = var.aks_subnet_name
        virtual_network_name = azurerm_virtual_network.test.name
        resource_group_name  = data.azurerm_resource_group.rg.name
        depends_on = [azurerm_virtual_network.test]
    }
    
    data "azurerm_subnet" "appgwsubnet" {
        name                 = "appgwsubnet"
        virtual_network_name = azurerm_virtual_network.test.name
        resource_group_name  = data.azurerm_resource_group.rg.name
        depends_on = [azurerm_virtual_network.test]
    }
    
    # Public Ip 
    resource "azurerm_public_ip" "test" {
        name                         = "publicIp1"
        location                     = data.azurerm_resource_group.rg.location
        resource_group_name          = data.azurerm_resource_group.rg.name
        allocation_method            = "Static"
        sku                          = "Standard"
    
        tags = var.tags
    }
    
    resource "azurerm_application_gateway" "network" {
        name                = var.app_gateway_name
        resource_group_name = data.azurerm_resource_group.rg.name
        location            = data.azurerm_resource_group.rg.location
    
        sku {
        name     = var.app_gateway_sku
        tier     = "Standard_v2"
        capacity = 2
        }
    
        gateway_ip_configuration {
        name      = "appGatewayIpConfig"
        subnet_id = data.azurerm_subnet.appgwsubnet.id
        }
    
        frontend_port {
        name = local.frontend_port_name
        port = 80
        }
    
        frontend_port {
        name = "httpsPort"
        port = 443
        }
    
        frontend_ip_configuration {
        name                 = local.frontend_ip_configuration_name
        public_ip_address_id = azurerm_public_ip.test.id
        }
    
        backend_address_pool {
        name = local.backend_address_pool_name
        }
    
        backend_http_settings {
        name                  = local.http_setting_name
        cookie_based_affinity = "Disabled"
        port                  = 80
        protocol              = "Http"
        request_timeout       = 1
        }
    
        http_listener {
        name                           = local.listener_name
        frontend_ip_configuration_name = local.frontend_ip_configuration_name
        frontend_port_name             = local.frontend_port_name
        protocol                       = "Http"
        }
    
        request_routing_rule {
        name                       = local.request_routing_rule_name
        rule_type                  = "Basic"
        http_listener_name         = local.listener_name
        backend_address_pool_name  = local.backend_address_pool_name
        backend_http_settings_name = local.http_setting_name
        }
    
        tags = var.tags
    
        depends_on = [azurerm_virtual_network.test, azurerm_public_ip.test]
    }
    
    resource "azurerm_role_assignment" "ra1" {
        scope                = data.azurerm_subnet.kubesubnet.id
        role_definition_name = "Network Contributor"
        principal_id         = var.aks_service_principal_object_id 
    
        depends_on = [azurerm_virtual_network.test]
    }
    
    resource "azurerm_role_assignment" "ra2" {
        scope                = azurerm_user_assigned_identity.testIdentity.id
        role_definition_name = "Managed Identity Operator"
        principal_id         = var.aks_service_principal_object_id
        depends_on           = [azurerm_user_assigned_identity.testIdentity]
    }
    
    resource "azurerm_role_assignment" "ra3" {
        scope                = azurerm_application_gateway.network.id
        role_definition_name = "Contributor"
        principal_id         = azurerm_user_assigned_identity.testIdentity.principal_id
        depends_on           = [azurerm_user_assigned_identity.testIdentity, azurerm_application_gateway.network]
    }
    
    resource "azurerm_role_assignment" "ra4" {
        scope                = data.azurerm_resource_group.rg.id
        role_definition_name = "Reader"
        principal_id         = azurerm_user_assigned_identity.testIdentity.principal_id
        depends_on           = [azurerm_user_assigned_identity.testIdentity, azurerm_application_gateway.network]
    }
    
    resource "azurerm_kubernetes_cluster" "k8s" {
        name       = var.aks_name
        location   = data.azurerm_resource_group.rg.location
        dns_prefix = var.aks_dns_prefix
    
        resource_group_name = data.azurerm_resource_group.rg.name
    
        linux_profile {
        admin_username = var.vm_user_name
    
        ssh_key {
            key_data = file(var.public_ssh_key_path)
        }
        }
    
        addon_profile {
        http_application_routing {
            enabled = false
        }
        }
    
        default_node_pool {
        name            = "agentpool"
        node_count      = var.aks_agent_count
        vm_size         = var.aks_agent_vm_size
        os_disk_size_gb = var.aks_agent_os_disk_size
        vnet_subnet_id  = data.azurerm_subnet.kubesubnet.id
        }
    
        service_principal {
        client_id     = var.aks_service_principal_app_id
        client_secret = var.aks_service_principal_client_secret
        }
    
        network_profile {
        network_plugin     = "azure"
        dns_service_ip     = var.aks_dns_service_ip
        docker_bridge_cidr = var.aks_docker_bridge_cidr
        service_cidr       = var.aks_service_cidr
        }
    
        role_based_access_control {
        enabled = var.aks_enable_rbac
        }
    
        depends_on = [azurerm_virtual_network.test, azurerm_application_gateway.network]
        tags       = var.tags
    }
    

    Viktiga punkter:

    • Koden i filen resources.tf anger namnet på klustret, platsen och resource_group_name.
    • Värdet dns_prefix – som utgör en del av det fullständigt kvalificerade domännamnet (FQDN) som används för att komma åt klustret – har angetts.
    • Med linux_profile posten kan du konfigurera inställningarna som aktiverar inloggning till arbetsnoderna med hjälp av SSH.
    • Med AKS betalar du bara för arbetarnoderna.
    • Posten agent_pool_profile konfigurerar informationen för dessa arbetsnoder.
    • agent_pool_profile recordinnehåller antalet arbetsnoder som ska skapas och typen av arbetsnoder.
    • Om du behöver skala upp eller ned klustret i framtiden ändrar du count värdet i agent_pool_profile record posten.
  5. Skapa en fil med output.tf namnet och infoga följande kod.

    output "client_key" {
        value = azurerm_kubernetes_cluster.k8s.kube_config.0.client_key
    }
    
    output "client_certificate" {
        value = azurerm_kubernetes_cluster.k8s.kube_config.0.client_certificate
    }
    
    output "cluster_ca_certificate" {
        value = azurerm_kubernetes_cluster.k8s.kube_config.0.cluster_ca_certificate
    }
    
    output "cluster_username" {
        value = azurerm_kubernetes_cluster.k8s.kube_config.0.username
    }
    
    output "cluster_password" {
        value = azurerm_kubernetes_cluster.k8s.kube_config.0.password
    }
    
    output "kube_config" {
        value = azurerm_kubernetes_cluster.k8s.kube_config_raw
        sensitive = true
    }
    
    output "host" {
        value = azurerm_kubernetes_cluster.k8s.kube_config.0.host
    }
    
    output "identity_resource_id" {
        value = azurerm_user_assigned_identity.testIdentity.id
    }
    
    output "identity_client_id" {
        value = azurerm_user_assigned_identity.testIdentity.client_id
    }
    

    Viktiga punkter:

    • Med Terraform-utdata kan du definiera värden som är markerade för användaren när Terraform tillämpar en plan.
    • Du kan köra frågor mot dessa värden med hjälp av terraform output kommandot .
    • I det här avsnittet skapar du en utdatafil som tillåter åtkomst till klustret med kubectl.
  6. Skapa en fil med terraform.tfvars namnet och infoga följande kod.

    resource_group_name = "<Name of the Resource Group already created>"
    
    location = "<Location of the Resource Group>"
        
    aks_service_principal_app_id = "<Service Principal AppId>"
        
    aks_service_principal_client_secret = "<Service Principal Client Secret>"
        
    aks_service_principal_object_id = "<Service Principal Object Id>"
    

    Viktiga punkter:

    • Kör az account list-locations för att hämta platsvärdet för din miljö

4. Testa Kubernetes-klustret

Kubernetes-verktygen kan användas för att verifiera det nyligen skapade klustret.

  1. Kör az aks get-credentials för att hämta Kubernetes-konfigurationen och autentiseringsuppgifterna för åtkomst från Azure.

    az aks get-credentials --name <aks_cluster_name>  --resource-group <resource_group_name>
    
  2. Kontrollera klustrets hälsotillstånd.

    kubectl get nodes
    

    Viktiga punkter:

    • Informationen om dina arbetsnoder visas med statusen Klar.

    Med verktyget kubectl kan du kontrollera ditt Kubernetes-klusters hälsotillstånd

5. Installera Azure AD-poddidentitet

Azure Active Directory poddidentitet ger tokenbaserad åtkomst till Azure Resource Manager.

Azure AD-poddidentitet lägger till följande komponenter i Kubernetes-klustret:

Om RBAC är aktiverat kördu följande kommando för att installera Azure AD-poddidentitet i klustret:

kubectl create -f https://raw.githubusercontent.com/Azure/aad-pod-identity/master/deploy/infra/deployment-rbac.yaml

Om RBAC är inaktiveratkör du följande kommando för att installera Azure AD-poddidentitet i klustret:

kubectl create -f https://raw.githubusercontent.com/Azure/aad-pod-identity/master/deploy/infra/deployment.yaml

6. Installera Helm

Koden i det här avsnittet använder Helm – Kubernetes-pakethanteraren – för att installera paketet:

Kör följande Helm-kommandon för att lägga till AGIC Helm-lagringsplatsen:

helm repo add application-gateway-kubernetes-ingress https://appgwingress.blob.core.windows.net/ingress-azure-helm-package/
helm repo update

7. Helm-diagram för installation av ingående styrenhet

  1. Ladda helm-config.yaml ned för att konfigurera AGIC:

    wget https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/master/docs/examples/sample-helm-config.yaml -O helm-config.yaml
    
  2. Redigera och helm-config.yaml ange lämpliga värden för appgwarmAuth avsnitten och .

    code helm-config.yaml
    

    Värdena beskrivs på följande sätt:

    • verbosityLevel: Anger den utförliga nivån för AGIC-loggningsinfrastrukturen. Se Loggningsnivåer för möjliga värden.
    • appgw.subscriptionId: Azure-prenumerations-ID för App Gateway. Exempel: a123b234-a3b4-557d-b2df-a0bc12de1234
    • appgw.resourceGroup: Namnet på den Azure-resursgrupp där App Gateway skapades.
    • appgw.name: Namnet på Application Gateway. Exempel: applicationgateway1.
    • appgw.shared: Den här booleska flaggan ska vara standardvärdet false . Ange till true om du behöver en delad true.
    • kubernetes.watchNamespace: Ange namnrymden som AGIC ska titta på. Namnområdet kan vara ett enda strängvärde eller en kommaavgränsad lista med namnområden. Om du lämnar den här variabeln kommenterad eller anger den till tom eller tom sträng resulterar det i att Ingress-kontrollanten observerar alla tillgängliga namnområden.
    • armAuth.type: Ett värde för antingen aadPodIdentity eller servicePrincipal .
    • armAuth.identityResourceID: Resurs-ID för den hanterade identiteten.
    • armAuth.identityClientId: Klient-ID för identiteten.
    • armAuth.secretJSON: Krävs endast när tjänsthuvudnamnshemlighetstyp väljs armAuth.type (när har angetts till servicePrincipal ).

    Viktiga punkter:

    • Värdet identityResourceID skapas i terraform-skriptet och kan hittas genom att köra: echo "$(terraform output identity_resource_id)" .
    • Värdet identityClientID skapas i terraform-skriptet och kan hittas genom att köra: echo "$(terraform output identity_client_id)" .
    • Värdet <resource-group> är resursgruppen för din App Gateway.
    • Värdet <identity-name> är namnet på den skapade identiteten.
    • Alla identiteter för en viss prenumeration kan visas med hjälp av: az identity list .
  3. Installera Application Gateway ingress-kontrollantpaketet:

    helm install -f helm-config.yaml application-gateway-kubernetes-ingress/ingress-azure --generate-name
    

8. Installera en exempelapp

När du har installerat App Gateway, AKS och AGIC installerar du en exempelapp.

  1. Använd curl-kommandot för att ladda ned YAML-filen:

    curl https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/master/docs/examples/aspnetapp.yaml -o aspnetapp.yaml
    
  2. Tillämpa YAML-filen:

    kubectl apply -f aspnetapp.yaml
    

9. Rensa resurser

När du inte längre behöver de resurser som skapats via Terraform gör du följande:

  1. Kör terraform-planen och ange flaggan.

    terraform plan -destroy -out main.destroy.tfplan
    

    Viktiga punkter:

    • Kommandot terraform plan skapar en körningsplan, men kör den inte. I stället avgör den vilka åtgärder som krävs för att skapa konfigurationen som anges i konfigurationsfilerna. Med det här mönstret kan du kontrollera om körningsplanen matchar dina förväntningar innan du gör några ändringar i faktiska resurser.
    • Med den -out valfria parametern kan du ange en utdatafil för planen. Med -out parametern ser du till att den plan som du granskade är exakt det som tillämpas.
    • Mer information om att bevara körningsplaner och säkerhet finns i säkerhetsvarningsavsnittet.
  2. Kör terraform apply för att tillämpa körningsplanen.

    terraform apply main.destroy.tfplan
    

Felsöka Terraform på Azure

Felsöka vanliga problem när du använder Terraform på Azure

Nästa steg