istio 是服務(wù)網(wǎng)格的一種實(shí)現(xiàn)诉瓦,目前經(jīng)過(guò)了 1.5 版本的架構(gòu)調(diào)整與重構(gòu)之后,優(yōu)化了很多內(nèi)容固额。istio 可以部署在單一集群中煞聪,也可以部署在多個(gè)集群中昔脯,istio 在多集群中的不同部署方式,可以用于規(guī)劃服務(wù)網(wǎng)格的規(guī)模大小以及控制面納管的集群隧饼,更細(xì)粒度則設(shè)計(jì)服務(wù)的跨集群部署碱鳞、服務(wù)跨集群安全訪問(wèn)等問(wèn)題窿给。
istio 目前提供了兩種多集群部署方案,這兩種方案都可以使多個(gè)集群構(gòu)建為一個(gè)大的服務(wù)網(wǎng)格:
多集群獨(dú)立控制面板:
每一個(gè)集群部署一套 istio 控制面板禁荒,不同網(wǎng)格間的服務(wù)通過(guò) istio 提供的gateway 相互訪問(wèn)角撞。多集群共享控制面板
多集群間使用同一套 istio 控制面板谒所,多集群構(gòu)成一個(gè)大規(guī)模的服務(wù)網(wǎng)格。
本文則著重探究 多集群獨(dú)立控制面板 的相關(guān)內(nèi)容
多集群獨(dú)立控制面板
使用多個(gè)獨(dú)立控制面板將多 K8s 集群構(gòu)建成為一個(gè)服務(wù)網(wǎng)格姐军,需要多個(gè)前置條件:
- root CA 作為統(tǒng)一的簽發(fā)機(jī)構(gòu)尖淘,每個(gè)控制面板的證書均需要此機(jī)構(gòu)簽發(fā)
- 跨集群服務(wù)間通信依賴于 istio 的 ingress-gateway 和 egress-gateway
- 每個(gè)群集中的istio-ingressgateway服務(wù)的IP地址必須可從其他每個(gè)群集訪問(wèn)
注意村生,此處官方建議使用 L4 負(fù)載均衡(NLB),這個(gè)需要cloud provider 支持辽话。若部署在沒(méi)有 NLB 的環(huán)境中時(shí)屡穗, 可能需要修改負(fù)載平衡的健康檢查。
在不同集群中部署 istio 控制面板
首先需要 root CA 為每個(gè)集群簽發(fā)一套證書,包括 ca-cert.pem ca-key.pem (簽發(fā)好的證書和key)础废、root-cert.pem(根證書)cert-chain.pem(證書鏈)
在部署 istio 控制面之前罕模,執(zhí)行以下命令:
kubectl create ns istio-system
kubectl create secret generic cacerts -n istio-system \
--from-file=<your path>/ca-cert.pem \
--from-file=<your path>/ca-key.pem \
--from-file=<your path>/root-cert.pem \
--from-file=<your path>/cert-chain.pem \
部署istio
istioctl manifest apply \
-f install/kubernetes/operator/examples/multicluster/values-istio-multicluster-gateways.yaml
values-istio-multicluster-gateways.yaml
是 istio 官方針對(duì)多集群進(jìn)行的配置淑掌,其內(nèi)容如下:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator # istio Operator 用于部署 istio 組件
spec:
addonComponents:
istiocoredns: # 開(kāi)啟 istiocoredns
enabled: true
components:
egressGateways: # 開(kāi)啟 egressGateway,因?yàn)閕ngressGateway默認(rèn)開(kāi)啟芋绸,此處沒(méi)有配置
- name: istio-egressgateway
enabled: true
values:
global:
# Provides dns resolution for global services
podDNSSearchNamespaces:
- global
- "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global"
multiCluster:
enabled: true
controlPlaneSecurityEnabled: true
# Multicluster with gateways requires a root CA
# Cluster local CAs are bootstrapped with the root CA.
# 關(guān)閉自簽名證書摔敛,使用我們上面創(chuàng)建的證書
security:
selfSigned: false
gateways:
istio-egressgateway:
env:
# Needed to route traffic via egress gateway if desired.
ISTIO_META_REQUESTED_NETWORK_VIEW: "external"
配置 dns 配置
CoreDNS
在配置 istio dns 之前马昙,我們需要了解一下 coredns 刹悴。目前 K8s 中默認(rèn)使用 CoreDNS 作為service name 解析服務(wù)。
CoreDNS 是一個(gè) CNCF 下的孵化級(jí)項(xiàng)目子房,其主要目的是構(gòu)建一個(gè)快速靈活的 DNS 服務(wù)器池颈,讓用戶可以通過(guò)不同方式訪問(wèn)和使用 DNS 內(nèi)的數(shù)據(jù)钓丰。基于 Caddy 服務(wù)器框架琢歇,CoreDNS 實(shí)現(xiàn)了一個(gè)插件鏈的架構(gòu)李茫,將大量邏輯抽象成插件 Plugin 的形式暴露給使用者,每個(gè)插件都執(zhí)行 DNS 功能秸侣,例如 Kubernetes 的 DNS 服務(wù)發(fā)現(xiàn)宠互、Prometheus 監(jiān)控等予跌。
CoreDNS 使用 Corefile 進(jìn)行配置,在Corefile中定義了以下內(nèi)容:
- 服務(wù)器以什么協(xié)議監(jiān)聽(tīng)在哪個(gè)端口(可以同時(shí)定義多個(gè) server 監(jiān)聽(tīng)不同端口)
- 服務(wù)器負(fù)責(zé)哪個(gè) zone 的 authoritative DNS 解析
- 服務(wù)器將加載哪些插件
Corefile 的典型結(jié)構(gòu)為:
ZONE:[PORT]:
[PLUGIN]...
下面是一個(gè)Corefile在K8s中的示例:
apiVersion: v1
data:
Corefile: |
.:53 { # 監(jiān)聽(tīng)域?yàn)楸镜仄到危O(jiān)聽(tīng)端口53
errors # 錯(cuò)誤記錄到標(biāo)準(zhǔn)輸出
health # 健康狀況 可以通過(guò)http://localhost:8080/health查看
# 根據(jù)服務(wù)的IP響應(yīng)DNS查詢請(qǐng)求航邢,Cluster Domain默認(rèn)為cluster.local
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
#upstream /etc/resolv.conf
fallthrough in-addr.arpa ip6.arpa
}
# 可以通過(guò)http://localhost:9153/metrics獲取prometheus格式的監(jiān)控?cái)?shù)據(jù)
prometheus :9153
# 若解析不到考阱,可以向上轉(zhuǎn)發(fā)到 /etc/resolve.conf 中定義的 dns服務(wù)中
#forward . /etc/resolv.conf
# 緩存時(shí)間
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
labels:
addonmanager.kubernetes.io/mode: EnsureExists
name: coredns
namespace: kube-system
當(dāng) CoreDNS 啟動(dòng)后乞榨,它將根據(jù)配置文件啟動(dòng)不同 server 吃既,每臺(tái) server 都擁有自己的插件鏈。當(dāng)有 DNS 請(qǐng)求時(shí)河质,它將依次經(jīng)歷如下 3 步邏輯:
- 如果有當(dāng)前請(qǐng)求的 server 有多個(gè) zone震叙,將采用貪心原則選擇最匹配的 zone媒楼。
- 一旦找到匹配的 server,按照 plugin.cfg 定義的順序執(zhí)行插件鏈上的插件扔嵌。
- 每個(gè)插件將判斷當(dāng)前請(qǐng)求是否應(yīng)該處理,將有以下幾種可能:
- 請(qǐng)求被當(dāng)前插件處理
插件將生成對(duì)應(yīng)的響應(yīng)并回給客戶端胁勺,此時(shí)請(qǐng)求結(jié)束署穗,下一個(gè)插件將不會(huì)被調(diào)用嵌洼,如 whoami 插件。 - 請(qǐng)求不被當(dāng)前插件處理
直接調(diào)用下一個(gè)插件。如果最后一個(gè)插件執(zhí)行錯(cuò)誤回溺,服務(wù)器返回 SERVFAIL 響應(yīng)混萝。 - 請(qǐng)求被當(dāng)前插件以 Fallthrough 形式處理
如果請(qǐng)求在該插件處理過(guò)程中有可能將跳轉(zhuǎn)至下一個(gè)插件逸嘀,該過(guò)程稱為 fallthrough,并以關(guān)鍵字 fallthrough 來(lái)決定是否允許此項(xiàng)操作翼岁,例如 host 插件琅坡,當(dāng)查詢域名未位于 /etc/hosts残家,則調(diào)用下一個(gè)插件。- 請(qǐng)求在處理過(guò)程被攜帶 Hint茴晋。
- 請(qǐng)求被插件處理诺擅,并在其響應(yīng)中添加了某些信息(hint)后繼續(xù)交由下一個(gè)插件處理毫玖。這些額外的信息將組成對(duì)客戶端的最終響應(yīng),如 metric 插件烹玉。
- 請(qǐng)求被當(dāng)前插件處理
接入 istiocoredns
在一開(kāi)始的部署過(guò)程中二打,我們開(kāi)啟了 istiocoredns,因此在 istio-system
namespace中會(huì)出現(xiàn)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istiocoredns ClusterIP 172.19.XX.XX <none> 53/UDP,53/TCP 44m
此外症杏,在集群的 CoreDNS 的 Corefile 中厉颤,也已經(jīng)出現(xiàn)了global
域的配置:
Corefile: |-
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
upstream
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
proxy . /etc/resolv.conf
cache 30
reload
}
global:53 {
errors
cache 30
proxy . {cluster IP of this istiocoredns service}
}
下文中 serviceEntry
會(huì)將集群外的服務(wù)配置為 global 域逼友,因此在dns 解析過(guò)程中秤涩,coredns會(huì)將帶有g(shù)lobal的解析請(qǐng)求上傳給 istiocoredns筐眷,由其完成解析工作。
不同集群間的服務(wù)通信
使用 serviceEntry
跨集群的服務(wù)通信依賴于 istio 的 ServiceEntry
照棋。假設(shè) A集群中有服務(wù)serviceA
振定,需要訪問(wèn)B集群中的serviceB
后频,此時(shí)我們需要在 A集群中創(chuàng)建 ServiceEntry
資源,其定義如下:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: serviceB
spec:
hosts:
# 此處需要將host 定義為 <serviceName>.<namespace>.global膏执,這樣才能通過(guò) coredns 的global 域從 istiocoredns 中獲取到 serviceB 中的ip
- serviceB.namespace.global
# 此處定義 serviceB 是服務(wù)網(wǎng)格中的內(nèi)部服務(wù)更米,因?yàn)锳集群和B集群是公用同一套根證書
location: MESH_INTERNAL
ports:
- name: http1
number: 8000
protocol: http
resolution: DNS
addresses:
# 此IP 是一個(gè)虛擬IP毫痕,且是A集群無(wú)法訪問(wèn)到的,當(dāng)有訪問(wèn)該IP的數(shù)據(jù)包時(shí)类腮,該流量會(huì)被 sidecar 劫持蛉加,并正確路由针饥。
- 240.0.0.2
endpoints:
# 此 ip 是 B集群中的 istioGateway 的ip
- address: ${CLUSTER2_GW_ADDR}
ports:
http1: 15443 # 此端口為 B集群 istioGateway 的加密端口,服務(wù)間通信均使用 TLS 加密筷凤。
注意上述 yaml 文件中的 address苞七, 如果serviceB
有明確的 vip莽鸭,則應(yīng)該直接定義吃靠,否則istio官方建議使用 E類地址 240.0.0.0/4
巢块,因?yàn)檫@類地址的流量會(huì)被 sidecar 劫持族奢。當(dāng)sidecar 劫持流量之后,會(huì)直接將流量導(dǎo)向 B集群的 ingressGateway中棚品。
如果 serviceB
有多個(gè)版本铜跑,我們可以在 serviceEntry 中添加 label 指定訪問(wèn)的版本:
endpoints:
- address: ${CLUSTER2_GW_ADDR}
labels:
cluster: cluster2
ports:
http1: 15443 # Do not change this port value
之后骡澈,在A集群中,我們可以同樣配置 VirtualService
和 DestinationRule
使用egress Gateway
我們也可以使用 egressGateway
囤锉,不讓流量從 sidecar 直接流量 B集群的 ingressGateway官地,而是統(tǒng)一走 egressGateway
所在的節(jié)點(diǎn)。這樣做可以統(tǒng)一管理集群邊界拧粪。
使用egressGateway
可霎,相應(yīng)的 serviceEntry
需要做如下變動(dòng):
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: serviceB
spec:
hosts:
# must be of form name.namespace.global
- serviceB.namespace.global
location: MESH_INTERNAL
ports:
- name: http1
number: 8000
protocol: http
# 解析規(guī)則設(shè)置為靜態(tài)
resolution: STATIC
addresses:
- 240.0.0.2
# endpoints 需要指定兩個(gè)ip癣朗,集群B的 ingressGateway ip旺罢;集群A的 egressGateway ip
endpoints:
- address: ${CLUSTER2_GW_ADDR}
network: external
ports:
http1: 15443
- address: ${CLUSTER1_EGW_ADDR}
ports:
http1: 15443
總結(jié)
下圖為 pod A 跨集群訪問(wèn)名為 serviceB 的 pod 時(shí)整個(gè)流程圖:
- podA 的 sidecar 會(huì)劫持出pod 的流量扁达,向集群中的 coredns 解析
serviceB.default.global
域名 - coredns 根據(jù)global 域向上請(qǐng)求 istioCoreDNS 解析域名正卧,istiocoredns 依據(jù) serviceEntry 將域名解析為
serviceEntry
yaml 文件中的address ip - sidecar 發(fā)現(xiàn)返回的ip并不存在,則直接轉(zhuǎn)發(fā)到
serviceEntry
中 clusterB 的 ingressGateway - clusterB ingressGateway 將流量轉(zhuǎn)發(fā)至 podB中
使用Istio網(wǎng)關(guān)跪解,公共根CA和serviceEntry
炉旷,可以跨多個(gè)Kubernetes集群配置單個(gè)Istio服務(wù)網(wǎng)格。
以這種方式配置后叉讥,流量可以透明地路由到遠(yuǎn)程集群窘行,而無(wú)需任何應(yīng)用程序的參與。
serviceEntry
的創(chuàng)建需要手動(dòng)或程序進(jìn)行創(chuàng)建图仓,istio并不會(huì)為我們創(chuàng)建罐盔。
這種方式部署簡(jiǎn)單,使用較為麻煩惶看,但它對(duì)于多集群是否處于同一網(wǎng)絡(luò)沒(méi)有要求,podIP六孵、service碳竟、namespace也沒(méi)有任何限制。
下一篇將繼續(xù)介紹 istio 多集群的另一種方式:多集群共享控制面板