做者 | 王夕宁 阿里云高级技术专家json
导读:本文摘自于阿里云高级技术专家王夕宁撰写的《Istio 服务网格技术解析与实战》一书,讲述了如何使用 Istio 进行多集群部署管理来阐述服务网格对多云环境、多集群即混合部署的支持能力。api
前文详情:服务器
在多控制平面拓扑的配置中,每一个 Kubernetes 集群都会安装相同的 Istio 控制平面,而且每一个控制平面只会管理本身集群内的服务端点。经过使用 Istio 网关、公共根证书颁发机构(CA)以及服务条目 ServiceEntry,能够将多个集群配置组成一个逻辑上的单一服务网格。这种方法没有特殊的网络要求,所以一般被认为是在 Kubernetes 集群之间没有通用网络链接时的一种最简单方法。网络
在这种拓扑配置下,Kubernetes 跨集群通讯须要服务之间的双向 TLS 链接,要在集群之间启用双向 TLS 通讯,每一个集群的 Citadel 将配置由共享的根 CA 生成的中间 CA 证书,如图所示。app
(多控制平面)负载均衡
从共享的根 CA 为每一个集群的 Citadel 生成中间 CA 证书,共享的根 CA 启用跨不一样集群的双向 TLS 通讯。为了便于说明,咱们将 samples/certs 目录下 Istio 安装中提供的示例根 CA 证书用于两个集群。在实际部署中,你可能会为每一个集群使用不一样的 CA 证书,全部 CA 证书都由公共根 CA 签名。less
在每一个 Kubernetes 集群中实施如下步骤,以在全部集群中部署相同的 Istio 控制平面配置。curl
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
for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done
helm template install/kubernetes/helm/istio --name istio --namespace istio-system \ -f install/kubernetes/helm/istio/values-istio-multicluster-gateways.yaml > ./istio.yaml kubectl apply -f ./istio.yaml
确保上述步骤在每一个 Kubernetes 集群中都执行成功。固然,经过 helm 生成 istio.yaml 的命令执行一次便可。ide
为远程集群中的服务提供 DNS 解析,则现有应用程序不须要作修改就能够运行,由于应用程序一般指望经过其 DNS 名称来解析服务并访问所获得的 IP 地址。Istio 自己不使用 DNS 在服务之间路由请求,同一个 Kubernetes 集群下的服务会共享一个相同的 DNS 后缀(例如 svc.cluster.local)。Kubernetes DNS 为这些服务提供 DNS 解析能力。为了给远程集群中的服务提供类似的设置,将远程集群中的服务以 <name>.<namespace>.global 的格式命名。微服务
Istio 安装包中附带了一个 CoreDNS 服务器,该服务器将为这些服务提供DNS解析能力。为了利用这个 DNS 解析能力,须要配置 Kubernetes 的 DNS 服务指向该 CoreDNS 服务。该 CoreDNS 服务将做为 .global DNS 域的 DNS 服务器。
对于使用 kube-dns 的集群,请建立如下配置项或更新现有的配置项:
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
对于使用 CoreDNS 的集群,请建立如下配置项或更新现有的配置项:
kubectl apply -f - <<EOF 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 reload loadbalance } global:53 { errors cache 30 proxy . $(kubectl get svc -n istio-system istiocoredns -o jsonpath={. spec.clusterIP}) } EOF
为了演示跨集群访问,在一个 Kubernetes 集群中部署 sleep 应用服务,在第二个集群中部署 httpbin 应用服务,而后验证 sleep 应用是否能够调用远程集群的 httpbin 服务。
kubectl create namespace app1 kubectl label namespace app1 istio-injection=enabled kubectl apply -n app1 -f samples/sleep/sleep.yaml export SLEEP_POD=$(kubectl get -n app1 pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl create namespace app2 kubectl label namespace app2 istio-injection=enabled kubectl apply -n app2 -f samples/httpbin/httpbin.yaml
export CLUSTER2_GW_ADDR=$(kubectl get svc --selector=app=istio-ingressgateway \ -n istio-system -o jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}")
对于 *.global 域下服务的 DNS 解析,须要为这些服务分配一个 IP 地址,而且保证 .globalDNS 域中的每一个服务在集群中必须具备惟一的 IP 地址。这些 IP 地址在 pod 以外是不可路由的。在这个例子中,咱们将使用网段 127.255.0.0/16 来避免与其余的IP冲突。这些 IP 的应用流量将由 Sidecar 代理捕获并路由到适当的其余远程服务。
在集群 cluster1 中建立该 httpbin 服务对应的 ServiceEntry,执行以下命令:
kubectl apply -n app1 -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: httpbin-app2 spec: hosts: # must be of form name.namespace.global - httpbin.app2.global # Treat remote cluster services as part of the service mesh # as all clusters in the service mesh share the same root of trust. location: MESH_INTERNAL ports: - name: http1 number: 8000 protocol: http resolution: DNS addresses: # the IP address to which httpbin.bar.global will resolve to # must be unique for each remote service, within a given cluster. # This address need not be routable. Traffic for this IP will be captured # by the sidecar and routed appropriately. - 127.255.0.2 endpoints: # This is the routable address of the ingress gateway in cluster2 that # sits in front of sleep.bar service. Traffic from the sidecar will be # routed to this address. - address: ${CLUSTER2_GW_ADDR} ports: http1: 15443 # Do not change this port value EOF
上面的配置将会使集群 cluster1 中访问 httpbin.app2.global 的全部流量,包括访问它的任何端口的流量,都会被路由到启用了双向 TLS 链接的端点 <IPofCluster2IngressGateway>:15443 上。
端口 15443 的网关是一个特殊的 SNI 感知的 Envoy 代理,它是在前面开始部分中做为多集群 Istio 安装步骤的一部分预先配置和安装的。进入端口 15443 的流量将在目标集群的适当内部服务的 pod 中进行负载均衡。
在集群 cluster1 下执行以下命令查看容器 istiocoredns,能够看到上述 ServiceEntry 的域名映射关系已经被加载:
export ISTIO_COREDNS=$(kubectl get -n istio-system po -l app=istiocoredns -o jsonpath={.items..metadata.name}) kubectl logs --tail 2 -n istio-system ${ISTIO_COREDNS} -c istio-coredns-plugin
执行结果以下所示:
kubectl exec $SLEEP_POD -n app1 -c sleep -- curl httpbin.app2.global:8000/headers
执行结果以下所示:
至此,集群 cluster1 与 cluster2 在多控制平面配置下完成了连通。
经过前面的文章,咱们已经了解了 Istio 的不少功能,例如基本版本的路由等,能够在单个 Kubernetes 集群上很容易地实现。而不少真实的业务场景中,基于微服务的应用程序并不是那么简单,而是须要在多个位置跨集群去分配和运行服务。那么问题就来了,是否 Istio 的这些功能一样能够很简单地运行在这些真实的复杂环境中呢?
下面咱们将会经过一个示例来了解 Istio 的流量管理功能如何在具备多个控制平面拓扑的多集群网格中正常运行。
kubectl create namespace hello kubectl label namespace hello istio-injection=enabled kubectl apply -n hello -f samples/sleep/sleep.yaml kubectl apply -n hello -f samples/helloworld/service.yaml kubectl apply -n hello -f samples/helloworld/helloworld.yaml -l version=v1
kubectl create namespace hello kubectl label namespace hello istio-injection=enabled kubectl apply -n hello -f samples/helloworld/service.yaml kubectl apply -n hello -f samples/helloworld/helloworld.yaml -l version=v2 kubectl apply -n hello -f samples/helloworld/helloworld.yaml -l version=v3
在咱们的例子中,它是 helloworld.hello.global,因此咱们须要在集群 cluster1 中建立服务条目 ServiceEntry 和目标规则 DestinationRule。服务条目 ServiceEntry 将使用集群 cluster2 的入口网关做为端点地址来访问服务。
经过使用如下命令在集群 cluster1 中建立 helloworld 服务对应的服务条目 ServiceEntry 和目标规则DestinationRule:
kubectl apply -n hello -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: helloworld spec: hosts: - helloworld.hello.global location: MESH_INTERNAL ports: - name: http1 number: 5000 protocol: http resolution: DNS addresses: - 127.255.0.8 endpoints: - address: ${CLUSTER2_GW_ADDR} labels: cluster: cluster2 ports: http1: 15443 # Do not change this port value --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: helloworld-global spec: host: helloworld.hello.global trafficPolicy: tls: mode: ISTIO_MUTUAL subsets: - name: v2 labels: cluster: cluster2 - name: v3 labels: cluster: cluster2 EOF
kubectl apply -n hello -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: helloworld spec: host: helloworld.hello.svc.cluster.local trafficPolicy: tls: mode: ISTIO_MUTUAL subsets: - name: v1 labels: version: v1 EOF
而在集群 cluster2 中建立子集 v2 和 v3 对应的目标规则,执行以下命令:
kubectl apply -n hello -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: helloworld spec: host: helloworld.hello.svc.cluster.local trafficPolicy: tls: mode: ISTIO_MUTUAL subsets: - name: v2 labels: version: v2 - name: v3 labels: version: v3 EOF
应用下面的虚拟服务将会使得来自用户 jason 对 helloworld 的流量请求指向位于集群 cluster2 中的版本 v2 和 v3,其中 v2 比例为 70%,v3 比例为 30%;来自任何其余用户对 helloworld 的流量请求都将转到位于集群 cluster1 中的版本 v1:
kubectl apply -n hello -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: helloworld spec: hosts: - helloworld.hello.svc.cluster.local - helloworld.hello.global http: - match: - headers: end-user: exact: jason route: - destination: host: helloworld.hello.global subset: v2 weight: 70 - destination: host: helloworld.hello.global subset: v3 weight: 30 - route: - destination: host: helloworld.hello.svc.cluster.local subset: v1 EOF
执行屡次调用,能够从下面的执行结果中看出,上述流量路由的规则生效,这也说明了在多控制平面拓扑下,用于路由的规则定义与在本地集群的使用方式是同样的:
设置多集群网格的最简单方法是使用多控制平面拓扑,由于它没有特殊的网络要求。经过上述示例能够看出,在单个 Kubernetes 集群上运行的路由功能一样很容易地在多个集群中使用运行。
《Istio服务网格技术解析与实战》读者可免费体验 ASM 产品进行学习!点击了解阿里云服务网格产品 ASM:www.aliyun.com/product/servicemesh
王夕宁 阿里云高级技术专家,阿里云服务网格产品 ASM 及 Istio on Kubernetes 技术负责人,专一于 Kubernetes、云原生、服务网格等领域。曾在 IBM 中国开发中心工做,担任过专利技术评审委员会主席,拥有 40 多项相关领域的国际技术专利。《Istio 服务网格解析与实战》一书由其撰写,详细介绍了 Istio 的基本原理与开发实战,包含大量精选案例和参考代码能够下载,可快速入门 Istio 开发。Gartner 认为,2020 年服务网格将成为全部领先的容器管理系统的标配技术。本书适合全部对微服务和云原生感兴趣的读者,推荐你们对本书进行深刻的阅读。
为了更多开发者可以享受到 Serverless 带来的红利,这一次,咱们集结了 10+ 位阿里巴巴 Serverless 领域技术专家,打造出最适合开发者入门的 Serverless 公开课,让你即学即用,轻松拥抱云计算的新范式——Serverless。
点击便可免费观看课程:https://developer.aliyun.com/learning/roadmap/serverless
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的公众号。”