基于开源istio治理CCE多集群--扁平网络场景
一 背景
创建2个CCE turbo集群,扁平网络模式,每个集群pod网段 service网段不重合。现在需要业务容灾部署、主备形式运行。
正常情况下,如果不借助istio的能力,没办法实现通过service访问远端集群的业务。
只会将流量路由到本集群的业务中。
如果此时将本集群业务不可用,则会出现访问失败的情况
二 方案简介
针对上述网络环境,本文档将以多集群容器扁平网络多控制面架构进行istio的安装
若需实现该方案,需要回答如下关键问题:
-
问题一、A、B集群的istiod如何获取到A、B集群的域名、clusterip、podip信息?
答:获取A、B集群的kubeconfig凭证(注意凭证的权限和有效期),基于istioctl的remotesecret命令生成对端集群的访问凭证,使得本端集群istiod可同时连接本端集群(通过serviceaccount方式)、对端集群(通过remotesecret)的kube-apiserver。通过这种方式,A集群的istiod可以获取A、B集群的域名、clusterip、podip等全量信息。 -
问题二、在A、B集群均部署相同业务前提下,某集群的istio-proxy如何将指定域名流量转发给两个集群的后端实例?
答:在问题一的回复基础上,A集群istiod获取A、B集群的全量域名、clusterip、podip,将对应信息通过xDS协议下发给本集群各个Pod的istio-proxy组件。当业务容器访问某容灾业务域名时(A、B均部署相同业务,域名相同),istio-proxy拦截流量后获取到与该域名关联的A、B集群中的podip信息,由于本模拟场景A、B集群容器网络扁平和互通,所以该流量直接可转发给A、B集群的相关业务后端,实现多集群容灾。 -
问题三、在A、B集群部署不同业务前提下,A集群如何通过B集群业务域名访问B集群后端实例,实现双集群东西向互访
答:在问题一的回复基础上,A集群istiod获取A、B集群的全量域名、clusterip、podip,将对应信息通过xDS协议下发给本集群各个Pod的istio-proxy组件。当业务容器通过servicename.cluster访问B集群业务时(A集群无对应业务,该集群在B集群部署),需要先通过影子service或者开启istio智能dns代理能力,使得域名可以解析组成TCP包发送。istio-proxy拦截流量后获取到与该域名关联的A、B集群中的podip信息,由于本模拟场景A、B集群容器网络扁平和互通,所以该流量直接可转发给B集群的相关业务后端,实现多集群业务东西向互访。 -
问题四、istio-proxy默认加密流量转发,为什么A、B集群isto-proxy可双向认证?
答:A、B集群的istio-proxy要基于同一根证书签发证书,使得A、B集群istio-proxy证书互信。
三 多集群网格环境搭建
3.1 创建CA证书
-
在istio多集群通信中,每个集群都会有一个istio控制面,其中包含一个CA服务,该CA服务会自动为每个集群中的Istio Sidecar 生成证书和密钥,并用于为Pod之间的mTLS加密认证提供证书签名。
-
这些证书和密钥是由Istio CA服务签发的,以确保通信的安全性和可靠性。多集群服务网格部署要求网格中的所有集群之间建立信任关系,所以需要使用同一个根证书Root CA来签发中间态证书
-
下载istio安装包
wget https://github.com/istio/istio/releases/download/1.22.3/istio-1.22.3-linux-amd64.tar.gz
CCE 集群的kubernetes 版本为1.28,可使用1.22版本的istio,kubernetes 和istio的对应关系 可参照:https://istio.io/latest/zh/docs/releases/supported-releases/#support-status-of-istio-releases -
在 Istio 安装包的顶层目录下,创建一个目录来存放证书和密钥
mkdir -p certs
pushd certs
-
生成根证书和密钥
make -f ../tools/certs/Makefile.selfsigned.mk root-ca
将会生成以下文件:
○ root-cert.pem:生成的根证书
○ root-key.pem:生成的根密钥
○ root-ca.conf:生成根证书的 openssl 配置
○ root-cert.csr:为根证书生成的 CSR
-
对于每个集群,为 Istio CA 生成一个中间证书和密钥
make -f ../tools/certs/Makefile.selfsigned.mk cluster1-cacerts
make -f ../tools/certs/Makefile.selfsigned.mk cluster2-cacerts
运行以上命令,将会在名为 cluster1、cluster2 的目录下生成以下文件:
○ ca-cert.pem:生成的中间证书
○ ca-key.pem:生成的中间密钥
○ cert-chain.pem:istiod 使用的生成的证书链
○ root-cert.pem:根证书
-
在每个集群中,创建一个私密 cacerts,包括所有输入文件 ca-cert.pem, ca-key.pem,root-cert.pem 和 cert-chain.pem
kubectl create namespace istio-system kubectl create secret generic cacerts -n istio-system \ --from-file=cluster1/ca-cert.pem \ --from-file=cluster1/ca-key.pem \ --from-file=cluster1/root-cert.pem \ --from-file=cluster1/cert-chain.pem
kubectl create namespace istio-system --context=cluster2 kubectl create secret generic cacerts -n istio-system \ --from-file=cluster2/ca-cert.pem \ --from-file=cluster2/ca-key.pem \ --from-file=cluster2/root-cert.pem \ --from-file=cluster2/cert-chain.pem --context=cluster2
-
证书创建完毕,返回istio 安装目录
popd
-
备注:以上证书内容仅用于演示。对于生产型集群的设置,强烈建议使用生产型 CA,如 Hashicorp Vault。 在具有强大安全保护功能的离线机器上管理根 CA 是一个很好的做法。
-
在扁平网络模式下,跨集群通信是Pod与Pod直连,不需要经过Istio Gateway,因此不需要强制使用mTLS,可以不用配置mTLS证书。istio默认sidecar之间使用加密流量通信,取消mtls方式可参考如下:
apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: "default" namespace: "istio-system" #网格范围:为根命名空间指定的策略 spec: mtls: mode: DISABLE #禁用双向 TLS,从安全角度来看,除非您提供自己的安全解决方案,否则请勿使用此模式。
3.2 将istio分别安装在各个集群中
因为是多istio控制面部署,所以每个集群都需要安装istio。本文档采用istioctl方式进行安装,安装API参数配置参考: https://istio.io/latest/zh/docs/reference/config/istio.operator.v1alpha1/
-
cluster1集群istio安装配置
apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: hub: swr.cn-north-4.myhuaweicloud.com/hjmtest #配置istio安装的镜像仓库 meshConfig: accessLogFile: /dev/stdout #开启访问日志 values: global: meshID: mesh1 multiCluster: clusterName: cluster1 network: network1 # 集群的网络标识
istioctl install --context=cluster1 -f cluster1.yaml
-
cluster2 集群istio 安装配置
apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: hub: swr.cn-north-4.myhuaweicloud.com/hjmtest #配置istio安装的镜像仓库 meshConfig: accessLogFile: /dev/stdout #开启访问日志 values: global: meshID: mesh1 #和cluster1 同属于一个mesh multiCluster: clusterName: cluster2 #需要区别cluster1 network: network1 # 集群的网络标识,扁平网络,和cluster1 在同一个网络下
istioctl install --context=cluster2 -f cluster2.yaml
3.3 istio控制面访问remote kubernetes集群配置
istiod 需要负责连接所有集群的kube-apiserver,并且List-Watch 获取每个集群的Service、Endpoint、Pod等。
- istiod 以RBAC的方式通过serviceaccount 绑定clusterrole 获取本集群的各种k8s资源信息,即通过Pod内置的token连接所在集群的Kube-apiserver。
- 至于如何获取remote集群中的k8s资源,则需要通过Secret为istiod提供访问凭据,这种特殊的Secret,其标签为istio/multiCluster: true,并包含集群的ID 及remote集群访问的凭据 KubeConfig,istiod可以通过该secret提供的访问凭据与remote集群建立连接,监听remote集群的所有服务和相关资源的变化。
-
在 cluster1 中安装remote集群的 secret,该 secret 提供 cluster2 的 kube-apiserver的访问权限。
istioctl create-remote-secret \ --context=cluster2 \ --name=cluster2 | \ kubectl apply -f - --context=cluster1
secret 大致内容如下
secret中的cluster2对应value值为:
-
在 cluster2 中安装remote集群的 secret,该 secret 提供 cluster1 的 kube-apiserver的访问权限。
istioctl create-remote-secret \ --context=cluster1 \ --name=cluster1 | \ kubectl apply -f - --context=cluster2
-
查看istiod 日志 。确认istio是否与remote集群建立连接
-
注意: istioctl create-remote-secret --context=xxx,采用对应的kubeconfig配置文件,需要kubeconfig能保证访问集群各项资源权限 同时还需要保证证书时间在网格使用期间不过期。
可参考istio源码:https://github.com/istio/istio/blob/master/istioctl/pkg/multicluster/remote_secret.go
四 验证多集群流量治理
4.1 验证istio跨集群流量
在两个集群中分别部署不同版本的服务
kubectl apply --context=cluster1 -f samples/helloworld/helloworld.yaml -l version=v1 -n sample
kubectl apply --context=cluster1 -f samples/helloworld/helloworld.yaml -l service=helloworld -n sample
kubectl apply --context=cluster2 -f samples/helloworld/helloworld.yaml -l version=v2 -n sample
kubectl apply --context=cluster2 -f samples/helloworld/helloworld.yaml -l service=helloworld -n sample
-
进行访问测试
-
查看 客户端的istio-proxy访问日志
访问日志记录了outbound流量相关信息。
4.2 验证多集群流量灰度发布
在istio多控制面模型中,Istio控制面目前只监听主集群(也就是istio所在集群)的 VirtualService、DestinationRule、Gateway等Istio API对象,因此 对于多控制面模型来说,相同的Istio配置需要被复制下发到多个集群中,否则不同集群的Sidecar订阅到的xDS配置可能会存在严重的不一致,导致不同集群的服务访问行为不一致。
-
针对需要灰度的服务配置VirtualService路由规则
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: helloworld namespace: sample spec: hosts: - helloworld http: - route: - destination: host: helloworld subset: v2 weight: 30 - destination: host: helloworld subset: v1 weight: 70
以上规则表示,当有流量访问域名为helloworld的服务时,客户端服务的sidecar容器istio-proxy会将30%的流量路由到v2版本的helloworld负载上,将70%的流量路由到v1版本的helloworld负载上。
-
针对需要灰度的服务配置DestinationRule目标规则
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: helloworld namespace: sample spec: host: helloworld subsets: - name: v2 labels: version: v2 - name: v1 labels: version: v1
以上规则表示,将域名为helloworld的服务创建两个subset子集。负载实例满足标签为version: v2 将被定义到subset v2中,负载实例满足标签为version: v1将被定义到subset v1中,一般和virtualservice结合使用。
-
于cluster1中创建上述两条istio crd资源
-
访问测试,以cluster1集群中的sleep服务作为客户端访问helloworld服务端
-
如果以cluster2集群中的客户端sleep服务进行访问,将会出现什么情况呢?还是否能够进行跨集群流量灰度发布
可以发现之前在cluster1中创建的流量治理规则,不会在cluster2中的数据面istio-proxy生效。 -
此时在cluster2中创建上述virtualservice、destinationrule资源,然后再进行访问测试。
可以发现流量比例不再是1:1,而是以设定的7:3的路由规则进行流量分发。
4.3 验证istio 智能DNS代理
我们可能会有疑问,在kubernetes集群中,coreDNS只负责集群内的服务域名解析,对其他集群的域名解析束手无策。
- 关于istio如何解析remote集群的service 域名,通常的做法是在每个集群中都创建相同的Service对象,可以没有pod实例 ,这种影子service作为占位符,仅供每个Kubernetes集群的coredns服务提供对服务网格的域名解析。
- 在 istio 1.8以后,istio 提供了智能的DNS代理,原生支持对Remote集群的service域名解析,不过该配置默认是关闭的,需要手动开启,开启方式分为全局开启和局部开启。详情可参考:https://istio.io/latest/zh/docs/ops/configuration/traffic-management/dns-proxy/
proxy.istio.io/config: |
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true"
ISTIO_META_DNS_AUTO_ALLOCATE: "true"
-
将cluster1 中helloword服务的实例缩容到0,然后发起访问
流量直接路由到cluster2中的helloworld实例上,访问还是成功的
-
如果将cluster1集群中helloworld service去除,将导致访问失败,即使cluster2中存在helloworld服务
-
于cluster1中发起对helloworld的访问
因为缺少影子service导致访问失败
-
此时给客户端添加配置
proxy.istio.io/config: | proxyMetadata: ISTIO_META_DNS_CAPTURE: "true" ISTIO_META_DNS_AUTO_ALLOCATE: "true"
-
再次进行访问测试
- 点赞
- 收藏
- 关注作者
评论(0)