如何使用Istio 1.6管理多集群中的微服务?

假如你正在一家典型的企业里工作,需要与多个团队一起工作,并为客户提供一个独立的软件,组成一个应用程序。你的团队遵循微服务架构,并拥有由多个Kube.netes集群组成的广泛基础设施。

由于微服务分布在多个集群中,你需要设计一个解决方案来集中管理所有微服务。幸运的是,你正在使用Istio,提供这个解决方案只不过是另一个配置的变化。

像Istio这样的服务网格技术可以帮助你安全地发现和连接分布在多个集群和环境中的微服务。今天我们来讨论一下使用Istio管理托管在多个[ 2 J {Kube.netes集群中的微服务。

架构说明

Istio使用以下组件提供跨集群服务发现

  • I, k R U hstio CoreDNS:每个Istio控制平面都有一个CoreDNS。IsK ] 4 M z ktio使用它来发现全局范围上定义的服务。例如,如果一个托管在集群1上的微服务q Q S ?需要连接到另一个托管在集群2上的微服务,你需要为运行在集群2上的微服务在Istio CoreDNS上做一个全局条目。
  • Root CA:由于Istio需要在不同集群上运行的服务之间建立mTLS连接,因此[ 3 u G } % A ^ k需要使用共享的Root CA为两个集群生成中间CA证书。这就在不同集群上? % V V $运行的微~ ` ? l ) D !服务之间建立了信_ / U S b } L任,因为中间CA共享同一个Root CA。
  • Istio Ingress网关:集群间的通信通过Ingress网关进行,服务之间没有直接连接。因此,你! 1 n s P {要确保Ingress网关是可发现的,并且所有集w F y k 0 t A a群都可以连接到它。

    服务发现

Istio使用以下步骤来促进服务发现:

  1. _ 2 ; )群上都有相同的控制平= % * b面,以促进高可用性。

  2. Kube DNS与Istio CoreDNS为支点,以提供全局服务发现。

  3. 用户通过Istio CoreDNS中的ServiceEntrA S y ;ies定j k a T ) &义远程服务的路由,格式为name.namespace.global。

  4. 源sidecar使用全局CR * ! M I O 9 B 7oreDNS条目将流量路由到目标Istio Ingress网关。

  5. 目标 Istio Ingress 网关将流量路由到正确的微服务 pod。

    前期准备

本文假设你已经对Kubernete; % 8 Hs以及Istio的工# X 4 h H 0 $作原理有一个基本的了解。如果你想了解Istio 1.5和1.6的详细内容,点击此处即可查看相关视频。为了能够跟上我们接下来的演示,请确保:

  • 你有至少两个S D Y d ( y 0 qKubernetes集群,Kubernetes的版& u % Q本为1.14、1.15或1.16

  • 拥有在集群内安装和配置Istio的权限

  • 你在两个Kubernetes集群上都有集群管理权限。

  • Ingress网关可通过网络负载均衡器或类似配置连g X W _ x F接到其他集群。扁平网络是不必要的。

    安装Istio

在两个集群上,使用以下命令安装Istio 1.6.1:

c^ N L ! = e +url -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.1 sh -
cd istio-1.6.1
export PATH=$PWD/bin:$PATH

由于我们需要用共享的根证书生成的中间证书来启动我们的Istio服务网格,所以使用中间证书创建一个secret。

在这个例子中,我们使用提供的样本证书。但是,我不建议你在生产中使用这些证书,因为它们一般都是可轻松获取的,而且是众所周知的。最好是使用你的组织的k A ; ~ , c m Y ,Root CA来生成中间CA证? g 6书。

在两个集群上运行以下命令来使用样, - S F B S l ( x本证书。如果你使用的是你的证书,请替换适用的文件路径

kubec2 | D rtl create namespace istio-system
kubectl create secret genL H V ~ 2 y 7eric caV $ 2 $certs -n istio2 8 : ; % }-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 creat} N =ed

由于我们需V E K # s要安装Istio进行多集群设置,所以在两个集群上使用提供的Ist; ] !io多集群网关m$ : S # =anifest文件

$ 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 comp{ S 5 Konent Pilot...
✔ Fg G 3 `inished applyih s 8 x ^ X L hng manifest for component Pilot.
Waiting for resources to become ready...
- Applying manifest for component AddonCompoz % = ( d | ; wnents...
- A2 y 6 P | G E P Tpplyin- ( 6 @g manifest for component IngressGateways...
- Applying maniff o pest for component EgressGateways...
✔ Finished applying manifest for component EgressGateways.
✔ Finished applying manifest for component IngresO o C X , N x 4 HsGateways.
✔ Finished applying manifest for component AddonComponents.
✔c R K Installation complete

配置KubeDNS

下一步是将DNS解析从Kube DNS联邦到Istiog = % 2 b CoreDNS。让我们通过为kube-dns定义一个ConfigMap来配置一个存根域。在两个集群上应用以下manifest:

$q 4 w P { kubectl apply -f - <<EOF
apiVersion: v1
kind: Confid n } w / + ?gMap
metadata:
name: kube-dns
namespace: kube-system
data:
stubDomainT f Ys: |
{f W & I l"global": ["$(kubectl get svc -n istio-( # a d H t sv f ` _ r #ystem istiocoredns -o jsonpath={.spec.clusterIP})"]}
EOF
configmap/kube-dns configured

设置上下文(context)

由于我们需要为不同得活动连接两个集群,因此获取上下文并将其存储在环境变量中会很有意义。有了这些,我们只要在kubectl命令中加入上下文,就可以在我们选择得集群中运行kubectl命令。

获取上下文:

$ kubectlK m n ! ? config get-contexts
CURRENT   NAME        CLUSTER     AUTHINFO      NAMESPACE
cluster-17 & ] ] / h ~ 4   cluster-1   cluster-1
*         cluster-2   cluster-2   cluster-2m X X [ a 8 3 t t

设置环境4 9 N变量以使用上下文N C t k

$ expol t 0 r D { } hrt CTX_CLUSTER1=$(kubectl config view -o j7  0 } U m Esonpath='{.contexts[0].6 z 5 B J d c c rname}')
$ export CTX_CLUSTER2=[ M M . * V f E ,$(kubectl config view -o jsonpath='{.contextP N ) Ns[1].name}')
$ echo CTX_CLUSTER1 = ${k + , V C ]CTX_CLUSTER1}, CTX_CL l 3 yLUSTER2 = ${CTK A  p CX_CLUSTER2}
CTX_CLUSTER1 =5 ` V t w cluster-1, CTX_CLUSTEo = O 4 6 zR2 = cluster-2

部署示例微服务

我们先在集群1的foo命名空间上部署sleep_ q 8微服务。

$ kubectl create --context=$CTX_x n d ECLUSTER1 namespace foo
na/ q x X k n Xmespace/7 } Gfoo created
$ kubectl labeF = L ? S r Ll --context=$CTX_CLUSTER1 namespace foo istio-injection=enabled
namespace/foo labeled
$ kubectl apply --cot K & 6 ~ A T n Lntext=$CTX_CLUSTER1 -n foo -f samples/sleep/sleep.yaml
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep cr$ P ! 0 y S feaR B l p -ted
$ export SLEEP_POD=$(kubectl get --context=$CTX_CLUSTER1 -n foo pod -l} i L ` : app=sleep& /  Z : ] -o jsonpath={.items..metadata.name}f I p)

现在我们在集群2的bar命名空间上部署httpbin微服务:

$ kD v 9 ? t Pubectl ch K w 3reate --context=$CTX_CLUSTER2 namespace bar
namespace/bar created
$ kubectl label --context=$CTX_CLUSTER2 namespace bar istio-injection=enabled
naml H Q z 1 espace/bar labeled
$ kubectl apply --context=$CTX_C| ] p } g t t QLUSTER2 -n bar -f samples/httpbiB 6 Z + # T . un/httpbin.yaml
serviceaccount/httpbin created
service/httpbin created
deployment.aK I R X .pps/httpbiy ^ d C 7n created

创建服务条目

现在我们需要在Istio CoreDNS上创建一个服务条目以便于我们可以从集群1中发现集群2上的服务v 7 @ 6。由c - n 4 z P于所有的通信都会通过Ingress 网关,导出集群2 Iz n ` rngress网关地址

export CLUSTER2_GW_ADDR=$(kubectC _ s r #l get --context=$CTX_CLUSTER2 svc --selector=app=istio-ingressgaA | w . A ; 7 Kteway \
-n istQ 4 eio-system -o j c * ~ 4sonpath='{.items[0].status.loadBalancer.ingress[0].ip}')

为了让集群1上的服务能W $ I j够发现集群2上的httpbin,我们需要在f D [ ; | e集群1上为httpbin.bar.global创建一个ServiceEntry。这样} N * V H ` d x +可以保证集群1上的Istio Core DNS在集群1上的服务到达httpbin.bar.global这个端点时,可以到达集群2的Ingress网关。下面的yaml:

  • 在hosts部分定义服务域名

  • 位置是mesh_INTERNAL,因为我们需要把其他服务当作同一个服务网格的一部分

  • 将服务暴露在8000端口上

  • 我们需要给该服务提供一个独特的IP地址。该IP地址不需要可路由,并且你可以使用240.0.0.0/16范围内的任意地址

  • 我们在端点地址部分上定义集群2 ingress网关地址,以便于请求可以路由给它。端口15S C [ N ! 5 4 F443是Ingress网关的SNI识别的Envo= # Ty代理端口,用于在目标群集服务的Pod之间w , * z Y f - R !路由流量。

应用y_ 1 s 7am_ Z g C $l文件:

$ kubectl apply --context=$CTX_CLUSTER1 -n foo -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntryS 1  h v
metadata:
name: httpbin-bar
spec:
hosts:
- httpd Q ebin.bar.global
location: MESH_INTEL , j cRNAL
ports:
- name: http1
number: 8000
proto$ { t = l A ! zcol: http
resolution: DNS
addresses:
- 240.0.0.2
endpoints:
- address: ${CLU( j rSTER2_GW_ADDR}
ports:
http1: 15443 # Do not change this port value
EOF
ser- l _ G ?viceentry.networking.istio.io/httpbin-bar created

测试服务

现在让我们从sleo ` ) * b P U 9ep微服务中v 6 ? j D W 4 I产生一些流量,看看它是否能到达集群2上运行的httpbin微服务。

$ kubectl e_ 0 R q F $ 6 J ]xec --context=$CTX_CLUSTER1 $SLEEPj z 9 y - Q D ! L_POD -n foo -c sleep -- curl -I httpbin.bar.global:8000/headers
% Total    % Received % Xferd  Average Speed   Timg h / Ce    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
c7  Y r [ 9 o 7onteW s [ w =nt-type: application/M l Ijl V c ? U Zson
content-length: 519
access-control-allow-origin: *
access-control-allow-credent` * 7 eials: true
x-envoy-upstream-service- D g j -time: 37

我们得到一个成功的响应!恭喜你,我/ N f W们已经成功地使用Istio在多个Kubernetes集群之间配V % ) )置了服务发现。S S z b

结 论

感谢你的阅读,希望你能喜欢这篇文章。

这是一个在多个集群上运行的高可用Istio服务网格配置的演示。你也可以有一个共享的控制平面配置,但这并不推荐用于生产——如果你因为中! i q !断而失去一个集群,你也会失去对正在运行的集群的控制。