Istio(十一):向istio服務網格中引入虛擬機器器

2022-10-30 15:01:32

一.模組概覽

在本模組中,我們將瞭解如何將執行在虛擬機器器上的工作負載納入istio服務網格。

向istio服務網格中引入虛擬機器器的前提是已經安裝好了istio,關於istio的安裝部署,請檢視部落格《Istio(二):在Kubernetes(k8s)叢集上安裝部署istio1.14》https://www.cnblogs.com/renshengdezheli/p/16836404.html

二.系統環境

伺服器版本 docker軟體版本 Kubernetes(k8s)叢集版本 Istio軟體版本 CPU架構
CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 v1.21.9 Istio1.14 x86_64

Kubernetes叢集架構:k8scloude1作為master節點,k8scloude2,k8scloude3作為worker節點

伺服器 作業系統版本 CPU架構 程序 功能描述
k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master節點
k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker節點
k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker節點

三.虛擬機器器負載

3.1 虛擬機器器負載

如果我們有在虛擬機器器上執行的工作負載,我們可以將它們連線到 Istio 服務網格,使其成為網格的一部分

帶有虛擬機器器的 Istio 服務網格有兩種架構:單網路架構和多網路架構

3.2 單網路架構

在這種情況下,有一個單一的網路。Kubernetes 叢集和在虛擬機器器上執行的工作負載都在同一個網路中,它們可以直接相互通訊。

控制平面的流量(設定更新、證書籤署)是通過 Gateway 傳送的

虛擬機器器被設定了閘道器地址,所以它們在啟動時可以連線到控制平面

3.3 多網路架構

多網路架構橫跨多個網路。Kubernetes 叢集在一個網路內,而虛擬機器器則在另一個網路內。這使得 Kubernetes 叢集中的 Pod 和虛擬機器器上的工作負載無法直接相互通訊。

所有的流量,控制平面和 pod 到工作負載的流量都流經閘道器,閘道器作為兩個網路之間的橋樑。

3.4 Istio 中如何表示虛擬機器器工作負載?

在 Istio 服務網格中,有兩種方式來表示虛擬機器器工作負載

工作負載組(WorkloadGroup 資源)類似於 Kubernetes 中的部署(Deployment),它代表了共用共同屬性的虛擬機器器工作負載的邏輯組。

描述虛擬機器器工作負載的第二種方法是使用工作負載條目(WorkloadEntry 資源)。工作負載條目類似於 Pod,它代表了一個虛擬機器器工作負載的單一範例。

請注意,建立上述資源將不會提供或執行任何虛擬機器器工作負載範例。這些資源只是用來參照或指向虛擬機器器工作負載的。Istio 使用它們來了解如何適當地設定網格,將哪些服務新增到內部服務登入檔中,等等。

為了將虛擬機器器新增到網格中,我們需要建立一個工作負載組,作為模板。然後,當我們設定並將虛擬機器器新增到網格中時,控制平面會自動建立一個相應的 WorkloadEntry。

我們已經提到,WorkloadEntry 的作用類似於 Pod。在新增虛擬機器器時,會建立 WorkloadEntry 資源,而當虛擬機器器的工作負載從網格中移除時,該資源會被自動刪除。

除了 WorkloadEntry 資源外,我們還需要建立一個 Kubernetes 服務。建立一個 Kubernetes 服務給了我們一個穩定的主機名和 IP 地址,以便使用選擇器欄位存取虛擬機器器工作負載和 pod。這也使我們能夠通過 DestinationRule 和 VirtualService 資源使用 Istio 的路由功能

四.實戰:向istio Mesh中引入虛擬機器器

4.1 將虛擬機器器引入到 Istio Mesh

在這個實驗中,我們將學習如何將虛擬機器器上執行的工作負載連線到 Kubernetes 叢集上執行的 Istio 服務網格。Kubernetes 叢集和虛擬機器器都將在谷歌雲平臺(GCP)上執行。我們將使用單一網路架構

在我們建立了一個 Kubernetes 叢集後,我們可以下載、安裝和設定 Istio。

4.2 在 Kubernetes 叢集上安裝 Istio

讓我們下載 Istio 1.10.3。

 $ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.10.3 sh -

下載了 Istio 後,我們可以使用 IstioOperator 來安裝它,它可以設定網格 ID、叢集名稱和網路名稱。網路名稱將是空的,因為我們要用單一網路架構

讓我們來設定幾個環境變數,我們將在本實驗中使用這些變數。

 export SERVICE_ACCOUNT="vm-sa"
 export VM_APP="hello-vm"
 export VM_NAMESPACE="vm-namespace"
 export WORK_DIR="${HOME}/vmfiles"
 export CLUSTER_NETWORK=""
 export VM_NETWORK=""
 export CLUSTER="Kubernetes"

我們還可以建立 $WORK_DIR,在這裡我們將儲存證書和其他我們必須複製到虛擬機器器上的檔案。

 mkdir -p $WORK_DIR

接下來,我們將初始化 Istio Operator 並安裝 Istio:

 getmesh istioctl operator init

一旦 Operator 被初始化,我們就可以建立 IstioOperator 資源,指定網格 ID、叢集名稱和網路,並安裝 Istio

 cat <<EOF | kubectl apply -f -
 apiVersion: install.istio.io/v1alpha1
 kind: IstioOperator
 metadata:
   name: istio
   namespace: istio-system
 spec:
   values:
     global:
       meshID: mesh1
       multiCluster:
         clusterName: "${CLUSTER}"
       network: "${CLUSTER_NETWORK}"
 EOF

我們可以使用 kubectl get iop -n istio-system 命令來檢查 Istio 安裝狀態何時變為健康

在下一步,我們將安裝東西向閘道器。這是控制平面用來與虛擬機器器工作負載對話的閘道器,反之亦然。

gen-eastwest-gateway.sh 指令碼是我們之前下載的 Istio 包的一部分。將資料夾改為 istio-1.10.3(或你解壓 Istio 的資料夾)並執行以下命令:

 samples/multicluster/gen-eastwest-gateway.sh --single-cluster | istioctl install -y -f -

gen-eastwest-gateway.sh 指令碼使用一個 IstioOperator 來部署一個額外的閘道器,名為 istio-eastwestgateway,並設定了伺服器埠。

我們可以通過檢視 istio-system 名稱空間中的 Kubernetes 服務來檢查新閘道器。

最後,我們還需要設定閘道器,通過它來暴露控制平面(istiod)。我們可以通過部署 expose-istiod.yaml 檔案來做到這一點:

 $ kubectl apply -n istio-system -f samples/multicluster/expose-istiod.yaml
 gateway.networking.istio.io/istiod-gateway created
 virtualservice.networking.istio.io/istiod-vs created

4.3 準備虛擬機器器名稱空間和檔案

對於虛擬機器器工作負載,我們必須建立一個單獨的名稱空間來儲存 WorkloadEntry 資源和任何其他虛擬機器器工作負載相關的資源。此外,我們還必須匯出叢集環境檔案、令牌、證書和其他我們必須轉移到虛擬機器器上的檔案

我們將把所有檔案存放在我們在實驗開始時建立的 $WORK_DIR 中。

讓我們在同一名稱空間中建立虛擬機器器名稱空間和我們將用於虛擬機器器工作負載的服務賬戶

 $ kubectl create ns "${VM_NAMESPACE}"
 namespace/vm-namespace created
 
 $ kubectl create serviceaccount "${SERVICE_ACCOUNT}" -n "${VM_NAMESPACE}"
 serviceaccount/vm-sa created

現在我們可以建立一個 WorkloadGroup 資源並將其儲存到 workloadgroup.yaml 中:

 cat <<EOF > workloadgroup.yaml
 apiVersion: networking.istio.io/v1alpha3
 kind: WorkloadGroup
 metadata:
   name: "${VM_APP}"
   namespace: "${VM_NAMESPACE}"
 spec:
   metadata:
     labels:
       app: "${VM_APP}"
   template:
     serviceAccount: "${SERVICE_ACCOUNT}"
     network: "${VM_NETWORK}"
 EOF

虛擬機器器需要關於叢集和 Istio 的控制平面的資訊來連線到它。為了生成所需檔案,我們可以執行 getmesh istioctl x workload entry 命令。我們將所有生成的檔案儲存到 $WORK_DIR 中:

 $ getmesh istioctl x workload entry configure -f workloadgroup.yaml -o "${WORK_DIR}" --clusterID "${CLUSTER}"
 Warning: a security token for namespace "vm-namespace" and service account "vm-sa" has been generated and stored at "/vmfiles/istio-token" 
 configuration generation into directory /vmfiles was successful

4.4 設定虛擬機器器

現在是時候建立和設定一個虛擬機器器了。我在 GCP 中執行這個虛擬機器器,就像 Kubernetes 叢集一樣。虛擬機器器使用的是 Debian GNU/Linux 10(Buster)映象。確保你在防火牆部分勾選了 "允許 HTTP 流量",並且你有 SSH 存取該範例的許可權。

在這個例子中,我們在 80 埠執行一個簡單的 Python HTTP 伺服器。你可以在不同的埠上設定任何其他服務。只要確保你設定了相應的安全和防火牆規則

  1. $WORK_DIR 中的檔案複製到範例的主資料夾中。相應地替換 USERNAMEINSTANCE_IP
 $ scp $WORK_DIR/* [USERNAME]@[INSTANCE_IP]:~
 Enter passphrase for key '/Users/peterj/.ssh/id_rsa':
 bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
 cluster.env                                          100%  589    12.6KB/s   00:00
 hosts                                                100%   38     0.8KB/s   00:00
 istio-token                                          100%  906    19.4KB/s   00:00
 mesh.yaml                                            100%  667    14.4KB/s   00:00
 root-cert.pem                                        100% 1094    23.5KB/s   00:00

或者,你可以使用 gcloud 命令和範例名稱: gcloud compute scp --zone=us-west1-b ${WORK_DIR}/* [INSTANCE_NAME]:~

  1. SSH 進入範例,將根證書複製到 /etc/certs
 sudo mkdir -p /etc/certs
 sudo cp root-cert.pem /etc/certs/root-cert.pem
  1. 拷貝 istio-token 檔案到 /var/run/secrets/tokens 目錄:
 sudo mkdir -p /var/run/secrets/tokens
 sudo cp istio-token /var/run/secrets/tokens/istio-token
  1. 下載和安裝 Istio sidecar 包:
 curl -LO https://storage.googleapis.com/istio-release/releases/1.10.3/deb/istio-sidecar.deb
 sudo dpkg -i istio-sidecar.deb
  1. 拷貝 cluster.env/var/lib/istio/envoy/
 sudo cp cluster.env /var/lib/istio/envoy/cluster.env
  1. 將 Mesh 設定(mesh.yaml)新增到 /etc/istio/config/mesh
 sudo cp mesh.yaml /etc/istio/config/mesh
  1. 將 istiod host 新增到 /etc/hosts 檔案中:
 sudo sh -c 'cat $(eval echo ~$SUDO_USER)/hosts >> /etc/hosts'
  1. /etc/certs/var/lib/istio/envoy 的所有者修改為 Istio proxy:
 sudo mkdir -p /etc/istio/proxy
 sudo chown -R istio-proxy /var/lib/istio /etc/certs /etc/istio/proxy /etc/istio/config /var/run/secrets /etc/certs/root-cert.pem

以上都就緒後,就可以在虛擬機器器中啟動 Istio:

 sudo systemctl start istio

此刻,虛擬機器器被設定為與 Kubernetes 叢集中 Istio 的控制平面通訊。

4.5 從虛擬機器器存取服務

讓我們在 Kubernetes 叢集中部署一個 Hello world 應用程式。首先,我們需要在 default 名稱空間中啟用自動 sidecar 注入:

 $ kubectl label namespace default istio-injection=enabled
 namespace/default labeled

接下來,建立 Hello world 的部署和服務。

 apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: hello-world
   labels:
     app: hello-world
 spec:
   replicas: 1
   selector:
     matchLabels:
       app: hello-world
   template:
     metadata:
       labels:
         app: hello-world
     spec:
       containers:
         - image: gcr.io/tetratelabs/hello-world:1.0.0
           imagePullPolicy: Always
           name: svc
           ports:
             - containerPort: 3000
 ---
 kind: Service
 apiVersion: v1
 metadata:
   name: hello-world
   labels:
     app: hello-world
 spec:
   selector:
     app: hello-world
   ports:
     - port: 80
       name: http
       targetPort: 3000

將上述檔案儲存為 hello-world.yaml,並使用 kubectl apply -f hello-world.yaml 進行部署。

等待 Pod 準備好,然後回到虛擬機器器上,嘗試存取 Kubernetes 服務:

 $ curl http://hello-world.default
 Hello World

你可以從虛擬機器器上存取在你的 Kubernetes 叢集內執行的任何服務。

4.6 在虛擬機器器上執行服務

我們也可以在虛擬機器器上執行一個工作負載。切換到範例上,執行一個簡單的 Python HTTP 伺服器:

 $ sudo python3 -m http.server 80
 Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

如果你試圖直接 curl 到範例 IP,你會得到一個響應(目錄列表)。:

 $ curl [INSTANCE_IP]
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dt
 d">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <title>Directory listing for /</title>
 </head>
 <body>
 <h1>Directory listing for /</h1>
 <hr>
 ...

但我們要做的是將工作負載(Python HTTP 服務)新增到網格中。出於這個原因,我們在前面建立了虛擬機器器名稱空間。所以讓我們建立一個代表虛擬機器器工作負載的 Kubernetes 服務。注意,名稱和標籤值等於我們之前設定的 VM_APP 環境變數的值。不要忘記將服務部署到 VM_NAMESPACE

 apiVersion: v1
 kind: Service
 metadata:
   name: hello-vm
   labels:
     app: hello-vm
 spec:
   ports:
   - port: 80
     name: http-vm
     targetPort: 80
   selector:
     app: hello-vm

將上述檔案儲存為 hello-vm-service.yaml,並使用 kubectl apply -f hello-vm-service.yaml -n vm-namespace 將其部署到 VM 名稱空間。

因為我們沒有使用實驗性的虛擬機器器自動註冊,它將自動建立 WorkloadEntry 資源,我們需要手動建立它們

我們需要一個代表虛擬機器器工作負載的 WorkloadEntry 資源——該資源使用虛擬機器器服務賬戶(SERVICE_ACCOUNT)和標籤中的應用程式名稱(VM_APP)。

請注意,我們還需要獲得虛擬機器器的內部 IP 地址,這樣 Istio 就知道在哪裡可以到達虛擬機器器。讓我們把它儲存在另一個環境變數中(確保用你的值替換 INSTANCE_NAMEZONE)。

 export VM_IP=$(gcloud compute instances describe [INSTANCE_NAME] --format='get(networkInterfaces[0].networkIP)' --zone=[ZONE])

我們現在可以建立 WorkloadEntry 資源:

 cat <<EOF > workloadentry.yaml
 apiVersion: networking.istio.io/v1alpha3
 kind: WorkloadEntry
 metadata:
   name: ${VM_APP}
   namespace: ${VM_NAMESPACE}
 spec:
   serviceAccount: ${SERVICE_ACCOUNT}
   address: ${VM_IP}
   labels:
     app: ${VM_APP}
     instance-id: vm1
 EOF

將上述檔案儲存為 workloadentry.yaml,然後在 $VM_NAMESPACE 名稱空間建立資源:

 kubectl apply -n ${VM_NAMESPACE} -f workloadentry.yaml

為了把虛擬機器器的工作負載加入到網格內,我們還需要定義 ServiceEntry:

 cat <<EOF > serviceentry.yaml
 apiVersion: networking.istio.io/v1alpha3
 kind: ServiceEntry
 metadata:
   name: ${VM_APP}
 spec:
   hosts:
   - ${VM_APP}
   location: MESH_INTERNAL
   ports:
   - number: 80
     name: http
     protocol: HTTP
     targetPort: 80
   resolution: STATIC
   workloadSelector:
     labels:
       app: ${VM_APP}

請注意,WorkloadEntry 和 ServiceEntry 在未來最終將自動建立。

$VM_NAMESPACE 中建立服務條目資源。

 kubectl apply -n ${VM_NAMESPACE} -f serviceentry.yaml

我們現在可以使用 Kubernetes 服務名稱 hello-vm.vm-namespace 來存取虛擬機器器上的工作負載。讓我們在叢集內執行一個 Pod,並嘗試從那裡存取該服務:

 $ kubectl run curl --image=radial/busyboxplus:curl -i --tty
 If you don't see a command prompt, try pressing enter.
 [ root@curl:/ ]$

在你得到 Pod 中的命令提示後,你可以執行 curl 並存取工作負載。你應該看到一個目錄列表的響應。同樣地,你會注意到在 HTTP 伺服器執行的範例上有一個紀錄檔條目:

 [ root@curl:/ ]$ curl hello-vm.vm-namespace
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dt
 d">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <title>Directory listing for /</title>
 </head>
 <body>
 <h1>Directory listing for /</h1>
 <hr>
 ...