共享控制平面(单一网络)

按照该指南安装一个 Istio 多集群服务网格以让每个 Kubernetes 集群的服务和应用能够将他们的内部 Kubernetes 网络暴露至其它集群。

在这个配置中,多个 Kubernetes 集群运行一份可以连接到一个共享 Istio 控制平面的远程配置。 一旦一个或多个远程 Kubernetes 集群连接到该 Istio 控制平面,Envoy 就会形成一个跨多集群的网格网络。

跨多 Kubernetes 集群的 Istio 网格可通过 VPN 直接访问远程 Pod
跨多 Kubernetes 集群的 Istio 网格可通过 VPN 直接访问远程 Pod

前提条件

  • 两个或更多运行受支持的 Kubernetes 版本(1.17, 1.18, 1.19)的集群。

  • 能够在多集群中的一个部署 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 组件。 您可以用下面两种方式之一来安装该组件:

  1. 在远程集群上使用下列命令来安装 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
    
  2. 下列命令示例标记了 default 命名空间。使用类似的命令标记所有需要自动进行 sidecar 注入的远程集群的命名空间。

    $ kubectl label namespace default istio-injection=enabled
    

    为所有需要设置自动 sidecar 注入的 Kubernetes 命名空间重复以上命令。

安装配置参数

你必须配置远程集群的 sidecar 与 Istio 控制平面交互,包括在 istio-remote 配置文件中的以下端点:pilotpolicytelemetry和跟踪服务。 该配置文件默认在远程集群中启用自动 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.enabledtrue, falsetrue指定是否在远程集群上启用自动 sidecar 注入
values.global.remotePilotCreateSvcEndpointtrue, falsefalse如果设置,将使用 remotePilotAddress IP 创建用于 istio-pilot 的无选择器的服务和端点,以确保 istio-pilot.<namespace> 在远程集群上可通过 DNS 解析。
values.global.createRemoteSvcEndpointstrue, falsefalse如果设置,istio-pilotistio-telemetryistio-policy 的 selector-less 服务和端点将用相应的远程 IP:remotePilotAddressremoteTelmetryAddressremotePolicyAddress 分别创建,这样确保在远程集群中服务名可以通过 DNS 解析。

为远程集群创建配置文件

Istio 控制平面需要访问网格中的所有集群以发现服务、端点和 pod 属性。 下列步骤描述了如何通过远程集群为 Istio 控制平面创建 kubeconfig 配置文件。

在每个远程集群上执行这些步骤以将集群加入服务网格。这些步骤需要具有远程集群的 cluster-admin 用户访问权限。

  1. 用以下命令设置为 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)
    
  2. 在工作目录中,用以下命令创建 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
    
  3. (可选) 创建环境变量文件以创建远程集群的 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_DIRCLUSTER_NAMENAMESPACE 环境变量以及为远程集群的 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 环境变量。

  1. 安装 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
    
  2. 为每个远程集群生成 kubeconfig 配置文件。

  3. 为每个远程集群实例化凭证

手动将 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-pilotistio-telemetryistio-policy 服务指向 Istio ingress 网关的负载均衡器 IP。 然后,所有的服务指向相同的 IP。 您必须接着创建 destination rules 以在 ingress 网关的主集群中访问到对应的 Istio 服务。

此方法提供了两种选择:

  • 重用提供的清单所创建的默认 Istio ingress 网关。您只需要添加正确的 destination rules。

  • 为多集群创建另外一个 Istio ingress 网关。

安全性

Istio 支持在控制平面组件之间以及注入到应用的 pods 的 sidecar 之间部署双向 TLS。

控制平面安全性

按照这些步骤启用控制平面安全性:

  1. 部署 Istio 控制平面集群需要:

    • 启用控制平面安全性。

    • 禁用 citadel 证书自签名。

    • Istio 控制平面命名空间中具有证书颁发机构(CA)证书的名为 cacerts 的 secret。

  2. 部署 Istio 远程集群需要:

    • 启用控制平面安全性。

    • 禁用 citadel 证书自签名。

    • Istio 控制平面命名空间中具有 CA 证书的名为 cacerts 的 secret。 主集群的证书颁发机构(CA)或根 CA 必须也为远程集群签名 CA 证书。

    • Istio pilot 服务主机名可被 DNS 解析。 DNS 解析是必需的,因为 Istio 将 sidecar 配置为使用 istio-pilot.<namespace> 主题名称格式来验证证书主题名称。

    • 设置控制平面 IPs 或可解析的主机名。

应用 pods 间的双向 TLS

按照这些步骤以为所有应用 pods 启用双向 TLS:

  1. 部署 Istio 控制平面集群需要:

    • 启用全局双向 TLS。

    • 禁用 Citadel 证书自签名。

    • Istio 控制平面命名空间中具有 CA 证书的名为 cacerts 的 secret。

  2. 部署 Istio 远程集群需要:

    • 启用全局双向 TLS。

    • 禁用 Citadel 证书自签名。

    • Istio 控制平面命名空间中具有 CA 证书的名为 cacerts 的 secret。 主集群的 CA 或根 CA 必须也为远程集群签名 CA 证书。

部署示例

这个示例过程将在同时启用控制平面双向 TLS 和应用 pod 双向 TLS 的情况下安装 Istio。 该过程用无选择器的服务和端点来设置远程集群。 Istio Pilot 用该服务和端点以让远程 sidecars 可以通过 Istio 的本地 Kubernetes DNS 解析 istio-pilot.istio-system 主机名。

主集群:部署控制平面集群

  1. 使用 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
    
  2. 部署 Istio 控制平面,并为控制平面和应用程序容器启用安全性:

    $ istioctl manifest apply \
      --set values.global.mtls.enabled=true \
      --set values.security.selfSigned=false
    

远程集群:部署 Istio 组件

  1. 使用 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
    
  2. 按照设置环境变量部分中的说明设置端点 IP 环境变量。

  3. 以下命令部署远程集群的组件,并为控制平面和应用程序 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
    
  4. 要为远程集群生成 kubeconfig 配置文件,请遵循 Kubernetes 配置部分中的步骤。

主集群:实例化凭证

您必须为每个远程集群都实例化凭证。请按照实例化凭证过程完成部署。

恭喜

您已将所有群集中的所有 Istio 组件都配置为在应用 sidecars、控制平面组件和其他应用 sidecars 之间使用双向 TLS。

这些信息有用吗?
Do you have any suggestions for improvement?

Thanks for your feedback!