做者 | 王夕宁 阿里巴巴高级技术专家json
**导读:**本文摘自于由阿里云高级技术专家王夕宁撰写的《Istio 服务网格技术解析与实践》一书,讲述了如何使用 Istio 进行多集群部署管理来阐述服务网格对多云环境、多集群即混合部署的支持能力。api
前文详情: 如何使用 Istio 进行多集群部署管理:单控制平面 VPN 链接拓扑服务器
单控制平面拓扑下,多个 Kubernetes 集群共同使用在其中一个集群上运行的单个 Istio 控制平面。控制平面的 Pilot 管理本地和远程集群上的服务,并为全部集群配置 Envoy Sidecar 代理。微信
集群感知的服务路由
Istio 1.1 中引入了集群感知的服务路由能力,在单一控制平面拓扑配置下,使用 Istio 的 Split-horizon EDS(水平分割端点发现服务)功能能够经过其入口网关将服务请求路由到其余集群。基于请求源的位置,Istio 可以将请求路由到不一样的端点。网络
在该配置中,从一个集群中的 Sidecar 代理到同一集群中的服务的请求仍然被转发到本地服务 IP。若是目标工做负载在其余集群中运行,则使用远程集群的网关 IP 来链接到该服务。app
(集群感知的服务路由)less
如图所示,主集群 cluster1 运行全套的 Istio 控制平面组件,同时集群 cluster2 仅运行 Istio Citadel、Sidecar Injector 和 Ingress 网关。不须要 VPN 链接,不一样集群中的工做负载之间也不须要直接网络访问。curl
从共享的根 CA 为每一个集群的 Citadel 生成中间 CA 证书,共享的根 CA 启用跨不一样集群的双向 TLS 通讯。为了便于说明,咱们将 samples/certs 目录下 Istio 安装中提供的示例根 CA 证书用于两个集群。在实际部署中,你可能会为每一个集群使用不一样的 CA 证书,全部 CA 证书都由公共根 CA 签名。ide
在每一个 Kubernetes 集群中(包括示例中的集群 cluster1 与 cluster2)使用如下命令为生成的 CA 证书建立 Kubernetes 密钥:微服务
kubectl create namespace 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 控制平面组件
在部署全套 Istio 控制平面组件的集群 cluster1 中,按照如下步骤执行:
1.安装 Istio 的 CRD 并等待几秒钟,以便将它们提交给 Kubernetes API 服务器,以下所示:
for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done
2.而后开始在集群 cluster1 中部署 Istio 控制平面。
若是 helm 依赖项缺失或者不是最新的,能够经过 helm dep update 来更新这些依赖项。须要注意的是,由于没有使用 istio-cni,能够暂时将其从依赖项 requirements.yaml 中去掉再执行更新操做。具体命令以下所示:
helm template --name=istio --namespace=istio-system \ --set global.mtls.enabled=true \ --set security.selfSigned=false \ --set global.controlPlaneSecurityEnabled=true \ --set global.meshExpansion.enabled=true \ --set global.meshNetworks.network2.endpoints[0].fromRegistry=n2-k8s-config \ --set global.meshNetworks.network2.gateways[0].address=0.0.0.0 \ --set global.meshNetworks.network2.gateways[0].port=15443 \ install/kubernetes/helm/istio > ./istio-auth.yaml
请注意,网关地址设置为 0.0.0.0。这是一个临时占位符值,在集群 cluster2 部署以后将更新为其网关的公共 IP 值。
将 Istio 部署到 cluster1,以下所示:
kubectl apply -f ./istio-auth.yaml
确保上述步骤在 Kubernetes 集群中执行成功。
3. 建立网关以访问远程服务,以下所示:
kubectl create -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: cluster-aware-gateway namespace: istio-system spec: selector: istio: ingressgateway servers: - port: number: 15443 name: tls protocol: TLS tls: mode: AUTO_PASSTHROUGH hosts: - "*" EOF
上述网关配置了一个专用端口 15443 用来将传入流量传递到请求的 SNI 标头中指定的目标服务,从源服务到目标服务一直使用双向 TLS 链接。
请注意虽然该网关定义应用于集群 cluster1,但由于两个集群都与同一个 Pilot 进行通讯,此网关实例一样也适用于集群 cluster2。
istio-remote 组件
在另外一集群 cluster2 中部署 istio-remote 组件,按照如下步骤执行:
1.首先获取集群 cluster1 的入口网关地址,以下所示:
export LOCAL_GW_ADDR=$(kubectl get svc --selector=app=istio-ingressgateway \ -n istio-system -o jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}")
经过执行如下命令,使用 Helm 建立 Istio remote 部署 YAML 文件:
helm template --name istio-remote --namespace=istio-system \ --values install/kubernetes/helm/istio/values-istio-remote.yaml \ --set global.mtls.enabled=true \ --set gateways.enabled=true \ --set security.selfSigned=false \ --set global.controlPlaneSecurityEnabled=true \ --set global.createRemoteSvcEndpoints=true \ --set global.remotePilotCreateSvcEndpoint=true \ --set global.remotePilotAddress=${LOCAL_GW_ADDR} \ --set global.remotePolicyAddress=${LOCAL_GW_ADDR} \ --set global.remoteTelemetryAddress=${LOCAL_GW_ADDR} \ --set gateways.istio-ingressgateway.env.ISTIO_META_NETWORK="network2" \ --set global.network="network2" \ install/kubernetes/helm/istio > istio-remote-auth.yaml
2. 将 Istio remote 组件部署到 cluster2,以下所示:
kubectl apply -f ./istio-remote-auth.yaml
确保上述步骤在 Kubernetes 集群中执行成功。
3.更新集群 cluster1 的配置项 istio,获取集群 cluster2 的入口网关地址,以下所示:
export REMOTE_GW_ADDR=$(kubectl get --context=$CTX_REMOTE svc --selector=app= istio-ingressgateway -n istio-system -o jsonpath="{.items[0].status.loadBalancer.ingress [0].ip}")
在集群 cluster1 中编辑命名空间 istio-system 下的配置项 istio,替换 network2 的网关地址,从 0.0.0.0 变成集群 cluster2 的入口网关地址 ${REMOTE_GW_ADDR}。保存后,Pilot 将自动读取更新的网络配置。
4.建立集群 cluster2 的 Kubeconfig。经过如下命令,在集群 cluster2 上建立服务帐号 istio-multi 的 Kubeconfig,并保存为文件 n2-k8s-config:
CLUSTER_NAME="cluster2" SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}") SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}') CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}") TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode) cat <<EOF > n2-k8s-config apiVersion: v1 kind: Config 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} users: - name: ${CLUSTER_NAME} user: token: ${TOKEN} EOF
5.将集群 cluster2 加入到 Istio 控制平面。
在集群 clusterl 执行如下命令,将上述生成的集群 cluster2 的 kubeconfig 添加到集群 cluster1 的 secret 中,执行这些命令后,集群 cluster1 中的 Istio Pilot 将开始监听集群 cluster2 的服务和实例,就像监听集群 cluster1 中的服务与实例同样:
kubectl create secret generic n2-k8s-secret --from-file n2-k8s-config -n istio-system kubectl label secret n2-k8s-secret istio/multiCluster=true -n istio-system
部署示例应用
为了演示跨集群访问,在第一个 Kubernetes 集群 cluster1 中部署 sleep 应用服务和版本 v1 的 helloworld 服务,在第二个集群 cluster2 中部署版本 v2 的 helloworld 服务,而后验证 sleep 应用是否能够调用本地或者远程集群的 helloworld 服务。
1.部署 sleep 和版本 v1 的 helloworld 服务到第一个集群 cluster1 中,执行以下命令:
kubectl create namespace app1 kubectl label namespace app1 istio-injection=enabled kubectl apply -n app1 -f samples/sleep/sleep.yaml kubectl apply -n app1 -f samples/helloworld/service.yaml kubectl apply -n app1 -f samples/helloworld/helloworld.yaml -l version=v1 export SLEEP_POD=$(kubectl get -n app1 pod -l app=sleep -o jsonpath={.items..metadata.name})
2.部署版本 v2 的 helloworld 服务到第二个集群 cluster2 中,执行以下命令:
kubectl create namespace app1 kubectl label namespace app1 istio-injection=enabled kubectl apply -n app1 -f samples/helloworld/service.yaml kubectl apply -n app1 -f samples/helloworld/helloworld.yaml -l version=v2
3.登陆到命名空间 istio-system 下的 istio-pilot 容器中,运行 curl localhost:8080/v1/registration | grep helloworld -A 11 -B 2 命令,若是获得以下相似的结果就说明版本 v1 与 v2 的 helloworld 服务都已经注册到 Istio 控制平面中了:
4.验证在集群 cluster1 中的 sleep 服务是否能够正常调用本地或者远程集群的 helloworld 服务,在集群 cluster1 下执行以下命令:
kubectl exec -it -n app1 $SLEEP_POD sh
登陆到容器中,运行 curl helloworld.app1:5000/hello。
若是设置正确,则在返回的调用结果中能够看到两个版本的 helloworld 服务,同时能够经过查看 sleep 容器组中的 istio-proxy 容器日志来验证访问的端点 IP 地址,返回结果以下所示:
《Istio服务网格技术解析与实战》读者可免费体验 ASM 产品进行学习!点击了解阿里云服务网格产品 ASM:www.aliyun.com/product/servicemesh
做者简介
王夕宁 阿里云高级技术专家,阿里云服务网格产品 ASM 及 Istio on Kubernetes 技术负责人,专一于 Kubernetes、云原生、服务网格等领域。曾在 IBM 中国开发中心工做,担任过专利技术评审委员会主席,拥有 40 多项相关领域的国际技术专利。《Istio 服务网格解析与实战》一书由其撰写,详细介绍了 Istio 的基本原理与开发实战,包含大量精选案例和参考代码能够下载,可快速入门 Istio 开发。Gartner 认为,2020 年服务网格将成为全部领先的容器管理系统的标配技术。本书适合全部对微服务和云原生感兴趣的读者,推荐你们对本书进行深刻的阅读。
课程推荐
为了更多开发者可以享受到 Serverless 带来的红利,这一次,咱们集结了 10+ 位阿里巴巴 Serverless 领域技术专家,打造出最适合开发者入门的 Serverless 公开课,让你即学即用,轻松拥抱云计算的新范式——Serverless。
点击便可免费观看课程:https://developer.aliyun.com/learning/roadmap/serverless
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的公众号。”