安装使用现有应用程序网关的应用程序网关入口控制器 (AGIC)

应用程序网关入口控制器 (AGIC) 是 Azure Kubernetes 服务 (AKS) 群集中的一个 pod。 AGIC 监视 Kubernetes 入口资源,并根据 Kubernetes 群集状态创建和应用应用程序网关配置。

轮廓

先决条件

本文档假设已安装以下工具和基础结构:

在安装 AGIC 之前,请备份应用程序网关的配置:

  1. Azure 门户 导航到应用程序网关实例。
  2. 在“自动化”部分下,选择“导出模板”,然后选择“下载”。

下载的 zip 文件包含 JSON 模板、bash 和 PowerShell 脚本,你可以根据需要使用它们来还原应用网关

安装 Helm

Helm 是 Kubernetes 的包管理器,用于安装 application-gateway-kubernetes-ingress 包。

安装 Helm 并运行以下命令:

  • 已启用 Kubernetes RBAC 的 AKS 群集
kubectl create serviceaccount --namespace kube-system tiller-sa
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller-sa
helm init --tiller-namespace kube-system --service-account tiller-sa

Azure 资源管理器身份验证

AGIC 与 Kubernetes API 服务器和 Azure 资源管理器通信。 它需要一个标识来访问这些 API。

设置 Microsoft Entra 工作负载 ID

Microsoft Entra 工作负载 ID 是分配给软件工作负载,用于进行身份验证和访问其他服务和资源的标识。 此标识使 AKS Pod 能够使用此标识并与其他 Azure 资源进行身份验证。 我们需要为此配置授权 AGIC pod 向 ARM 发出 HTTP 请求。

  1. 使用 Azure CLI az account set 命令将特定订阅设置为当前活动订阅。 然后使用 az identity create 命令创建托管标识。 需要在 节点资源组 中创建标识。 默认情况下会为节点资源组分配一个名称,例如 MC_myResourceGroup_myAKSCluster_chinanorth2

    az account set --subscription "subscriptionID"
    
    az identity create --name "userAssignedIdentityName" --resource-group "resourceGroupName" --location "location" --subscription "subscriptionID"
    
  2. 对于角色分配,运行以下命令以确认新创建标识的标识 principalId

    $resourceGroup="resource-group-name"
    $identityName="identity-name"
    az identity list -g $resourceGroup --query "[?name == '$identityName'].principalId | [0]" -o tsv
    
  3. 授予该标识对应用程序网关的 参与者 访问权限。 需要应用程序网关的 ID,示例如下所示:/subscriptions/A/resourceGroups/B/providers/Microsoft.Network/applicationGateways/C。 首先,通过运行以下命令获取订阅中应用程序网关 ID 的列表:

    az network application-gateway list --query '[].id'
    

    运行以下命令,以向标识分配 参与者 访问权限:

    $resourceGroup="resource-group-name"
    $identityName="identity-Name"
    # Get the Application Gateway ID
    $AppGatewayID=$(az network application-gateway list --query '[].id' -o tsv)
    $role="contributor"
    # Get the principal ID for the User assigned identity
    $principalId=$(az identity list -g $resourceGroup --query "[?name == '$identityName'].principalId | [0]" -o tsv)
    az role assignment create --assignee $principalId --role $role --scope $AppGatewayID
    
  4. 授予标识对应用程序网关资源组的 读取 访问权限。 资源组 ID 格式示例如下所示:/subscriptions/A/resourceGroups/B。 可使用以下命令获取所有资源组:az group list --query '[].id'

    $resourceGroup="resource-group-name"
    $identityName="identity-Name"
    # Get the Application Gateway resource group
    $AppGatewayResourceGroup=$(az network application-gateway list --query '[].resourceGroup' -o tsv)
    # Get the Application Gateway resource group ID
    $AppGatewayResourceGroupID=$(az group show --name $AppGatewayResourceGroup --query id -o tsv)
    $role="Reader"
    # Get the principal ID for the User assigned identity
    $principalId=$(az identity list -g $resourceGroup --query "[?name == '$identityName'].principalId | [0]" -o tsv)
    # Assign the Reader role to the User assigned identity at the resource group scope
    az role assignment create --role $role --assignee $principalId  --scope $AppGatewayResourceGroupID
    

注意

请确保 AGIC 使用的标识已将 Microsoft.Network/virtualNetworks/subnets/join/action 权限委托给应用程序网关部署到的子网。 如果未使用此权限定义自定义角色,则可以使用包含 Microsoft.Network/virtualNetworks/subnets/join/action 权限的内置“网络参与者”角色。

使用服务主体

还可以使用 Kubernetes 机密为 AGIC 提供对 ARM 的访问权限。

  1. 创建 Active Directory 服务主体并使用 base64 编码。 JSON Blob 需要使用 base64 编码才能保存到 Kubernetes 中。

    az ad sp create-for-rbac --role Contributor --sdk-auth | base64 -w0
    
  2. 将 base64 编码的 JSON Blob 添加到 helm-config.yaml 文件中。 下一部分提供了有关 helm-config.yaml 的详细信息。

    armAuth:
        type: servicePrincipal
        secretJSON: <Base64-Encoded-Credentials>
    

部署 Azure 应用程序网关入口控制器加载项

创建入口控制器部署清单

---
# file: pet-supplies-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: pet-supplies-ingress
spec:
  ingressClassName: azure-application-gateway
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: store-front
            port:
              number: 80
      - path: /order-service
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 3000
      - path: /product-service
        pathType: Prefix
        backend:
          service:
            name: product-service
            port:
              number: 3002

部署入口控制器

$namespace="namespace"
$file="pet-supplies-ingress.yaml"
kubectl apply -f $file -n $namespace

以 Helm 图表的形式安装入口控制器

前几个步骤在 Kubernetes 群集上安装了 Helm 的 Tiller。 安装 AGIC Helm 包:

  1. 执行 helm 更新

    helm repo update
    
  2. 下载 helm-config.yaml,用于配置 AGIC:

    wget https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/master/docs/examples/sample-helm-config.yaml -O helm-config.yaml
    

    或者复制以下 YAML 文件:

    # This file contains the essential configs for the ingress controller helm chart
    
    # Verbosity level of the App Gateway Ingress Controller
    verbosityLevel: 3
    
    ################################################################################
    # Specify which application gateway the ingress controller must manage
    #
    appgw:
        subscriptionId: <subscriptionId>
        resourceGroup: <resourceGroupName>
        name: <applicationGatewayName>
        environment: AzureChinaCloud
    
        # Setting appgw.shared to "true" creates an AzureIngressProhibitedTarget CRD.
        # This prohibits AGIC from applying config for any host/path.
        # Use "kubectl get AzureIngressProhibitedTargets" to view and change this.
        shared: false
    
    ################################################################################
    # Specify which kubernetes namespace the ingress controller must watch
    # Default value is "default"
    # Leaving this variable out or setting it to blank or empty string would
    # result in Ingress Controller observing all accessible namespaces.
    #
    # kubernetes:
    #   watchNamespace: <namespace>
    
    ################################################################################
    # Specify the authentication with Azure Resource Manager
    #
    # Two authentication methods are available:
    # - Option 1: Azure-AD-workload-identity
    armAuth:
        type: workloadIdentity
        identityClientID:  <identityClientId>
    
    ## Alternatively you can use Service Principal credentials
    # armAuth:
    #    type: servicePrincipal
    #    secretJSON: <<Generate this value with: "az ad sp create-for-rbac --role Contributor --sdk-auth | base64 -w0" >>
    
    ################################################################################
    # Specify if the cluster is Kubernetes RBAC enabled or not
    rbac:
        enabled: false # true/false
    
    # Specify aks cluster related information. THIS IS BEING DEPRECATED.
    aksClusterConfiguration:
        apiServerAddress: <aks-api-server-address>
    
  3. 编辑 helm-config.yaml 并填写 appgwarmAuth 的值。

    注意

    <identity-client-id> 是上一部分中设置的 Microsoft Entra 工作负载 ID 的属性。 可以通过运行以下命令来检索此信息:az identity show -g <resourcegroup> -n <identity-name>,其中 <resourcegroup> 是托管与 AKS 群集、应用程序网关和托管标识相关的基础结构资源的资源组。

  4. 使用上一步骤中的 helm-config.yaml 配置安装 Helm 图表

    helm install agic-controller oci://mcr.microsoft.com/azure-application-gateway/charts/ingress-azure --version 1.7.5 -f helm-config.yaml
    

    或者,可以在一个步骤中结合使用 helm-config.yaml 和 Helm 命令:

    helm install oci://mcr.microsoft.com/azure-application-gateway/charts/ingress-azure \
         --name agic-controller \
         --version 1.7.5 \
         --namespace default \
         --debug \
         --set appgw.name=applicationgatewayABCD \
         --set appgw.resourceGroup=your-resource-group \
         --set appgw.subscriptionId=subscription-uuid \
         --set appgw.environment=AzureChinaCloud \
         --set appgw.shared=false \
         --set armAuth.type=servicePrincipal \
         --set armAuth.secretJSON=$(az ad sp create-for-rbac --role Contributor --sdk-auth | base64 -w0) \
         --set rbac.enabled=true \
         --set verbosityLevel=3 \
         --set kubernetes.watchNamespace=default \
         --set aksClusterConfiguration.apiServerAddress=aks-abcdefg.hcp.chinanorth2.azmk8s.io
    
  5. 检查新建 pod 的日志,以确认它是否已正确启动

请参阅此操作指南,了解如何使用 Azure 应用程序网关通过 HTTP 或 HTTPS 向 Internet 公开 AKS 服务。

共享应用程序网关

默认情况下,AGIC 对它所链接到的应用程序网关拥有完全所有权。 AGIC 0.8.0 和更高版本可与其他 Azure 组件共享单个应用程序网关。 例如,我们可以对虚拟机规模集上托管的某个应用以及某个 AKS 群集使用同一个应用程序网关。

在启用此设置之前,请备份应用程序网关的配置:

  1. Azure 门户导航到 Application Gateway 实例
  2. 在“自动化”部分下,选择“导出模板”,然后选择“下载”。

下载的 zip 文件包含可用于还原应用程序网关的 JSON 模板、bash 和 PowerShell 脚本

示例方案

让我们探讨一个虚构的应用程序网关,它将管理两个网站的流量:

  • dev.contoso.com - 托管在新 AKS 群集上,使用应用程序网关和 AGIC
  • prod.contoso.com - 托管在 Azure 虚拟机规模集

使用默认设置时,AGIC 拥有它所指向的应用程序网关的完全所有权。 AGIC 将覆盖应用程序网关的所有配置。 如果手动为 prod.contoso.com 创建侦听器(在应用程序网关上),但未在 Kubernetes 入口中定义该侦听器,则 AGIC 很快就会删除 prod.contoso.com 配置。

若要安装 AGIC 并从虚拟机规模集计算机为 prod.contoso.com 提供服务,必须将 AGIC 约束为仅配置 dev.contoso.com。 实例化以下 CRD 可化简化此过程:

cat <<EOF | kubectl apply -f -
apiVersion: "appgw.ingress.k8s.io/v1"
kind: AzureIngressProhibitedTarget
metadata:
  name: prod-contoso-com
spec:
  hostname: prod.contoso.com
EOF

以上命令创建一个 AzureIngressProhibitedTarget 对象。 这会使 AGIC(0.8.0 和更高版本)意识到 prod.contoso.com 的应用程序网关配置的存在,并显式指示应用程序网关避免更改与该主机名相关的任何配置。

在新的 AGIC 安装中启用

若要将 AGIC(0.8.0 和更高版本)限制为一部分应用程序网关配置,请修改 helm-config.yaml 模板。 在 appgw: 节下,添加 shared 键并将其设置为 true

appgw:
    subscriptionId: <subscriptionId>    # existing field
    resourceGroup: <resourceGroupName>  # existing field
    name: <applicationGatewayName>      # existing field
    environment: AzureChinaCloud        # existing field
    shared: true                        # <<<<< Add this field to enable shared Application Gateway >>>>>

应用 Helm 更改:

  1. 使用以下命令确保安装 AzureIngressProhibitedTarget CRD:

    kubectl apply -f https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/7b55ad194e7582c47589eb9e78615042e00babf3/crds/AzureIngressProhibitedTarget-v1-CRD-v1.yaml
    
  2. 更新 Helm:

    helm upgrade \
        --recreate-pods \
        -f helm-config.yaml \
        agic-controller
        oci://mcr.microsoft.com/azure-application-gateway/charts/ingress-azure
    

因此,AKS 群集有一个名为 prohibit-all-targetsAzureIngressProhibitedTarget 新实例:

kubectl get AzureIngressProhibitedTargets prohibit-all-targets -o yaml

顾名思义,prohibit-all-targets 对象将禁止 AGIC 更改任何主机和路径的配置。 使用 appgw.shared=true 的 Helm 安装会部署 AGIC,但不会对应用程序网关进行任何更改。

放宽权限

由于带有 appgw.shared=true 和默认 prohibit-all-targets 的 Helm 会阻止 AGIC 应用某个配置,因此请放宽 AGIC 权限:

  1. 使用以下代码片段创建名为 AzureIngressProhibitedTarget 的新 YAML 文件,其中包含特定设置:

    cat <<EOF | kubectl apply -f -
    apiVersion: "appgw.ingress.k8s.io/v1"
    kind: AzureIngressProhibitedTarget
    metadata:
      name: your-custom-prohibitions
    spec:
      hostname: your.own-hostname.com
    EOF
    
  2. 只有在创建自己的自定义禁止规则之后,才能删除默认的禁止规则(该规则过于宽泛):

    kubectl delete AzureIngressProhibitedTarget prohibit-all-targets
    

为现有的 AGIC 安装启用

假设我们的群集中已有一个正常运行的 AKS 群集、应用程序网关且已配置 AGIC。 我们有 prod.contoso.com 的入口,并且能够成功地从群集为它提供流量。 我们想要将 staging.contoso.com 添加到现有的应用程序网关,但需要将此网关托管在 VM 上。 我们将重复使用现有的应用程序网关,并为 staging.contoso.com 手动配置侦听器和后端池。 但是,手动调整应用程序网关配置(使用门户ARM APITerraform)将与 AGIC 拥有完全所有权的事实相冲突。 应用更改后不久,AGIC 会覆盖或删除这些更改。

我们可以禁止 AGIC 对一部分配置进行更改。

  1. 使用以下代码片段创建名为 AzureIngressProhibitedTarget 的新 YAML 文件:

    cat <<EOF | kubectl apply -f -
    apiVersion: "appgw.ingress.k8s.io/v1"
    kind: AzureIngressProhibitedTarget
    metadata:
      name: manually-configured-staging-environment
    spec:
      hostname: staging.contoso.com
    EOF
    
  2. 查看新建的对象:

    kubectl get AzureIngressProhibitedTargets
    
  3. 从 Azure 门户修改应用程序网关配置 - 添加侦听器、路由规则、后端等。创建的新对象 (manually-configured-staging-environment) 会禁止 AGIC 覆盖与 staging.contoso.com 相关的应用程序网关配置。