Istio(十一):向istio服務網格中引入虛擬機
一.模塊概覽
在本模塊中,我們將了解如何將運行在虛擬機上的工作負載納入istio服務網格。
向istio服務網格中引入虛擬機的前提是已經安裝好了istio,關於istio的安裝部署,請查看博客《Istio(二):在Kubernetes(k8s)集群上安裝部署istio1.14》//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 //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 服務器。你可以在不同的端口上配置任何其他服務。只要確保你配置了相應的安全和防火牆規則。
- 將
$WORK_DIR
中的文件複製到實例的主文件夾中。相應地替換USERNAME
和INSTANCE_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]:~
。
- SSH 進入實例,將根證書複製到
/etc/certs
:
sudo mkdir -p /etc/certs
sudo cp root-cert.pem /etc/certs/root-cert.pem
- 拷貝
istio-token
文件到/var/run/secrets/tokens
目錄:
sudo mkdir -p /var/run/secrets/tokens
sudo cp istio-token /var/run/secrets/tokens/istio-token
- 下載和安裝 Istio sidecar 包:
curl -LO //storage.googleapis.com/istio-release/releases/1.10.3/deb/istio-sidecar.deb
sudo dpkg -i istio-sidecar.deb
- 拷貝
cluster.env
到/var/lib/istio/envoy/
:
sudo cp cluster.env /var/lib/istio/envoy/cluster.env
- 將 Mesh 配置(
mesh.yaml
)添加到/etc/istio/config/mesh
:
sudo cp mesh.yaml /etc/istio/config/mesh
- 將 istiod host 添加到
/etc/hosts
文件中:
sudo sh -c 'cat $(eval echo ~$SUDO_USER)/hosts >> /etc/hosts'
- 將
/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 //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 (//0.0.0.0:8000/) ...
如果你試圖直接 curl 到實例 IP,你會得到一個響應(目錄列表)。:
$ curl [INSTANCE_IP]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "//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_NAME
和 ZONE
)。
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" "//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>
...