用于现代化改造的配置更新
本文档介绍了在将网格从 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,请按照以下步骤操作。 同时或连续执行以下步骤:
通过设置
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"}}'
删除旧 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 的工作原理。
以下部分介绍了如何启用工作负载身份联合。
在集群上启用工作负载身份联合
检查是否已为您的集群启用工作负载身份联合。为此,请确保 GKE 集群已配置工作负载身份联合池,这对于 IAM 凭证验证至关重要。
使用以下命令检查为集群设置的工作负载身份池:
gcloud container clusters describe CLUSTER_NAME \ --format="value(workloadIdentityConfig.workloadPool)"
将
CLUSTER_NAME
替换为 GKE 集群的名称。如果您尚未指定 gcloud 的默认可用区或区域,则您可能还需要在运行此命令时指定--region
或--zone
标志。如果输出为空,请按照更新现有集群中的说明在现有 GKE 集群上启用工作负载身份。
在节点池上启用工作负载身份联合
在集群上启用工作负载身份联合后,必须将节点池配置为使用 GKE 元数据服务器。
列出 Standard 集群的所有节点池。运行 gcloud container node-pools list 命令:
gcloud container node-pools list --cluster CLUSTER_NAME
将
CLUSTER_NAME
替换为 GKE 集群的名称。如果您尚未指定 gcloud 的默认可用区或区域,则您可能还需要在运行此命令时指定--region
或--zone
标志。验证每个节点池是否使用 GKE 元数据服务器:
gcloud container node-pools describe NODEPOOL_NAME \ --cluster=CLUSTER_NAME \ --format="value(config.workloadMetadataConfig.mode)"
替换以下内容:
- 将
NODEPOOL_NAME
替换为节点池的名称。 - 将
CLUSTER_NAME
替换为 GKE 集群的名称。
- 将
如果输出不包含
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 设置流程如下所示:
- CNI 插件会设置 Pod 网络接口、分配 Pod IP 并将流量重定向到尚未启动的 Istio 边车代理。
- 所有 init 容器都执行并完成。
- Istio 边车代理与应用容器一起启动。
因此,如果 init 容器尝试建立出站网络连接或连接到网格中的服务,则来自 init 容器的网络请求可能会被丢弃或错误路由。这是因为在发出请求时,用于管理 Pod 网络流量的 Istio 边车代理未运行。如需了解详情,请参阅 Istio CNI 文档。
为集群启用托管式 CNI
请按照本部分中的步骤在集群上启用托管式 CNI。
从 init 容器中移除网络依赖项。请考虑以下替代方案:
- 修改应用逻辑或容器:您可以修改服务,以在边车代理启动后移除对需要网络请求或在应用容器内执行网络操作的 init 容器的依赖关系。
- 使用 Kubernetes ConfigMap 或 Secret:将网络请求提取的配置数据存储在 Kubernetes ConfigMap 或 Secret 中,并将其挂载到应用容器中。如需了解替代解决方案,请参阅 Istio 文档。
在集群上启用托管式 CNI:
进行以下配置更改:
运行以下命令以找到
controlPlaneRevision
。kubectl get controlplanerevision -n istio-system
在
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 列下的值。在 asm-options ConfigMap 中,将
ASM_OPTS
值设置为CNI=on
。kubectl patch configmap asm-options -n istio-system \ -p '{"data":{"ASM_OPTS":"CNI=on"}}'
在
ControlPlaneRevision
(CPR) 自定义资源 (CR) 中,将标签mesh.cloud.google.com/force-reprovision
设置为true
。此操作会触发控制平面重启。kubectl label controlplanerevision CPR_NAME \ -n istio-system mesh.cloud.google.com/force-reprovision=true \ --overwrite
检查功能状态。使用以下命令检索功能状态:
gcloud container fleet mesh describe --project FLEET_PROJECT_ID
将
FLEET_PROJECT_ID
替换为您的舰队宿主项目的 ID。通常,FLEET_PROJECT_ID
的名称与项目相同。- 验证
MANAGED_CNI_NOT_ENABLED
条件是否已从servicemesh.conditions
中移除。 - 请注意,状态更新最多可能需要 15-20 分钟。尝试等待几分钟,然后重新运行该命令。
- 验证
当集群功能中的
controlPlaneManagement.state
为Active
时,请重启 Pod。
停止在边车中使用非标准二进制文件
本部分提出了使部署与 Distroless Envoy 代理映像兼容的方法。
Distroless Envoy 代理边车映像
Cloud Service Mesh 会根据您的控制平面配置使用两种类型的 Envoy 代理边车映像:基于 Ubuntu 的映像(包含各种二进制文件)和 Distroless 映像。Distroless 基础映像是最小的容器映像,仅包含必要组件,可优先考虑安全性和资源优化。攻击面会缩小,有助于防止出现漏洞。如需了解详情,请参阅有关 Distroless 代理映像的文档。
二进制文件兼容性
最佳做法是将容器运行时的内容限制为仅包含必要的软件包。此方法可提高常见漏洞和披露 (CVE) 扫描程序的安全性和信噪比。Distroless 边车映像具有一组最少的依赖项,并且已剥离所有非必要的可执行文件、库和调试工具。因此,无法在容器中执行 shell 命令或使用 curl、ping 或其他调试实用程序(例如 kubectl exec
)。
使集群与 Distroless 映像兼容
- 从配置中移除对任何不受支持的二进制文件(如 bash 或 curl)的引用。特别是在就绪性、启动和活跃性探测以及 istio-proxy、istio-init 或 istio-validation 容器内的生命周期 PostStart 和 PreStop 钩子中。
- 对于某些应用场景,请考虑使用 holdApplicationUntilProxyStarts 等替代方案。
- 如需进行调试,您可以使用临时容器附加到正在运行的工作负载 Pod。然后,您可以检查该 Pod 并运行自定义命令。如需查看示例,请参阅收集 Cloud Service Mesh 日志。
如果您找不到适用于特定应用场景的解决方案,请参阅获取支持,与 Google Cloud支持团队联系。
迁移到 Istio Ingress 网关
本部分介绍了如何迁移到 Istio Ingress 网关。您可以通过以下两种方法迁移到 Istio Ingress 网关:
通过流量拆分进行分阶段迁移
此方法优先考虑尽量减少中断,您将逐步向新的 Istio 网关发送流量,以便监控其在一小部分请求中的性能,并在必要时快速还原。请注意,对于某些应用,配置第 7 层流量拆分可能具有挑战性,因此您需要在过渡期间同时管理这两个网关系统。如需了解相关步骤,请参阅通过流量拆分进行分阶段迁移。
直接迁移
此方法涉及在您彻底完成测试后,同时将所有流量重新路由到新的 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 网关
按照部署示例网关部分中的步骤部署新的 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"
应用网关配置来管理流量:
kubectl apply -f istio-ingressgateway.yaml -n GATEWAY_NAMESPACE
确保网关资源中的“spec.selector”与
ingress-gateway
Pod 的标签匹配。例如,如果ingress-gateway
Pod 具有istio=ingressgateway
标签,则您的网关配置也必须选择此istio=ingressgateway
标签。
为新网关配置初始路由
使用 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
应用 VirtualService:
kubectl apply -f my-app-vs-new.yaml -n MY_APP_NAMESPACE
通过新部署的 Istio Ingress 网关访问后端 (httpbin) 服务
将 Ingress 主机环境变量设置为与最近部署的
istio-ingressgateway
负载均衡器关联的外部 IP 地址:export INGRESS_HOST=$(kubectl -n GATEWAY_NAMESPACE get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
验证应用 (httpbin) 是否可使用新网关进行访问:
curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/get"
输出类似于以下内容:
HTTP/1.1 200 OK
修改现有 Ingress 以进行流量拆分
确认新网关(例如 istio-api-gateway)已成功设置后,您可以开始通过该网关路由部分流量。为此,请更新当前的 HTTPRoute,以将一小部分流量定向到新网关,而大部分流量继续使用现有网关 (k8-api-gateway)。
打开 httproute 进行修改:
kubectl edit httproute httpbin-route -n MY_APP_NAMESPACE
添加指向新 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
使用引用授权授予跨命名空间引用的权限。
如需允许应用命名空间(默认)中的
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
应用引用授权:
kubectl apply -f istio-ingress-grant.yaml -n GATEWAY_NAMESPACE
验证对现有外部 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
执行该脚本以确认无论流量路由如何,都不会有请求失败:
chmod +x check-traffic-flow.sh ./check-traffic-flow.sh
逐步提高流量百分比
如果现有外部 IP 地址(例如 34.57.246.68
)未出现任何请求失败情况,请通过调整 HTTPRoute
中的后端权重,逐步将更多流量转移到新的 Istio Ingress 网关。以小增量(例如 10%、20% 等)增加 istio-ingressgateway
的权重,并减小旧网关的权重。
使用以下命令更新现有 HTTPRoute
:
kubectl edit httproute httpbin-route -n MY_APP_NAMESPACE
完全迁移流量并移除旧网关
当新的 Istio Ingress 网关表现出稳定的性能并成功处理请求时,将所有流量转移到该网关。更新
HTTPRoute
,将旧网关的后端权重设置为0
,并将新网关的后端权重设置为100
。流量完全路由到新网关后,请更新应用主机名(例如
httpbin.example.com
)的外部 DNS 记录,以指向在预配新的 Istio Ingress 网关中创建的负载均衡器服务的外部 IP 地址。最后,删除旧网关及其关联资源:
kubectl delete gateway OLD_GATEWAY -n GATEWAY_NAMESPACE kubectl delete service OLD_GATEWAY_SERVICE -n GATEWAY_NAMESPACE
直接迁移
配置新的 Istio Ingress 网关
按照部署示例网关部分中的步骤部署新的 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"
应用网关配置来管理流量:
kubectl apply -f istio-ingressgateway.yaml -n GATEWAY_NAMESPACE
确保网关资源中的“spec.selector”与
ingress-gateway
Pod 的标签匹配。例如,如果ingress-gateway
Pod 具有istio=ingressgateway
标签,则您的网关配置也必须选择此istio=ingressgateway
标签。
为新网关配置初始路由
使用 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
应用 VirtualService:
kubectl apply -f my-app-vs-new.yaml -n MY_APP_NAMESPACE
通过新部署的 Istio Ingress 网关访问后端 (httpbin) 服务
将 Ingress 主机环境变量设置为与最近部署的
istio-ingressgateway
负载均衡器关联的外部 IP 地址:export INGRESS_HOST=$(kubectl -n GATEWAY_NAMESPACE get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
验证应用 (httpbin) 是否可使用新网关进行访问:
curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/get"
输出类似于以下内容:
HTTP/1.1 200 OK
测试和监控新网关
测试所有路由规则,验证 TLS 配置、安全政策和其他功能。执行负载测试,以验证新网关是否可以处理预期流量。
对新网关进行全面测试后,请更新应用主机名(例如
httpbin.example.com
)的外部 DNS 记录,以指向在预配新的 Istio Ingress 网关中创建的负载均衡器服务的外部 IP 地址。监控请求成功率、延迟时间、错误率和应用 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 终结。