用于现代化改造的配置更新

本文档介绍了在将网格从 ISTIOD 控制平面现代化改造为 TRAFFIC_DIRECTOR 控制平面之前,您可能需要对托管式 Cloud Service Mesh 进行的配置更新。

下面列出了为使集群准备好现代化改造而需要进行的可能的配置更新。如需查看更新说明,请参阅各个部分:

如需详细了解现代化改造工作流,请参阅托管式控制平面现代化改造页面。

从 Istio Secret 迁移到 multicluster_mode

当集群使用 TRAFFIC_DIRECTOR 控制平面时,不支持多集群 Secret。本文档介绍了如何从使用 Istio 多集群 Secret 现代化改造到使用 multicluster_mode。

Istio Secret 与声明式 API 概览

开源 Istio 多集群端点发现的工作原理是:使用 istioctl 或其他工具在集群中创建 Kubernetes Secret。借助此 Secret,集群可以将流量负载均衡到网格中的其他集群。然后,ISTIOD 控制平面会读取此 Secret,并开始将流量路由到这一其他集群。

Cloud Service Mesh 具有声明式 API 来控制多集群流量,而不是直接创建 Istio Secret。 此 API 会将 Istio Secret 视为实现细节,且比手动创建 Istio Secret 更可靠。将来的 Cloud Service Mesh 功能将依赖于声明式 API,您无法直接将这些新功能与 Istio Secret 搭配使用。声明式 API 是未来唯一受支持的路径。

如果您使用的是 Istio Secret,请尽快迁移到使用声明式 API。请注意,multicluster_mode 设置指示每个集群将流量定向到网格中的其他每个集群。使用 Secret 可实现更灵活的配置,让您为每个集群配置它应将流量定向到网格中的哪个其他集群。如需查看声明式 API 和 Istio Secret 支持的功能之间的差异的完整列表,请参阅使用 Istio API 支持的功能。

从 Istio Secret 迁移到声明式 API

如果您使用舰队功能 API 通过自动管理配置 Cloud Service Mesh,则无需按照这些说明操作。仅当您使用 asmcli --managed 进行初始配置时,才需要执行这些步骤。

请注意,此过程会更改指向集群的 Secret。在此过程中,系统会移除端点,然后重新添加端点。在移除和添加端点之间,流量会暂时还原到本地路由,而不是负载均衡到其他集群。如需了解详情,请参阅 GitHub 问题。

如需从使用 Istio Secret 迁移到声明式 API,请按照以下步骤操作。 同时或连续执行以下步骤:

  1. 通过设置 multicluster_mode=connected,为舰队中要启用多集群端点发现的每个集群启用声明式 API。请注意,如果您不希望集群可发现,则需要明确设置 multicluster_mode=disconnected。

    使用以下命令将集群加入多集群端点发现:

     kubectl patch configmap/asm-options -n istio-system --type merge -p '{"data":{"multicluster_mode":"connected"}}'
    

    使用以下命令将集群从端点发现中退出:

     kubectl patch configmap/asm-options -n istio-system --type merge -p '{"data":{"multicluster_mode":"disconnected"}}'
    
  2. 删除旧 Secret。

    在集群上设置 multicluster_mode=connected 后,每个集群都会为已设置 multicluster_mode=connected 的每个其他集群生成一个新 Secret。Secret 位于 istio-system 命名空间中,格式如下:

    istio-remote-secret-projects-PROJECT_NAME-locations-LOCATION-memberships-MEMBERSHIPS
    

    每个 Secret 还会应用标签 istio.io/owned-by: mesh.googleapis.com。

    创建新 Secret 后,您可以删除使用 istioctl create-remote-secret 手动创建的任何 Secret:

    kubectl delete secret SECRET_NAME -n istio-system
    

迁移完成后,检查请求指标,以确保请求按预期路由。

启用 Workload Identity Federation for GKE

工作负载身份联合是建议用于 Google Kubernetes Engine 的安全方法。这样一来,便可访问 Compute Engine、BigQuery 和 Machine Learning API 等 Google Cloud 服务。工作负载身份联合使用 IAM 政策,因此无需手动配置或安全性较低的方法(例如服务账号密钥文件)。如需详细了解工作负载身份联合,请参阅 Workload Identity Federation for GKE 的工作原理。

以下部分介绍了如何启用工作负载身份联合。

在集群上启用工作负载身份联合

  1. 检查是否已为您的集群启用工作负载身份联合。为此,请确保 GKE 集群已配置工作负载身份联合池,这对于 IAM 凭证验证至关重要。

    使用以下命令可检查为集群设置的工作负载身份池:

    gcloud container clusters describe CLUSTER_NAME \
      --format="value(workloadIdentityConfig.workloadPool)"
    

    将 CLUSTER_NAME 替换为 GKE 集群的名称。如果您尚未指定 gcloud 的默认可用区或区域,则您可能还需要在运行此命令时指定 --region 或 --zone 标志。

  2. 如果输出为空,请按照更新现有集群中的说明在现有 GKE 集群上启用工作负载身份。

在节点池上启用工作负载身份联合

在集群上启用工作负载身份联合后,必须将节点池配置为使用 GKE 元数据服务器。

  1. 列出 Standard 集群的所有节点池。运行 gcloud container node-pools list 命令:

    gcloud container node-pools list --cluster CLUSTER_NAME
    

    将 CLUSTER_NAME 替换为 GKE 集群的名称。如果您尚未指定 gcloud 的默认可用区或区域,则您可能还需要在运行此命令时指定 --region 或 --zone 标志。

  2. 验证每个节点池是否都在使用 GKE 元数据服务器:

    gcloud container node-pools describe NODEPOOL_NAME \
        --cluster=CLUSTER_NAME \
        --format="value(config.workloadMetadataConfig.mode)"
    

    替换以下内容:

    • 将 NODEPOOL_NAME 替换为节点池的名称。
    • 将 CLUSTER_NAME 替换为 GKE 集群的名称。
  3. 如果输出不包含 GKE_METADATA,请按照更新现有节点池指南更新节点池。

启用托管式容器网络接口 (CNI)

本部分将指导您在 Google Kubernetes Engine 上为 Cloud Service Mesh 启用托管式 CNI。

托管式 CNI 概览

托管式容器网络接口 (CNI) 是 Google 管理的 Istio CNI 实现。CNI 插件 通过配置 iptables 规则简化 pod 网络。这样,应用和 Envoy 代理之间就可以进行流量重定向,而无需管理 iptables 所需的 init-container 特权权限。

Istio CNI 插件取代了 istio-init 容器。以前,istio-init 容器负责设置 Pod 的网络环境,以便为 Istio 边车实现流量拦截。CNI 插件执行相同的网络重定向功能,但额外的好处是减少了对提权的需求,从而增强了安全性。

因此,为了增强安全性和可靠性,并简化管理和问题排查,所有托管式 Cloud Service Mesh 部署都需要使用托管式 CNI。

对 init 容器的影响

init 容器是一种专用容器,在应用容器之前运行,用于执行设置任务。设置任务可以包括下载配置文件、与外部服务通信或执行应用预初始化等任务。在集群中启用托管式 CNI 后,依赖于网络访问权限的 Init 容器可能会遇到问题。

使用托管式 CNI 的 Pod 设置流程如下所示:

  1. CNI 插件设置 Pod 网络接口、分配 Pod IP 并将流量重定向到尚未启动的 Istio 边车代理。
  2. 所有 init 容器都执行并完成。
  3. Istio 边车代理与应用容器一起启动。

因此,如果 init 容器尝试建立出站网络连接或连接到网格中的服务,则来自 init 容器的网络请求可能会被丢弃或错误路由。这是因为在发出请求时,用于管理 Pod 网络流量的 Istio 边车代理未运行。更多详情请参阅Istio CNI 文档。

为集群启用托管式 CNI

请按照本部分中的步骤在集群上启用托管式 CNI。

  1. 从 init 容器中移除网络依赖项。不妨考虑以下替代方案:

    • 修改应用逻辑或容器:您可以修改服务,以在边车代理启动后移除对需要网络请求或在应用容器内执行网络操作的 init 容器的依赖项。
    • 使用 Kubernetes ConfigMap 或 Secret:将网络请求提取的配置数据存储在 Kubernetes ConfigMap 或 Secret 中,并将其挂载到应用容器中。如需了解替代解决方案,请参阅 Istio 文档。
  2. 在集群上启用托管式 CNI:

    1. 进行以下配置更改:

      1. 运行以下命令以找到 controlPlaneRevision。

        kubectl get controlplanerevision -n istio-system
        
      2. 在 ControlPlaneRevision (CPR) 自定义资源 (CR) 中,将标签 mesh.cloud.google.com/managed-cni-enabled 设置为 true。

        kubectl label controlplanerevision CPR_NAME \
            -n istio-system mesh.cloud.google.com/managed-cni-enabled=true \
            --overwrite
        

        将 CPR_NAME 替换为上一步输出中 NAME 列下的值。

      3. 在 asm-options ConfigMap 中,将 ASM_OPTS 值设置为 CNI=on。

        kubectl patch configmap asm-options -n istio-system \
            -p '{"data":{"ASM_OPTS":"CNI=on"}}'
        
      4. 在 ControlPlaneRevision (CPR) 自定义资源 (CR) 中,将注解 mesh.cloud.google.com/force-reprovision 设置为 true。此操作会触发控制平面重启。

        kubectl annotate controlplanerevision CPR_NAME \
            -n istio-system mesh.cloud.google.com/force-reprovision=true \
            --overwrite
        
    2. 检查功能状态。使用以下命令检索功能状态:

      gcloud container fleet mesh describe --project FLEET_PROJECT_ID
      

      将 FLEET_PROJECT_ID 替换为您的舰队宿主项目的 ID。 通常,FLEET_PROJECT_ID 与项目的名称相同。

      • 验证 MANAGED_CNI_NOT_ENABLED 条件是否已从 servicemesh.conditions 中移除。
      • 请注意,状态更新可能需要 15-20 分钟。尝试等待几分钟,然后重新运行该命令。
    3. 当集群功能中的 controlPlaneManagement.state 为 Active 时,请重启 Pod。

停止在边车中使用非标准二进制文件

本部分提出了使部署与 Distroless Envoy 代理映像兼容的方法。

Distroless Envoy 代理边车映像

Cloud Service Mesh 会根据您的控制平面配置使用两种类型的 Envoy 代理边车映像:default 代理映像(包含各种调试二进制文件)和 distroless 代理映像。

对于具有托管式 TRAFFIC_DIRECTOR 控制平面的集群:

  • 直接载入的集群:默认使用 distroless 映像。
  • 从 CSM-ISTIOD 迁移的集群:默认使用 default 镜像。您可以明确选择启用 distroless 图片,以提升安全状况。

如需为从 CSM-ISTIOD 迁移的集群选择启用 distroless 映像,您可以在 MeshConfig 中使用 defaultConfig.image.imageType: distroless 进行全局配置,也可以使用 sidecar.istio.io/proxyImageType: distroless pod 注解按工作负载进行配置。

Distroless 基础映像是最小的容器映像,仅包含必要组件,可优先考虑安全性和资源优化。攻击面会缩小,有助于防止出现漏洞。如需了解详情,请参阅有关 Distroless 代理映像的文档。

二进制文件兼容性

最佳做法是将容器运行时的内容限制为仅包含必要的软件包。此方法可提高常见漏洞和披露 (CVE) 扫描程序的安全性和信噪比。Distroless 边车映像具有一组最少的依赖项,并且已剥离所有非必要的可执行文件、库和调试工具。因此,无法在容器中执行 shell 命令或使用 curl、ping 或其他调试实用程序(例如 kubectl exec)。

使集群与 Distroless 映像兼容

  • 从配置中移除对任何不受支持的二进制文件(例如 bash 或 curl)的引用。尤其是在 istio-proxy、istio-init 或 istio-validation 容器内的就绪性、启动和活跃性探测以及生命周期 PostStart 和 PreStop 钩子中。
  • 对于某些应用场景,请考虑使用 holdApplicationUntilProxyStarts 等替代方案。
  • 为了进行调试,您可以使用 临时容器 连接到正在运行的工作负载 Pod。然后,您可以检查该 Pod 并运行自定义命令。如需查看示例,请参阅收集 {service_mesh_name} 日志。

如果您找不到适用于特定应用场景的解决方案,请参阅获取支持,与 Google Cloud支持团队联系。

迁移到 Istio Ingress 网关

本部分介绍了如何迁移到 Istio Ingress 网关。您可以通过以下两种方法迁移到 Istio Ingress 网关:

  1. 通过流量拆分进行分阶段迁移

    此方法优先考虑尽量减少中断,您将逐步向新的 Istio 网关发送流量,以便监控其在一小部分请求中的性能,并在必要时快速还原。请注意,为某些应用配置第 7 层流量分配可能比较困难,因此您需要在过渡期间同时管理这两个网关系统。如需了解相关步骤,请参阅通过流量分配进行分阶段迁移。

  2. 直接迁移

    此方法涉及在您全面完成测试后,同时将所有流量重新路由到新的 Istio 网关。此方法的优势在于完全与旧网关的基础设施分离,从而可以灵活配置新网关,而不受现有设置的限制。不过,如果在过渡期间新网关出现意外问题,停机风险会增加。如需了解相关步骤,请参阅直接迁移。

以下迁移示例假设您有一个 HTTP 服务 (httpbin) 在应用命名空间(默认)中运行,并使用 Kubernetes Gateway API 对外公开。相关配置如下:

  • 网关:k8-api-gateway(位于 istio-ingress 命名空间中)- 配置为在端口 80 上监听以 .example.com 结尾的任何主机名的 HTTP 流量。
  • HTTPRoute:httpbin-route(位于 default 命名空间中)- 将主机名为 httpbin.example.com 且路径以 /get 开头的任何 HTTP 请求定向到 default 命名空间中的 httpbin 服务。
  • httpbin 应用可使用外部 IP 34.57.246.68 进行访问。

基本网关示意图

通过流量拆分进行分阶段迁移

配置新的 Istio Ingress 网关

  1. 按照部署示例网关部分中的步骤部署新的 Ingress 网关,并根据您的需求自定义示例配置。anthos-service-mesh 仓库中的示例旨在部署 istio-ingressgateway loadBalancer 服务和相应的 ingress-gateway Pod。

    网关资源示例 (istio-ingressgateway.yaml)

     apiVersion: networking.istio.io/v1beta1
     kind: Gateway
     metadata:
       name: istio-api-gateway
       namespace: GATEWAY_NAMESPACE
     spec:
       selector:
         istio: ingressgateway  # The selector should match the ingress-gateway pod labels.
       servers:
       - port:
           number: 80
           name: http
           protocol: HTTP
         hosts:   # or specific hostnames if needed
         - "httpbin.example.com"
    
  2. 应用网关配置来管理流量:

    kubectl apply -f istio-ingressgateway.yaml -n GATEWAY_NAMESPACE
    

    确保网关资源中的“spec.selector”与 ingress-gateway Pod 的标签匹配。例如,如果 ingress-gateway Pod 具有 istio=ingressgateway 标签,则您的网关配置也必须选择此 istio=ingressgateway 标签。

为新网关配置初始路由

  1. 使用 Istio VirtualService 为应用定义初始路由规则。

    VirtualService 示例 (my-app-vs-new.yaml):

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: httpbin-vs
      namespace: APPLICATION_NAMESPACE
    spec:
        gateways:
        - istio-ingress/istio-api-gateway  # Replace with <gateway-namespace/gateway-name>
        hosts:
        - httpbin.example.com
        http:
        - match:
          - uri:
              prefix: /get
          route:
          - destination:
              host: httpbin
              port:
                number: 8000
    
  2. 应用 VirtualService:

    kubectl apply -f my-app-vs-new.yaml -n MY_APP_NAMESPACE
    

通过新部署的 Istio Ingress 网关访问后端 (httpbin) 服务

  1. 将 Ingress 主机环境变量设置为与最近部署的 istio-ingressgateway 负载均衡器关联的外部 IP 地址:

    export INGRESS_HOST=$(kubectl -n GATEWAY_NAMESPACE get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    
  2. 验证应用 (httpbin) 是否可使用新网关进行访问:

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

    输出类似于以下内容:

    HTTP/1.1 200 OK
    

使用新的 Istio Ingress 网关的请求流

修改现有 Ingress 以进行流量拆分

确认新网关(例如 istio-api-gateway)设置成功后,就可以开始将部分流量路由到该网关了。 为此,请更新当前的 HTTPRoute,以将一小部分流量定向到新网关,而大部分流量继续使用现有网关 (k8-api-gateway)。

  1. 打开 httproute 进行修改:

    kubectl edit httproute httpbin-route -n MY_APP_NAMESPACE
    
  2. 添加指向新 Ingress 网关的 loadbalancer 服务的新后端引用,初始权重为 10%,并更新旧网关后端的权重。

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin-route
      namespace: MY_APP_NAMESPACE  # your application's namespace
    spec:
      parentRefs:
      - name: k8-api-gateway
        namespace: istio-ingress
      hostnames: ["httpbin.example.com"]
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /get
        backendRefs:
        - name: httpbin
          port: 8000
          weight: 90
        - name: istio-ingressgateway # Newly deployed load balancer service
          namespace: GATEWAY_NAMESPACE
          port: 80
          weight: 10
    
  3. 使用引用授权授予跨命名空间引用权限。

    如需允许应用命名空间(默认)中的 HTTPRoute 访问网关命名空间 (istio-ingress) 中的 loadbalancer 服务,您可能需要创建引用授权。此资源充当安全控制,用于明确定义允许哪些跨命名空间引用。

    以下istio-ingress-grant.yaml描述了一个参考授权示例:

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: ReferenceGrant
    metadata:
      name: istio-ingressgateway-grant
      namespace: istio-ingress # Namespace of the referenced resource
    spec:
      from:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        namespace: MY_APP_NAMESPACE # Namespace of the referencing resource
      to:
      - group: ""               # Core Kubernetes API group for Services
        kind: Service
        name: istio-ingressgateway # Loadbalancer Service of the new ingress gateway
    
  4. 应用引用授权:

    kubectl apply -f istio-ingress-grant.yaml -n GATEWAY_NAMESPACE
    
  5. 验证对现有外部 IP 地址(例如 34.57.246.68)的请求是否未失败。以下 check-traffic-flow.sh 描述了一个用于检查请求失败情况的脚本:

    # Update the following values based on your application setup
    external_ip="34.57.246.68" # Replace with existing external IP
    url="http://$external_ip/get"
    host_name="httpbin.example.com"
    
    # Counter for successful requests
    success_count=0
    
    # Loop 50 times
    for i in {1..50}; do
      # Perform the curl request and capture the status code
      status_code=$(curl -s -HHost:"$host_name" -o /dev/null -w "%{http_code}" "$url")
      # Check if the request was successful (status code 200)
      if [ "$status_code" -eq 200 ]; then
        ((success_count++))  # Increment the success counter
      else
        echo "Request $i: Failed with status code $status_code"
      fi
    done
    
    # After the loop, check if all requests were successful
    if [ "$success_count" -eq 50 ]; then
      echo "All 50 requests were successful!"
    else
      echo "Some requests failed.  Successful requests: $success_count"
    fi
    
  6. 执行该脚本以确认无论流量路由如何,都不会有请求失败:

    chmod +x check-traffic-flow.sh
    ./check-traffic-flow.sh
    

在现有网关和新的 Istio Ingress 网关之间进行流量拆分的请求流

缓慢提高流量百分比

如果现有外部 IP 地址(例如 34.57.246.68)未出现任何请求失败情况,请通过调整 HTTPRoute 中的后端权重,逐步将更多流量转移到新的 Istio Ingress 网关。以较小增量(例如 10%、20% 等)增加 istio-ingressgateway 的权重,并减小旧网关的权重。

使用以下命令更新现有 HTTPRoute:

kubectl edit httproute httpbin-route -n MY_APP_NAMESPACE

完全迁移流量并移除旧网关

  1. 当新的 Istio 入站流量网关表现出稳定的性能并成功处理请求后,将所有流量转移到该网关。更新 HTTPRoute,将旧网关的后端权重设置为 0,并将新网关的后端权重设置为 100。

  2. 流量完全路由到新网关后,请更新应用主机名(例如 httpbin.example.com)的外部 DNS 记录,以指向在预配新的 Istio Ingress 网关中创建的负载均衡器服务的外部 IP 地址。

  3. 最后,删除旧网关及其关联资源:

    kubectl delete gateway OLD_GATEWAY -n GATEWAY_NAMESPACE
    kubectl delete service OLD_GATEWAY_SERVICE -n GATEWAY_NAMESPACE
    

直接迁移

配置新的 Istio Ingress 网关

  1. 按照部署示例网关部分中的步骤部署新的 Ingress 网关,并根据您的需求自定义示例配置。anthos-service-mesh 仓库中的示例旨在部署 istio-ingressgateway loadBalancer 服务和相应的 ingress-gateway Pod。

    网关资源示例 (istio-ingressgateway.yaml)

     apiVersion: networking.istio.io/v1beta1
     kind: Gateway
     metadata:
       name: istio-api-gateway
       namespace: GATEWAY_NAMESPACE
     spec:
       selector:
         istio: ingressgateway  # The selector should match the ingress-gateway pod labels.
       servers:
       - port:
           number: 80
           name: http
           protocol: HTTP
         hosts:   # or specific hostnames if needed
         - "httpbin.example.com"
    
  2. 应用网关配置来管理流量:

    kubectl apply -f istio-ingressgateway.yaml -n GATEWAY_NAMESPACE
    

    确保网关资源中的“spec.selector”与 ingress-gateway Pod 的标签匹配。例如,如果 ingress-gateway Pod 具有 istio=ingressgateway 标签,则您的网关配置也必须选择此 istio=ingressgateway 标签。

为新网关配置初始路由

  1. 使用 Istio VirtualService 为应用定义初始路由规则。

    VirtualService 示例 (my-app-vs-new.yaml):

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: httpbin-vs
      namespace: APPLICATION_NAMESPACE
    spec:
        gateways:
        - istio-ingress/istio-api-gateway  # Replace with <gateway-namespace/gateway-name>
        hosts:
        - httpbin.example.com
        http:
        - match:
          - uri:
              prefix: /get
          route:
          - destination:
              host: httpbin
              port:
                number: 8000
    
  2. 应用 VirtualService:

    kubectl apply -f my-app-vs-new.yaml -n MY_APP_NAMESPACE
    

通过新部署的 Istio Ingress 网关访问后端 (httpbin) 服务

  1. 将 Ingress 主机环境变量设置为与最近部署的 istio-ingressgateway 负载均衡器关联的外部 IP 地址:

    export INGRESS_HOST=$(kubectl -n GATEWAY_NAMESPACE get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    
  2. 验证应用 (httpbin) 是否可使用新网关进行访问:

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

    输出类似于以下内容:

    HTTP/1.1 200 OK
    

使用新的 Istio Ingress 网关的请求流

测试和监控新网关

  1. 测试所有路由规则,验证 TLS 配置、安全政策和其他功能。执行负载测试,以验证新网关是否可以处理预期流量。

  2. 对新网关进行全面测试后,请更新应用主机名(例如 httpbin.example.com)的外部 DNS 记录,以指向在预配新的 Istio Ingress 网关中创建的负载均衡器服务的外部 IP 地址。

  3. 监控请求成功率、延迟时间、错误率和应用 Pod 的资源利用率等关键指标,以验证新 Istio Ingress 网关的稳定性。稳定后,您可以删除旧网关及其关联的资源

    kubectl delete gateway OLD_GATEWAY -n GATEWAY_NAMESPACE
    kubectl delete service OLD_GATEWAY_SERVICE -n GATEWAY_NAMESPACE
    

重要注意事项:如果您的应用需要 HTTPS,请确保在新的 Istio Ingress 网关上正确设置 TLS 证书和配置。如需了解详情,请参阅在入站流量网关中设置 TLS 终结。

修复多个控制平面这一问题

Cloud Service Mesh 以前支持使用 asmcli(已弃用)进行初始配置,这不会阻止预配多个控制平面。Cloud Service Mesh 现在强制执行最佳实践,即每个集群仅部署一个与集群渠道匹配的渠道,不支持在同一集群中使用多个已部署的渠道。

如果您想在快速渠道中对网格的新版本进行 Canary 部署,然后再在稳定渠道或常规渠道中提供这些新版本,则需要使用两个不同的集群,每个集群都有单独的渠道。请注意,渠道由 GKE 集群渠道控制,并且网格没有与之关联的单独渠道。

您可以查看成员资格的 UNSUPPORTED_MULTIPLE_CONTROL_PLANES 状态条件,确认自己是否拥有多个渠道。如果未显示此警告,则表示您未受到影响,可以跳过本部分。

  1. 运行以下命令,检查集群是否具有多个控制平面渠道:

    gcloud container fleet mesh describe
    

    输出类似于以下内容:

    ...
    projects/.../locations/global/memberships/my-membership:
        servicemesh:
          conditions:
          - code: UNSUPPORTED_MULTIPLE_CONTROL_PLANES
            details: 'Using multiple control planes is not supported. Please remove a control plane from your cluster.'
            documentationLink: https://cloud.google.com/service-mesh/v1.29/docs/migrate/modernization-configuration-updates#multiple_control_planes
            severity: WARNING
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-stable'
            implementation: ISTIOD
            state: ACTIVE
    ...
    
  2. 如果出现 UNSUPPORTED_MULTIPLE_CONTROL_PLANES 条件,请确定集群存在哪些渠道:

    kubectl get controlplanerevisions -n istio-system
    

    输出类似于以下内容:

    NAME                 RECONCILED   STALLED   AGE
    asm-managed-stable   True         False     97d
    asm-managed          True         False     97d
    asm-managed-rapid    True         False     97d
    

    在此示例中,预配了所有三个渠道:

    • asm-managed-stable -> STABLE
    • asm-managed -> REGULAR
    • asm-managed-rapid -> RAPID

    如果只显示 1 个结果,则表示您的集群上仅预配了 1 个渠道,您可以跳过其余步骤。

    如果显示 2 个或更多结果,请按照其余步骤操作,移除多余的渠道。

将工作负载整合到一个渠道

您必须先确保工作负载仅使用单个渠道,然后才能移除其他渠道。

  1. 查找您在集群中使用的所有标签:

    kubectl get namespaces -l istio.io/rev=RELEASE_CHANNEL
    

    根据上一个命令的输出,将 RELEASE_CHANNEL 替换为 asm-managed-stable、asm-managed 或 asm-managed-rapid。针对每个预配的渠道重复执行此步骤。

    输出类似于以下内容:

    NAME      STATUS   AGE
    default   Active   110d
    

    请注意,在此示例中,默认命名空间在通过常规渠道注入。

    如果您的所有工作负载已使用同一渠道,则可以跳至移除额外渠道这一步。否则,请继续阅读本部分。

  2. 更改标签,以便仅使用一个渠道:

    • 在某些情况下,还可以使用 sidecar.istio.io/inject 标签直接注入 Pod。请务必检查这些标签是否也用于该用途。
    • 在此步骤中,您可以忽略 istio-injection=enabled 标签。 具有该标签的命名空间将自动更改为与集群中剩余的任何渠道相匹配。
    • 选择要保留的渠道时,请尽量选择与 GKE 集群渠道相同的渠道。如果此渠道不存在,请选择任何一个有效渠道。
    • 您选择的实际渠道无关紧要。GKE 集群通道决定您获得的网状网络版本,而不是网状网络通道。
    • 检查所用任何有效渠道之间的 meshconfig 配置,确保它们之间没有差异。每个渠道都使用单独的 configmap 进行配置,因此将两个渠道整合为一个渠道应能确保这两个渠道的行为保持一致。kubectl get configmap istio-asm-managed{-rapid | -stable} -n istio-system -o yaml
    kubectl label namespace NAMESPACE istio.io/rev- istio-injection=enabled --overwrite
    

    将 NAMESPACE 替换为您的命名空间名称。

    最佳实践是使用 istio-injection=enabled。不过,如果您不想使用该标签,也可以使用 istio.io/rev=RELEASE_CHANNEL。

    更改命名空间/Pod 的标签后,您必须重启所有工作负载,以便它们由正确的控制平面注入。

移除额外渠道

确认所有工作负载都在单个渠道上运行后,您可以移除未使用的额外渠道。如果预配了所有三个发布渠道,请务必针对每个渠道运行以下命令。

  1. 删除额外 ControlPlaneRevision 资源:

    kubectl delete controlplanerevision RELEASE_CHANNEL -n istio-system
    

    将 RELEASE_CHANNEL 替换为 asm-managed-stable、asm-managed 或 asm-managed-rapid。

  2. 删除 MutatingWebhookConfiguration:

    kubectl delete mutatingwebhookconfiguration istiod-RELEASE_CHANNEL
    
  3. 删除 meshconfig configmap:

    kubectl delete configmap istio-RELEASE_CHANNEL
    

启用自动代管

  1. 运行以下命令以启用自动代管:

    gcloud container fleet mesh update \
        --management automatic \
        --memberships MEMBERSHIP_NAME \
        --project PROJECT_ID \
        --location MEMBERSHIP_LOCATION
    

    替换以下内容:

    • MEMBERSHIP_NAME 是您在验证集群是否已注册到舰队时列出的成员资格名称。
    • PROJECT_ID 是您的项目的项目 ID。
    • MEMBERSHIP_LOCATION 是您的成员资格的位置(区域或 global)。您可以使用 gcloud container fleet memberships list --project PROJECT_ID 检查您的成员资格的位置。
  2. 确认已启用自动管理:

    gcloud container fleet mesh describe
    

    输出类似于以下内容:

    ...
    membershipSpecs:
      projects/.../locations/us-central1/memberships/my-member:
        mesh:
          management: MANAGEMENT_AUTOMATIC
    membershipStates:
      projects/.../locations/us-central1/memberships/my-member:
        servicemesh:
          conditions:
          - code: VPCSC_GA_SUPPORTED
            details: This control plane supports VPC-SC GA.
            documentationLink: http://cloud.google.com/service-mesh/v1.29/docs/managed/vpc-sc
            severity: INFO
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed'
            implementation: TRAFFIC_DIRECTOR
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: |-
            Revision ready for use: asm-managed.
            All Canonical Services have been reconciled successfully.
    ...
    

对 EnvoyFilter 压缩器配置进行现代化改造

如果您使用的是 envoy.extensions.filters.http.compressor.v3.Compressor 过滤条件,Envoy 中已弃用多个顶级字段,并将其移至 response_direction_config.common_config 和 request_direction_config.common_config。

如需了解如何将 EnvoyFilter 资源更新为受支持的新式格式,请参阅实现 EnvoyFilter 压缩器配置现代化指南。

启用必需的组织政策

Cloud Service Mesh 需要启用特定政策才能成功运行。

必需的政策

compute.disableInternetNetworkEndpointGroup

Cloud Service Mesh 需要能够创建互联网 网络端点组 (NEG)。这些 NEG 是将流量路由到 Google Cloud之外的服务的必要组件。

constraints/compute.disableInternetNetworkEndpointGroup 限制条件可能会阻止创建这些必需的互联网 NEG。

如果此组织政策在您的项目、文件夹或组织中强制执行,则会阻止 Cloud Service Mesh 与 Traffic Director 控制平面正常工作。这将阻止迁移到此 Cloud Service Mesh 配置或使其成功运行。

如果 Enforced 设置为 true,则会停用互联网 NEG 的创建。

如何判断我是否受到影响?

您可以使用 Google Cloud 控制台或 Google Cloud CLI 查看项目的有效政策。如需查看组织政策,请参阅官方文档中的查看组织政策部分。

例如,您可以使用以下 Google Cloud CLI 命令:

gcloud resource-manager org-policies describe constraints/compute.disableInternetNetworkEndpointGroup --project YOUR_PROJECT_ID --effective

如果政策显示 enforced: true 值,则表示您会受到影响。

constraint: constraints/compute.disableInternetNetworkEndpointGroup
booleanPolicy:
  enforced: true

如果该政策显示不同的值或为空,则您不会受到影响。

constraint: constraints/compute.disableInternetNetworkEndpointGroup
booleanPolicy: {}

解决问题

如果该策略已强制执行,则需要在组织、文件夹或项目级别禁用此约束(设置为 false)。

如需详细了解如何修改组织政策(包括此类布尔值限制条件),请参阅创建和管理组织政策指南。您通常需要拥有 roles/orgpolicy.policyAdmin 角色才能进行这些更改。

共享 VPC 权限

如果使用托管式 Cloud Service Mesh 和共享 VPC,且集群位于服务项目中,而 VPC 网络位于宿主项目中,则舰队项目中的 Cloud Service Mesh 服务代理需要额外的权限。

在迁移到 TRAFFIC_DIRECTOR 控制平面期间,Cloud Service Mesh 需要获得管理宿主项目中的防火墙规则的权限,以确保健康检查和网络功能正常运行。之前的 ISTIOD 控制平面不需要这样做。

如何判断我是否受到影响?

如果您符合以下情况,则会受到影响:

  1. 您的 GKE 集群位于一个服务项目中。
  2. 这些集群使用托管在其他项目(VPC 宿主项目)中的共享 VPC 网络。
  3. 舰队项目的 Cloud Service Mesh 服务代理没有管理 VPC 宿主项目中的防火墙规则的权限。

您可能会在舰队功能状态中看到代码为 SHARED_VPC_MISSING_PERMISSIONS 的警告消息。如需详细了解如何了解和解决此问题(包括系统管理和用户管理选项),请参阅了解健康检查。

缺少控制平面配置

Cloud Service Mesh 在管理服务网格方面的最佳实践是使用 Google Kubernetes Engine Fleet API 将 Management 字段设置为 AUTOMATIC。这样可以完全自动管理许多网格功能,例如 webhook 和控制平面。此外,它还会设置集群,以便在发布新更新和功能时自动接收。某些旧版安装方法未以这种方式配置 Cloud Service Mesh,您必须采取一些手动步骤来修补它们。

如何判断我是否受到影响?

检查集群中是否有 ControlPlaneRevision:

kubectl get controlplanerevisions -n istio-system

如果您的集群中已有 ControlPlaneRevision,则本指南不适用于您。如果您没有 ControlPlaneRevision,请使用本指南来更新您的集群。

如果您收到 MISSING_CONTROL_PLANE_CONFIG 警告,但不想使用 Cloud Service Mesh,请停用 Cloud Service Mesh。

现代化改造步骤

请按照以下步骤确定需要采取哪些措施才能使您的配置符合当前标准。

gcloud container fleet mesh describe --project PROJECT_ID

根据输出执行以下步骤:

输出 要执行的步骤
API [gkehub.googleapis.com] not enabled on project [my-project]. Would you like to enable and retry (this will take a few minutes)? (y/N)? 回答 y,然后重试。
ERROR: (gcloud.container.fleet.mesh.describe) Service Mesh Feature for project [my-project] is not enabled 前往1. 启用网格功能。
... resourceState: state: ACTIVE ... 继续前往2. 向舰队注册集群。

1. 启用网格功能

您可以使用以下命令启用网状网络功能。这样,Cloud Service Mesh 就可以在您的项目上运行。如需了解详情和潜在的附带效应,请参阅配置服务网格。

gcloud container fleet mesh enable --project PROJECT_ID

启用网格功能后,请继续执行2. 向舰队注册集群。

2. 向舰队注册集群

检查您的集群是否已注册到舰队:

gcloud container fleet memberships list --project PROJECT_ID

如果您的集群未列出,请按照以下说明注册集群:向舰队注册集群。

将集群注册到舰队后,该集群便可以通过舰队管理 Cloud Service Mesh 等功能。

3. 确定网状网络频道

Cloud Service Mesh 依赖于集群的 Google Kubernetes Engine 渠道,而不是独立的网格渠道。过去,Cloud Service Mesh 支持选择一个或多个网格渠道(与 Google Kubernetes Engine 集群渠道不同)。您的网状网配置中可能仍有对这些渠道的引用。

首先,确定您使用的是哪些渠道。如果您使用的是多个渠道,请按照修复多个控制平面中的说明将使用量减少到单个渠道。

如需确定您使用的是哪个网格渠道,请检查命名空间上的标签。请注意,如果您专门在工作负载上添加了注入标签,可能还需要检查工作负载。以下命令会检查集群中的所有工作负载,并过滤输出以显示用于这些工作负载的控制平面和注入标记。

kubectl get namespaces,pods,deployments,statefulsets,daemonsets --all-namespaces --show-labels | grep -E "istio.io/rev|istio-injection"

如果您手动创建了任何自定义标记或 webhook,也需要检查这些内容。

输出类似于以下内容:

namespace/default                                 Active   153d   istio-injection=enabled,istio.io/rev=asm-managed,kubernetes.io/metadata.name=default
namespace/payments                                Active   42d    istio.io/rev=asm-managed-stable,kubernetes.io/metadata.name=payments
default    pod/frontend-847f569874-v9kjz          2/2      Running  0   2m     app=frontend,istio.io/rev=asm-managed,pod-template-hash=847f569874
payments   pod/checkout-0                         2/2      Running  0   5d     app=checkout,istio.io/rev=asm-managed-stable,controller-revision-hash=5c68b9487
default    deployment.apps/frontend               1/1      1        1   153d   app=frontend,istio.io/rev=asm-managed
payments   statefulset.apps/checkout              1/1      1        1   42d    app=checkout,istio.io/rev=asm-managed-stable

请注意 istio.io/rev={channel} 的当前值。名称以这种方式与渠道匹配。如果使用了多个渠道,请按照修复多个控制平面中的说明减少到单个渠道:

值 渠道
asm-managed-stable 稳定
asm-managed 普通
asm-managed-rapid 快速

如果网格渠道与 Google Kubernetes Engine 集群渠道一致,请跳至第 5 步。

4. 为网格渠道创建 ControlPlaneRevision 资源

如果网格渠道与 Google Kubernetes Engine 集群渠道一致,您可以跳过此步骤。如果您的渠道与集群渠道匹配,启用自动控制平面管理功能后,系统会自动创建此 ControlPlaneRevision 资源。

为所使用的网格渠道创建 ControlPlaneRevision 资源:

稳定

kubectl create ns istio-system
cat <<EOF | kubectl apply -f -
apiVersion: mesh.cloud.google.com/v1beta1
kind: ControlPlaneRevision
metadata:
  name: asm-managed-stable
  namespace: istio-system
spec:
  type: managed_service
  channel: stable
EOF

普通

kubectl create ns istio-system
cat <<EOF | kubectl apply -f -
apiVersion: mesh.cloud.google.com/v1beta1
kind: ControlPlaneRevision
metadata:
  name: asm-managed
  namespace: istio-system
spec:
  type: managed_service
  channel: regular
EOF

快速

kubectl create ns istio-system
cat <<EOF | kubectl apply -f -
apiVersion: mesh.cloud.google.com/v1beta1
kind: ControlPlaneRevision
metadata:
  name: asm-managed-rapid
  namespace: istio-system
spec:
  type: managed_service
  channel: rapid
EOF

5. 启用自动管理

如需停用多集群端点发现,请在启用控制平面的自动管理功能之前,按照端点发现声明式 API 中的“停用”说明操作。

如需停用代管式数据平面,请按照停用代管式数据平面中的说明操作。

如需启用自动管理,请运行以下命令。这样一来,舰队管理的 Cloud Service Mesh 就可以管理集群的控制平面配置了。

gcloud container fleet mesh update --management automatic --memberships MY_CLUSTER_MEMBERSHIP --project PROJECT_ID

将 MY_CLUSTER_MEMBERSHIP 替换为您的集群的成员资格名称。

6. 验证安装

运行以下命令:

gcloud container fleet mesh describe --project PROJECT_ID

输出类似于以下内容:

createTime: '2025-02-24T22:10:10.826263363Z'
etag: XjjRZB3-ZsueoaKihEBUupYhMDUjvoSyUHTVD2YgR6k
membershipSpecs:
  projects/1234567890/locations/us-central1/memberships/my-cluster-membership:
    mesh:
      management: MANAGEMENT_AUTOMATIC # See item 1 below
membershipStates:
  projects/1234567890/locations/us-central1/memberships/my-cluster-membership:
    servicemesh:
      conditions: [] # See item 2 below
      controlPlaneManagement: # See item 3 below
        details:
        - code: REVISION_READY
          details: 'Ready: asm-managed'
        implementation: TRAFFIC_DIRECTOR
        state: ACTIVE
      dataPlaneManagement: # See item 4 below
        details:
        - code: OK
          details: Service is running.
        state: ACTIVE
    state:
      code: OK
      description: |-
        Revision ready for use: asm-managed.
        All Canonical Services have been reconciled successfully.
      updateTime: '2025-06-17T23:39:05.267540058Z'
name: projects/my-project/locations/global/features/servicemesh
resourceState:
  state: ACTIVE
spec: {}
updateTime: '2025-02-25T04:12:16.280672401Z'
  1. 在 membershipSpecs 中,舰队中的每个成员都有单独的规范。请确保每个成员的管理权限都正确设置为 MANAGEMENT_AUTOMATIC。
  2. 每项会员资格都附带一系列状态条件。请确保此处没有错误或警告,并按照提供的文档链接解决任何问题。
  3. controlPlaneManagement 包含控制平面的状态。确保控制平面处于 ACTIVE 状态。
  4. dataPlaneManagement 包含数据平面的状态。建议启用此功能。