如何使用 Istio 進行多集羣部署管理:多控制平面

頭圖.png

做者 | 王夕寧  阿里雲高級技術專家json

導讀:本文摘自於阿里雲高級技術專家王夕寧撰寫的《Istio 服務網格技術解析與實戰》一書,講述瞭如何使用 Istio 進行多集羣部署管理來闡述服務網格對多雲環境、多集羣即混合部署的支持能力。api

前文詳情:服務器

在多控制平面拓撲的配置中,每一個 Kubernetes 集羣都會安裝相同的 Istio 控制平面,而且每一個控制平面只會管理本身集羣內的服務端點。經過使用 Istio 網關、公共根證書頒發機構(CA)以及服務條目 ServiceEntry,能夠將多個集羣配置組成一個邏輯上的單一服務網格。這種方法沒有特殊的網絡要求,所以一般被認爲是在 Kubernetes 集羣之間沒有通用網絡鏈接時的一種最簡單方法。網絡

在這種拓撲配置下,Kubernetes 跨集羣通訊須要服務之間的雙向 TLS 鏈接,要在集羣之間啓用雙向 TLS 通訊,每一個集羣的 Citadel 將配置由共享的根 CA 生成的中間 CA 證書,如圖所示。app

1.png
(多控制平面)負載均衡

部署控制平面

從共享的根 CA 爲每一個集羣的 Citadel 生成中間 CA 證書,共享的根 CA 啓用跨不一樣集羣的雙向 TLS 通訊。爲了便於說明,咱們將 samples/certs 目錄下 Istio 安裝中提供的示例根 CA 證書用於兩個集羣。在實際部署中,你可能會爲每一個集羣使用不一樣的 CA 證書,全部 CA 證書都由公共根 CA 簽名。less

在每一個 Kubernetes 集羣中實施如下步驟,以在全部集羣中部署相同的 Istio 控制平面配置。curl

  1. 使用如下的命令爲生成的 CA 證書建立 Kubernetes 密鑰,以下所示:
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
  1. 安裝 Istio 的 CRD 並等待幾秒鐘,以便將它們提交給 Kubernetes API 服務器,以下所示:
for
i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i;
done
  1. 部署 Istio 控制平面:若是 helm 依賴項缺失或者不是最新的,能夠經過 helm dep update 來更新這些依賴項。注意由於沒有使用 istio-cni,能夠暫時將其從依賴項 requirements.yaml 中去掉再執行更新操做。具體執行命令以下:
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 解析,則現有應用程序不須要作修改就能夠運行,由於應用程序一般指望經過其 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 服務。

  1. 部署 sleep 服務到第一個集羣 cluster1 中,執行以下命令:
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})
  1. 部署 httpbin 服務到第二個集羣 cluster2 中,執行以下命令:
kubectl
create namespace app2
kubectl
label namespace app2 istio-injection=enabled
kubectl
apply -n app2 -f samples/httpbin/httpbin.yaml
  1. 獲取集羣 cluster2 的入口網關地址,以下所示:
export
CLUSTER2_GW_ADDR=$(kubectl get svc --selector=app=istio-ingressgateway \
  -n istio-system -o
jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}")
  1. 爲了讓在集羣 cluster1 中的服務 sleep 可以訪問集羣 cluster2 中的服務 httpbin,咱們須要在集羣 cluster1 中爲服務 httpbin 建立一個服務條目 ServiceEntry 資源。服務條目 ServiceEntry 的主機名應該是<name>.<namespace>.globalname,其中 name 和 namespace 分別對應於集羣 cluster2 中的遠程服務的名稱和命名空間。

對於 *.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

執行結果以下所示:

2.png

  1. 驗證在集羣 cluster1 中的 sleep 服務是否能夠正常調用位於集羣 cluster2 中的 httpbin 服務,在集羣 cluster1 執行以下命令:
kubectl
exec $SLEEP_POD -n app1 -c sleep -- curl httpbin.app2.global:8000/headers

執行結果以下所示:

3.png

至此,集羣 cluster1 與 cluster2 在多控制平面配置下完成了連通。

跨集羣的版本路由

經過前面的文章,咱們已經瞭解了 Istio 的不少功能,例如基本版本的路由等,能夠在單個 Kubernetes 集羣上很容易地實現。而不少真實的業務場景中,基於微服務的應用程序並不是那麼簡單,而是須要在多個位置跨集羣去分配和運行服務。那麼問題就來了,是否 Istio 的這些功能一樣能夠很簡單地運行在這些真實的複雜環境中呢?

下面咱們將會經過一個示例來了解 Istio 的流量管理功能如何在具備多個控制平面拓撲的多集羣網格中正常運行。

  1. 首先,部署版本 v1 的 helloworld 服務到第一個集羣 cluster1 中,執行以下命令:
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
  1. 部署版本 v2 與 v3 的 helloworld 服務到第二個集羣 cluster2 中,執行以下命令:
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
  1. 如前面章節中所述,多控制平面下,須要使用以 .global 爲後綴的 DNS 名稱訪問遠程服務

在咱們的例子中,它是 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
  1. 在兩個集羣上建立目標規則。在集羣 cluster1 中建立子集 v1 對應的目標規則,執行以下命令:
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
  1. 建立虛擬服務以路由流量。

應用下面的虛擬服務將會使得來自用戶 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

執行屢次調用,能夠從下面的執行結果中看出,上述流量路由的規則生效,這也說明了在多控制平面拓撲下,用於路由的規則定義與在本地集羣的使用方式是同樣的:

4.png

設置多集羣網格的最簡單方法是使用多控制平面拓撲,由於它沒有特殊的網絡要求。經過上述示例能夠看出,在單個 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 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」

相關文章
相關標籤/搜索