自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Istio多集群實踐,你都學會了嗎?

開發(fā) 前端
Istio 多集群網(wǎng)格有多種模型,在網(wǎng)絡拓撲上分為扁平網(wǎng)絡和非扁平網(wǎng)絡,在控制面上分為單一控制平面和多控制平面。

為了實現(xiàn)應用高并發(fā)和高可用,企業(yè)通常會選擇將應用部署在多個地域的多個集群,甚至多云、混合云環(huán)境中。在這種情況下,如何在多個集群中部署和管理應用,成為了一個挑戰(zhàn),當然多集群方案也逐步成為了企業(yè)應用部署的最佳選擇了。同樣對多云、混合云、虛擬機等異構基礎設施的服務治理也是 Istio 重點支持的場景之一,Istio 從 v1.0 版本開始支持一些多集群功能,并在之后的版本中添加了新功能。

多集群服務網(wǎng)格的好處是所有服務對客戶端看起來都一樣,不管工作負載實際上運行在哪里,無論是部署在單個還是多個網(wǎng)格中,它對應用程序都是透明的。要實現(xiàn)此行為,需要使用單個邏輯控制平面管理所有服務。但是,單個邏輯控制平面不一定需要是單個物理 Istio 控制平面。

多集群模型

Istio 多集群網(wǎng)格有多種模型,在網(wǎng)絡拓撲上分為扁平網(wǎng)絡和非扁平網(wǎng)絡,在控制面上分為單一控制平面和多控制平面。

  • 扁平網(wǎng)絡:所有集群都在同一個網(wǎng)絡中,可以直接訪問到其他集群的服務,不需要通過網(wǎng)關。
  • 優(yōu)點: 跨集群訪問不經(jīng)過東西向網(wǎng)關,延遲低
  • 缺點:組網(wǎng)較為復雜,Service、Pod 網(wǎng)段不能重疊,借助 VPN 等技術將所有集群的 Pod 網(wǎng)絡打通,需要考慮網(wǎng)絡安全問題
  • 非扁平網(wǎng)絡:集群之間的網(wǎng)絡是隔離的,需要通過網(wǎng)關訪問其他集群的服務。
  • 優(yōu)點:不同集群的網(wǎng)絡是互相隔離的,安全性更高,不需要打通不同集群的容器網(wǎng)絡,不用提前規(guī)劃集群的網(wǎng)段

  • 缺點:跨集群訪問依賴東西向網(wǎng)關,延遲高。東西向網(wǎng)關工作模式是 TLS AUTO_PASSTHROUGH,不支持 HTTP 路由策略。

  • 單控制面:所有集群共用一個控制平面,所有集群的配置都在同一個控制平面中。

  • 優(yōu)點:所有集群的配置都在同一個控制平面中,集群之間的配置可以共享,部署運維更簡單

  • 缺點:控制平面的性能和可用性會受到影響,不適合大規(guī)模集群

  • 多控制面:每個集群都有一個獨立的控制平面,集群之間的配置不共享。

  • 優(yōu)點:控制平面的性能和可用性不會受到影響,適合大規(guī)模集群

  • 缺點:集群之間的配置不共享,部署運維較為復雜

總體來說 Istio 目前支持 4 種多集群模型:扁平網(wǎng)絡單控制面、扁平網(wǎng)絡多控制面、非扁平網(wǎng)絡單控制面、非扁平網(wǎng)絡多控制面。其中扁平網(wǎng)絡單控制面是最簡單的模型,非扁平網(wǎng)絡多控制面是最復雜的模型。

扁平網(wǎng)絡單控制面

該模型下只需要將 Istio 控制面組件部署在主集群中,然后可以通過這個控制面來管理所有集群的 Service 和 Endpoint,其他的 Istio 相關的 API 比如 VirtualService、DestinationRule 等也只需要在主集群中配置即可,其他集群不需要部署 Istio 控制面組件。

控制平面的 Istiod 核心組件負責連接所有集群的 kube-apiserver,獲取每個集群的 Service、Endpoint、Pod 等信息,所有集群的 Sidecar 均連接到這個中心控制面,由這個中心控制面負責所有的 Envoy Sidecar 的配置生成和分發(fā)。

扁平網(wǎng)絡單控制面

多集群扁平網(wǎng)絡模型和單一集群的服務網(wǎng)格在訪問方式上幾乎沒什么區(qū)別,但是需要注意不同集群的 Service IP 和 Pod 的 IP 不能重疊,否則會導致集群之間的服務發(fā)現(xiàn)出現(xiàn)問題,這也是扁平網(wǎng)絡模型的一個缺點,需要提前規(guī)劃好集群的網(wǎng)段。

非扁平網(wǎng)絡單控制面

在很多場景下我們多個集群并不在同一個網(wǎng)絡中,為滿足這個場景 Istio 又提出了一種更加靈活的網(wǎng)絡方案,即非扁平網(wǎng)絡。在非扁平網(wǎng)絡中,我們可以通過配置東西向網(wǎng)關來轉發(fā)跨集群的訪問流量。和扁平網(wǎng)絡的方案一樣,Istio 控制面一樣需要連接所有 Kubernetes 集群的 kube-apiserver,訂閱所有集群的 Service、Endpoint 等資源,所有集群的 Envoy Sidecar 都被連接到同一控制平面。

非扁平網(wǎng)絡單控制面

非扁平網(wǎng)絡單控制面模型在同一集群內部的服務訪問和單集群模型還是一樣的,但是如果有一個目標服務實例運行在另外一個集群中,那么這個時候就需要目標集群的東西向網(wǎng)關來轉發(fā)跨集群的服務請求。

扁平網(wǎng)絡多控制面

多控制面模型是每個集群都使用自己的 Istio 控制面,但是每個 Istio 控制面仍然要感知所有集群中的 Service、Endpoint 等資源,并控制集群內或者跨集群的服務間訪問。對于多控制面模型來說,相同的 Istio 配置需要被復制下發(fā)到多個集群中,否則不同集群的 Sidecar 訂閱到的 xDS 配置可能會存在不一致,導致不同集群的服務訪問行為不一致的情況。多控制面模型還有以下的一些特點:

  • 共享根 CA:為了支持跨集群的 mTLS 通信,多控制面模型要求每個集群的控制面 Istiod 都是有相同 CA 機構頒發(fā)的中間 CA 證書,供 Citadel 簽發(fā)證書使用,以支持跨集群的 TLS 雙向認證通信。
  • Sidecar 與本集群的 Istiod 控制面連接訂閱 xDS,xDS 通信的可靠性相對更高。
  • 與單控制面模型相比,多控制面模型的控制面性能和可用性更好,適合大規(guī)模集群。

扁平網(wǎng)絡多控制面

這種模型適用于控制面可用性和控制面時延要求較高的場景,但是由于每個集群都需要部署 Istio 控制面,所以部署和運維的成本也會相應增加,同一配置規(guī)則需要重復創(chuàng)建多份,存在資源冗余的問題。

非扁平網(wǎng)絡多控制面

非扁平網(wǎng)絡多控制面模型與扁平網(wǎng)絡多控制面模型類似,它們在控制面方面完全相同,每個 Kubernetes 集群分別部署獨立的 Istio 控制面,并且每個控制面都監(jiān)聽所有 Kubernetes 集群的 Service、Endpoint 等資源。

非扁平網(wǎng)絡多控制面

因為是非扁平網(wǎng)絡模型,所以不同的集群不需要三層打通,跨集群的服務訪問通過 Istio 的東西向網(wǎng)關來轉發(fā)。每個集群的 Pod 地址范圍與服務地址可以與其他集群重疊,不同的集群之間互不干擾。另外集群的 Sidecar 只連接到本集群的 Istio 控制面,通信效率更高。

多集群安裝

在選擇 Istio 多集群模型時,當然需要結合自己的實際場景來決定。如果集群之間的網(wǎng)絡是扁平的,那么可以選擇扁平網(wǎng)絡模型,如果集群之間的網(wǎng)絡是隔離的,那么可以選擇非扁平網(wǎng)絡模型。如果集群規(guī)模較小,那么可以選擇單控制面模型,如果集群規(guī)模較大,那么可以選擇多控制面模型。

接下來我們這里選擇跨網(wǎng)絡多主架構的模型來進行安裝說明,即非扁平網(wǎng)絡多控制面模型。這里我們將在 cluster1 和 cluster2 兩個集群上,分別安裝 Istio 控制平面, 且將兩者均設置為主集群(primary cluster)。 集群 cluster1 在 network1 網(wǎng)絡上,而集群 cluster2 在 network2 網(wǎng)絡上,這意味著這些跨集群邊界的 Pod 之間,網(wǎng)絡不能直接連通。

為了方便測試,我們這里使用 kind 來測試多集群,先保證已經(jīng)安裝了 Docker 和 KinD:

$ docker version
Client:
 Cloud integration: v1.0.29
 Version:           20.10.21
 API version:       1.41
 Go version:        go1.18.7
 Git commit:        baeda1f
 Built:             Tue Oct 25 18:01:18 2022
 OS/Arch:           darwin/arm64
 Context:           orbstack
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          24.0.7
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.10
  Git commit:       311b9ff
  Built:            Thu Oct 26 09:08:17 2023
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          v1.7.7
  GitCommit:        8c087663b0233f6e6e2f4515cee61d49f14746a8
 runc:
  Version:          1.1.9
  GitCommit:        82f18fe0e44a59034f3e1f45e475fa5636e539aa
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
$ kind version
kind v0.20.0 go1.20.4 darwin/arm64

這里我們將安裝多集群的相關腳本放在了 github.com/cnych/multi-cluster-istio-kind 倉庫中,先將這個倉庫克隆到本地,然后進入到 multi-cluster-istio-kind 目錄,在 kind-create 目錄下面是我們定義了一個 create-cluster.sh 腳本,用于創(chuàng)建多個 K8s 集群:

# This script handles the creation of multiple clusters using kind and the
# ability to create and configure an insecure container registry.

set -o xtrace
set -o errexit
set -o nounset
set -o pipefail

# shellcheck source=util.sh
NUM_CLUSTERS="${NUM_CLUSTERS:-2}"
KIND_IMAGE="${KIND_IMAGE:-}"
KIND_TAG="${KIND_TAG:-v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72}"
OS="$(uname)"
function create-clusters() {
  local num_clusters=${1}

  local image_arg=""
  if [[ "${KIND_IMAGE}" ]]; then
    image_arg="--image=${KIND_IMAGE}"
  elif [[ "${KIND_TAG}" ]]; then
    image_arg="--image=kindest/node:${KIND_TAG}"
  fi
  for i in $(seq "${num_clusters}"); do
    kind create cluster --name "cluster${i}" "${image_arg}"
    fixup-cluster "${i}"
    echo

  done
}
function fixup-cluster() {
  local i=${1} # cluster num

  if [ "$OS" != "Darwin" ];then
    # Set container IP address as kube API endpoint in order for clusters to reach kube API servers in other clusters.
    local docker_ip
    docker_ip=$(docker inspect --format='{{range .NetworkSettingkc s.Networks}}{{.IPAddress}}{{end}}' "cluster${i}-control-plane")
    kubectl config set-cluster "kind-cluster${i}" --server="https://${docker_ip}:6443"
  fi

  # Simplify context name
  kubectl config rename-context "kind-cluster${i}" "cluster${i}"
}
echo "Creating ${NUM_CLUSTERS} clusters"
create-clusters "${NUM_CLUSTERS}"
kubectl config use-context cluster1

echo "Kind CIDR is $(docker network inspect -f '{{$map := index .IPAM.Config 0}}{{index $map "Subnet"}}' kind)"

echo "Complete"

上面的腳本默認會創(chuàng)建兩個 v1.27.3 版本的 K8s 集群,這里需要注意的是我們安裝的每個集群的 APIServer 必須能被網(wǎng)格中其他集群訪問,很多云服務商通過網(wǎng)絡負載均衡器(NLB)開放 APIServer 的公網(wǎng)訪問。如果 APIServer 不能被直接訪問,則需要調整安裝流程以放開訪問,我們這里容器的 IP 地址設置為 kube API 端點地址,以便集群可以訪問其他集群中的 kube API 服務器。

直接運行上面的腳本即可創(chuàng)建兩個 K8s 集群:

cd kind-create
bash ./create-cluster.sh

可以安裝一個 kubectx 工具來方便切換集群。

另外 istio 創(chuàng)建的入口和出口網(wǎng)關都需要外部 IP,我們可以使用 MetalLB 來進行分配。

# install-metallb.sh
#!/usr/bin/env bash

set -o xtrace
set -o errexit
set -o nounset
set -o pipefail
NUM_CLUSTERS="${NUM_CLUSTERS:-2}"

for i in $(seq "${NUM_CLUSTERS}"); do
  echo "Starting metallb deployment in cluster${i}"
  kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/master/manifests/namespace.yaml --context "cluster${i}"
  kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" --context "cluster${i}"
  kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/master/manifests/metallb.yaml --context "cluster${i}"
  kubectl apply -f ./metallb-configmap-${i}.yaml --context "cluster${i}"
  echo "----"
done

kind 集群控制的 IP 地址范圍可以通過 docker network inspect -f '{{$map := index .IPAM.Config 0}}{{index $map "Subnet"}}' kind 獲取。比如我們這里上述命令的輸出是 192.168.247.0/24,我們已經(jīng)創(chuàng)建了 metallb-configmap-1.yaml 和 metallb-configmap-2.yaml,這會將 192.168.247.225-192.168.247.250 和 192.168.247.200-192.168.247.224 IP 范圍分別分配給 cluster1 和 cluster2。

應用上面的腳本安裝 metallb:

cd kind-create
bash ./install-metallb.sh

多集群服務網(wǎng)格部署要求我們在網(wǎng)格中的所有集群之間建立信任,我們需要使用一個公共的根 CA 來為每個集群生成中間證書,在 kind-create 目錄中同樣我們定義了一個安裝 CA 的腳本:

cd kind-create
bash ./install-cacerts.sh

在 tools/certs 目錄下面包含兩個用于生成新根證書、中間證書和工作負載證書的 Makefile:

  • Makefile.k8s.mk:基于 k8s 集群中的 root-ca 創(chuàng)建證書。默認 kubeconfig 中的當前上下文用于訪問集群。
  • Makefile.selfsigned.mk:根據(jù)生成的自簽名根創(chuàng)建證書。

執(zhí)行上面的腳本后會生成一個公共的根 CA 證書,然后會使用這個證書為 cluster1 和 cluster2 集群生成中間證書,而且在這個腳本中,我們將 istio 命名空間添加了一個 topology.istio.io/network=network${i} 標簽。

Root CA

接下來就可以安裝 Istio 集群了,在 istio-create 目錄下面我們定義了一個 install-istio.sh 腳本,用于安裝 Istio 集群:

#!/usr/bin/env bash

set -o xtrace
set -o errexit
set -o nounset
set -o pipefail

OS="$(uname)"
NUM_CLUSTERS="${NUM_CLUSTERS:-2}"

for i in $(seq "${NUM_CLUSTERS}"); do
echo "Starting istio deployment in cluster${i}"

kubectl --cnotallow="cluster${i}" get namespace istio-system && \
kubectl --cnotallow="cluster${i}" label namespace istio-system topology.istio.io/network="network${i}"

sed -e "s/{i}/${i}/" cluster.yaml > "cluster${i}.yaml"
istioctl install --force --cnotallow="cluster${i}" -f "cluster${i}.yaml"

echo
done

其中有一個比較重要的是 cluster.yaml 文件,這個文件定義了 Istio 的安裝配置,由于我們這里使用的是非扁平網(wǎng)絡多控制面模型,所以我們需要在這個文件中定義 network 和 clusterName 用來標識不同的 Istio 集群,這里我們將 network 設置為 network${i},將 clusterName 設置為 cluster${i}。

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      meshID: mesh{i}
      multiCluster:
        clusterName: cluster{i}
      network: network{i}

直接運行上面的腳本即可在兩個 Kubernetes 集群中分別安裝 Istio 集群:

cd istio-create
bash ./install-istio.yaml

在安裝過程需要手動確認是否安裝 Istio,輸入 y 即可。默認安裝完成后會有 istiod、istio-ingressgateway 以及 istio-eastwestgateway 三個組件:

# 兩個 kubernetes 集群都有這三個組件
$ kubectl get pods -n istio-system
NAME                                     READY   STATUS    RESTARTS   AGE
istio-eastwestgateway-66758cf789-dztsz   1/1     Running   0          23m
istio-ingressgateway-6d4bc4cc8f-ppdjx    1/1     Running   0          2m6s
istiod-79d66c57dd-gmx76                  1/1     Running   0          2m8s
$ kubectl get svc -n istio-system
NAME                    TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                                                           AGE
istio-eastwestgateway   LoadBalancer   10.96.251.150   192.168.247.226   15021:31106/TCP,15443:30675/TCP,15012:30483/TCP,15017:30517/TCP   24m
istio-ingressgateway    LoadBalancer   10.96.111.72    192.168.247.225   15021:30540/TCP,80:31137/TCP,443:32705/TCP                        47m
istiod                  ClusterIP      10.96.45.118    <none>            15010/TCP,15012/TCP,443/TCP,15014/TCP                             47m

由于我們在 Kubernetes 集群中安裝了 metallb,所以我們可以看到 istio-ingressgateway 服務的 EXTERNAL-IP 被分配了一個 IP 地址,這個地址是我們在 metallb-configmap-1.yaml 和 metallb-configmap-2.yaml 中定義的范圍內。

前面我們提到過非扁平網(wǎng)絡多控制面模型的場景下需要一個專用于東西向流量的網(wǎng)關,所有配置都依賴于專用于東西向流量的單獨網(wǎng)關部署。這樣做是為了避免東西向流量淹沒默認的南北向入口網(wǎng)關。上面的腳本中同樣也包括生成東西向網(wǎng)關的配置。

到這里 istio 集群和專用于東西向流量的網(wǎng)關都安裝成功了。因為集群位于不同的網(wǎng)絡中,所以我們需要在兩個集群東西向網(wǎng)關上開放所有服務(*.local)。雖然此網(wǎng)關在互聯(lián)網(wǎng)上是公開的,但它背后的服務只能被擁有可信 mTLS 證書、工作負載 ID 的服務訪問, 就像它們處于同一網(wǎng)絡一樣。執(zhí)行下面的命令在兩個集群中暴露服務:

NUM_CLUSTERS="${NUM_CLUSTERS:-2}"

for i in $(seq "${NUM_CLUSTERS}"); do
  echo "Expose services in cluster${i}"
  kubectl --cnotallow="cluster${i}" apply -n istio-system -f samples/multicluster/expose-services.yaml

  echo
done

上面的命令其實就是在兩個集群中創(chuàng)建如下所示的 Gateway 對象,用來暴露所有的服務:

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: cross-network-gateway
spec:
  selector:
    istio: eastwestgateway # 專用于東西向流量的網(wǎng)關
  servers:
    - port:
        number: 15443 # 已經(jīng)聲明了
        name: tls
        protocol: TLS
      tls:
        mode: AUTO_PASSTHROUGH # 東西向網(wǎng)關工作模式是 TLS AUTO_PASSTHROUGH,不支持 HTTP 路由策略
      hosts:
        - "*.local" # 暴露所有的服務

最后我們還需要配置每個 istiod 來 watch 其他集群的 APIServer,我們使用 K8s 集群的憑據(jù)來創(chuàng)建 Secret 對象,以允許 Istio 訪問其他 (n-1) 個遠程 kubernetes apiserver。

cd istio-setup
bash ./enable-endpoint-discovery.sh

在上面的腳本中我們將使用 istioctl create-remote-secret 命令來使用 K8s 集群的憑據(jù)來創(chuàng)建 Secret 對象,以允許 Istio 訪問遠程的 Kubernetes apiservers。

docker_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "cluster${i}-control-plane")
istioctl create-remote-secret \
--cnotallow="cluster${i}" \
--server="https://${docker_ip}:6443" \
--name="cluster${i}" | \
    kubectl apply --validate=false --cnotallow="cluster${j}" -f -

這樣 cluster1 和 cluster2 均可以監(jiān)測兩個集群 API Server 的服務端點了,我們的非扁平網(wǎng)絡多控制面模型的 Istio 集群就安裝完成了。

多集群應用測試

接下來我們可以部署一個簡單的示例來驗證下我們的多集群服務網(wǎng)格是否安裝成功了。

這里我們將在所有集群中創(chuàng)建名為 sample 的命名空間,然后在所有集群中創(chuàng)建 helloworld 的 Service,并在每個集群中交替部署 helloworld 的 v1 和 v2 兩個版本。

cd testing
bash ./deploy-app.sh

部署完成后在 cluster1 集群中將運行 v2 版本,在 cluster2 集群中將運行 v1 版本:

# cluster1 集群
$ kubectl get pods -n sample
NAME                             READY   STATUS    RESTARTS   AGE
helloworld-v2-79d5467d55-7k2hv   2/2     Running   0          3m57s
# cluster2 集群
$ kubectl get pods -n sample
NAME                           READY   STATUS    RESTARTS   AGE
helloworld-v1-b6c45f55-8lw2j   2/2     Running   0          4m25s

此外我們還在 sample 命名空間下面部署了一個用于測試的 sleep 應用,我們可以到 sleep Pod 中進行測試,如下的命令:

while true; do curl -s "helloworld.sample:5000/hello"; done

正常會輸出如下所示的內容:

Hello version: v1, instance: helloworld-v1-776f57d5f6-znwk5
Hello version: v2, instance: helloworld-v2-54df5f84b-qmg8t..
...

同樣我們換另外一個集群的 sleep Pod 重復上面的命令,重復幾次這個請求,驗證 HelloWorld 的版本在 v1 和 v2 之間切換:

Hello version: v1, instance: helloworld-v1-776f57d5f6-znwk5
Hello version: v2, instance: helloworld-v2-54df5f84b-qmg8t..
...

到這里我們就成功在多集群環(huán)境中安裝、并驗證了 Istio!

地域負載均衡

接下來我們來了解下如何在 Istio 中配置地域負載均衡。

一個地域定義了 workload instance 在網(wǎng)格中的地理位置。這三個元素定義了一個地域:

  • Region:代表較大的地理區(qū)域,例如 us-east,一個地區(qū)通常包含許多可用區(qū)。在 Kubernetes 中,標簽 topology.kubernetes.io/region 決定了節(jié)點所在的地區(qū)。
  • Zone:區(qū)域內的一組計算資源。通過在地區(qū)內的多個區(qū)域中運行服務,可以在地區(qū)內的區(qū)域之間進行故障轉移,同時保持最終用戶的數(shù)據(jù)地域性。在 Kubernetes 中,標簽 topology.kubernetes.io/zone 決定了節(jié)點所在的區(qū)域。
  • Sub-zone:分區(qū),允許管理員進一步細分區(qū)域,以實現(xiàn)更細粒度的控制。Kubernetes 中不存在分區(qū)的概念,在 Istio 中引入了自定義節(jié)點標簽 topology.istio.io/subzone 來定義分區(qū)。

如果你使用托管的 Kubernetes 服務,則云提供商會為你配置地區(qū)和區(qū)域標簽。如果你正在運行自己的 Kubernetes 集群,則需要將這些標簽添加到自己的節(jié)點上。比如前面我們使用 Kind 搭建的兩個集群已經(jīng)添加上了相應的標簽:

$ kubectl get nodes --show-labels --context cluster1
NAME                     STATUS   ROLES           AGE   VERSION   LABELS
cluster1-control-plane   Ready    control-plane   38h   v1.27.3   beta.kubernetes.io/arch=arm64,beta.kubernetes.io/os=linux,kubernetes.io/arch=arm64,kubernetes.io/hostname=cluster1-control-plane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=,topology.kubernetes.io/reginotallow=region1,topology.kubernetes.io/znotallow=zone1
$ kubectl get nodes --show-labels --context cluster2
NAME                     STATUS   ROLES           AGE   VERSION   LABELS
cluster2-control-plane   Ready    control-plane   38h   v1.27.3   beta.kubernetes.io/arch=arm64,beta.kubernetes.io/os=linux,kubernetes.io/arch=arm64,kubernetes.io/hostname=cluster2-control-plane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=,topology.kubernetes.io/reginotallow=region2,topology.kubernetes.io/znotallow=zone2

地域是分層的,按匹配順序排列:Region -> Zone -> Sub-zone。這意味著,在 foo 地區(qū)的 bar 區(qū)域中運行 Pod 不會被視為在 baz 地區(qū)的 bar 區(qū)域中運行的 Pod。

配置權重分布

現(xiàn)在我們有兩個 Istio 集群,接下來我們來配置下權重分布。權重分布是一種流量管理策略,它允許您將流量分配到不同的地區(qū)。這里我們配置 region1 -> zone1 和 region1 -> zone2 兩個地區(qū)的權重分別為 80% 和 20%。

首先為 helloworld 服務創(chuàng)建一個專用的 Gateway 和 VirtualService 對象:

# helloworld-gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: helloworld-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: helloworld
spec:
  hosts:
    - "*"
  gateways:
    - helloworld-gateway
  http:
    - match:
        - uri:
            exact: /hello
      route:
        - destination:
            host: helloworld
            port:
              number: 5000

在兩個集群中都需要部署這個 Gateway 和 VirtualService 對象:

kubectl apply -f samples/helloworld/helloworld-gateway.yaml -n sample --context cluster1
kubectl apply -f samples/helloworld/helloworld-gateway.yaml -n sample --context cluster2

接下來我們就可以分別通過 cluster1 和 cluster2 集群的 Gateway 來訪問 helloworld 服務了:

# 集群 1
$ kubectl get svc istio-ingressgateway -n istio-system --context cluster1
NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                                      AGE
istio-ingressgateway   LoadBalancer   10.96.199.106   192.168.247.225   15021:31651/TCP,80:32531/TCP,443:32631/TCP   38h
$ while true; do curl -s "http://192.168.247.225/hello"; done
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
# 集群 2
$ kubectl get svc istio-ingressgateway -n istio-system --context cluster2
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)                                      AGE
istio-ingressgateway   LoadBalancer   10.96.149.60   192.168.247.175   15021:31057/TCP,80:30392/TCP,443:32610/TCP   38h
$ while true; do curl -s "http://192.168.247.175/hello"; done
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69

從上面結果可以看出來無論我們訪問哪個集群的 Gateway,都會將流量負載到兩個集群中的 helloworld 服務上,當然如果是在線上環(huán)境,我們在最前面可以加上一個統(tǒng)一的 LB 入口,這樣就可以將流量負載到不同地區(qū)/區(qū)域的集群中了。

如果我們想對流量進行更精細的控制,比如我們想將 region1 -> zone1 和 region1 -> zone2 兩個地區(qū)的權重分別為 80% 和 20%,那么我們可以使用 DestinationRule 來配置權重分布了。

創(chuàng)建如下所示的 DestinationRule 對象:

# locality-lb-weight.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: sample
spec:
  host: helloworld.sample.svc.cluster.local
  trafficPolicy:
    connectionPool:
      http:
        maxRequestsPerConnection: 1
    loadBalancer:
      simple: ROUND_ROBIN
      localityLbSetting:
        enabled: true
        distribute:
          - from: region1/*
            to:
              "region1/*": 80
              "region2/*": 20
          - from: region2/*
            to:
              "region2/*": 80
              "region1/*": 20
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 1s
      baseEjectionTime: 1m

在上面的 DestinationRule 對象中我們指定了流量策略,其中最重要的是 localityLbSetting,它定義了流量按地區(qū)的分布策略,如果流量請求來自 region1 地區(qū),那么將有 80% 的流量被負載到 region1,有 20% 的流量被負載到 region2,反之亦然,這樣就實現(xiàn)了地區(qū)的按權重的負載均衡。最后通過 outlierDetection 配置了故障檢測。

在兩個集群中都需要部署這個 DestinationRule 對象:

kubectl apply -f samples/helloworld/locality-lb-weight.yaml -n sample --context cluster1
kubectl apply -f samples/helloworld/locality-lb-weight.yaml -n sample --context cluster2

創(chuàng)建過后當我們再次訪問 helloworld 服務時,就會按照我們配置的權重分布來負載流量了:

# 集群1
$ while true; do curl -s "http://192.168.247.225/hello"; done
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
# 集群2
$ while true; do curl -s "http://192.168.247.175/hello"; done
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v2, instance: helloworld-v2-79d5467d55-mvgms

到這里我們就成功的在 Istio 中配置了按權重的地域負載均衡了。

配置地域故障轉移

我們知道當我們在多個地區(qū)/區(qū)域部署多個服務實例時,如果某個地區(qū)/區(qū)域的服務實例不可用,那么我們可以將流量轉移到其他地區(qū)/區(qū)域的服務實例上,實現(xiàn)地域故障轉移,這樣就可以保證服務的高可用性。

同樣在 Istio 中要實現(xiàn)地域故障轉移,我們需要使用 DestinationRule 對象來配置故障轉移策略,比如我們將 region1 故障轉移到 region2,region2 故障轉移到 region1。創(chuàng)建如下所示的 DestinationRule 對象:

# locality-lb-failover.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: sample
spec:
  host: helloworld.sample.svc.cluster.local
  trafficPolicy:
    connectionPool:
      http:
        maxRequestsPerConnection: 1 # 關閉 HTTP Keep-Alive,強制每個HTTP請求使用一個新連接的策略
    loadBalancer:
      simple: ROUND_ROBIN
      localityLbSetting:
        enabled: true
        failover:
          - from: region1
            to: region2
          - from: region2
            to: region1
    outlierDetection:
      consecutive5xxErrors: 1 # 連續(xù) 1 次 5xx 錯誤
      interval: 1s # 檢測間隔 1s
      baseEjectionTime: 1m # 基礎驅逐時間 1m

要實現(xiàn)故障轉移非常簡單,只需要在 localityLbSetting 中配置 failover,這里我們將 region1 故障轉移到 region2,region2 故障轉移到 region1。

在兩個集群中都需要部署這個 DestinationRule 對象:

kubectl apply -f samples/helloworld/locality-lb-failover.yaml -n sample --context cluster1
kubectl apply -f samples/helloworld/locality-lb-failover.yaml -n sample --context cluster2

創(chuàng)建完成后我們先訪問從集群 1 訪問 helloworld 服務:

# 集群1
$ while true; do curl -s "http://192.168.247.225/hello"; done
Hello version: v2, instance: helloworld-v2-79d5467d55-m7sp9
Hello version: v2, instance: helloworld-v2-79d5467d55-m7sp9
Hello version: v2, instance: helloworld-v2-79d5467d55-m7sp9
Hello version: v2, instance: helloworld-v2-79d5467d55-m7sp9
Hello version: v2, instance: helloworld-v2-79d5467d55-m7sp9

驗證響應中的 version 是 v2,也就是說我們訪問的是 region1 的 helloworld 服務。重復幾次,驗證響應總是相同的,因為現(xiàn)在沒有任何故障,所以只訪問本區(qū)域的實例。

接下來,觸發(fā)故障轉移到 region2。這里我們將 region1 中 HelloWorld 逐出 Envoy Sidecar 代理:

$ kubectl --cnotallow=cluster1 exec \
  "$(kubectl get pod --cnotallow=cluster1 -n sample -l app=helloworld \
  -l versinotallow=v2 -o jsnotallow='{.items[0].metadata.name}')" \
  -n sample -c istio-proxy -- curl -sSL -X POST 127.0.0.1:15000/drain_listeners

再次訪問 helloworld 服務:

$ while true; do curl -s "http://192.168.247.225/hello"; done
upstream connect error or disconnect/reset before headers. retried and the latest reset reason: remote connection failure, transport failure reason: delayed connect error: 111
upstream connect error or disconnect/reset before headers. retried and the latest reset reason: remote connection failure, transport failure reason: delayed connect error: 111
# ......
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69
Hello version: v1, instance: helloworld-v1-b6c45f55-r2l69

前面幾次調用將會失敗,差不多一分鐘后故障檢測生效,這將觸發(fā)故障轉移,多次重復該命令,并驗證響應中的 version 始終為 v1,也就是說我們訪問的是 region2 的 helloworld 服務,這樣就實現(xiàn)了地域故障轉移。

責任編輯:姜華 來源: k8s技術圈
相關推薦

2024-04-28 08:24:27

分布式架構Istio

2023-06-12 07:41:16

dockerspark集群

2023-06-27 08:00:35

2022-11-03 08:16:33

MySQL·窗口函數(shù)

2023-01-10 08:43:15

定義DDD架構

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺工具

2024-01-19 08:25:38

死鎖Java通信

2023-04-10 09:31:00

路由技術廠商

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機器學習模型

2024-04-09 13:16:21

Rust命名規(guī)范

2022-06-21 07:51:15

云原生應用鏈路

2022-04-22 08:10:45

云上數(shù)據(jù)安全

2024-10-24 23:49:42

2022-11-03 08:56:43

RediskeyBitmap

2023-06-30 08:54:39

2024-05-06 00:00:00

InnoDBView隔離

2024-08-06 09:47:57

2022-07-08 09:27:48

CSSIFC模型
點贊
收藏

51CTO技術棧公眾號