Istio多集群管理方案详解
随着Kubernetes成为云原生领域应用编排的标准,传统企业及新型互联网企业都在逐步将应用容器化及云化。为了实现高并发和高可用,企业通常会将应用部署在多集群甚至多云、混合云等多种环境中,因此,多集群方案逐步成为企业应用部署的最佳选择。很多云厂商都推出了自己的多云、混合云方案,虽然几乎都提供了多集群管理及跨集群的服务访问能力,但是在服务治理方面都有所欠缺。
因此,越来越多的用户对跨集群的服务治理表现出强烈的兴趣和需求。在此背景下,Istio作为Service Mesh领域的事实标准,推出了三种多集群管理方案,这里讲解其中的多控制面管理方案。
多控制面拓扑模型是在Istio 1.1中新增的一种多集群管理模型,如图7-1所示,每个Kubernetes集群都分别部署自己独立的Istio控制面,并且每个集群的控制面部署形态都是相似的,都各自管理自身的Endpoint。
多控制面拓扑模型
多控制面模型还有以下特点。
共享根CA。为了支持安全的跨集群通信mTLS,该模型要求每个集群控制面都使用相同的中间CA证书,供Citadel签发证书使用,以支持跨集群的TLS双向认证。
不要求不同集群之间共享网络,即容器网络不需要打通,跨集群的访问通过Istio Gateway转发。
每个Kubernetes集群的Pod地址范围与服务地址范围都可以与其他集群重叠,双方集群互不干扰,因为每个集群的Istio控制面都只管理自己集群的Endpoint。
该模型依赖于DNS解析,允许服务实例解析本集群或者远端集群的服务名称。它除了使用了Kubernetes默认的cluster.local和<namesapce>.cluster.local后缀,还扩展了Pod的DNS解析,添加了对“.global”后缀的服务支持,以支持remote集群的服务地址解析。
在多控制面Gateway直连模型中,每个工作负载都可以像单集群一样使用典型的Kubernetes服务域名访问同一集群内的服务。然而对于Remote集群的服务访问,Istio扩展了CoreDNS服务器,处理“<name>.<namespace>.global”形式的服务地址解析。
在多控制面Gateway直连模型中,服务间的访问方式分为以下两种。
同一集群内部的服务访问。这种访问方式与单集群模型没有任何区别。
跨集群的服务访问。这种方式需要用户创建ServiceEntry规则,将Remote集群的服务暴露在本集群的服务网格内,并且由于集群之间的网络并不互通,所以这种模型依赖Remote集群的Gateway中转流量。
第
1
则
服务DNS解析的原理
在多控制面模型中,每个集群都由独立的Istio控制面管理。我们可以在宏观上认为不同集群的工作负载属于不同的网格。但是在微观上,其实是所有集群联合起来构建了一个大的网格,因为在本地集群中可以以服务域名的形式访问Remote集群的服务。例如,Remote集群的forecast服务在命名空间weather中,那么本地集群在访问forecast服务时使用的是forecast. weather.global域名。这种带“.global”后缀的域名是Istio在多控制面模型中设计的虚假域名。在本地集群中,DNS将这种带“.global”后缀的服务域名解析成一个虚假的在服务网格内没有使用的IP地址。
多控制面DNS的解析原理为:多控制面模型要求Istio能够提供Remote集群的服务地址解析,并且不影响已有的服务。典型的应用期望使用服务DNS名称解析服务地址,并通过地址访问服务。Istio的Sidecar本身在服务之间路由请求时并不使用DNS名称,但是Istio离不开DNS解析,这是因为在一般情况下服务实例是以域名形式访问其他服务的,所以在服务实例发起请求时首先进行DNS解析,才能将请求发送出去。本地集群的服务共享相同的DNS后缀(svc.cluster.local),Kubernetes集群默认的DNS服务器提供对这类服务的域名解析。
对于Remote集群的服务,本地集群的DNS显得束手无策,因为Kubernetes DNS只能通过Kube-apiserver获取本集群的服务及服务实例信息。Istio为支持Remote集群的服务DNS解析,做出了如下要求。
1、在每个Kubernetes集群中都额外部署一个istiocoredns组件
istiocoredns与在集群中默认安装的kube-dns和CoreDNS是级联的关系,协助默认的DNS服务器解析带“.global”后缀的服务,因此需要配置kube-dns和CoreDNS的私有DNS域服务器。如下所示为kube-dns服务器配置私有DNS域(stub domains):
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})"]}
CoreDNS的私有DNS域设置如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data: 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
loop
reload
loadbalance
} global:53 {
errors
cache 30
proxy . $(kubectl get svc -n istio-system istiocoredns -o jsonpath={.spec.clusterIP})
}
这两种DNS服务器的私有DNS域服务器都指向了istiocoredns服务,这样“<name>.<namespace>.global”类型的域名解析都会被转发到istiocoredns服务器上。至于istiocoredns服务器为什么可以解析“<name>.<namespace>.global”,请继续阅读下文。
2、为Remote集群服务创建ServiceEntry
我们可以通过创建ServiceEntry将Remote集群的服务暴露到本地集群内,除此之外,在多控制面模型中,ServiceEntry还可以用于带“.global”后缀的服务DNS进行解析。如下所示是remote集群的forecast服务在primary集群中创建的ServiceEntry:
apiVersion: v1
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: forecast
spec:
hosts:
# 必须是 name.namespace.global 的格式
- forecast.weather.global
# 将Remote集群的服务认为是网格内部的服务,因为所有的集群共享相同的根证书
location: MESH_INTERNAL
ports:
- name: http1
number: 8000
protocol: http
resolution: DNS
addresses:
# 虚假的地址,所有发到这个地址的流量都会被Envoy拦截
# 并转发到${CLUSTER2_GW_ADDR}
- 127.255.0.2
endpoints:
# 集群2的入口网关地址
- address: ${CLUSTER2_GW_ADDR}
ports:
http1: 15443 # Do not change this port value
其中,host名称必须是“<name>.<namespace>.global”形式,address字段必须是在网格中没有使用过的唯一IP地址,“<name>.<namespace>.global”服务的地址将被istiocoredns解析成该IP地址。必须将endpoints设置为Remote集群的Gateway的地址和端口,这里的端口必须是网关服务的TLS端口,默认是15443。
注意:在多控制面的多集群模式下,网关地址必须是从对端集群可以访问的地址,在一般情况下,会通过负载均衡器为网关服务分配一个从集群外部可以访问的虚拟IP地址。
继续回到forecast.weather.global域名解析的主题上来,Kubernetes集群默认部署的DNS服务器根本没有该类型服务的IP信息,但是配置了存根域DNS服务器istiocoredns。istiocoredns是Istio社区为了支持全局的服务DNS解析而专门部署的。Istio社区专门开发了一个CoreDNS插件(https://github.com/istio-ecosystem/istio-coredns-plugin/blob/master/ plugin.go)用于解析ServiceEntry获取全局服务的IP地址,然后与CoreDNS部署在同一个Pod中,通过gRPC协议提供“*.global”类型的服务的DNS解析。
“*.global”类型的服务域名解析流程如下:
为支持Remote集群的forecast服务访问,需要创建ServiceEntry。
在本地集群中访问“forecast.weather.global”服务时首先会进行DNS解析,Kubernetes集群内的DNS解析首先会被发送到kube-dns服务。
默认的kube-dns/coredns根据存根DNS的设置,将“*.global”类型的域名解析请求转发到私有DNS服务器istiocoredns。
istiocoredns通过Kube-apiserver获取ServiceEntry进而获取“forecast.weather. global”的IP地址。
*.global类型的服务域名解析流程如下图所示。
*.global类型的服务域名解析流程
第
2
则
Gateway连接的原理
在多控制面模型中,Istio对于底层网络连通性没有过多的要求,跨集群的服务访问完全通过Gateway转发,因而只需每个集群的Gateway服务都对外暴露一个虚拟IP地址,供集群外部访问。从网络拓扑来看,多控制面模型部署比较轻量化。
最简单的多控制面跨集群访问模型如图7-3所示,其中,Cluster1中的frontend服务访问Cluster2中的forecast服务,集群1中的工作负载发起到forecast.weather.global的请求,请求首先被Sidecar拦截,Sidecar再根据配置规则将请求转发到Cluster2的Gateway,Gateway再将请求转发到forecast服务实例,基本的流量转发依赖Istio的ServiceEntry、Gateway、VirtualService配置规则。
随着多集群的复杂度提高,例如在级联多集群场景下,相同的应用及服务跨集群部署频见,这对Istio配置规则的设置要求非常高,并且很难自动控制不同集群中服务实例的负载均衡权重。虽然这种多控制面模型基本能够满足跨集群的服务访问,但是需要额外设置很多VirtualService、DestinationRule、Gateway、ServiceEntry等API对象,比较复杂。
最简单的多控制面跨集群访问模型