多集群部署模型
根据官网的 部署模型说明,istio 部署时,在下面四个纬度都可以进行自由选择:
- 单一或多个集群
- 单一或多个网络
- 单一或多控制平面
- 单一或多个网格
因此多集群情况下,后面三个都可以任意组合,总共有 8 种可能。
多网络部署
多集群可以处在不同的网络中,不同网络中的工作负载只能通过一个或多个 istio 网关相互访问。
控制平面纬度
多集群部署可以共享一个控制平面实例。在这种情况下,控制平面实例可以驻留在一个或多个集群中:
多集群部署也可以使用不同的控制平面,下面是在东西两个地域,分别部署了一个控制平面:
多网格部署
通过网格联邦可以实现多网格部署,多网格主要优点是:
- 组织边界:业务范围
- 服务名称或命名空间复用:比如 default 的使用
- 加强隔离:将测试工作负载与生产工作负载隔离
部署架构如下:
多集群部署实践
实践准备
创建两个 k8s 集群,这里用两台云主机,分别安装 k3s 集群,参考 安装文档,因为 k3s 的安装的 kubectl 命令默认用的 kubernetes 配置路径为/etc/rancher/k3s/k3s.yaml,这里先设置环境 KUBECONFIG="/root/.kube/config",保证 kubectl 和 istioctl 配置一致。
1
2
3
4
|
vim ~/.bashrc # 文件中添加 export KUBECONFIG="/root/.kube/config"
source ~/.bashrc
curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
|
查看两个集群节点上的 kubeconfig 配置,除了认证外其他配置基本一样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxx # 省略
server: https://127.0.0.1:6443
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
user:
client-certificate-data: xxx # 省略
client-key-data: xxx # 省略
|
需要在两个集群节点上做如下设置 kubernetes 的 context,这里两台云主机的内网地址分别为:192.168.60.113、192.168.60.9。这里在 192.168.60.113 主机上执行以下步骤:
- 进入 kubeconfig 目录:
cd /root/.kube
- 拷贝 config 为 config1:
cp config config1
- 拷贝另一个集群的 config 为 config2:
scp root@192.168.60.9:/root/.kube/config config2
- 修改 config1 和 config2,将集群名称、用户名称、context 名称改为不一样的,比如 cluster1、cluster2,并将 127.0.0.1 替换为内网地址
- 将两个 config 合并为一个 config,
KUBECONFIG=config1:config2 kubectl config view --flatten > config
此时查看/root/.kube/config 配置为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
apiVersion: v1
clusters:
- cluster:
server: https://192.168.60.113:6443
certificate-authority-data: xxx # 省略
name: cluster1
- cluster:
server: https://192.168.60.9:6443
certificate-authority-data: xxx # 省略
name: cluster2
contexts:
- context:
cluster: cluster1
user: user-cluster1
name: context-cluster1
- context:
cluster: cluster2
user: user-cluster2
name: context-cluster2
current-context: context-cluster1
kind: Config
preferences: {}
users:
- name: user-cluster1
user:
client-certificate-data: xxx # 省略
client-key-data: xxx # 省略
- name: user-cluster2
user:
client-certificate-data: xxx # 省略
client-key-data: xxx # 省略
|
并将上面的 kubeconfig 配置复制为 cluster2 集群节点的~/.kube/config。这时使用 kubectl config 就可以在两个环境切换了:
1
2
3
4
5
6
7
8
9
10
|
root@cluster1:~/.kube# kubectl config use-context context-cluster1
Switched to context "context-cluster1".
root@cluster1:~/.kube# kubectl get nodes
NAME STATUS ROLES AGE VERSION
cluster1 Ready control-plane,master 6h20m v1.25.4+k3s1
root@cluster1:~/.kube# kubectl config use-context context-cluster2
Switched to context "context-cluster2".
root@cluster1:~/.kube# kubectl get nodes
NAME STATUS ROLES AGE VERSION
cluster2 Ready control-plane,master 50d v1.25.4+k3s1
|
设置 context 的环境变量:
1
2
|
export CTX_CLUSTER1=context-cluster1
export CTX_CLUSTER2=context-cluster2
|
继续配置证书和密钥,使用 这里的配置方式,即需要先手动生成一个根证书,然后由根证书生成多个集群的中间证书。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# 创建根证书
cd ~/zt/istio/istio-1.16.1
mkdir -p certs && cd certs
make -f ../tools/certs/Makefile.selfsigned.mk root-ca
# 创建 cluster1 和 cluster2 的中间证书
make -f ../tools/certs/Makefile.selfsigned.mk cluster1-cacerts
make -f ../tools/certs/Makefile.selfsigned.mk cluster2-cacerts
# 在安装 istio 之前,配置两个 istio 集群的证书
kubectl create --context="${CTX_CLUSTER1}" namespace istio-system
kubectl create --context="${CTX_CLUSTER2}" namespace istio-system
kubectl create secret --context="${CTX_CLUSTER1}" 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 secret --context="${CTX_CLUSTER2}" 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
|
创建的根证书和密钥时生成以下四个文件:
- root-cert.pem:根证书
- root-key.pem: 根密钥
- root-ca.conf: 用来生成根证书的openssl配置
- root-cert.csr:为根证书生成的证书签名请求文件
为clsuter1和cluster2生成的文件夹中包含以下文件:
- ca-cert.pem:中间证书
- ca-key.pem:中间密钥
- cert-chain.pem: 生成的给istiod用的证书链
- root-cert.pem:根证书
多网络多控制面板
多网络多控制面板部署方式,即在两个集群 cluster1 和 cluster2 中都部署 istio 控制面板,两个集群都成为主集群,cluster1 在 network1 中,cluster2 在 network2 中,两个集群必须通过东西向的 gateway 来通信,如下图所示:
分别在 cluster1 和 cluster2 安装 istio 并配置 gateway:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# cluster1 安装 istio
kubectl --context="${CTX_CLUSTER1}" get namespace istio-system && \
kubectl --context="${CTX_CLUSTER1}" label namespace istio-system topology.istio.io/network=network1
cat <<EOF > cluster1.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
# 增加 envoy 响应日志
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: "JSON"
values:
global:
meshID: mesh1
multiCluster:
clusterName: cluster1
network: network1
EOF
istioctl install --context="${CTX_CLUSTER1}" -f cluster1.yaml
# cluster1 部署 gateway
samples/multicluster/gen-eastwest-gateway.sh \
--mesh mesh1 --cluster cluster1 --network network1 | \
istioctl --context="${CTX_CLUSTER1}" install -y -f -
# 查看 external ip,这个 ip 是这台 cluster1 云主机的内网 ip
kubectl --context="${CTX_CLUSTER1}" get svc istio-eastwestgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
istio-eastwestgateway LoadBalancer 10.45.180.156 192.168.60.113 15021:31814/TCP...
# cluster1 对外暴露 gateway 服务
kubectl --context="${CTX_CLUSTER1}" apply -n istio-system -f \
samples/multicluster/expose-services.yaml
# cluster2 安装 istio
kubectl --context="${CTX_CLUSTER2}" get namespace istio-system && \
kubectl --context="${CTX_CLUSTER2}" label namespace istio-system topology.istio.io/network=network2
cat <<EOF > cluster2.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
# 增加 envoy 响应日志
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: "JSON"
values:
global:
meshID: mesh1
multiCluster:
clusterName: cluster2
network: network2
EOF
istioctl install --context="${CTX_CLUSTER2}" -f cluster2.yaml
# cluster2 部署 gateway
samples/multicluster/gen-eastwest-gateway.sh \
--mesh mesh1 --cluster cluster2 --network network2 | \
istioctl --context="${CTX_CLUSTER2}" install -y -f -
# 查看 external ip,这个 ip 是这台 cluster2 云主机的内网 ip
kubectl --context="${CTX_CLUSTER2}" get svc istio-eastwestgateway -n istio-system
# cluster2 对外暴露 gateway 服务
kubectl --context="${CTX_CLUSTER2}" apply -n istio-system -f \
samples/multicluster/expose-services.yaml
|
在两个集群中分别设置另一个集群 api-server 的访问证书的 secret:
1
2
3
4
5
6
7
8
9
10
|
# 设置 cluster2 集群访问 cluster1 的访问证书
istioctl x create-remote-secret \
--context="${CTX_CLUSTER1}" \
--name=cluster1 | \
kubectl apply -f - --context="${CTX_CLUSTER2}"
# 设置 cluster1 集群访问 cluster2 的访问证书
istioctl x create-remote-secret \
--context="${CTX_CLUSTER2}" \
--name=cluster2 | \
kubectl apply -f - --context="${CTX_CLUSTER1}"
|
进行这些步骤后,多网络多控制面板部署方式就完成了,可以参考 验证部署 进行验证。
单网络多控制面板
注意:要使得安装的两个集群 pods、service 之间能互相通信,还需要在安装集群过程进行设置,比如使用 submariner,以下步骤不包含此设置。
这种部署模式,是在两个集群 cluster1 和 cluster2 都部署 istio 控制面板,两个集群都成为主集群,两个集群在同一个网络中。如下图所示,这种配置方式每个控制面板都会观测两个集群的服务变化,并且两个集群的 pods 负载之间可以直接通信。
在 cluster1 创建 istio 配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
cat <<EOF > cluster1.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
# 增加 envoy 响应日志
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: "JSON"
values:
global:
meshID: mesh1
multiCluster:
clusterName: cluster1
network: network1
EOF
|
执行安装 istio,执行结果如下:
1
2
3
4
5
6
7
8
9
|
root@cluster1:~/zt/istio/istio-1.16.1/multicluster# istioctl install --context="${CTX_CLUSTER1}" -f cluster1.yaml
This will install the Istio 1.16.1 default profile with ["Istio core" "Istiod" "Ingress gateways"] components into the cluster. Proceed? (y/N) y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete
Making this installation the default for injection and validation.
Thank you for installing Istio 1.16. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/99uiMML96AmsXY5d6
|
同样为 cluster2 集群创建配置并安装:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
cat <<EOF > cluster2.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
global:
meshID: mesh1
multiCluster:
clusterName: cluster2
network: network1
EOF
istioctl install --context="${CTX_CLUSTER2}" -f cluster2.yaml
|
在两个集群中分别设置另一个集群 api-server 的访问证书的 secret:
1
2
3
4
5
6
7
8
9
10
|
# 设置 cluster2 集群访问 cluster1 的访问证书
istioctl x create-remote-secret \
--context="${CTX_CLUSTER1}" \
--name=cluster1 | \
kubectl apply -f - --context="${CTX_CLUSTER2}"
# 设置 cluster1 集群访问 cluster2 的访问证书
istioctl x create-remote-secret \
--context="${CTX_CLUSTER2}" \
--name=cluster2 | \
kubectl apply -f - --context="${CTX_CLUSTER1}"
|
进行这些步骤后,多网络多控制面板部署方式就完成了,可以参考 验证部署 进行验证。
验证部署
通过部署一个 HelloWorld 应用的 v1 版本在 cluster1,v2 版本在 cluster2,当收到请求,将会根据请求的版本来进行响应。同时在两个集群都会部署一个 Sleep 容器,用这些 pods 作为请求源模拟网格内的流量。
在 cluster1 的 istio/istio-1.16.1 目录下执行以下命令来安装,在执行之前,可以在另一个窗口打印 istiod 的日志,查看执行输出结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 分别创建命名空间
kubectl create --context="${CTX_CLUSTER1}" namespace sample
kubectl create --context="${CTX_CLUSTER2}" namespace sample
# 分别开启 istio 注入
kubectl label --context="${CTX_CLUSTER1}" namespace sample istio-injection=enabled
kubectl label --context="${CTX_CLUSTER2}" namespace sample istio-injection=enabled
# 分别创建 service
kubectl apply --context="${CTX_CLUSTER1}" \
-f samples/helloworld/helloworld.yaml \
-l service=helloworld -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f samples/helloworld/helloworld.yaml \
-l service=helloworld -n sample
# 分别创建 deployment
kubectl apply --context="${CTX_CLUSTER1}" \
-f samples/helloworld/helloworld.yaml \
-l version=v1 -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f samples/helloworld/helloworld.yaml \
-l version=v2 -n sample
|
这时在 cluster2 的 istiod 对应的日志为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
# 创建 cluster1 的 service helloworld 产生的日志
2023-01-16T09:13:51.374303Z info ads Incremental push, service helloworld.sample.svc.cluster.local at shard Kubernetes/cluster1 has no endpoints
2023-01-16T09:13:51.474543Z info ads Push debounce stable[19] 2 for config ServiceEntry/sample/helloworld.sample.svc.cluster.local: 100.177423ms since last change, 106.769424ms since last push, full=true
2023-01-16T09:13:51.475013Z info ads XDS: Pushing:2023-01-16T09:13:51Z/12 Services:7 ConnectedEndpoints:1 Version:2023-01-16T09:13:51Z/12
2023-01-16T09:13:51.475432Z info ads CDS: PUSH for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:15 size:14.5kB cached:13/14
2023-01-16T09:13:51.475475Z info ads LDS: PUSH for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:0 size:0B
2023-01-16T09:13:51.479356Z info ads EDS: PUSH request for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:1 size:52B empty:1 cached:0/1 filtered:13
# 创建 cluster2 的 service helloworld 产生的日志
2023-01-16T09:15:26.712662Z info ads Incremental push, service helloworld.sample.svc.cluster.local at shard Kubernetes/cluster2 has no endpoints
2023-01-16T09:15:26.813742Z info ads Push debounce stable[20] 2 for config ServiceEntry/sample/helloworld.sample.svc.cluster.local: 101.02765ms since last change, 104.914465ms since last push, full=true
2023-01-16T09:15:26.814195Z info ads XDS: Pushing:2023-01-16T09:15:26Z/13 Services:7 ConnectedEndpoints:1 Version:2023-01-16T09:15:26Z/13
2023-01-16T09:15:26.814514Z info ads CDS: PUSH for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:15 size:14.5kB cached:13/14
2023-01-16T09:15:26.814568Z info ads EDS: PUSH INC for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:1 size:52B empty:1 cached:0/1
2023-01-16T09:15:26.814602Z info ads LDS: PUSH for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:0 size:0B
# 创建 cluster1 的 deployment helloworld 产生的日志
2023-01-16T09:16:04.805493Z info ads Incremental push, service helloworld.sample.svc.cluster.local at shard Kubernetes/cluster1 has no endpoints
2023-01-16T09:16:04.905918Z info ads Push debounce stable[21] 1 for config ServiceEntry/sample/helloworld.sample.svc.cluster.local: 100.365169ms since last change, 100.364925ms since last push, full=false
2023-01-16T09:16:04.906018Z info ads XDS: Incremental Pushing:2023-01-16T09:15:26Z/13 ConnectedEndpoints:1 Version:2023-01-16T09:15:26Z/13
2023-01-16T09:16:06.813715Z info ads Full push, new service sample/helloworld.sample.svc.cluster.local
2023-01-16T09:16:06.914790Z info ads Push debounce stable[22] 1 for config ServiceEntry/sample/helloworld.sample.svc.cluster.local: 100.821371ms since last change, 100.821083ms since last push, full=true
2023-01-16T09:16:06.915430Z info ads XDS: Pushing:2023-01-16T09:16:06Z/14 Services:7 ConnectedEndpoints:1 Version:2023-01-16T09:16:06Z/14
2023-01-16T09:16:06.915867Z info ads CDS: PUSH for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:15 size:14.5kB cached:13/14
2023-01-16T09:16:06.916113Z info ads EDS: PUSH INC for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:1 size:217B empty:0 cached:0/1
2023-01-16T09:16:06.916175Z info ads LDS: PUSH for node:istio-ingressgateway-5bc5cb6888-dqqkq.istio-system resources:0 size:0B
# 创建 cluster2 的 deployment helloworld 产生的日志
2023-01-16T09:17:51.310335Z info Sidecar injection request for sample/helloworld-v2-54dddc5567-***** (actual name not yet known)
2023-01-16T09:17:52.458115Z info ads Incremental push, service helloworld.sample.svc.cluster.local at shard Kubernetes/cluster2 has no endpoints
2023-01-16T09:17:52.558430Z info ads Push debounce stable[23] 1 for config ServiceEntry/sample/helloworld.sample.svc.cluster.local: 100.238395ms since last change, 100.238086ms since last push, full=false
2023-01-16T09:17:52.558500Z info ads XDS: Incremental Pushing:2023-01-16T09:16:06Z/14 ConnectedEndpoints:1 Version:2023-01-16T09:16:06Z/14
2023-01-16T09:17:52.963838Z info ads ADS: new connection for node:helloworld-v2-54dddc5567-99j9l.sample-4
2023-01-16T09:17:52.964083Z info ads CDS: PUSH request for node:helloworld-v2-54dddc5567-99j9l.sample resources:18 size:15.9kB cached:13/14
2023-01-16T09:17:52.978204Z info ads EDS: PUSH request for node:helloworld-v2-54dddc5567-99j9l.sample resources:14 size:2.7kB empty:0 cached:14/14
2023-01-16T09:17:52.995232Z info ads LDS: PUSH request for node:helloworld-v2-54dddc5567-99j9l.sample resources:16 size:46.5kB
2023-01-16T09:17:53.033523Z info ads RDS: PUSH request for node:helloworld-v2-54dddc5567-99j9l.sample resources:8 size:4.8kB cached:7/8
2023-01-16T09:17:53.471174Z info ads CDS: PUSH for node:helloworld-v2-54dddc5567-99j9l.sample resources:18 size:15.9kB cached:13/14
2023-01-16T09:17:53.471290Z info ads EDS: PUSH for node:helloworld-v2-54dddc5567-99j9l.sample resources:14 size:2.7kB empty:0 cached:14/14
2023-01-16T09:17:53.472629Z info ads LDS: PUSH for node:helloworld-v2-54dddc5567-99j9l.sample resources:16 size:46.5kB
2023-01-16T09:17:53.472977Z info ads RDS: PUSH for node:helloworld-v2-54dddc5567-99j9l.sample resources:8 size:4.8kB cached:7/8
2023-01-16T09:17:53.582899Z info ads Push debounce stable[24] 1 for config ServiceEntry/sample/helloworld.sample.svc.cluster.local: 100.230617ms since last change, 100.230465ms since last push, full=false
2023-01-16T09:17:53.582963Z info ads XDS: Incremental Pushing:2023-01-16T09:16:06Z/14 ConnectedEndpoints:2 Version:2023-01-16T09:16:06Z/14
|
分别查看创建的 pods:
1
2
3
4
5
6
|
root@cluster1:~/zt/istio/istio-1.16.1# kubectl get pods --context="${CTX_CLUSTER1}" -nsample
NAME READY STATUS RESTARTS AGE
helloworld-v1-78b9f5c87f-pkxxj 2/2 Running 0 5m40s
root@cluster1:~/zt/istio/istio-1.16.1# kubectl get pods --context="${CTX_CLUSTER2}" -nsample
NAME READY STATUS RESTARTS AGE
helloworld-v2-54dddc5567-99j9l 2/2 Running 0 3m57s
|
分别部署 Sleep 应用:
1
2
3
4
|
kubectl apply --context="${CTX_CLUSTER1}" \
-f samples/sleep/sleep.yaml -n sample
kubectl apply --context="${CTX_CLUSTER2}" \
-f samples/sleep/sleep.yaml -n sample
|
为了验证多集群的负载均衡能按预期执行,可以在 Sleep pod 多次调用 HelloWorld 服务。在 cluster1 发送一次请求:
1
2
3
4
5
6
7
8
|
kubectl exec --context="${CTX_CLUSTER1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_CLUSTER1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl helloworld.sample:5000/hello
# 多执行几次,会从 v1 pods 和 v2 pods 返回结果
Hello version: v1, instance: helloworld-v1-78b9f5c87f-pkxxj
Hello version: v2, instance: helloworld-v2-54dddc5567-99j9l
|
问题
不能返回多版本结果
刚开始进行验证测试单网络多控制面板时,在 cluster1 执行访问 HelloWorld 服务,只能返回 v1 版本,在 cluster2 执行访问 HelloWorld 服务,只能返回 v2 版本。通过参考 调试 Envoy 和 Istiod,执行了以下命令进行排查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
istioctl proxy-config --context="${CTX_CLUSTER2}" cluster -n sample sleep-78ff5975c6-pdk2v --fqdn helloworld.sample.svc.cluster.local -o json
[
{
"name": "outbound|5000||helloworld.sample.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {},
"initialFetchTimeout": "0s",
"resourceApiVersion": "V3"
},
"serviceName": "outbound|5000||helloworld.sample.svc.cluster.local"
},
"connectTimeout": "10s",
"lbPolicy": "LEAST_REQUEST",
"commonLbConfig": {
"localityWeightedLbConfig": {}
},
}
]
# 查看 endpoints 发现 cluster2 的 sleep pods 中 envoy 配置两个集群的 helloworld 的 pod 地址
istioctl proxy-config --context="${CTX_CLUSTER2}" endpoints -nsample sleep-78ff5975c6-pdk2v --cluster "outbound|5000||helloworld.sample.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.42.0.22:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
10.42.0.27:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
|
发现 envoy 配置中 cluster 和 endpoints 配置是正常的,再排查是否是因为两个环境不能联通。在 cluster2 的 sleep pods 执行:
1
2
|
/ $ curl 10.42.0.27:5000/hello
upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: delayed connect error: 113
|
解决办法:需要在安装 kubernetes 集群进行配置,使得两个集群的 pods 能够互相访问,比如使用 submariner。
多集群通信原理
多网络多控制面板
多网络多控制面板部署方式,两个集群通信的关键在于配置了 gateway,下面对其中涉及的 gateway 配置和 envoy 配置进行解析,来说明两个集群是如何通信的。首先是部署配置了 gateway 的控制面板,在前面是用以下命名部署的:
1
2
3
|
samples/multicluster/gen-eastwest-gateway.sh \
--mesh mesh1 --cluster cluster1 --network network1 | \
istioctl --context="${CTX_CLUSTER1}" install -y -f -
|
使用samples/multicluster/gen-eastwest-gateway.sh --mesh mesh1 --cluster cluster1 --network network1
查看生成的 yaml,主要是部署 gateway 的 deploy、service 等资源:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: eastwest
spec:
revision: ""
profile: empty
components:
ingressGateways:
- name: istio-eastwestgateway
label:
istio: eastwestgateway
app: istio-eastwestgateway
topology.istio.io/network: network1
enabled: true
k8s: # 设置 gateway 资源的环境变量和 service 端口
env:
# traffic through this gateway should be routed inside the network
- name: ISTIO_META_REQUESTED_NETWORK_VIEW
value: network1
service:
ports:
- name: status-port
port: 15021
targetPort: 15021
- name: tls
port: 15443
targetPort: 15443
- name: tls-istiod
port: 15012
targetPort: 15012
- name: tls-webhook
port: 15017
targetPort: 15017
values:
gateways:
istio-ingressgateway:
injectionTemplate: gateway
global:
network: network1
|
部署完成后,查看环境中的 IstioOperator 资源、deploy 资源、service 资源:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
root@cluster1:~/zt/istio/istio-1.16.1# kubectl get IstioOperator -nistio-system
NAME REVISION STATUS AGE
installed-state 3h51m # 第一次 istioctl install 生成的
installed-state-eastwest 3h50m # 第二次增加 gateway 时 istioctl install 生成的
root@cluster1:~/zt/istio/istio-1.16.1# kubectl get deploy -nistio-system
NAME READY UP-TO-DATE AVAILABLE AGE
istiod 1/1 1 1 4h22m
istio-ingressgateway 1/1 1 1 4h22m
istio-eastwestgateway 1/1 1 1 4h21m
# 查看 cluster2 的 service,暴露的端口跟上面 IstioOperator 一致
root@cluster2:~/zt/istio# kubectl --context="${CTX_CLUSTER2}" get svc istio-eastwestgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
istio-eastwestgateway LoadBalancer 10.145.117.132 192.168.60.9 15021:32700/TCP,15443:30138/TCP,15012:31335/TCP,15017:30145/TCP
|
要了解跨网络情况下两个集群的 pod 是如何通信的,即要知道示例中 cluster1 集群的 sleep pod 请求 helloworld 服务时,请求具体是怎么到达 cluster1 的 helloworld 服务的。
通过查看 cluster1 集群的 sleep pod 中 envoy 的 cluster 配置(需要先获取 listeners 和 routes 来确定 cluster 名称),知道请求会被转发到 serviceName 对应的 endpoints:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
istioctl proxy-config --context="${CTX_CLUSTER2}" cluster -n sample sleep-78ff5975c6-pdk2v --fqdn helloworld.sample.svc.cluster.local -o json
[
{
"transportSocketMatches": [
{
"name": "tlsMode-istio",
"match": {
"tlsMode": "istio"
},
},
],
"name": "outbound|5000||helloworld.sample.svc.cluster.local",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {},
"initialFetchTimeout": "0s",
"resourceApiVersion": "V3"
},
"serviceName": "outbound|5000||helloworld.sample.svc.cluster.local"
},
"connectTimeout": "10s",
}
]
|
查看 cluster1 集群的 sleep pods 中 serviceName 对应的 endpoints 配置:
1
2
3
4
|
root@cluster1:~/zt/istio/istio-1.16.1# istioctl proxy-config --context="${CTX_CLUSTER1}" endpoints -nsample sleep-78ff5975c6-4xpv4 --cluster "outbound|5000||helloworld.sample.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.44.0.13:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
192.168.60.9:15443 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
|
可以看到其中一个 endpoint 指向的是 cluster2 的 istio-eastwestgateway 暴露的 15443 端口,即 istio 自动将 cluster2 集群的 helloworld-v2 pod 的地址和端口替换为了 cluster2 集群 istio-eastwestgateway 地址,达到了通过 gateway 来转发两个集群之间的请求。因为 gateway 和 sidecar 用的镜像相同,都是使用的 envoy,通过查看 cluster2 的 gateway pods 中对应的 endpoints 配置:
1
2
3
4
5
6
|
root@cluster1:~/zt/istio/istio-1.16.1# istioctl proxy-config --context="${CTX_CLUSTER2}" endpoints -nistio-system istio-eastwestgateway-74bcf5c77c-m5qbr --cluster "outbound|5000||helloworld.sample.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.144.0.15:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
root@cluster1:~/zt/istio/istio-1.16.1# kubectl --context="${CTX_CLUSTER2}" get endpoints -nsample helloworld
NAME ENDPOINTS AGE
helloworld 10.144.0.15:5000 4h51m
|
因此 cluster2 的 gateway pods 会将请求转发到 helloworld 的 pods 去。
单网络多控制面板
在单网络多控制面板部署方式下,两个集群没有 gateway 配置。cluster2 的 sleep pods 中 envoy 配置两个集群的 helloworld 的 pod 地址:
1
2
3
4
|
istioctl proxy-config --context="${CTX_CLUSTER2}" endpoints -nsample sleep-78ff5975c6-pdk2v --cluster "outbound|5000||helloworld.sample.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.42.0.22:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
10.42.0.27:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
|
因此只要 cluster2 的 sleep pods 可以直接通过 pods ip 连接 cluster1 的 helloworld pods,就可以直接进行通信,因此问题关键在于需要打通两个环境的 pods ip 的直连,比如 submariner。
参考