Istio 支持多集群部署,并能够实现跨集群服务发现和跨集群负载均衡。Istio 多集群的部署方案一般有两种,分别是多副本控制平面部署和共享控制平面部署。而共享控制平面部署又分为单一网络和多网络部署。在多集群联邦环境中集群常分布在不同可用区下,因此集群不会处于同一网络,则共享控制平面的多网络部署模式符合多集群联邦场景下的负载均衡场景。
使用共享控制平面方案部署,需要有一个主集群用来部署 control plane,其他远程集群要加入 istio 网格的集群则需要连接主集群的 control plane。在Istio 1.7的部署方案中,控制平面将会以istiod形态部署,远程集群中部署的istiod用于CA和集群中工作负载的webhook注入,服务发现则会导向主集群中的控制面实现。集群间通信通过gateway实现,不同集群的工作负载之间既不要求 VPN 连接也不要求直接网络访问。
以下以两个处于不同VPC环境的集群为例,基于集群联邦实现Istio多集群网格部署以及跨集群负载均衡。
登录容器服务控制台,分别在华北1(北京)和华东1(上海)创建两个Kubernetes 集群。
在容器控制台进入多集群-联邦管理,联邦地域为目标Host集群所在地域,点击新建集群联邦。
选择地域与目标Host集群,点击创建,即开始联邦控制面的部署。
查看部署状态,当全部组件部署成功后,此时Host集群处于"未加入"状态,点击更多 > 加入联邦将集群加入到联邦集群中。
接着添加另一个Kubernetes 集群,点击新增Member集群。
为了演示我们选择与Host集群不同的区域下的集群,这也是使用联邦集群实现跨地域容灾常用部署方式。
添加完成后,联邦集群页面中已经可以看到有两个Kubernetes集群。
进入联邦Host集群节点,获取当前联邦的集群信息。
$ kubectl get kubefedclusters -n kube-federation-system
NAME AGE READY
d161c69e-286b-4541-901f-b121c9517f4e 5m True
fcb0f8d3-9907-4a4a-9653-4584b367ee29 12m True
在安装好联邦集群后,联邦证书会默认保存在Host集群kube-system namespaces下的kubefedconfig的configMap中。将集群证书保存到本地~/.kube/config中,便于kubectl及kubefedctl读取使用。
$ kubectl get cm -n kube-system kubefedconfig -o yaml
验证证书是否正确配置,并将当前context指向Host集群。
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
context-d161c69e-286b-4541-901f-b121c9517f4e cluster-d161c69e-286b-4541-901f-b121c9517f4e admin-d161c69e-286b-4541-901f-b121c9517f4e
context-fcb0f8d3-9907-4a4a-9653-4584b367ee29 cluster-fcb0f8d3-9907-4a4a-9653-4584b367ee29 admin-fcb0f8d3-9907-4a4a-9653-4584b367ee29
$ kubectl config use-context context-fcb0f8d3-9907-4a4a-9653-4584b367ee29
Switched to context "context-fcb0f8d3-9907-4a4a-9653-4584b367ee29".
下载kubefedctl命令行工具。
$ wget https://github.com/kubernetes-sigs/kubefed/releases/download/v0.4.1/kubefedctl-0.4.1-linux-amd64.tgz
$ tar zxvf kubefedctl-0.4.1-linux-amd64.tgz
$ rm kubefedctl /usr/local/bin/
部署示例用到了istioctl命令和istio提供的配置文件,下载并安装。
$ curl -L https://istio.io/downloadIstio | sh -
$ cd istio-1.7.2 && export PATH=$PWD/bin:$PATH
在本配置中,安装 Istio 时同时开启控制平面和应用pods的双向TLS。对于共享的根CA使用Istio示例目录下相同的Istio证书,在host和member集群中都创建相同的namespace和secret保存根证书。
# 创建 Namespace/istio-system 和 FederatedNamespace/istio-system
$ kubectl create namespace istio-system
$ kubefedctl federate ns istio-system
# 创建secret 和 FederatedSecret
$ 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
$ kubefedctl federate secret cacerts -n istio-system
在联邦Host集群部署istio控制面板服务,在部署istio控制面服务时会使用以下环境变量用于替换其中配置模板中定义的变量并生成配置文件。
# 设置环境变量
$ export MAIN_CLUSTER_CTX=context-fcb0f8d3-9907-4a4a-9653-4584b367ee29
$ export REMOTE_CLUSTER_CTX=context-d161c69e-286b-4541-901f-b121c9517f4e
$ export MAIN_CLUSTER_NAME=cluster-fcb0f8d3-9907-4a4a-9653-4584b367ee29
$ export REMOTE_CLUSTER_NAME=cluster-d161c69e-286b-4541-901f-b121c9517f4e
$ export MAIN_CLUSTER_NETWORK=network1
$ export REMOTE_CLUSTER_NETWORK=network2
# 创建主集群配置文件
cat <<EOF> istio-main-cluster.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
global:
multiCluster:
clusterName: ${MAIN_CLUSTER_NAME}
network: ${MAIN_CLUSTER_NETWORK}
# Mesh network configuration. This is optional and may be omitted if
# all clusters are on the same network.
meshNetworks:
${MAIN_CLUSTER_NETWORK}:
endpoints:
- fromRegistry: ${MAIN_CLUSTER_NAME}
gateways:
- registry_service_name: istio-ingressgateway.istio-system.svc.cluster.local
port: 443
${REMOTE_CLUSTER_NETWORK}:
endpoints:
- fromRegistry: ${REMOTE_CLUSTER_NAME}
gateways:
- registry_service_name: istio-ingressgateway.istio-system.svc.cluster.local
port: 443
# Use the existing istio-ingressgateway.
meshExpansion:
enabled: true
EOF
# 部署控制面板
$ istioctl install -f istio-main-cluster.yaml --context=${MAIN_CLUSTER_CTX}
Detected that your cluster does not support third party JWT authentication. Falling back to less secure first party JWT. See https://istio.io/docs/ops/best-practices/security/#configure-third-party-service-account-tokens for details.
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete
$ kubectl get pod -n istio-system --context=${MAIN_CLUSTER_CTX}
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-6bdbbc5566-c9kxk 1/1 Running 0 26s
istiod-689b5cbd7d-2dsml 1/1 Running 0 37s
# 设置环境变量`ISTIOD_REMOTE_EP`
$ export ISTIOD_REMOTE_EP=$(kubectl get svc -n istio-system --context=${MAIN_CLUSTER_CTX} istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ echo "ISTIOD_REMOTE_EP is ${ISTIOD_REMOTE_EP}"
# 创建远程集群配置文件
cat <<EOF> istio-remote0-cluster.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
global:
# The remote cluster's name and network name must match the values specified in the
# mesh network configuration of the primary cluster.
multiCluster:
clusterName: ${REMOTE_CLUSTER_NAME}
network: ${REMOTE_CLUSTER_NETWORK}
# Replace ISTIOD_REMOTE_EP with the the value of ISTIOD_REMOTE_EP set earlier.
remotePilotAddress: ${ISTIOD_REMOTE_EP}
## The istio-ingressgateway is not required in the remote cluster if both clusters are on
## the same network. To disable the istio-ingressgateway component, uncomment the lines below.
components:
ingressGateways:
- name: istio-ingressgateway
enabled: true
EOF
$ istioctl install -f istio-remote0-cluster.yaml --context=${REMOTE_CLUSTER_CTX}
$ kubectl get pod -n istio-system
在联邦集群多网络共享控制平面场景下,使用Istio ingress gateway作为流量入口,实现跨网络间通信。为了提高网络通信安全性,需要配置ingress gateway使用443端口和SNI header。
cat <<EOF> cluster-aware-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: cluster-aware-gateway
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: tls
protocol: TLS
tls:
mode: AUTO_PASSTHROUGH
hosts:
- "*.local"
EOF
在Host和Member集群中创建gateway,部署gateway用于实现跨集群服务路由。
$ kubectl apply -f cluster-aware-gateway.yaml --context=${MAIN_CLUSTER_CTX}
$ kubectl apply -f cluster-aware-gateway.yaml --context=${REMOTE_CLUSTER_CTX}
为了实现联邦集群跨集群负载均衡,部署联邦的Host集群上的控制面必须要能够访问到全部集群的kube-apiserver服务,以实现服务发现,获取endpoints和pod属性等。 要访问member集群需要配置member集群的kube-apiserver公网访问证书。获取金山云kubernetes集群公网,容器服务控制台中选择需要获取证书的集群,进入集群基本信息页面,点击获取集群config,选择公网访问config。
将获取到的remote集群的公网访问证书添加到.kube/config文件中,并执行以下操作。Istio将使用该公网证书在remote集群创建serviceaccount io-reader-service-account
和相关role、rolebinding, 并在host集群中创建secret保存io-reader-service-account
的证书信息。
$ istioctl x create-remote-secret --name ${REMOTE_CLUSTER_NAME} --context=${REMOTE_CLUSTER_CTX} | \
kubectl apply -f - --context=${MAIN_CLUSTER_CTX}
在Host集群和Member集群都部署一个 helloworld 服务,在主集群部署 v1 版本服务,在从集群部署 v2版本服务。部署完成后,在任何一个集群访问该服务,流量会在多集群服务间路由。
创建 sample namespace 并设置 istio-injection=enabled 标签。
$ kubectl create namespace sample --context=${MAIN_CLUSTER_CTX}
$ kubectl label namespace sample istio-injection=enabled --context=${MAIN_CLUSTER_CTX}
创建 federatenamespace。
$ kubefedctl federate ns sample
创建 federatedeployment 部署在两个集群中的helloworld服务并使用不同的镜像版本,分别为v1和v2。helloworld-deploy.yaml:
apiVersion: types.kubefed.io/v1beta1
kind: FederatedDeployment
metadata:
name: helloworld
namespace: sample
spec:
template:
metadata:
labels:
app: helloworld
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: helloworld
version: v1
template:
metadata:
labels:
app: helloworld
version: v1
spec:
containers:
- image: docker.io/istio/examples-helloworld-v1
name: helloworld
placement:
clusters:
- name: fcb0f8d3-9907-4a4a-9653-4584b367ee29
- name: d161c69e-286b-4541-901f-b121c9517f4e
overrides:
- clusterName: d161c69e-286b-4541-901f-b121c9517f4e
clusterOverrides:
- path: "/spec/template/spec/containers/0/image"
value: "docker.io/istio/examples-helloworld-v2"
- path: "/spec/template/metadata/labels/version"
value: "v2"
- path: "/spec/selector/matchLabels/version"
value: "v2"
- path: "/metadata/labels/version"
value: "v2"
helloworld-svc.yaml:
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
在Host和Member中部署helloworld服务:
kubectl apply -f helloworld-svc.yaml -n sample --context=${MAIN_CLUSTER_CTX}
kubectl apply -f helloworld-svc.yaml -n sample --context=${REMOTE_CLUSTER_CTX}
为了演示访问 helloworld 服务的流量是分布到多集群的,需要部署一个示例提供的 sleep 服务来调用 helloworld 服务。
# 在Host和member集群分别部署sleep服务
$ kubectl apply -f samples/sleep/sleep.yaml -n sample --context=${MAIN_CLUSTER_CTX}
$ kubectl apply -f samples/sleep/sleep.yaml -n sample --context=${REMOTE_CLUSTER_CTX}
# 在Host集群中多次调用helloworld.sample服务
$ kubectl exec -it -n sample -c sleep --context=${MAIN_CLUSTER_CTX} $(kubectl get pod -n sample -l app=sleep --context=${MAIN_CLUSTER_CTX} -o jsonpath='{.items[0].metadata.name}') -- curl helloworld.sample:5000/hello
# 在Member集群中多次调用helloworld.sample服务
$ kubectl exec -it -n sample -c sleep --context=${REMOTE_CLUSTER_CTX} $(kubectl get pod -n sample -l app=sleep --context=${REMOTE_CLUSTER_CTX} -o jsonpath='{.items[0].metadata.name}') -- curl helloworld.sample:5000/hello
NOTE: 如果部署正确,服务helloworld.sample
的流量会分发到cluster-d161c69e-286b-4541-901f-b121c9517f4e和cluster-fcb0f8d3-9907-4a4a-9653-4584b367ee29集群,得到的响应会是v1和v2两种。
Hello version: v2, instance: helloworld-v2-758dd55874-cxjnw
Hello version: v1, instance: helloworld-v1-7c5df4c84d-vzjtj
在Host集群中通过如下命令查看istio为helloworld 服务注册的路由信息,如下,对于 helloworld 服务,istio 发现并注册了两个路由,一个指向本地的 helloworld 服务,另一个通过成员集群的 ingress gateway 的EIP来路由到从集群部署的helloworld 服务。
$ kubectl get pod -n sample -l app=sleep --context=${MAIN_CLUSTER_CTX} -o name | cut -f2 -d'/' | xargs -I{} istioctl -n sample --context=${MAIN_CLUSTER_CTX} proxy-config endpoints {} --cluster "outbound|5000||helloworld.sample.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.2.2.14:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
120.92.145.63:443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
# 本地Host集群helloworld endpoint 信息
$ kubectl get ep helloworld -n sample --context=${MAIN_CLUSTER_CTX}
NAME ENDPOINTS AGE
helloworld 10.2.2.14:5000 20m
# 远程Member集群helloworld endpoint 信息
$ kubectl get svc -n istio-system istio-ingressgateway --context=${REMOTE_CLUSTER_CTX}
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.254.60.1 120.92.145.63 15021:31509/TCP,80:32473/TCP,443:30816/TCP,15443:31135/TCP 20m
文档内容是否对您有帮助?
评价建议不能为空
非常感谢您的反馈,我们会继续努力做到更好!