VPN 连接

这是一个关于当每个集群中的 pod 可以直连访问其他集群中的 pod 时,可以跨多个集群安装 Istio 网格的说明。

在此配置中,运行远程配置的多个 Kubernetes 控制平面将连接到单个 Istio 控制平面。一旦一个或多个远程 Kubernetes 集群连接到 Istio 控制平面,Envoy 就可以与单个控制平面通信并形成跨多个集群的服务网格。

通过 VPN 直连远程 pod 的多 Kubernetes 集群 Istio 网格
通过 VPN 直连远程 pod 的多 Kubernetes 集群 Istio 网格

先决条件

  • 两个以上运行 Kubernetes 1.9 或更高版本的集群。

  • 能够在其中一个集群上部署 Istio 控制平面的能力。

  • RFC1918 网络、VPN或是满足以下可选条件的更高级的网络技术:

    • 单集群 Pod 和服务的 CIDR 范围在多集群环境中必须唯一,最好不要重叠。

    • 每个集群中的所有 Pod CIDR 必须的相互可达的。

    • 所有 Kubernetes 控制平面 API 服务必须是相互可达的。

  • Helm 2.7.2 或更高版本。 也可选择使用 Tiller 。

本指南将介绍如何使用 Istio 仓库中提供的清单和 Helm charts 安装一个多集群的 Istio 拓扑。

部署本地控制平面

一个 Kubernetes 集群中安装 Istio 控制平面

安装 Istio 远程组件

你必须将 istio-remote 组件部署到每一个远程 Kubernetes 集群中。 你可以通过以下两种方式之一安装组件:

设置环境变量

等待 Istio 控制平面完成初始化,然后再执行本节中的步骤。

你必须在 Istio 控制平面上运行这些操作以捕获 Istio 控制平面服务端点,如:Pilot、Policy 端点。

如果你在每个远程组件上使用 Helm 和 Tiller,你必须将环境变量复制到每个节点,然后再使用 Helm 将远程集群连接到 Istio 控制平面。

通过以下命令设置环境变量:

$ 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}')
$ export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')

接着,你必须将远程集群与本地集群连接。

继续你先前的选项:

通常,需要启动远程 sidecar 注入。如果需要执行手动 sidecar 注入,请参阅手动 sidecar 注入示例

安装并管理远程集群

通过 Helm 和 kubectl

  1. 通过以下 helm template 命令在远程集群中指定 Istio 控制平面服务端点:
$ helm template install/kubernetes/helm/istio-remote --namespace istio-system \
   --name istio-remote \
   --set global.remotePilotAddress=${PILOT_POD_IP} \
   --set global.remotePolicyAddress=${POLICY_POD_IP} \
   --set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \
   --set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > $HOME/istio-remote.yaml
  1. 通过以下命令给远程 Istio 创建一个 istio-system 命名空间:

    $ kubectl create ns istio-system
    
  2. 通过以下命令实例化远程集群与 Istio 控制平面的连接:

    $ kubectl apply -f $HOME/istio-remote.yaml
    
  3. 使用以下示例命令标记 default 命名空间。使用相似命令标记所有需要自动 sidecar 注入的远程集群命名空间。

    $ kubectl label namespace default istio-injection=enabled
    

对需要设置 sidecar 注入的所有 Kubernetes 命名空间需要重复此操作。

Helm chart 配置参数

你必须配置远程集群的 sidecar 与 Istio 控制平面的交互,包括 istio-remote 的 Helm chart: pilot, policy, telemetry, statsd 和 追踪服务。

该 chart 默认启动自动 sidecar 注入。你可以通过 chart 变量来禁用该功能。

下表显示了已通过的 istio-remote Helm chart 配置变量:

Helm 变量可选值默认用途
global.remotePilotAddress一个合法的 IP 地址或主机名None指定 Istio 控制平面的 pilot Pod IP 地址或远程集群 DNS 可解析的主机名。
global.remotePolicyAddress一个合法的 IP 地址或主机名None指定 Istio 控制平面的 policy Pod IP 地址或远程集群 DNS 可解析的主机名。
global.remoteTelemetryAddress一个合法的 IP 地址或主机名None指定 Istio 控制平面的 telemetry Pod IP 地址或远程集群 DNS 可解析的主机名。
global.remoteZipkinAddress一个合法的 IP 地址或主机名None指定 Istio 控制平面追踪应用的 Pod IP 地址或远程集群 DNS 可解析的主机名。例如:zipkinjaeger
sidecarInjectorWebhook.enabledtrue, falsetrue指定是否在远程集群中启用了自动 sidecar 注入
global.remotePilotCreateSvcEndpointtrue, falsefalse如果设置该项,一个无选择器服务和端点将以remotePilotAddress IP的形式被创建给 istio-pilot.<namespace>是远程集群 DNS 可解析的。

为远程集群生成配置文件

Istio 控制平面需要服务所有集群中的网格来发现服务、端点和 pod 属性。

以下步骤描述了如何生成一个 kubeconfig 配置文件给 Istio 控制面板以使用远程集群。

istio-remote Helm chart 在远程集群中创建了一个叫 istio-multi 的 Kubernetes service account 用于最小化 RBAC 访问请求。 此过程通过使用先前所述的 istio-multi service account 凭证生成了一个远程集群的 kubeconfig 配置文件。

每个远程集群上执行此过程以将集群添加到服务网格。此过程需要 cluster-admin 用户访问远程集群的权限。

  1. 通过以下命令为 istio-multi 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-multi
    $ 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-multi 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. (可选) 使用环境变量创建文件以创建远程集群的密钥:

    $ 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 创建了环境变量文件,请通过以下命令获取该文件:

$ 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}

卸载远程集群

你必须使用与他们安装相同的方法卸载远程集群。

通过 kubectl + HelmTiller + Helm 合理卸载他们。

通过 kubectl

要卸载集群,你必须移除 istio-remote.yaml文件进行的配置。 通过以下命令卸载:

$ kubectl delete -f $HOME/istio-remote.yaml

手动 sidecar 注入示例

以下示例将展示如何使用 helm template 命令生成清单以禁用集群的自动 sidecar 注入。此外,示例将展示如何使用远程集群的 configmaps ,通过 istioctl kube-inject 命令为远程集群生成任何应用的清单。

对远程集群执行以下过程:

在开始之前,请按照设置环境变量部分设置端点 IP 环境变量

  1. 在远程集群使用 helm template 命令指定 Istio 控制平面的 service 端点:

    $ helm template install/kubernetes/helm/istio-remote --namespace istio-system --name istio-remote --set global.remotePilotAddress=${PILOT_POD_IP} --set global.remotePolicyAddress=${POLICY_POD_IP} --set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} --set global.remoteZipkinAddress=${ZIPKIN_POD_IP} --set sidecarInjectorWebhook.enabled=false > $HOME/istio-remote_noautoinj.yaml
    
  2. 为远程 Istio 创建 istio-system 命名空间:

    $ kubectl create ns istio-system
    
  3. 实例化远程集群与 Istio 控制平面的连接:

    $ kubectl apply -f $HOME/istio-remote_noautoinj.yaml
    
  4. 为每个远程集群生成 kubeconfig 配置文件。

  5. 为每个集群实例化凭证

手动将 sidecars 注入到应用清单中

以下示例通过 istioctl 命令将 sidecar 注入到应用清单。

在终端中运行以下命令,通过 kubeconfig 为远程集群设置上下文。

$ 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 服务端点的 IP 地址并用他们来调用 Helm。 这个过程在远程集群创建了 Istio 服务。作为在远程集群创建这些服务和端点的一部分,Kubernetes 将 DNS 条目加入到了 kube-dns 配置对象中。 这将允许在远程集群中 kube-dns 配置对象将解析 Istio 服务名给所有 Envoy sidecar。 由于 Kubernetes pods 没有固定的 IP 地址,在控制平面中重启任何 Istio 服务 pod 都会导致它端点的改变。 因此,任何从远程集群到任何端点的连接都会中断。Istio issue #4822详细记录了该问题。

要避免或解决此问题,有多个选项可供选择。本节提供了以下选项的高级概述:

  • 更新 DNS 条目
  • 切换负载均衡服务类型
  • 通过网关暴露 Istio 服务

更新 DNS 条目

在发生任何故障或 pod 重启时,在远程集群重启 kube-dns 可以为 Istio 服务正确更新端点的映射关系。 有很多方法可以做到这点。常规做法是在远程节点重新运行 Helm 安装,之后 Istio 服务便会在控制平面上重启。

切换负载均衡类型

在 Kubernetes 中,你可以以 LoadBalancer 类型声明服务。 更多内容详见 Kubernetes 的服务类型

pod 重启的一个简单的解决方案是给 Istio 服务使用负载均衡器。

接着,你可以使用负载均衡器的 IP 地址作为 Istio 服务端点的 IP 地址以配置远程集群。你或许需要这些 Istio 服务的负载均衡器:

  • istio-pilot
  • istio-telemetry
  • istio-policy
  • zipkin

目前,Istio 安装不提供为 Istio 服务指定服务类型的选项。 您可以在 Istio Helm chart 或 Istio 清单中手动指定服务类型。

通过网关暴露 Istio 服务

此方法使用了 Istio ingress 网关的功能。远程集群有 istio-pilotistio-telemetryistio-policy、 和 zipkin 服务,它们指向了 Istio ingress 网关的负载均衡 IP 地址。然后,所有的服务均指向相同的 IP 地址。你必须创建目标规则以在主集群的 ingress 网关中获得正确的 Istio 服务。

以下两种方案可供选择:

  • 重新使用清单或 Helm charts 提供安装的默认 Istio ingress 网关。您只需添加正确的目标规则。

  • 专门为集群创建另一个 Istio ingress 网关。

安装

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

控制平面安全

要启用控制平面安全性,请遵循以下常规步骤:

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

    • 控制平面安全已启用。

    • citadel 证书自签署禁用。

    • cacerts 的 secret 通过证书颁发机构 (CA) 证书下发在Istio 控制平面命名空间中。

  2. 部署 Istio 远程集群:

    • 控制平面安全已启用。

    • citadel 证书自签署禁用。

    • cacerts 的 secret 通过(CA) 证书下发在Istio 控制平面命名空间中。

    主集群的证书颁发机构(CA)或根 CA 也必须为远程群集签署 CA 证书。

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

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

应用 Pod 之间的双向 TLS

为了确保应用 Pod 之间的双向 TLS,请按照以下常规步骤操作:

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

    • 全局启用了相互TLS。

    • Citadel 证书自签名禁用。

    • cacerts 的 secret 通过(CA) 证书下发在Istio 控制平面命名空间中。

  2. 部署Istio远程集群:

    • 全局启用了相互TLS。

    • Citadel 证书自签名禁用。

    • cacerts 的 secret 通过(CA) 证书下发在Istio 控制平面命名空间中。 主集群的 CA 或根 CA 也必须为远程集群签署CA证书。

部署示例

此示例为安装 Istio 的过程,同时启用控制平面双向 TLS 和 应用 pod 双向 TLS。该过程 使用无选择器服务和端点设置远程集群。Istio Pilot 使用服务和端点允许远程 sidecar 通过 Istio 的本地 Kubernetes DNS 解析主机名。

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

  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 控制平面,并为控制平面和应用 pod 启用安全:

    $ helm template --namespace=istio-system \
      --values install/kubernetes/helm/istio/values.yaml \
      --set global.mtls.enabled=true \
      --set security.selfSigned=false \
      --set global.controlPlaneSecurityEnabled=true \
      install/kubernetes/helm/istio > ${HOME}/istio-auth.yaml
    $ kubectl apply -f ${HOME}/istio-auth.yaml
    

远程群集:部署 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. 按照设置环境变量的说明为 pod 的 IP 地址设置环境变量。

  3. 通过以下命令为部署远程集群的组件并为控制平面和应用 pod 启用安全,同时启用创建 Istio Pilot 无选择器服务和端点以在远程集群中获取 DNS 条目。

    $ helm template install/kubernetes/helm/istio-remote \
      --name istio-remote \
      --namespace=istio-system \
      --set global.mtls.enabled=true \
      --set security.selfSigned=false \
      --set global.controlPlaneSecurityEnabled=true \
      --set global.remotePilotCreateSvcEndpoint=true \
      --set global.remotePilotAddress=${PILOT_POD_IP} \
      --set global.remotePolicyAddress=${POLICY_POD_IP} \
      --set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} > ${HOME}/istio-remote-auth.yaml
    $ kubectl apply -f ${HOME}/istio-remote-auth.yaml
    
  4. 要为远程集群生成 kubeconfig 配置文件,请按照Kubernetes 配置部分的步骤操作。

主集群:实例化凭据

你必须为每个远程群集实例化凭据。请按照实例化凭据工程完成部署。

恭喜!

你已经在两个集群中配置了所有 Istio 组件以及在应用 sidecar、控制平面组件和其他应用 sidecar 之间开启了双向TLS。