共享控制平面(单一网络)
按照该指南安装一个 Istio 多集群服务网格以让每个 Kubernetes 集群的服务和应用能够将他们的内部 Kubernetes 网络暴露至其它集群。
在这个配置中,多个 Kubernetes 集群运行一份可以连接到一个共享 Istio 控制平面的远程配置。 一旦一个或多个远程 Kubernetes 集群连接到该 Istio 控制平面,Envoy 就会形成一个跨多集群的网格网络。
前提条件
两个或更多运行受支持的 Kubernetes 版本(1.14, 1.15, 1.16)的集群。
能够在多集群中的一个上部署 Istio 控制平面。
满足下列要求的 RFC1918 网络、VPN、或其它更高级的网络技术:
各集群的 Pod CIDR 范围和服务 CIDR 范围在多群集环境中必须唯一,并且不能重叠。
每个集群中的所有 pod CIDRs 必须互相可路由。
所有 Kubernetes 控制平面 API 服务必须互相可路由。
本指南介绍如何使用 Istio 提供的远程配置文件安装多群集 Istio 拓扑。
部署本地控制平面
在 Kubernetes 集群之一上安装 Istio 控制平面。
设置环境变量
在执行本节中的步骤之前,请等待 Istio 控制平面完成初始化。
您必须在 Istio 控制平面集群上执行这些操作,以获取 Istio 控制平面服务端点,例如,Pilot 和 Policy Pod IP 端点。
运行以下命令设置环境变量:
$ export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
$ export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
$ export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
通常,在远程集群上自动 sidecar 注入已经启用。 要执行手动 sidecar 注入,请参考手动 sidecar 示例。
安装 Istio 远程组件
您必须在每个远程 Kubernetes 集群上都部署 istio-remote
组件。
您可以用下面两种方式之一来安装该组件:
在远程集群上使用下列命令来安装 Istio 控制平面服务端点:
$ istioctl manifest apply \ --set profile=remote \ --set values.global.controlPlaneSecurityEnabled=false \ --set values.global.createRemoteSvcEndpoints=true \ --set values.global.remotePilotCreateSvcEndpoint=true \ --set values.global.remotePilotAddress=${PILOT_POD_IP} \ --set values.global.remotePolicyAddress=${POLICY_POD_IP} \ --set values.global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \ --set gateways.enabled=false \ --set autoInjection.enabled=true
下列命令示例标记了
default
命名空间。使用类似的命令标记所有需要自动进行 sidecar 注入的远程集群的命名空间。$ kubectl label namespace default istio-injection=enabled
为所有需要设置自动 sidecar 注入的 Kubernetes 命名空间重复以上命令。
安装配置参数
你必须配置远程集群的 sidecar 与 Istio 控制平面交互,包括在 istio-remote
配置文件中的以下端点:pilot
、policy
、telemetry
和跟踪服务。
该配置文件默认在远程集群中启用自动 sidecar 注入。
您可以通过单独的设置禁用自动 sidecar 注入。
下列表格展示了 istioctl
针对远程集群的配置值:
安装设置 | 可选值 | 默认 | 值作用 |
---|---|---|---|
values.global.remotePilotAddress | 有效的 IP 地址或主机名 | None | 指定 Istio 控制平面的 pilot Pod IP 地址或远程集群 DNS 可解析的主机名 |
values.global.remotePolicyAddress | 有效的 IP 地址或主机名 | None | 指定 Istio 控制平面的 policy Pod IP 地址或远程集群 DNS 可解析的主机名 |
values.global.remoteTelemetryAddress | 有效的 IP 地址或主机名 | None | 指定 Istio 控制平面的 telemetry Pod IP 地址或远程集群 DNS 可解析的主机名 |
values.sidecarInjectorWebhook.enabled | true, false | true | 指定是否在远程集群上启用自动 sidecar 注入 |
values.global.remotePilotCreateSvcEndpoint | true, false | false | 如果设置,将使用 remotePilotAddress IP 创建用于 istio-pilot 的无选择器的服务和端点,以确保 istio-pilot.<namespace> 在远程集群上可通过 DNS 解析。 |
values.global.createRemoteSvcEndpoints | true, false | false | 如果设置,istio-pilot 、istio-telemetry 和 istio-policy 的 selector-less 服务和端点将用相应的远程 IP:remotePilotAddress 、remoteTelmetryAddress 和 remotePolicyAddress 分别创建,这样确保在远程集群中服务名可以通过 DNS 解析。 |
为远程集群创建配置文件
Istio 控制平面需要访问网格中的所有集群以发现服务、端点和 pod 属性。
下列步骤描述了如何通过远程集群为 Istio 控制平面创建 kubeconfig
配置文件。
在每个远程集群上执行这些步骤以将集群加入服务网格。这些步骤需要具有远程集群的 cluster-admin
用户访问权限。
用以下命令设置为
istio-reader-service-account
服务账号构建kubeconfig
文件所需的环境变量:$ export WORK_DIR=$(pwd) $ CLUSTER_NAME=$(kubectl config view --minify=true -o jsonpath='{.clusters[].name}') $ export KUBECFG_FILE=${WORK_DIR}/${CLUSTER_NAME} $ SERVER=$(kubectl config view --minify=true -o jsonpath='{.clusters[].cluster.server}') $ NAMESPACE=istio-system $ SERVICE_ACCOUNT=istio-reader-service-account $ SECRET_NAME=$(kubectl get sa ${SERVICE_ACCOUNT} -n ${NAMESPACE} -o jsonpath='{.secrets[].name}') $ CA_DATA=$(kubectl get secret ${SECRET_NAME} -n ${NAMESPACE} -o jsonpath="{.data['ca\.crt']}") $ TOKEN=$(kubectl get secret ${SECRET_NAME} -n ${NAMESPACE} -o jsonpath="{.data['token']}" | base64 --decode)
在工作目录中,用以下命令创建
istio-reader-service-account
服务账号对应的kubeconfig
文件:$ cat <<EOF > ${KUBECFG_FILE} apiVersion: v1 clusters: - cluster: certificate-authority-data: ${CA_DATA} server: ${SERVER} name: ${CLUSTER_NAME} contexts: - context: cluster: ${CLUSTER_NAME} user: ${CLUSTER_NAME} name: ${CLUSTER_NAME} current-context: ${CLUSTER_NAME} kind: Config preferences: {} users: - name: ${CLUSTER_NAME} user: token: ${TOKEN} EOF
(可选) 创建环境变量文件以创建远程集群的 secret:
$ cat <<EOF > remote_cluster_env_vars export CLUSTER_NAME=${CLUSTER_NAME} export KUBECFG_FILE=${KUBECFG_FILE} export NAMESPACE=${NAMESPACE} EOF
至此,您已在当前目录中创建了远程集群的 kubeconfig
文件。
kubeconfig
文件的文件名与原始集群名称相同。
实例化凭证
在运行 Istio 控制平面的集群上执行这一步骤。
该步骤使用了来自上一节的 WORK_DIR
、CLUSTER_NAME
和 NAMESPACE
环境变量以及为远程集群的 secret 创建的文件。
如果您已经为远程集群的 secret 创建了环境变量文件,运行以下命令加载该文件:
$ source remote_cluster_env_vars
您可以将 Istio 安装到不同的命名空间。
本步骤使用了 istio-system
命名空间。
创建一个 secret 并为每个远程集群正确标记:
$ kubectl create secret generic ${CLUSTER_NAME} --from-file ${KUBECFG_FILE} -n ${NAMESPACE}
$ kubectl label secret ${CLUSTER_NAME} istio/multiCluster=true -n ${NAMESPACE}
卸载远程集群
运行下列命令以卸载远程集群:
$ istioctl manifest generate \
--set profile=remote \
--set values.global.controlPlaneSecurityEnabled=false \
--set values.global.createRemoteSvcEndpoints=true \
--set values.global.remotePilotCreateSvcEndpoint=true \
--set values.global.remotePilotAddress=${PILOT_POD_IP} \
--set values.global.remotePolicyAddress=${POLICY_POD_IP} \
--set values.global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
--set gateways.enabled=false \
--set autoInjection.enabled=true | kubectl delete -f -
手动 sidecar 注入示例
下列例子展示了如何使用 istioctl manifest
命令来为禁用自动 sidecar 注入的远程集群生成清单。
另外,这个例子还展示了如何通过 istioctl kube-inject
命令使用远程集群的 configmaps
来为远程集群生成任意应用的清单。
对远程集群执行下列步骤。
在开始之前,请按照设置环境变量部分中的说明设置端点 IP 环境变量。
安装 Istio 远程配置文件:
$ istioctl manifest apply \ --set profile=remote \ --set values.global.controlPlaneSecurityEnabled=false \ --set values.global.createRemoteSvcEndpoints=true \ --set values.global.remotePilotCreateSvcEndpoint=true \ --set values.global.remotePilotAddress=${PILOT_POD_IP} \ --set values.global.remotePolicyAddress=${POLICY_POD_IP} \ --set values.global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \ --set gateways.enabled=false \ --set autoInjection.enabled=false
为每个远程集群生成
kubeconfig
配置文件。为每个远程集群实例化凭证。
手动将 sidecars 注入到应用程序清单
以下示例 istioctl
命令将 sidecar 注入到应用程序清单中。
在为远程集群设置了 kubeconfig
上下文的 shell 中运行以下命令。
$ ORIGINAL_SVC_MANIFEST=mysvc-v1.yaml
$ istioctl kube-inject --injectConfigMapName istio-sidecar-injector --meshConfigMapName istio -f ${ORIGINAL_SVC_MANIFEST} | kubectl apply -f -
从不同的集群中访问服务
Kubernetes 基于集群解析 DNS。
由于 DNS 解析与集群有关,因此无论服务端点的位置在哪,您都必须在运行客户端的每个集群中定义服务对象。
为确保这种情况,请使用 kubectl
将服务对象复制到每个集群。
复制可确保 Kubernetes 可以解析任何集群中的服务名称。
由于服务对象是在命名空间中定义的,如果该命名空间不存在,您必须定义它,并将其包含在所有集群的服务定义中。
部署注意事项
前面的步骤提供了一个简单且按部就班的部署多集群环境的指导。
一个生产环境需要更多的步骤或更复杂的部署选项。
本节收集 Istio 服务的端点 IPs 并使用它们来调用 istioctl
。
这个过程会在远程集群上创建 Istio 服务。
作为在远程集群中创建那些服务和端口的一部分,Kubernetes 会往 kube-dns
配置对象中添加 DNS 条目。
这让远程集群上的 kube-dns
配置对象可以为那些远程集群中的所有 Envoy sidecars 解析 Istio 服务名。
因为 Kubernetes pods 没有固定的 IPs,控制平面中的任意 Istio 服务 pod 的重启都会导致它的端点变化。
因此,任何从远程集群到那个端点的连接都会断开。
这个行为记录在 Istio 问题 #4822。
有几个选项可以避免或解决这个情况。本节概述了这些选项:
- 更新 DNS 条目
- 使用负载均衡服务类型
- 通过网关暴露这些 Istio 服务
更新 DNS 条目
本地 Istio 控制平面发生任何故障或重新启动时,必须使用 Istio 服务的正确端点映射更新远程集群上的 kube-dns
。
有许多方法可以做到这一点。
最明显的是在控制平面集群上的 Istio 服务重新启动后,在远程集群中重新运行 istioctl
命令。
使用负载均衡服务类型
在 Kubernetes 中,您可以声明一个服务的服务类型为 LoadBalancer
。
更多信息请参考 Kubernetes 文档的服务类型。
Pod 重启问题的一个简单的解决方案就是为 Istio 服务使用负载均衡器。 然后,您可以使用负载均衡器的 IPs 作为 Istio 服务的端点 IPs 来配置远程集群。 您可能需要下列 Istio 服务的负载均衡器 IPs:
istio-pilot
istio-telemetry
istio-policy
目前,Istio 安装没有提供用于为 Istio 服务指定服务类型的选项。 您可以在 Istio 清单中手动指定服务类型。
通过网关暴露这些 Istio 服务
这个方法使用了 Istio ingress 网关功能。
远程集群需要 istio-pilot
、istio-telemetry
和 istio-policy
服务指向 Istio ingress 网关的负载均衡器 IP。
然后,所有的服务指向相同的 IP。
您必须接着创建 destination rules 以在 ingress 网关的主集群中访问到对应的 Istio 服务。
此方法提供了两种选择:
重用提供的清单所创建的默认 Istio ingress 网关。您只需要添加正确的 destination rules。
为多集群创建另外一个 Istio ingress 网关。
安全性
Istio 支持在控制平面组件之间以及注入到应用的 pods 的 sidecar 之间部署双向 TLS。
控制平面安全性
按照这些步骤启用控制平面安全性:
部署 Istio 控制平面集群需要:
启用控制平面安全性。
禁用
citadel
证书自签名。Istio 控制平面命名空间中具有证书颁发机构(CA)证书的名为
cacerts
的 secret。
部署 Istio 远程集群需要:
启用控制平面安全性。
禁用
citadel
证书自签名。Istio 控制平面命名空间中具有 CA 证书的名为
cacerts
的 secret。 主集群的证书颁发机构(CA)或根 CA 必须也为远程集群签名 CA 证书。Istio pilot 服务主机名可被 DNS 解析。 DNS 解析是必需的,因为 Istio 将 sidecar 配置为使用
istio-pilot.<namespace>
主题名称格式来验证证书主题名称。设置控制平面 IPs 或可解析的主机名。
应用 pods 间的双向 TLS
按照这些步骤以为所有应用 pods 启用双向 TLS:
部署 Istio 控制平面集群需要:
启用全局双向 TLS。
禁用 Citadel 证书自签名。
Istio 控制平面命名空间中具有 CA 证书的名为
cacerts
的 secret。
部署 Istio 远程集群需要:
启用全局双向 TLS。
禁用 Citadel 证书自签名。
Istio 控制平面命名空间中具有 CA 证书的名为
cacerts
的 secret。 主集群的 CA 或根 CA 必须也为远程集群签名 CA 证书。
部署示例
这个示例过程将在同时启用控制平面双向 TLS 和应用 pod 双向 TLS 的情况下安装 Istio。
该过程用无选择器的服务和端点来设置远程集群。
Istio Pilot 用该服务和端点以让远程 sidecars 可以通过 Istio 的本地 Kubernetes DNS 解析 istio-pilot.istio-system
主机名。
主集群:部署控制平面集群
使用
istio-system
命名空间中的 Istio 证书示例创建cacerts
secret:$ kubectl create ns istio-system $ kubectl create secret generic cacerts -n istio-system --from-file=samples/certs/ca-cert.pem --from-file=samples/certs/ca-key.pem --from-file=samples/certs/root-cert.pem --from-file=samples/certs/cert-chain.pem
部署 Istio 控制平面,并为控制平面和应用程序容器启用安全性:
$ istioctl manifest apply \ --set values.global.mtls.enabled=true \ --set values.security.selfSigned=false
远程集群:部署 Istio 组件
使用
istio-system
命名空间中的 Istio 证书示例创建cacerts
secret:$ kubectl create ns istio-system $ kubectl create secret generic cacerts -n istio-system --from-file=samples/certs/ca-cert.pem --from-file=samples/certs/ca-key.pem --from-file=samples/certs/root-cert.pem --from-file=samples/certs/cert-chain.pem
按照设置环境变量部分中的说明设置端点 IP 环境变量。
以下命令部署远程集群的组件,并为控制平面和应用程序 pod 启用安全性,并启用 Istio Pilot 无选择器服务和端点的创建,以在远程集群中获取 DNS 条目。
$ istioctl manifest apply \ --set profile=remote \ --set values.global.mtls.enabled=true \ --set values.security.selfSigned=false \ --set values.global.createRemoteSvcEndpoints=true \ --set values.global.remotePilotCreateSvcEndpoint=true \ --set values.global.remotePilotAddress=${PILOT_POD_IP} \ --set values.global.remotePolicyAddress=${POLICY_POD_IP} \ --set values.global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \ --set gateways.enabled=false \ --set autoInjection.enabled=true
要为远程集群生成
kubeconfig
配置文件,请遵循 Kubernetes 配置部分中的步骤。
主集群:实例化凭证
您必须为每个远程集群都实例化凭证。请按照实例化凭证过程完成部署。
恭喜
您已将所有群集中的所有 Istio 组件都配置为在应用 sidecars、控制平面组件和其他应用 sidecars 之间使用双向 TLS。