你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

快速入门 - 使用 Terraform 部署 Azure Kubernetes 服务 (AKS) 群集

Azure Kubernetes 服务 (AKS) 是可用于快速部署和管理群集的托管式 Kubernetes 服务。 在本快速入门中,请执行以下操作:

  • 使用 Terraform 部署 AKS 群集。
  • 使用一组微服务和模拟零售场景的 Web 前端运行示例多容器应用程序。

注意

为了开始快速预配 AKS 群集,本文介绍了仅针对评估目的部署具有默认设置的群集的步骤。 在部署生产就绪群集之前,建议熟悉我们的基线参考体系结构,考虑它如何与你的业务需求保持一致。

开始之前

注意

Azure Linux 节点池现已正式发布 (GA)。 若要了解权益和部署步骤,请参阅适用于 AKS 的 Azure Linux 容器主机简介

登录到 Azure 帐户

首先,登录到 Azure 帐户并使用下一部分中描述的方法之一进行身份验证。

Terraform 和 Azure 身份验证方案

Terraform 仅支持通过 Azure CLI 向 Azure 进行身份验证。 不支持使用 Azure PowerShell 进行身份验证。 因此,虽然可以在进行 Terraform 工作时使用 Azure PowerShell 模块,不过首先需要使用 Azure CLI 向 Azure 进行身份验证。

本文说明如何在以下方案中向 Azure 验证 Terraform。 有关向 Azure 验证 Terraform 的选项的详细信息,请参阅使用 Azure CLI 进行身份验证

通过 Microsoft 帐户向 Azure 进行身份验证

Microsoft 帐户是用于登录 Microsoft 服务(如 Azure)的用户名(与电子邮件及其凭据关联)。 Microsoft 帐户可以与一个或多个 Azure 订阅关联,其中一个订阅是默认订阅。

以下步骤演示了操作方法:

  • 使用 Microsoft 帐户以交互方式登录到 Azure
  • 列出帐户的关联 Azure 订阅(包括默认)
  • 设置当前订阅。
  1. 打开有权访问 Azure CLI 的命令行。

  2. 运行不带任何参数的 az login,并按照说明登录 Azure。

    az login
    

    要点

    • 成功登录后,az login 会显示与已登录 Microsoft 帐户相关联的 Azure 订阅的列表(包括默认订阅)。
  3. 若要查看当前 Azure 订阅,请运行 az account show

    az account show
    
  4. 若要查看特定 Microsoft 帐户的所有 Azure 订阅名称和 ID,请运行 az account list

    az account list --query "[?user.name=='<microsoft_account_email>'].{Name:name, ID:id, Default:isDefault}" --output Table
    

    要点

    • <microsoft_account_email> 占位符替换为要列出其 Azure 订阅的 Microsoft 帐户电子邮件地址。
    • 使用 Live 帐户(如 Hotmail 或 Outlook)时,可能需要指定完全限定的电子邮件地址。 例如,如果电子邮件地址为 admin@hotmail.com,则可能需要将占位符替换为 live.com#admin@hotmail.com
  5. 若要使用特定 Azure 订阅,请运行 az account set

    az account set --subscription "<subscription_id_or_subscription_name>"
    

    要点

    • <subscription_id_or_subscription_name> 占位符替换为要使用的订阅的 ID 或名称。
    • 调用 az account set 不会显示切换到指定的 Azure 订阅的结果。 但是,可以使用 az account show 来确认当前的 Azure 订阅是否已更改。
    • 如果运行上一步中的 az account list 命令,则会看到默认 Azure 订阅已更改为使用 az account set 指定的订阅。

创建服务主体

部署或使用 Azure 服务的自动化工具(例如 Terraform)应始终具有受限权限。 Azure 提供了服务主体,而不是让应用程序以具有完全特权的用户身份登录。

最常见的模式是以交互方式登录 Azure,创建服务主体,测试服务主体,然后将该服务主体用于将来的身份验证(以交互方式或通过脚本)。

  1. 若要创建服务主体,请登录到 Azure。 通过 Microsoft 帐户向 Azure 进行身份验证之后,请返回此处。

  2. 如果通过 Git Bash 创建服务主体,请设置 MSYS_NO_PATHCONV 环境变量。 (如果使用的是 Cloud Shell,则此步骤不是必需的。)

    export MSYS_NO_PATHCONV=1    
    

    要点

    • 可以在全局(为所有终端会话)或本地(只为当前会话)设置 MSYS_NO_PATHCONV 环境变量。 由于创建服务主体不是经常执行的操作,因此示例会为当前会话设置值。 若要在全局设置此环境变量,请将设置添加到 ~/.bashrc 文件。
  3. 若要创建服务主体,请使用 az ad sp create-for-rbac

    az ad sp create-for-rbac --name <service_principal_name> --role Contributor --scopes /subscriptions/<subscription_id>
    

    要点

    • 可以将 <service-principal-name> 替换为适用于环境的自定义名称,也可以完全省略该参数。 如果省略该参数,则基于当前日期和时间生成服务主体名称。
    • 成功完成后,az ad sp create-for-rbac 会显示多个值。 下一步中将使用 appIdpasswordtenant 值。
    • 如果丢失了密码,则无法对其进行检索。 因此,应将密码存储在安全的位置。 如果忘记了密码,则可以重置服务主体凭据
    • 对于本文,会使用一个具有“参与者”角色的服务主体。 有关基于角色的访问控制 (RBAC) 角色的详细信息,请参阅 RBAC:内置角色
    • 创建服务主体的输出包含敏感凭据。 请确保没有将这些凭据包含在代码中,也没有将凭据签入到源代码管理中。
    • 有关使用 Azure CLI 创建服务主体时的选项的详细信息,请参阅使用 Azure CLI 创建 Azure 服务主体一文。

在环境变量中指定服务主体凭据

创建服务主体后,可以通过环境变量将其凭据指定给 Terraform。

  1. 通过添加以下环境变量来编辑 ~/.bashrc 文件。

    export ARM_SUBSCRIPTION_ID="<azure_subscription_id>"
    export ARM_TENANT_ID="<azure_subscription_tenant_id>"
    export ARM_CLIENT_ID="<service_principal_appid>"
    export ARM_CLIENT_SECRET="<service_principal_password>"
    
  2. 若要执行 ~/.bashrc 脚本,请运行 source ~/.bashrc(或其缩写等效项 . ~/.bashrc)。 还可以退出并重新打开 Cloud Shell 以便自动运行脚本。

    . ~/.bashrc
    
  3. 设置环境变量后,可以验证其值,如下所示:

    printenv | grep ^ARM*
    

要点

  • 与任何环境变量一样,若要从 Terraform 脚本中访问 Azure 订阅值,请使用以下语法:${env.<environment_variable>}。 例如,若要访问 ARM_SUBSCRIPTION_ID 值,请指定 ${env.ARM_SUBSCRIPTION_ID}
  • 创建并应用 Terraform 执行计划会对与服务主体关联的 Azure 订阅进行更改。 如果登录一个 Azure 订阅,而环境变量指向另一个 Azure 订阅,这一事实有时可能会令人困惑。 请看以下示例进行说明。 假设有两个 Azure 订阅:SubA 和 SubB。 如果当前 Azure 订阅是 SubA(通过 az account show 确定),而环境变量指向 SubB,则 Terraform 进行的任何更改都在 SubB 上。 因此,需要登录 SubB 订阅运行 Azure CLI 命令或 Azure PowerShell 命令以查看更改。

在 Terraform 提供程序块中指定服务主体凭据

Azure 提供程序块定义用于指定 Azure 订阅的身份验证信息的语法。

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}

provider "azurerm" {
  features {}

  subscription_id   = "<azure_subscription_id>"
  tenant_id         = "<azure_subscription_tenant_id>"
  client_id         = "<service_principal_appid>"
  client_secret     = "<service_principal_password>"
}

# Your code goes here

注意

能够在 Terraform 配置文件中指定 Azure 订阅凭据可能会十分方便 - 尤其是在测试时。 但是,不建议将凭据存储在可以由不受信任的个人查看的明文文件中。

实现 Terraform 代码

注意

本文中的示例代码位于 Azure Terraform GitHub 存储库中。 你可以查看包含当前和以前 Terraform 版本的测试结果的日志文件。

有关更多示例,请参阅演示如何使用 Terraform 管理 Azure 资源的文章和示例代码

  1. 创建用于测试示例 Terraform 代码的目录,并将其设为当前目录。

  2. 创建名为 providers.tf 的文件并插入下列代码:

    terraform {
      required_version = ">=1.0"
    
      required_providers {
        azapi = {
          source  = "azure/azapi"
          version = "~>1.5"
        }
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~>3.0"
        }
        time = {
          source  = "hashicorp/time"
          version = "0.9.1"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
  3. 创建名为 ssh.tf 的文件并插入下列代码:

    resource "random_pet" "ssh_key_name" {
      prefix    = "ssh"
      separator = ""
    }
    
    resource "azapi_resource_action" "ssh_public_key_gen" {
      type        = "Microsoft.Compute/sshPublicKeys@2022-11-01"
      resource_id = azapi_resource.ssh_public_key.id
      action      = "generateKeyPair"
      method      = "POST"
    
      response_export_values = ["publicKey", "privateKey"]
    }
    
    resource "azapi_resource" "ssh_public_key" {
      type      = "Microsoft.Compute/sshPublicKeys@2022-11-01"
      name      = random_pet.ssh_key_name.id
      location  = azurerm_resource_group.rg.location
      parent_id = azurerm_resource_group.rg.id
    }
    
    output "key_data" {
      value = jsondecode(azapi_resource_action.ssh_public_key_gen.output).publicKey
    }
    
  4. 创建名为 main.tf 的文件并插入下列代码:

    # Generate random resource group name
    resource "random_pet" "rg_name" {
      prefix = var.resource_group_name_prefix
    }
    
    resource "azurerm_resource_group" "rg" {
      location = var.resource_group_location
      name     = random_pet.rg_name.id
    }
    
    resource "random_pet" "azurerm_kubernetes_cluster_name" {
      prefix = "cluster"
    }
    
    resource "random_pet" "azurerm_kubernetes_cluster_dns_prefix" {
      prefix = "dns"
    }
    
    resource "azurerm_kubernetes_cluster" "k8s" {
      location            = azurerm_resource_group.rg.location
      name                = random_pet.azurerm_kubernetes_cluster_name.id
      resource_group_name = azurerm_resource_group.rg.name
      dns_prefix          = random_pet.azurerm_kubernetes_cluster_dns_prefix.id
    
      identity {
        type = "SystemAssigned"
      }
    
      default_node_pool {
        name       = "agentpool"
        vm_size    = "Standard_D2_v2"
        node_count = var.node_count
      }
      linux_profile {
        admin_username = var.username
    
        ssh_key {
          key_data = jsondecode(azapi_resource_action.ssh_public_key_gen.output).publicKey
        }
      }
      network_profile {
        network_plugin    = "kubenet"
        load_balancer_sku = "standard"
      }
    }
    
  5. 创建名为 variables.tf 的文件并插入下列代码:

    variable "resource_group_location" {
      type        = string
      default     = "eastus"
      description = "Location of the resource group."
    }
    
    variable "resource_group_name_prefix" {
      type        = string
      default     = "rg"
      description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription."
    }
    
    variable "node_count" {
      type        = number
      description = "The initial quantity of nodes for the node pool."
      default     = 3
    }
    
    variable "msi_id" {
      type        = string
      description = "The Managed Service Identity ID. Set this value if you're running this example using Managed Identity as the authentication method."
      default     = null
    }
    
    variable "username" {
      type        = string
      description = "The admin username for the new cluster."
      default     = "azureadmin"
    }
    
  6. 创建名为 outputs.tf 的文件并插入下列代码:

    output "resource_group_name" {
      value = azurerm_resource_group.rg.name
    }
    
    output "kubernetes_cluster_name" {
      value = azurerm_kubernetes_cluster.k8s.name
    }
    
    output "client_certificate" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].client_certificate
      sensitive = true
    }
    
    output "client_key" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].client_key
      sensitive = true
    }
    
    output "cluster_ca_certificate" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].cluster_ca_certificate
      sensitive = true
    }
    
    output "cluster_password" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].password
      sensitive = true
    }
    
    output "cluster_username" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].username
      sensitive = true
    }
    
    output "host" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].host
      sensitive = true
    }
    
    output "kube_config" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config_raw
      sensitive = true
    }
    

初始化 Terraform

运行 terraform init,将 Terraform 部署进行初始化。 此命令将下载管理 Azure 资源所需的 Azure 提供程序。

terraform init -upgrade

要点:

  • 参数 -upgrade 可将必要的提供程序插件升级到符合配置版本约束的最新版本。

创建 Terraform 执行计划

运行 terraform plan 以创建执行计划。

terraform plan -out main.tfplan

要点:

  • terraform plan 命令将创建一个执行计划,但不会执行它。 它会确定创建配置文件中指定的配置需要执行哪些操作。 此模式允许你在对实际资源进行任何更改之前验证执行计划是否符合预期。
  • 使用可选 -out 参数可以为计划指定输出文件。 使用 -out 参数可以确保所查看的计划与所应用的计划完全一致。

应用 Terraform 执行计划

运行 terraform apply,将执行计划应用到云基础结构。

terraform apply main.tfplan

要点:

  • 示例 terraform apply 命令假设你先前运行了 terraform plan -out main.tfplan
  • 如果为 -out 参数指定了不同的文件名,请在对 terraform apply 的调用中使用该相同文件名。
  • 如果未使用 -out 参数,请调用不带任何参数的 terraform apply

验证结果

  1. 请使用以下命令获取 Azure 资源组名称。

    resource_group_name=$(terraform output -raw resource_group_name)
    
  2. 使用 az aks list 命令显示新 Kubernetes 群集的名称。

    az aks list \
      --resource-group $resource_group_name \
      --query "[].{\"K8s cluster name\":name}" \
      --output table
    
  3. 使用以下命令从 Terraform 状态中获取 Kubernetes 配置,并将其存储在 kubectl 可以读取的文件中。

    echo "$(terraform output kube_config)" > ./azurek8s
    
  4. 使用以下命令 确认上一个命令未添加 ASCII EOT 字符。

    cat ./azurek8s
    

    要点

    • 如果在开头看到 << EOT,在末尾看到 EOT,请从文件中移除这些字符。 否则,可能会收到以下错误消息:error: error loading config file "./azurek8s": yaml: line 2: mapping values are not allowed in this context
  5. 使用以下命令设置环境变量,以便 kubectl 选取正确的配置。

    export KUBECONFIG=./azurek8s
    
  6. 使用 kubectl get nodes 命令验证群集的运行状况。

    kubectl get nodes
    

要点

  • 如果已创建 AKS 群集,则已启用监视功能来捕获群集节点和 Pod 的运行状况指标。 Azure 门户提供这些运行状况指标。 有关容器运行状况监视的详细信息,请参阅监视 Azure Kubernetes 服务运行状况
  • 在应用 Terraform 执行计划时,有几个键值分类为输出。 例如,输出主机地址、AKS 群集用户名和 AKS 群集密码。

部署应用程序

若要部署应用程序,请使用清单文件创建运行 AKS 应用商店应用程序所需的所有对象。 Kubernetes 清单文件定义群集的所需状态,例如,要运行哪些容器映像。 该清单包含以下 Kubernetes 部署和服务:

Azure 应用商店示例体系结构的屏幕截图。

  • 门店:Web 应用程序,供客户查看产品和下单。
  • 产品服务:显示产品信息。
  • 订单服务:下单。
  • Rabbit MQ:订单队列的消息队列。

注意

不建议在没有持久性存储用于生产的情况下,运行有状态容器(例如 Rabbit MQ)。 为简单起见,建议使用托管服务,例如 Azure CosmosDB 或 Azure 服务总线。

  1. 创建名为 aks-store-quickstart.yaml 的文件,并将以下清单复制到其中:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: rabbitmq
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: rabbitmq
      template:
        metadata:
          labels:
            app: rabbitmq
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: rabbitmq
            image: mcr.microsoft.com/mirror/docker/library/rabbitmq:3.10-management-alpine
            ports:
            - containerPort: 5672
              name: rabbitmq-amqp
            - containerPort: 15672
              name: rabbitmq-http
            env:
            - name: RABBITMQ_DEFAULT_USER
              value: "username"
            - name: RABBITMQ_DEFAULT_PASS
              value: "password"
            resources:
              requests:
                cpu: 10m
                memory: 128Mi
              limits:
                cpu: 250m
                memory: 256Mi
            volumeMounts:
            - name: rabbitmq-enabled-plugins
              mountPath: /etc/rabbitmq/enabled_plugins
              subPath: enabled_plugins
          volumes:
          - name: rabbitmq-enabled-plugins
            configMap:
              name: rabbitmq-enabled-plugins
              items:
              - key: rabbitmq_enabled_plugins
                path: enabled_plugins
    ---
    apiVersion: v1
    data:
      rabbitmq_enabled_plugins: |
        [rabbitmq_management,rabbitmq_prometheus,rabbitmq_amqp1_0].
    kind: ConfigMap
    metadata:
      name: rabbitmq-enabled-plugins            
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: rabbitmq
    spec:
      selector:
        app: rabbitmq
      ports:
        - name: rabbitmq-amqp
          port: 5672
          targetPort: 5672
        - name: rabbitmq-http
          port: 15672
          targetPort: 15672
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: order-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: order-service
      template:
        metadata:
          labels:
            app: order-service
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: order-service
            image: ghcr.io/azure-samples/aks-store-demo/order-service:latest
            ports:
            - containerPort: 3000
            env:
            - name: ORDER_QUEUE_HOSTNAME
              value: "rabbitmq"
            - name: ORDER_QUEUE_PORT
              value: "5672"
            - name: ORDER_QUEUE_USERNAME
              value: "username"
            - name: ORDER_QUEUE_PASSWORD
              value: "password"
            - name: ORDER_QUEUE_NAME
              value: "orders"
            - name: FASTIFY_ADDRESS
              value: "0.0.0.0"
            resources:
              requests:
                cpu: 1m
                memory: 50Mi
              limits:
                cpu: 75m
                memory: 128Mi
          initContainers:
          - name: wait-for-rabbitmq
            image: busybox
            command: ['sh', '-c', 'until nc -zv rabbitmq 5672; do echo waiting for rabbitmq; sleep 2; done;']
            resources:
              requests:
                cpu: 1m
                memory: 50Mi
              limits:
                cpu: 75m
                memory: 128Mi    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: order-service
    spec:
      type: ClusterIP
      ports:
      - name: http
        port: 3000
        targetPort: 3000
      selector:
        app: order-service
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: product-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: product-service
      template:
        metadata:
          labels:
            app: product-service
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: product-service
            image: ghcr.io/azure-samples/aks-store-demo/product-service:latest
            ports:
            - containerPort: 3002
            resources:
              requests:
                cpu: 1m
                memory: 1Mi
              limits:
                cpu: 1m
                memory: 7Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: product-service
    spec:
      type: ClusterIP
      ports:
      - name: http
        port: 3002
        targetPort: 3002
      selector:
        app: product-service
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: store-front
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: store-front
      template:
        metadata:
          labels:
            app: store-front
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: store-front
            image: ghcr.io/azure-samples/aks-store-demo/store-front:latest
            ports:
            - containerPort: 8080
              name: store-front
            env: 
            - name: VUE_APP_ORDER_SERVICE_URL
              value: "http://order-service:3000/"
            - name: VUE_APP_PRODUCT_SERVICE_URL
              value: "http://product-service:3002/"
            resources:
              requests:
                cpu: 1m
                memory: 200Mi
              limits:
                cpu: 1000m
                memory: 512Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-front
    spec:
      ports:
      - port: 80
        targetPort: 8080
      selector:
        app: store-front
      type: LoadBalancer
    

    有关 YAML 清单文件的明细,请参阅部署和 YAML 清单

    如果在本地创建并保存 YAML 文件,则可以通过选择“上传/下载文件”按钮并从本地文件系统中选择文件,将清单文件上传到 CloudShell 中的默认目录。

  2. 使用 kubectl apply 命令部署应用程序,并指定 YAML 清单的名称。

    kubectl apply -f aks-store-quickstart.yaml
    

    以下示例输出显示部署和服务:

    deployment.apps/rabbitmq created
    service/rabbitmq created
    deployment.apps/order-service created
    service/order-service created
    deployment.apps/product-service created
    service/product-service created
    deployment.apps/store-front created
    service/store-front created
    

测试应用程序

应用程序运行时,Kubernetes 服务将向 Internet 公开应用程序前端。 此过程可能需要几分钟才能完成。

  1. 使用 kubectl get pods 命令查看已部署的 Pod 的状态。 在继续操作之前,将所有 Pod 都设置为 Running

    kubectl get pods
    
  2. 检查应用商店前端应用程序的公共 IP 地址。 使用带有 --watch 参数的 kubectl get service 命令来监视进度。

    kubectl get service store-front --watch
    

    store-front 服务的 EXTERNAL-IP 输出最初显示为“pending”

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   <pending>     80:30025/TCP   4h4m
    
  3. EXTERNAL-IP 地址从 pending 更改为实际公共 IP 地址后,请使用 CTRL-C 来停止 kubectl 监视进程。

    以下示例输出显示向服务分配了有效的公共 IP 地址:

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   20.62.159.19   80:30025/TCP   4h5m
    
  4. 打开 Web 浏览器并转到服务的外部 IP 地址,以查看 Azure 应用商店应用的实际效果。

    AKS 应用商店示例应用程序的屏幕截图。

清理资源

删除 AKS 资源

不再需要通过 Terraform 创建的资源时,请执行以下步骤:

  1. 运行 terraform plan 并指定 destroy 标志。

    terraform plan -destroy -out main.destroy.tfplan
    

    要点:

    • terraform plan 命令将创建一个执行计划,但不会执行它。 它会确定创建配置文件中指定的配置需要执行哪些操作。 此模式允许你在对实际资源进行任何更改之前验证执行计划是否符合预期。
    • 使用可选 -out 参数可以为计划指定输出文件。 使用 -out 参数可以确保所查看的计划与所应用的计划完全一致。
  2. 运行 terraform apply 以应用执行计划。

    terraform apply main.destroy.tfplan
    

删除服务主体

  1. 使用以下命令获取服务主体 ID。

    sp=$(terraform output -raw sp)
    
  2. 使用 az ad sp delete 命令删除服务主体。

    az ad sp delete --id $sp
    

克隆 Azure Developer CLI 模板

使用 Azure Developer CLI,可以从 Azure-Samples 存储库快速下载示例。 在本快速入门中,你将下载 aks-store-demo 应用程序。 有关常规用例的详细信息,请参阅 azd 概述

  1. 使用带有--template参数的azd init命令从 Azure 示例存储库中克隆 AKS 存储演示模板。

    azd init --template Azure-Samples/aks-store-demo
    
  2. 输入仅使用字母数字字符和连字符的项目的环境名称,例如 aks-terraform-1

    Enter a new environment name: aks-terraform-1
    

登录到 Azure 云帐户

azd模板包含创建服务所需的所有代码,但需要登录到 Azure 帐户才能在 AKS 上托管应用程序。

  1. 使用azd auth login命令登录到帐户。

    azd auth login
    
  2. 复制输出中显示的设备代码,然后按 Enter 登录。

    Start by copying the next code: XXXXXXXXX
    Then press enter and continue to log in from your browser...
    

    重要

    如果正在使用网络外虚拟机或 GitHub Codespace,则某些 Azure 安全策略在用于使用azd auth login登录时会导致冲突。 如果在此处遇到问题,可以按照提供的 azd auth 解决方法进行操作,这涉及使用对运行 azd auth login 后重定向到的 localhost URL 的 curl 请求。

  3. 在组织的登录页上使用凭据进行身份验证。

  4. 确认是你在尝试从 Azure CLI 进行连接。

  5. 验证消息“设备代码身份验证已完成。 已登录到 Azure。”显示在原始终端中。

    Waiting for you to complete authentication in the browser...
    Device code authentication completed.
    Logged in to Azure.
    

azd auth 解决方法

此解决方法要求安装Azure CLI

  1. 打开终端窗口,使用az login命令通过 Azure CLI 登录,--scope参数设置为https://graph.microsoft.com/.default

    az login --scope https://graph.microsoft.com/.default
    

    应重定向到新选项卡中的身份验证页以创建浏览器访问令牌,如以下示例所示:

    https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?clientid=<your_client_id>.
    
  2. 复制尝试使用azd auth login登录后收到的网页的 localhost URL。

  3. 在新终端窗口中,使用以下curl请求登录。 请确保将<localhost>占位符替换为在上一步中复制的 localhost URL。

    curl <localhost>
    

    成功登录会输出 HTML 网页,如以下示例所示:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="refresh" content="60;url=https://docs.microsoft.com/cli/azure/">
        <title>Login successfully</title>
        <style>
            body {
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            }
    
            code {
                font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
                display: inline-block;
                background-color: rgb(242, 242, 242);
                padding: 12px 16px;
                margin: 8px 0px;
            }
        </style>
    </head>
    <body>
        <h3>You have logged into Microsoft Azure!</h3>
        <p>You can close this window, or we will redirect you to the <a href="https://docs.microsoft.com/cli/azure/">Azure CLI documentation</a> in 1 minute.</p>
        <h3>Announcements</h3>
        <p>[Windows only] Azure CLI is collecting feedback on using the <a href="https://learn.microsoft.com/windows/uwp/security/web-account-manager">Web Account Manager</a> (WAM) broker for the login experience.</p>
        <p>You may opt-in to use WAM by running the following commands:</p>
        <code>
            az config set core.allow_broker=true<br>
            az account clear<br>
            az login
        </code>
    </body>
    </html>
    
  4. 关闭当前终端并打开原始终端。 应看到订阅的 JSON 列表。

  5. 复制要使用的订阅的id字段。

  6. 使用 az account set 命令设置订阅。

    az account set --subscription <subscription_id>
    

为群集创建和部署资源

若要部署该应用程序,请使用 azd up 命令创建运行 AKS 应用商店应用程序所需的所有对象。

  • azure.yaml 文件定义群集的所需状态,例如要提取的容器映像,并包括以下 Kubernetes 部署和服务:

显示 Azure 应用商店示例体系结构的图表。

  • 门店:Web 应用程序,供客户查看产品和下单。
  • 产品服务:显示产品信息。
  • 订单服务:下单。
  • Rabbit MQ:订单队列的消息队列。

注意

不建议在没有持久性存储用于生产的情况下,运行有状态容器(例如 Rabbit MQ)。 为简单起见,建议使用托管服务,例如 Azure Cosmos DB 或 Azure 服务总线。

部署应用程序资源

本快速入门的 azd 模板使用 AKS 群集和 Azure 密钥保管库新建资源组。 密钥保管库存储客户端机密,并在 pets 命名空间中运行服务。

  1. 使用azd up命令创建所有应用程序资源。

    azd up
    

    azd up运行azd-hooks文件夹中的所有挂钩,以预注册、预配和部署应用程序服务。

    自定义挂钩,将自定义代码添加到 azd 工作流阶段。 有关详细信息,请参阅 azd 挂钩参考。

  2. 为计费使用情况选择 Azure 订阅。

    ? Select an Azure Subscription to use:  [Use arrows to move, type to filter]
    > 1. My Azure Subscription (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
    
  3. 选择要将应用程序部署到的区域。

    Select an Azure location to use:  [Use arrows to move, type to filter]
      1.  (South America) Brazil Southeast (brazilsoutheast)
      2.  (US) Central US (centralus)
      3.  (US) East US (eastus)
    > 43. (US) East US 2 (eastus2)
      4.  (US) East US STG (eastusstg)
      5.  (US) North Central US (northcentralus)
      6.  (US) South Central US (southcentralus)
    

    azd 自动运行预配前和预配后挂钩,以便为应用程序创建资源。 此过程可能需要几分钟才能完成。 完成后,应看到类似于以下示例的输出:

    SUCCESS: Your workflow to provision and deploy to Azure completed in 9 minutes 40 seconds.
    

生成 Terraform 计划

在 Azure Developer 模板中,/infra/terraform 文件夹包含用于生成 Terraform 计划的所有代码。

azd 预配步骤中,Terraform 使用 terraform apply 部署和运行命令。 完成后,应看到类似于以下示例的输出:

Plan: 5 to add, 0 to change, 0 to destroy.
...
Saved the plan to: /workspaces/aks-store-demo/.azure/aks-terraform-azd/infra/terraform/main.tfplan

测试应用程序

应用程序运行时,Kubernetes 服务将向 Internet 公开应用程序前端。 此过程可能需要几分钟才能完成。

  1. 使用kubectl set-context命令将命名空间设置为演示命名空间pets

    kubectl config set-context --current --namespace=pets
    
  2. 使用 kubectl get pods 命令查看已部署的 Pod 的状态。 在继续操作之前,请确保所有 Pod 都 Running

    kubectl get pods
    
  3. 使用带有--watch参数的kubectl get service命令检查存储前端应用程序的公共 IP 地址,并监视进度。

    kubectl get service store-front --watch
    

    store-front 服务的 EXTERNAL-IP 输出最初显示为“pending”

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   <pending>     80:30025/TCP   4h4m
    
  4. EXTERNAL-IP 地址从 pending 更改为实际公共 IP 地址后,请使用 CTRL-C 来停止 kubectl 监视进程。

    以下示例输出显示向服务分配了有效的公共 IP 地址:

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   20.62.159.19   80:30025/TCP   4h5m
    
  5. 打开 Web 浏览器并转到服务的外部 IP 地址,以查看 Azure 应用商店应用的实际效果。

    AKS 应用商店示例应用程序的屏幕截图。

删除群集

完成快速入门后,清理不必要的资源以避免 Azure 费用。

  1. 使用 azd down 命令删除在快速入门中创建的所有资源。

    azd down
    
  2. 键入y并按Enter,以确认决定从订阅中删除所有已用资源。

    ? Total resources to delete: 14, are you sure you want to continue? (y/N)
    
  3. 键入y并按Enter,以允许清除以重复使用快速入门变量。

    [Warning]: These resources have soft delete enabled allowing them to be recovered for a period or time after deletion. During this period, their names can't be reused. In the future, you can use the argument --purge to skip this confirmation.
    

Azure 上的 Terraform 故障排除

排查在 Azure 上使用 Terraform 时遇到的常见问题

后续步骤

在本快速入门中,你部署了一个 Kubernetes 群集,然后在其中部署了示例多容器应用程序。 此示例应用程序仅用于演示目的,并未展示出 Kubernetes 应用程序的所有最佳做法。 有关使用生产版 AKS 创建完整解决方案的指南,请参阅 AKS 解决方案指南

若要详细了解 AKS 并演练完整的代码到部署示例,请继续阅读 Kubernetes 群集教程。