假如你正在一家典型的企业里工作,需要与多个团队一起工作,并为客户提供一个独立的软件,组成一个应用程序。你的团队遵循微服务架构,并拥有由多个Kubernetes集群组成的广泛基础设施。
由于微服务分布在多个集群中,你需要设计一个解决方案来集中管理所有微服务。幸运的是,你正在使用Istio,提供这个解决方案只不过是另一个配置的变化。
像Istio这样的服务网格技术可以帮助你安全地发现和连接分布在多个集群和环境中的微服务。今天我们来讨论一下使用Istio管理托管在多个Kubernetes集群中的微服务。
Istio使用以下组件提供跨集群服务发现:
集群间通信
Istio使用以下步骤来促进服务发现:
本文假设你已经对Kubernetes以及Istio的工作原理有一个基本的了解。为了能够跟上我们接下来的演示,请确保:
在两个集群上,使用以下命令安装Istio 1.6.1:
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.1 sh -
cd istio-1.6.1
export PATH=$PWD/bin:$PATH
由于我们需要用共享的根证书生成的中间证书来启动我们的Istio服务网格,所以使用中间证书创建一个secret。
在这个例子中,我们使用提供的样本证书。但是,我不建议你在生产中使用这些证书,因为它们一般都是可轻松获取的,而且是众所周知的。最好是使用你的组织的Root CA来生成中间CA证书。
在两个集群上运行以下命令来使用样本证书。如果你使用的是你的证书,请替换适用的文件路径。
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
secret/cacerts created
由于我们需要安装Istio进行多集群设置,所以在两个集群上使用提供的Istio多集群网关manifest文件。
$ istioctl manifest Apply -f install/kubernetes/operator/examples/multicluster/values-istio-multicluster-gateways.yaml
- Applying manifest for component Base...
✔ Finished applying manifest for component Base.
- Applying manifest for component Pilot...
✔ Finished applying manifest for component Pilot.
Waiting for resources to become ready...
- Applying manifest for component AddonComponents...
- Applying manifest for component IngressGateways...
- Applying manifest for component EgressGateways...
✔ Finished applying manifest for component EgressGateways.
✔ Finished applying manifest for component IngressGateways.
✔ Finished applying manifest for component AddonComponents.
✔ Installation complete
下一步是将DNS解析从Kube DNS联邦到Istio CoreDNS。让我们通过为kube-dns定义一个ConfigMap来配置一个存根域。在两个集群上应用以下manifest:
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-dns
namespace: kube-system
data:
stubDomains: |
{"global": ["$(kubectl get svc -n istio-system istiocoredns -o jsonpath={.spec.clusterIP})"]}
EOF
configmap/kube-dns configured
由于我们需要为不同的活动连接两个集群,因此获取上下文并将其存储在环境变量中会很有意义。有了这些,我们只要在kubectl命令中加入上下文,就可以在我们选择的集群中运行kubectl命令。
获取上下文:
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
cluster-1 cluster-1 cluster-1
* cluster-2 cluster-2 cluster-2
设置环境变量以使用上下文:
$ export CTX_CLUSTER1=$(kubectl config view -o jsonpath='{.contexts[0].name}')
$ export CTX_CLUSTER2=$(kubectl config view -o jsonpath='{.contexts[1].name}')
$ echo CTX_CLUSTER1 = ${CTX_CLUSTER1}, CTX_CLUSTER2 = ${CTX_CLUSTER2}
CTX_CLUSTER1 = cluster-1, CTX_CLUSTER2 = cluster-2
我们先在集群1的foo命名空间上部署sleep微服务。
$ kubectl create --context=$CTX_CLUSTER1 namespace foo
namespace/foo created
$ kubectl label --context=$CTX_CLUSTER1 namespace foo istio-injection=enabled
namespace/foo labeled
$ kubectl apply --context=$CTX_CLUSTER1 -n foo -f samples/sleep/sleep.yaml
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
$ export SLEEP_POD=$(kubectl get --context=$CTX_CLUSTER1 -n foo pod -l app=sleep -o jsonpath={.items..metadata.name})
现在我们在集群2的bar命名空间上部署httpbin微服务:
$ kubectl create --context=$CTX_CLUSTER2 namespace bar
namespace/bar created
$ kubectl label --context=$CTX_CLUSTER2 namespace bar istio-injection=enabled
namespace/bar labeled
$ kubectl apply --context=$CTX_CLUSTER2 -n bar -f samples/httpbin/httpbin.yaml
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created
现在我们需要在Istio CoreDNS上创建一个服务条目以便于我们可以从集群1中发现集群2上的服务。由于所有的通信都会通过Ingress 网关,导出集群2 Ingress网关地址。
export CLUSTER2_GW_ADDR=$(kubectl get --context=$CTX_CLUSTER2 svc --selector=app=istio-ingressgateway
-n istio-system -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
为了让集群1上的服务能够发现集群2上的httpbin,我们需要在集群1上为httpbin.bar.global创建一个ServiceEntry。这样可以保证集群1上的Istio Core DNS在集群1上的服务到达httpbin.bar.global这个端点时,可以到达集群2的Ingress网关。下面的yaml:
应用yaml文件:
$ kubectl apply --context=$CTX_CLUSTER1 -n foo -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-bar
spec:
hosts:
- httpbin.bar.global
location: MESH_INTERNAL
ports:
- name: http1
number: 8000
protocol: http
resolution: DNS
addresses:
- 240.0.0.2
endpoints:
- address: ${CLUSTER2_GW_ADDR}
ports:
http1: 15443 # Do not change this port value
EOF
serviceentry.networking.istio.io/httpbin-bar created
现在让我们从sleep微服务中产生一些流量,看看它是否能到达集群2上运行的httpbin微服务。
$ kubectl exec --context=$CTX_CLUSTER1 $SLEEP_POD -n foo -c sleep -- curl -I httpbin.bar.global:8000/headers
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0HTTP/1.1 200 OK
0 519 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
server: envoy
date: Sat, 16 May 2020 23:03:22 GMT
content-type: application/json
content-length: 519
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 37
我们得到一个成功的响应!恭喜你,我们已经成功地使用Istio在多个Kubernetes集群之间配置了服务发现。
感谢你的阅读,希望你能喜欢这篇文章。
这是一个在多个集群上运行的高可用Istio服务网格配置的演示。你也可以有一个共享的控制平面配置,但这并不推荐用于生产——如果你因为中断而失去一个集群,你也会失去对正在运行的集群的控制。