使用适用于 Azure Kubernetes 服务的 Kubernetes 网关 API 配置 Istio 入口(预览版)

重要

AKS 预览功能可在自助服务和自愿选择的基础上启用。 预览版按“现状”和“视供应情况”提供,它们不包括在服务级别协议和有限保证范围内。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

Istio 服务网格加载项支持 Istio 自己的入口流量管理 API 和用于入口流量管理的 Kubernetes 网关 API。 可以使用 Istio 网关 API 自动部署模型手动部署模型。 本文介绍如何使用 Kubernetes 网关 API 和 自动化部署模型为 Istio 服务网格加载项配置入口流量管理。

限制和注意事项

  • 仅在手动部署模型中支持将 Kubernetes 网关 API 用于出口流量管理与 Istio 服务网格加载项。
  • 资源的 ConfigMap 自定义 Gateway 必须位于资源自定义允许列表中。 未在允许列表中的字段将被禁止,并通过加载项管理的 Webhook 阻止。 有关详细信息,请参阅 Istio 服务网格附加支持策略

先决条件

  • 在 AKS 群集上启用 托管网关 API
  • 安装 Istio 服务网格插件修订版 asm-1-26 或更高版本。 如果尚未安装 Istio 服务网格加载项,请遵循 安装指南 ;如果使用的是较低次要修订,请遵循 升级指南

设置环境变量。

设置以下环境变量,以便在整个文章中使用:

Variable Description
RESOURCE_GROUP 包含 AKS 群集的资源组的名称。
CLUSTER_NAME AKS 群集的名称。
LOCATION 部署 AKS 群集的 Azure 区域。
KEY_VAULT_NAME 要创建的用于存储 TLS 机密的 Azure Key Vault 资源的名称。 如果有现有资源,请使用该名称。

部署示例应用程序

  • 使用httpbin命令在default命名空间中部署示例kubectl apply应用程序。

    kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.26/samples/httpbin/httpbin.yaml
    

创建 Kubernetes 网关和 HTTPRoute

示例清单创建可从群集外部访问的外部入口负载均衡器服务。 可以添加 批注 以创建内部负载均衡器并自定义其他负载均衡器设置。

  • default命名空间中部署一个网关 API 配置,将gatewayClassName设置为istio,并使用HTTPRoute将流量路由到httpbin服务,使用以下清单:

    kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      gatewayClassName: istio
      listeners:
      - name: http
        port: 80
        protocol: HTTP
        allowedRoutes:
          namespaces:
            from: Same
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: http
      namespace: default
    spec:
      parentRefs:
      - name: httpbin-gateway
      hostnames: ["httpbin.example.com"]
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /get
        backendRefs:
        - name: httpbin
          port: 8000
    EOF
    

    注释

    如果要执行小版本升级,并且在群集上同时安装了两个 Istio 服务网格加载项修订,则小版本中较高版本的控制平面会默认接管Gateways 的管理权限。 可以将istio.io/rev标签添加到Gateway,以控制哪个控制平面修订版本拥有它。 如果添加修订版标签,请确保在回滚或完成升级作业之前,将其相应更新为适当的控制平面修订版。

验证资源创建

  • 验证DeploymentServiceHorizontalPodAutoscalerPodDisruptionBudget资源是否已使用以下kubectl get命令创建:

    kubectl get deployment httpbin-gateway-istio
    kubectl get service httpbin-gateway-istio
    kubectl get hpa httpbin-gateway-istio
    kubectl get pdb httpbin-gateway-istio
    

    示例输出:

    # Deployment resource
    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    httpbin-gateway-istio   2/2     2            2           31m
    
    # Service resource
    NAME                    TYPE           CLUSTER-IP   EXTERNAL-IP      PORT(S)                        AGE
    httpbin-gateway-istio   LoadBalancer   10.0.65.45   <external-ip>    15021:32053/TCP,80:31587/TCP   33m
    
    # HPA resource
    NAME                    REFERENCE                          TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    httpbin-gateway-istio   Deployment/httpbin-gateway-istio   cpu: 3%/80%   2         5         3          34m
    
    # PDB resource
    NAME                    MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    httpbin-gateway-istio   1               N/A               2                     36m
    

将请求发送到示例应用程序

  1. 尝试向curlhttpbin应用程序发送请求。 首先,设置 INGRESS_HOST 环境变量:

    kubectl wait --for=condition=programmed gateways.gateway.networking.k8s.io httpbin-gateway
    export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io httpbin-gateway -ojsonpath='{.status.addresses[0].value}')
    
  2. 尝试向 httpbin 发送 HTTP 请求。

    curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/get"
    

    在输出中,应会看到响应 HTTP 200

使用 Kubernetes 网关 API 保护 Istio 入口流量

Istio 服务网格加载项支持从 Azure Key Vault 同步机密,以便通过 传输层安全性(TLS)终止服务器名称指示(SNI)传递来保护基于网关 API 的入口流量。 在以下部分中,使用 适用于机密存储容器存储接口(CSI)驱动程序插件的 Azure Key Vault 提供程序,将机密从 Azure Key Vault 同步至 AKS 集群,并在入口网关上进行 TLS 终止。

创建客户端/服务器证书和密钥

  1. 创建根证书和私钥用于为示例服务的证书签名:

    mkdir httpbin_certs
    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout httpbin_certs/example.com.key -out httpbin_certs/example.com.crt
    
  2. 生成证书和私钥,用于 httpbin.example.com

    openssl req -out httpbin_certs/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin_certs/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
    openssl x509 -req -sha256 -days 365 -CA httpbin_certs/example.com.crt -CAkey httpbin_certs/example.com.key -set_serial 0 -in httpbin_certs/httpbin.example.com.csr -out httpbin_certs/httpbin.example.com.crt
    

设置 Azure Key Vault 并创建机密

  1. 创建一个 Azure Key Vault 实例,以使用 az keyvault create 命令向 Istio 服务网格加载项提供证书和密钥输入。 如果已有 Azure Key Vault 实例,可以跳过此步骤。

    az keyvault create --name $KEY_VAULT_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. 使用命令在群集上az aks enable-addons

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME
    
  3. 如果密钥保管库使用 Azure 基于角色的访问控制(RBAC)作为权限模型,请按照 提供对 Azure Key Vault 密钥、证书和机密的访问权限中的说明,通过 Azure 基于角色的访问控制 为加载项的用户分配 Key Vault 机密用户的 Azure 角色。 或者,如果密钥保管库使用保管库访问策略权限模型,请使用命令授权加载项的用户分配的托管标识,以使用访问策略 az keyvault set-policy 访问 Azure Key Vault 资源。

    OBJECT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.objectId' -o tsv | tr -d '\r')
    CLIENT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.clientId')
    TENANT_ID=$(az keyvault show --resource-group $RESOURCE_GROUP --name $KEY_VAULT_NAME --query 'properties.tenantId')
    
    az keyvault set-policy --name $KEY_VAULT_NAME --object-id $OBJECT_ID --secret-permissions get list
    
  4. 使用以下命令 az keyvault secret set 使用证书和密钥在 Azure Key Vault 中创建机密:

    az keyvault secret set --vault-name $KEY_VAULT_NAME --name test-httpbin-key --file httpbin_certs/httpbin.example.com.key
    az keyvault secret set --vault-name $KEY_VAULT_NAME --name test-httpbin-crt --file httpbin_certs/httpbin.example.com.crt
    

部署 SecretProviderClass 和示例 Pod

  1. 部署 SecretProviderClass,以便使用以下清单向 CSI 驱动程序提供 Azure Key Vault 特定参数。 在此示例中, test-httpbin-keytest-httpbin-crt 是 Azure Key Vault 中机密对象的名称。

    cat <<EOF | kubectl apply -f -
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: httpbin-credential-spc
    spec:
      provider: azure
      secretObjects:
      - secretName: httpbin-credential
        type: kubernetes.io/tls
        data:
        - objectName: test-httpbin-key
          key: tls.key
        - objectName: test-httpbin-crt
          key: tls.crt
      parameters:
        useVMManagedIdentity: "true"
        userAssignedIdentityID: $CLIENT_ID 
        keyvaultName: $KEY_VAULT_NAME
        cloudName: ""
        objects:  |
          array:
            - |
              objectName: test-httpbin-key
              objectType: secret
              objectAlias: "test-httpbin-key"
            - |
              objectName: test-httpbin-crt
              objectType: secret
              objectAlias: "test-httpbin-crt"
        tenantId: $TENANT_ID
    EOF
    

    注释

    或者,若要直接从 Azure Key Vault 引用证书对象类型,请使用以下清单部署 SecretProviderClass。 在此示例中, test-httpbin-cert-pxf 是 Azure Key Vault 中证书对象的名称。

    cat <<EOF | kubectl apply -f -
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: httpbin-credential-spc
    spec:
      provider: azure
      secretObjects:
      - secretName: httpbin-credential
        type: kubernetes.io/tls
        data:
        - objectName: test-httpbin-key
          key: tls.key
        - objectName: test-httpbin-crt
          key: tls.crt
      parameters:
        useVMManagedIdentity: "true"
        userAssignedIdentityID: $CLIENT_ID 
        keyvaultName: $KEY_VAULT_NAME
        cloudName: ""
        objects:  |
          array:
            - |
              objectName: test-httpbin-cert-pfx  #certificate object name from keyvault
              objectType: secret
              objectAlias: "test-httpbin-key"
            - |
              objectName: test-httpbin-cert-pfx #certificate object name from keyvault
              objectType: cert
              objectAlias: "test-httpbin-crt"
        tenantId: $TENANT_ID
    EOF
    
  2. 使用以下清单部署示例 Pod。 用于机密存储的 Azure Key Vault 提供程序(CSI)驱动程序加载项要求 Pod 引用 SecretProviderClass 资源,以确保机密从 Azure Key Vault 同步到群集。

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: secrets-store-sync-httpbin
    spec:
      containers:
        - name: busybox
          image: mcr.azk8s.cn/oss/busybox/busybox:1.33.1
          command:
            - "/bin/sleep"
            - "10"
          volumeMounts:
          - name: secrets-store01-inline
            mountPath: "/mnt/secrets-store"
            readOnly: true
      volumes:
        - name: secrets-store01-inline
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: "httpbin-credential-spc"
    EOF
    

验证 TLS 密钥创建

  • 验证httpbin-credential是否在default命名空间中按照 SecretProviderClass 资源的定义创建了一个kubectl describe secret机密,使用kubectl describe secret命令进行。

    kubectl describe secret/httpbin-credential
    

    示例输出:

    Name:         httpbin-credential
    Namespace:    default
    Labels:       secrets-store.csi.k8s.io/managed=true
    Annotations:  <none>
    
    Type:  kubernetes.io/tls
    
    Data
    ====
    tls.crt:  1180 bytes
    tls.key:  1675 bytes
    

部署 TLS 网关

  1. 使用以下清单创建一个在 TLS 配置下引用 httpbin-credential 密钥的 Kubernetes 网关:

    cat <<EOF | kubectl apply -f -
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      gatewayClassName: istio
      listeners:
      - name: https
        hostname: "httpbin.example.com"
        port: 443
        protocol: HTTPS
        tls:
          mode: Terminate
          certificateRefs:
          - name: httpbin-credential
        allowedRoutes:
          namespaces:
            from: Selector
            selector:
              matchLabels:
                kubernetes.io/metadata.name: default
    EOF
    

    注释

    在网关定义中, tls.certificateRefs.name 必须与 SecretProviderClass 资源匹配 secretName

  2. 创建一个相应的 HTTPRoute,使用以下清单通过 HTTPS 路由入口流量到 httpbin 服务:

    cat <<EOF | kubectl apply -f -
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin
    spec:
      parentRefs:
      - name: httpbin-gateway
      hostnames: ["httpbin.example.com"]
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /status
        - path:
            type: PathPrefix
            value: /delay
        backendRefs:
        - name: httpbin
          port: 8000
    EOF
    
  3. 使用以下命令获取入口网关的外部 IP 地址和安全端口:

    kubectl wait --for=condition=programmed gateways.gateway.networking.k8s.io httpbin-gateway
    export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io httpbin-gateway -o jsonpath='{.status.addresses[0].value}')
    export SECURE_INGRESS_PORT=$(kubectl get gateways.gateway.networking.k8s.io httpbin-gateway -o jsonpath='{.spec.listeners[?(@.name=="https")].port}')
    
  4. 发送 HTTPS 请求以访问 httpbin 服务:

    curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \
    --cacert httpbin_certs/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    

    输出应显示 httpbin 服务返回 418 我是茶壶 代码。

    注释

    若要配置对 HTTPS 服务的 HTTPS 入口访问,请将网关定义中的 TLS 模式更新为 Passthrough。 此配置指示网关 按原样传递入口流量,而不会终止 TLS。

自定义批注设置

可以在spec.infrastructure.annotations下添加注释以配置负载均衡器设置,用于Gateway。 例如,若要创建附加到特定子网的内部负载均衡器,可以使用以下注释创建一个 Gateway

spec:
  # ... existing spec content ...
  infrastructure:
    annotations: 
      service.beta.kubernetes.io/azure-load-balancer-internal: "true"
      service.beta.kubernetes.io/azure-load-balancer-internal-subnet: "my-subnet"

ConfigMap 自定义设置

Istio 服务网格附加组件支持对为 生成的 Gateways 进行自定义,其中包括:

  • 服务
  • 部署
  • 水平 Pod 自动缩放器 (HPA)
  • Pod 故障预算 (PDB)

这些资源的默认设置是在 istio-gateway-class-defaults 命名空间中的 aks-istio-system ConfigMap 中设定的。 此ConfigMap必须将标签设置为gateway.istio.io/defaults-for-classistio,以便自定义项对所有Gatewaysspec.gatewayClassName: istio的项生效。 启用GatewayClass后,aks-istio-system 命名空间中默认会安装 级别的 ConfigMap。 安装托管网关 API CRD 后,ConfigMap 的部署可能最多需要五分钟 istio-gateway-class-defaults

kubectl get configmap istio-gateway-class-defaults -n aks-istio-system -o yaml
...
data:
  horizontalPodAutoscaler: |
    spec:
      minReplicas: 2
      maxReplicas: 5
  podDisruptionBudget: |
    spec:
      minAvailable: 1
...

可以通过更新 Gateways ConfigMap 来修改所有 Istio GatewayClassistio-gateway-class-defaults 的这些设置,也可以为单个Gateway资源设置这些设置。 必须在给定资源中为 GatewayClass 级别和 Gateway 级别的 ConfigMaps 添加字段至允许列表。 如果同时对 GatewayClass 和单个 Gateway 进行了自定义,那么 Gateway 级别的配置将优先。

允许列表字段的部署自定义

字段路径 Description
metadata.labels 部署标签
metadata.annotations 部署注释
spec.replicas 部署副本计数
spec.template.metadata.labels Pod 标签
spec.template.metadata.annotations Pod 批注
spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms 节点相关性
spec.template.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution 节点相关性
spec.template.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution Pod 相关性
spec.template.spec.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution Pod 相关性
spec.template.spec.affinity.podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution Pod 反相关性
spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution Pod 反相关性
spec.template.spec.containers.resizePolicy 容器资源利用率
spec.template.spec.containers.resources.limits 容器资源利用率
spec.template.spec.containers.resources.requests 容器资源利用率
spec.template.spec.containers.stdin 容器调试
spec.template.spec.containers.stdinOnce 容器调试
spec.template.spec.nodeSelector Pod 调度
spec.template.spec.nodeName Pod 调度
spec.template.spec.tolerations Pod 调度
spec.template.spec.topologySpreadConstraints Pod 调度

服务自定义允许列表字段

字段路径 Description
metadata.labels 服务标签
metadata.annotations 服务注释
spec.type 服务类型
spec.loadBalancerSourceRanges 服务负载均衡器设置
spec.loadBalancerClass 服务负载均衡器设置
spec.externalTrafficPolicy 服务流量策略
spec.internalTrafficPolicy 服务流量策略

HorizontalPodAutoscaler(HPA)自定义允许列表字段

字段路径 Description
metadata.labels HPA 标签
metadata.annotations HPA 批注
spec.behavior.scaleUp.stabilizationWindowSeconds HPA 纵向扩展行为
spec.behavior.scaleUp.selectPolicy HPA 纵向扩展行为
spec.behavior.scaleUp.policies HPA 纵向扩展行为
spec.behavior.scaleDown.stabilizationWindowSeconds HPA 缩减行为
spec.behavior.scaleDown.selectPolicy HPA 缩减行为
spec.behavior.scaleDown.policies HPA 缩减行为
spec.metrics HPA 缩放资源指标
spec.minReplicas HPA 最小副本计数。 不得低于 2。
spec.maxReplicas HPA 最大副本计数

PodDisruptionBudget (PDB) 自定义允许列表字段

字段路径 Description
metadata.labels PDB 标签
metadata.annotations PDB 注释
spec.minAvailable PDB 最低可用性
spec.unhealthyPodEvictionPolicy PDB 逐出策略

注释

PDB修改最小可用性和逐出策略可能会导致集群/节点升级和删除操作期间出现潜在错误。 按照 PDB 故障排除指南 解决因 而导致的 PDB 错误。

配置 GatewayClass 级设置

  1. 使用GatewayClass命令在aks-istio-system命名空间中更新kubectl edit configmap级别的ConfigMap。

    kubectl edit cm istio-gateway-class-defaults -n aks-istio-system
    
  2. 根据需要编辑 data 部分中的资源设置。 例如,若要更新 HPA 最小/最大副本数并向 Deployment 添加标签,请按如下方式修改 ConfigMap:

    ...
    data:
      deployment: |
        metadata:
          labels:
            test.azureservicemesh.io/deployment-config: "updated"
      horizontalPodAutoscaler: |
        spec:
          minReplicas: 3
          maxReplicas: 6
      podDisruptionBudget: |
        spec:
          minAvailable: 1
    ...
    

    注释

    每个GatewayClass只允许一个ConfigMap。

  3. 现在,你应该会看到你之前创建的 HPA 中的 httpbin-gateway,已经更新为新的最小值/最大值。 HPA使用kubectl get hpa命令验证设置。

    kubectl get hpa httpbin-gateway-istio
    

    示例输出:

    NAME                    REFERENCE                          TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    httpbin-gateway-istio   Deployment/httpbin-gateway-istio   cpu: 3%/80%   3         6         3          36m
    
  4. 使用Deployment命令验证kubectl get deployment是否已更新为新标签。

    kubectl get deployment httpbin-gateway-istio -ojsonpath='{.metadata.labels.test\.azureservicemesh\.io\/deployment-config}'
    

    示例输出:

    updated
    

配置特定网关的参数

  1. 使用以下清单为网关创建具有资源自定义的 httpbin ConfigMap:

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: gw-options
    data:
      horizontalPodAutoscaler: |
        spec:
          minReplicas: 2
          maxReplicas: 4
      deployment: |
        metadata:
          labels:
            test.azureservicemesh.io/deployment-config: "updated-per-gateway"
    EOF
    
  2. 请更新httpbinGateway以引用ConfigMap。

    spec:
      # ... existing spec content ...
      infrastructure:
        parametersRef:
          group: ""
          kind: ConfigMap
          name: gw-options
    
  3. 使用 kubectl apply 命令应用更新。

    kubectl apply -f httpbin-gateway-updated.yaml
    
  4. 请使用HPA命令验证kubectl get hpa是否已更新为新的最小值/最大值。 如果你还配置了GatewayClass级别的ConfigMap,Gateway级别的设置应优先。

    kubectl get hpa httpbin-gateway-istio
    

    示例输出:

    NAME                    REFERENCE                          TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    httpbin-gateway-istio   Deployment/httpbin-gateway-istio   cpu: 3%/80%   2         4         2          4h14m
    
  5. 检查Deployment标签,确保test.azureservicemesh.io/deployment-config已使用kubectl get deployment命令更新为新值。

    kubectl get deployment httpbin-gateway-istio -ojsonpath='{.metadata.labels.test\.azureservicemesh\.io\/deployment-config}'
    

    示例输出:

    updated-per-gateway
    

清理资源

如果不再需要本文中创建的资源,可以将其删除,以避免产生任何费用。

  1. 使用以下命令 kubectl delete 删除网关和 HTTPRoute 资源:

    kubectl delete gateways.gateway.networking.k8s.io httpbin-gateway
    kubectl delete httproute httpbin
    
  2. 如果创建了用于自定义网关资源的 ConfigMap,请使用 kubectl delete configmap 命令将其删除。

    kubectl delete configmap gw-options
    
  3. 如果创建了用于 TLS 终止的 SecretProviderClass 和机密, kubectl delete 请使用以下命令删除资源:

    kubectl delete secret httpbin-credential
    kubectl delete pod secrets-store-sync-httpbin
    kubectl delete secretproviderclass httpbin-credential-spc