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

使用 Kubernetes 网关 API 配置 Istio 入口 - 预览版

重要

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

除了 Istio 自己的入口流量管理 API,Istio 服务网格加载项还支持 Kubernetes 网关 API 进行入口流量管理。 若要使用 Istio 加载项从 Azure 接收对基于网关 API 的部署的支持,必须在群集上启用 托管网关 API 安装 。 可以使用 Istio 网关 API 自动部署模型手动部署模型 进行入口流量管理。 ConfigMap 自定义必须属于 资源自定义允许列表

局限性

  • 对于手动部署模型,仅支持通过 Istio 加载项使用 Kubernetes 网关 API 进行出口流量管理
  • 针对Gateway资源的ConfigMap自定义必须属于资源自定义允许列表。 允许列表中未包含的字段不被允许,且通过加载项管理的 webhook 进行阻止。 若要详细了解 allowedblocked 功能,请参阅 supported

先决条件

使用 Kubernetes 网关配置入口

部署示例应用程序

首先,在httpbin命名空间中部署default示例应用。

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

创建 Kubernetes 网关和 HTTPRoute

接下来,在 default 命名空间中部署网关 API 配置,并将其 gatewayClassName 设置为 istio.

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,以控制哪个控制平面修订版本拥有它。 如果添加修订版标签,请确保在回滚或完成升级作业之前,将其相应更新为适当的控制平面修订版。

验证是否为 Deployment 创建了 ServiceHorizontalPodAutoscalerPodDisruptionBudgethttpbin-gateway

kubectl get deployment httpbin-gateway-istio
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
httpbin-gateway-istio   2/2     2            2           31m
kubectl get service httpbin-gateway-istio
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
kubectl get hpa httpbin-gateway-istio
NAME                    REFERENCE                          TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
httpbin-gateway-istio   Deployment/httpbin-gateway-istio   cpu: 3%/80%   2         5         3          34m
kubectl get pdb httpbin-gateway-istio
NAME                    MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
httpbin-gateway-istio   1               N/A               2                     36m

可以通过修改 默认值 ConfigMap 或通过将 ConfigMap 附加到特定的 GatewayClass 上来Gateway

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

最后,尝试向 curl 应用程序发送 httpbin 请求。 首先,设置 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}')

然后,尝试将 HTTP 请求发送到 httpbin

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

应会看到响应 HTTP 200

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

Istio 加载项支持从 Azure Key Vault (AKV) 同步机密,以使用 传输层安全性(TLS)终止服务器名称指示(SNI)传递来保护基于网关 API 的入口流量。 可以按照以下说明使用 AKV 机密存储容器存储接口(CSI)驱动程序加载项 将 AKV 中的机密同步到 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
  1. 生成证书和私钥,用于 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

配置 TLS 入口网关

设置 Azure 密钥保管库并将机密同步到群集
  1. 创建 Azure Key Vault

    需要 [Azure Key Vault 资源][akv-quickstart] 才能向 Istio 加载项提供证书和密钥输入。

    export AKV_NAME=<azure-key-vault-resource-name>  
    az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. 在群集上启用 [适用于机密存储 CSI 驱动程序的 Azure 密钥保管库提供程序][akv-addon] 加载项。

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. 如果您的 Key Vault 使用 Azure RBAC 作为权限模型,请按照 此处 的说明,将 Azure 角色 "Key Vault 机密用户" 分配给加载项的用户分配的托管标识。 或者,如果密钥保管库使用的是保管库访问策略权限模型,请授权用户分配的加载项托管标识使用访问策略访问 Azure 密钥保管库资源:

    OBJECT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.objectId' -o tsv | tr -d '\r')
    CLIENT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.clientId')
    TENANT_ID=$(az keyvault show --resource-group $RESOURCE_GROUP --name $AKV_NAME --query 'properties.tenantId')
    
    az keyvault set-policy --name $AKV_NAME --object-id $OBJECT_ID --secret-permissions get list
    
  4. 使用证书和密钥在 Azure 密钥保管库中创建机密。

    az keyvault secret set --vault-name $AKV_NAME --name test-httpbin-key --file httpbin_certs/httpbin.example.com.key
    az keyvault secret set --vault-name $AKV_NAME --name test-httpbin-crt --file httpbin_certs/httpbin.example.com.crt
    
  5. 使用以下清单部署 SecretProviderClass,为 CSI 驱动程序提供 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: $AKV_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 中证书对象的名称。 有关详细信息,请参阅[获取证书和密钥][akv-csi-driver-obtain-cert-and-keys] 部分。

    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: $AKV_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
    
  6. 使用以下清单部署示例 Pod。 机密存储 CSI 驱动程序需要一个 Pod 来引用 SecretProviderClass 资源,以确保机密从 Azure 密钥保管库同步到群集。

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: secrets-store-sync-httpbin
    spec:
      containers:
        - name: busybox
          image: mcr.microsoft.com/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
    
    • 验证 httpbin-credential 机密是否在 default SecretProviderClass 资源中定义的命名空间中创建。

      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. 创建一个 Kubernetes 网关,在 TLS 配置下引用 httpbin-credential 机密。

    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

    然后,创建一个对应的 HTTPRoute 来配置网关的入口流量路由。

    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
    

    获取网关地址和端口:

    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}')
    
  2. 发送 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 入口访问(即,将入口网关配置为对传入请求执行 SNI 直通而不是 TLS 终止),请将网关定义中的 tls 模式更新为 Passthrough。 这会指示网关“按原样”传递入口流量,而不会终止 TLS。

资源自定义

自定义批注设置

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

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
  infrastructure:
    annotations: 
      service.beta.kubernetes.io/azure-load-balancer-internal: "true"
      service.beta.kubernetes.io/azure-load-balancer-internal-subnet: "my-subnet"
EOF

ConfigMap 自定义设置

Istio 加载项还支持对为生成的资源进行自定义,即:

  • 服务
  • 部署
  • 水平 Pod 自动缩放程序 (HPA)
  • Pod 中断预算 (PDB)

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

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 在 GatewayClass 级别修改所有 Istio istio-gateway-class-defaults 的这些设置,也可为单个 Gateway 资源设定这些设置。 对于 GatewayClass 级别和 Gateway 级别的 ConfigMaps,字段必须添加到给定资源的允许列表中。 如果同时对 GatewayClass 和单个 Gateway 进行了自定义,那么 Gateway 级别的配置将优先。

资源自定义允许列表

资源允许列表中未包含的字段不被允许,且通过加载项管理的 webhook 进行阻止。 若要详细了解 allowedblocked 功能,请参阅 supported

部署字段

字段路径 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 逐出失败而导致的 UpgradeFailed 错误。

配置 GatewayClass 级设置

GatewayClass命名空间中更新aks-istio-system级别的ConfigMap。

kubectl edit cm istio-gateway-class-defaults -n aks-istio-system

编辑资源设置:

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

注释

每个GatewayClass只允许一个ConfigMap。

现在,你应该会看到你之前创建的 HPAhttpbin-gateway 已更新:

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

此外,请验证 Deployment 是否已更新为新标签:

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

配置特定网关的参数

httpbinGateway 创建带有资源自定义的 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

请更新httpbinGateway以引用ConfigMap。

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: httpbin-gateway
spec:
  gatewayClassName: istio
  infrastructure:
    parametersRef:
      group: ""
      kind: ConfigMap
      name: gw-options
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same
EOF

验证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

此外,检查 Deployment 标签,以确保将 test.azureservicemesh.io/deployment-config 更新为新值。

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

清理资源

运行以下命令以删除 GatewayHttpRoute

kubectl delete gateways.gateway.networking.k8s.io httpbin-gateway
kubectl delete httproute httpbin

如果您创建了用于定制Gateway的ConfigMap,请运行以下命令删除该ConfigMap:

kubectl delete configmap gw-options

如果创建了用于 TLS 终止的 SecretProviderClass 和机密,请删除以下资源:

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

后续步骤