Istio Ambient Mesh 介紹
1 Ambient Mesh 介紹
Istio 的傳統模式是將 Envoy proxy 作為 sidecar 部署在工作負載的 Pod 中,雖然與重構應用程式相比,sidecar 具有顯著的優勢,但是仍然會產生一些限制:
- 侵入性:sidecar 必須通過修改 Kubernetes Pod 的配置和重定向流量來“注入”應用程式。因此,安裝和升級 sidecar 需要重新啟動 Pod,這將會對工作負載產生影響。
- 資源利用率低:由於在每個工作負載 Pod 都注入了 sidecar 代理 ,因此 Pod 必須為 sidecar 預留足夠的 CPU 和記憶體資源,從而導致整個叢集的資源利用率不足。
- 流量中斷:流量捕獲和 HTTP 處理通常是由 Istio 的 sidecar 完成的,計算需要消耗大量的資源,並且可能會破壞一些不符合 HTTP 實現的應用程式。
Istio ambient mesh 是 Istio 的一個無 sidecar 的資料平面,旨在降低基礎設施成本和提高效能。 它的本質是分離 sidecar proxy(Envoy)中的 L4 和 L7 功能,讓一部分僅需要安全功能的使用者可以最小阻力(低資源消耗、運維成本)地使用 Istio service mesh。
ambient mesh 將 Istio 的功能拆分為 2 個不同的層次:
- L4 安全覆蓋層:使用者可以使用 TCP 路由,mTLS 和有限的可觀測性等功能。
- L7 處理層:使用者可以按需啟用 L7 功能,以獲得 Istio 的全部功能,例如限速,故障注入,負載均衡,熔斷等等。
ztunnel 是 ambient mesh 在每個節點上執行的共享代理,以 DaemonSet 的方式部署,處於類似於 CNI 的網格底層。ztunnel 在節點間構建零信任的隧道(zero-trust tunnel, ztunnel),負責安全地連線和驗證網格內的元素。在 ambient mesh 中的工作負載的所有流量會重定向到本地的 ztunnel 進行處理,ztunnel 識別流量的工作負載併為其選擇正確的證書以建立 mTLS 連線。
ztunnel 實現了服務網格中的核心功能:零信任,它會為啟用了 ambient mesh 的 Namespace 中的工作負載建立一個安全覆蓋層,提供 mTLS,遙測,認證和 L4 授權等功能,而無需終止或解析 HTTP。 在啟用 ambient mesh 和建立安全覆蓋層之後,可以選擇性地為 namespace 啟用 L7 功能,這允許名稱空間實現全套的 Istio 功能,包括 Virtual Service、L7 遙測 和 L7 授權策略。waypoint proxy 可以根據所服務的 Namespace 的實時流量自動擴縮容,這將為使用者節省大量的資源。
Istio 會為根據服務的 service account 建立相應的 waypoint proxy,可以幫助使用者在減少資源消耗的情況下同時儘可能地縮小故障域,參見下圖 Model III。
2 Ambient Mesh 支援的環境和限制
目前已知 ambient mesh 僅支援以下環境,其他環境目前尚未經過測試。
- GKE (without Calico or Dataplane V2)
- EKS
- kind
並且 ambient mesh 還有許多限制,例如:
- AuthorizationPolicy 在某些情況下沒有預期的那麼嚴格,或者根本無效。
- 在某些情況下直接訪問 Pod IP 而不是 Service 的請求將無效。
- ambient mesh 下的服務無法通過 LoadBalance 和 NodePort 的方式訪問,不過你可以部署一個入口閘道器(未啟用 ambient mesh)以從外部訪問服務;
- STRICT mTLS 不能完全阻止明文流量。
- 不支援 EnvoyFilter。
詳細說明請參見 Ambient Mesh[1]。
3 使用 Eksctl 在 AWS 上建立 Kubernetes 叢集
在本示例中,將使用 eksctl 在 AWS 上建立 EKS 叢集來測試 Istio ambient mesh。eksctl[2] 是一個用於管理 EKS(Amazon 託管 Kubernetes 服務)的 CLI 工具。有關 eksctl 的安裝和使用參見 eksctl Getting started[3]。
建立叢集配置檔案 cluster.yaml,我們將建立一個 2 個 Worker 節點的 EKS 叢集,每個節點資源為 2C8G,叢集版本為 1.23。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: aws-demo-cluster01
region: us-east-1
version: '1.23'
nodeGroups:
- name: ng-1
instanceType: m5.large
desiredCapacity: 2
volumeSize: 100
ssh:
allow: true # will use ~/.ssh/id_rsa.pub as the default ssh key
執行以下命令,建立 EKS 叢集。
eksctl create cluster -f cluster.yaml
建立完成後,檢視 EKS 叢集。
> eksctl get cluster
NAME REGION EKSCTL CREATED
aws-demo-cluster01 us-east-1 True
執行以下命令,將 aws-demo-cluster01 叢集的 kubeconfig 檔案更新到 ~/.kube/config 檔案中,讓我們本地的 kubectl 工具可以訪問到 aws-demo-cluster01 叢集。
aws eks update-kubeconfig --region us-east-1 --name aws-demo-cluster01
有關 aws CLI 工具的安裝參見 Installing or updating the latest version of the AWS CLI[4],aws CLI 的認證參見 Configuration basics[5]。
4 下載 Istio
根據對應作業系統下載支援 ambient mesh 的 istioctl 二進位制檔案和示例資原始檔,參見 Istio 下載[6]。其中 istioctl 的二進位制檔案可以在 bin 目錄中找到,示例資原始檔可以在 samples 目錄中找到。
5 部署示例應用
部署 Istio 示例的 Bookinfo 應用程式,以及 sleep 和 notsleep 兩個客戶端。sleep 和 notsleep 可以執行 curl 命令來發起 HTTP 請求。
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f http://raw.githubusercontent.com/linsun/sample-apps/main/sleep/sleep.yaml
kubectl apply -f http://raw.githubusercontent.com/linsun/sample-apps/main/sleep/notsleep.yaml
當前我們部署的 istio 和應用的 Pod 和 Service 如下所示。
6 部署 Istio
執行以下命令,安裝 Istio,並指定 profile=ambient
引數部署 ambient mesh 相關的元件。
istioctl install --set profile=ambient
如果安裝成功將會輸出以下結果。
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ CNI installed
✔ Installation complete
安裝完成以後我們在 istio-system 名稱空間內可以看到以下元件:
- istiod:Istio 的核心元件。
- istio-ingressgateway:管理進出叢集的南北向流量,在本示例中我們不會用到 istio-ingressgateway。
- istio-cni:為加入 ambient mesh 的 Pod 配置流量重定向,將 Pod 的進出流量重定向到相同節點的 ztunnel 上。
- ztunnel:ztunnel 在節點間構建零信任的隧道,提供 mTLS,遙測,認證和 L4 授權等功能。
> kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
istio-cni-node-gfmqp 1/1 Running 0 100s
istio-cni-node-t2flv 1/1 Running 0 100s
istio-ingressgateway-f6d95c86b-mfk4t 1/1 Running 0 101s
istiod-6c99d96db7-4ckbm 1/1 Running 0 2m23s
ztunnel-fnjg2 1/1 Running 0 2m24s
ztunnel-k4jhb 1/1 Running 0 2m24s
7 抓包設定
為了更直觀地觀察流量的訪問情況 ,我們可以對 Pod 進行抓包,但是應用 Pod 並沒有安裝相關的抓包工具,這時候我們可以使用 kubectl debug 工具建立一個 ephemeral 臨時容器共享容器的名稱空間來進行除錯。有關 kubectl debug 詳情請參見除錯執行中的 Pod[7]。
在 4 個終端分別執行以下命令,對 sleep 和 productpage 以及兩個節點上的 ztunnel Pod 進行抓包。--image
引數指定臨時容器的映象,這裡使用的 nicolaka/netshoot
映象中預裝了 tcpdump, tshark, termshark 等常用的網路抓包工具。
kubectl debug -it sleep-55697f8897-n2ldz --image=nicolaka/netshoot
kubectl debug -it productpage-v1-5586c4d4ff-z8jbb --image=nicolaka/netshoot
kubectl debug -it -n istio-system ztunnel-fnjg2 --image=nicolaka/netshoot
kubectl debug -it -n istio-system ztunnel-k4jhb --image=nicolaka/netshoot
在 4 個終端分別執行 termshark -i eth0
命令,對 Pod 的 eth0 網絡卡進行抓包。由於 istio-cni 會持續對 ztunnel 發起路徑為 /healthz/ready
的HTTP 健康探測,為了避免該流量影響我們的觀察,在 2 個 ztunnel Pod 中的 termshark Filter 框中設定以下過濾條件。
# ztunnel-fnjg2,sleep 所在節點的 ztunnel
ip.addr==192.168.58.148 || ip.addr==192.168.13.108
# ztunnel-k4jhb,productpage 所在節點的 ztunnel
ip.addr==192.168.13.108
8 未使用 Ambient Mesh 管理流量
由於當前 default Namespace 還沒有加入 ambient mesh,此時應用的流量並不會經過 ztunnel,Pod 之間通過 kubernetes 的 Service 進位制進行通訊,Pod 之間的流量也不會進行 mTLS 加密,而是以明文的方式進行傳播。
使用 sleep 向 productpage 發起一次請求。
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
# 返回結果,響應結果的第一行內容
<!DOCTYPE html>
檢視 sleep 和 productpage 的抓包結果可以看到,sleep (192.168.58.148) 訪問 productpage Service 名稱 DNS 解析後的 service IP(10.100.171.143),經過 kubernetes Service 的轉發後,最終訪問到 productpage 的實際 Pod IP (192.168.13.108)。
此時 ambient mesh 還未接管 default Namespace 的流量,因此在 ztunnel 上不會抓到相關的資料包。
9 將 Default Namespace 加入 Ambient Mesh(L4 功能)
為 default Namespace 新增 istio.io/dataplane-mode=ambient
標籤,表示將該 Namespace 加入到 ambient mesh 中。
kubectl label namespace default istio.io/dataplane-mode=ambient
一旦 Namespace 加入 ambient mesh,istio-cni DaemonSet 就會為該 Namespace 中的 Pod 設定 iptables 重定向規則,將 Pod 的所有出入流量重定向到執行在相同節點的 ztunnel 上。
9.1 MTLS 流量加密
ztunnel 會為啟用了 ambient mesh 的 Namespace 中的工作負載建立一個安全覆蓋層,提供 mTLS,遙測,認證和 L4 授權等功能。
為了方便檢視,可以先清除先前在 sleep 和 productpage 上抓到的報文。
然後使用 sleep 向 productpage 發起一次請求。
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
在 sleep 和 productpage 上依然可以抓到明文的資料包,只是這回在 productpage 上抓到的資料包的源 IP 變為的 sleep 所在節點的 ztunnel 的 IP 地址。
在 sleep 節點所在的 ztunnel 上我們可以抓到 sleep 發過來的明文的資料包,ztunnel 會對資料包進行加密以後傳送給 productpage 節點上的 ztunnel。productpage 節點上的 ztunnel 收到加密的資料包後,進行解密,然後傳送給 productpage。
我們還可以在 sleep 和 productpage 所在節點的 ztunnel 的日誌中看到訪問記錄。檢視 outbound 方向的流量日誌(sleep -> sleep node 上的 ztunnel)。
kubectl logs -n istio-system ztunnel-fnjg2 -f
我們可以看到 outbound 流量的日誌中有(no waypoint proxy)的字樣,ambient mesh 預設只進行 L4 處理,不會進行 L7 處理。因此此時流量只會通過 ztunnel ,不會經過 waypoint proxy。
檢視 inbound 方向的流量日誌(productpage 上的 ztunnel -> productpage)。
kubectl logs -n istio-system ztunnel-k4jhb -f
9.2 L4 授權策略
安全覆蓋層可以實現簡單的 L4 授權策略,如下所示建立一個 AuthorizationPolicy,只允許 Service Account 是 sleep 的使用者訪問標籤是 app=productpage 應用。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: productpage-viewer
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/sleep"]
EOF
分別在 sleep 和 notsleep 上執行以下請求,由於當前還沒有啟用 L7 處理,因此還無法針對 HTTP 請求方法,路徑等條件進行限制。
# 成功
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
# 成功
kubectl exec deploy/sleep -- curl -XDELETE -s http://productpage:9080/ | head -n1
# 失敗,只允許 sa 是 sleep 的使用者
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/ | head -n1
10 啟用 L7 功能
要為服務啟用 L7 網格能力,需要顯式建立一個 Gateway,注意建立的 Gateway 資源中的 gatewayClassName 必須設定為 istio-mesh,這樣 Istio 才會為 productpage 建立對應的 waypoint proxy。任何發往 productpage 服務的流量都將經過 waypoint proxy 這個 L7 代理進行處理。
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: productpage
annotations:
istio.io/service-account: bookinfo-productpage
spec:
gatewayClassName: istio-mesh
EOF
檢視 Istio 為 productpage 建立的 waypoint proxy。
從 sleep 訪問 productpage。
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
檢視 outbound 方向的流量日誌(sleep -> sleep node 上的 ztunnel -> waypoint proxy)。
kubectl logs -n istio-system ztunnel-fnjg2 -f
從下面的日誌中可以看到(to server waypoint proxy)的字樣,說明請求發往 waypoint proxy 進行處理。
檢視 inbound 方向的流量日誌(productpage 上的 ztunnel -> productpage)。
kubectl logs -n istio-system ztunnel-k4jhb -f
10.1 L7 授權策略
接下來更新 AuthorizationPolicy 只允許 Service Account 是 sleep 的使用者通過 GET 的方式訪問標籤是 app=productpage 應用。
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: productpage-viewer
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/sleep"]
to:
- operation:
methods: ["GET"]
EOF
分別在 sleep 和 notsleep 上執行以下請求,這次在 sleep 上執行 HTTP DELETE 請求也會被拒絕了。
# 成功
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
# 失敗,RBAC 錯誤,因為不是 GET 請求
kubectl exec deploy/sleep -- curl -X DELETE -s http://productpage:9080/ | head -n1
# 失敗,RBAC 錯誤,只允許 sa 是 sleep 的使用者
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/ | head -n1
10.2 可觀測性
在 productpage waypoint proxy 上可以檢視所有對 productpage 服務請求的 L7 指標。
kubectl exec deploy/bookinfo-productpage-waypoint-proxy -- curl -s http://localhost:15020/stats/prometheus | grep istio_requests_total
10.3 流量控制
首先為 reviews 服務建立一個 gateway,啟用 L7 能力。
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: reviews
annotations:
istio.io/service-account: bookinfo-reviews
spec:
gatewayClassName: istio-mesh
EOF
然後分別建立 VirtualService 和 DestinationRule 來控制流量以 90/10 的比例發往 v1 版本和 v2 版本的 reviews 服務。
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 90
- destination:
host: reviews
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
EOF
執行以下命令,從 sleep 往 productpage 傳送 10 個請求,可以看到大約有 10% 的流量流向了 reviews-v2。
# 注意訪問路徑是 http://productpage:9080/productpage,會呼叫 reviews 服務
kubectl exec -it deploy/sleep -- sh -c 'for i in $(seq 1 10); do curl -s http://productpage:9080/productpage | grep reviews-v.-; done'
# 返回結果
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v2-6bdd859457-7lxhc</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v1-7598cc9867-dh7hp</u>
<u>reviews-v2-6bdd859457-7lxhc</u>
10.4 故障注入
為 productpage 服務建立一個 VirtualService,在請求中注入 5s 的延時。
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
spec:
hosts:
- productpage
http:
- route:
- destination:
host: productpage
fault:
delay:
percentage:
value: 100.0
fixedDelay: 5s
EOF
從 sleep 訪問 productpage,可以看到請求消耗的時間大約在 5s 左右。
> kubectl exec deploy/sleep -- time curl -s http://productpage:9080 | head -n 1
# 返回結果
<!DOCTYPE html>
real 0m 5.04s
user 0m 0.00s
sys 0m 0.00s
11 清理環境
# 解除安裝 Istio
istioctl uninstall -y --purge && istioctl delete ns istio-system
# 刪除示例應用
kubectl delete -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl delete -f http://raw.githubusercontent.com/linsun/sample-apps/main/sleep/sleep.yaml
kubectl delete -f http://raw.githubusercontent.com/linsun/sample-apps/main/sleep/notsleep.yaml
# 刪除叢集
eksctl delete cluster aws-demo-cluster01
12 體驗 Demo
想要快速體驗 ambient mesh 的朋友也可以在 solo.io 官網[8] 上嘗試上手教程。
13 參考資料
- [1] Ambient Mesh: http://github.com/istio/istio/blob/experimental-ambient/README.md
- [2] eksctl: http://eksctl.io/
- [3] eksctl Getting started: http://eksctl.io/introduction/#installation
- [4] Installing or updating the latest version of the AWS CLI: http://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- [5] Configuration basics: http://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds
- [6] Istio 下載: http://gcsweb.istio.io/gcs/istio-build/dev/0.0.0-ambient.191fe680b52c1754ee72a06b3e0d3f9d116f2e82
- [7] 除錯執行中的 Pod: http://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-running-pod/
- [8] solo.io 官網: http://academy.solo.io/get-started-with-istio-ambient-mesh-with-istio-ambient-mesh-foundation-certification
- [9] Ambient Mesh Security Deep Dive: http://istio.io/latest/blog/2022/ambient-security/
- [10] Get Started with Istio Ambient Mesh: http://istio.io/latest/blog/2022/get-started-ambient/
- [11] Istio Ambient Mesh Launch Demo: http://www.youtube.com/watch?v=nupRBh9Iypo
- [12] Istio 無 sidecar 代理資料平面 ambient 模式簡介: http://lib.jimmysong.io/blog/introducing-ambient-mesh/
- [13] 譯文:Istio Ambient 模式安全架構深度解析: http://www.zhaohuabing.com/post/2022-09-09-ambient-mesh-security-deep-dive/
- [14] 如何評價 Istio 新推出的 Ambient 模式?: http://mp.weixin.qq.com/s/98wXMdeutx0wHqcJUIFl8A
- [15] 初探 Istio Ambient 模式: http://mp.weixin.qq.com/s/YA2My5PSHXIwovWLRKmsgA
- [16] Istio Ambient 模式 HBONE 隧道原理詳解 - 上: http://mp.weixin.qq.com/s/ksiYJEJKnit65KfIIGoN8Q
- [17] Create a kubeconfig for Amazon EKS: http://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html
- [18] Beyond Istio OSS —— Istio 服務網格的現狀與未來: http://jimmysong.io/blog/beyond-istio-oss/#sidecar-management
- Istio Ambient Mesh 介紹
- 使用 Containerlab Kind 快速部署 Cilium BGP 環境
- 如何往 Kafka 傳送大訊息?
- 實現 LRU 快取演算法
- Cilium 多叢集 ClusterMesh 介紹
- Elasticsearch 日誌監控方案
- Habor 入門指南
- Elasticsearch VS ClickHouse
- Nginx UpSync Consul 實現 Dynamic Upstream
- CDH 部署教程
- 跨域問題總結
- Kubectl debug 除錯容器
- Nginx 第三方模組使用與開發
- Nginx 平滑升級
- Nginx Location 匹配規則
- MySQL 資料備份恢復(一)select into outfile & load data infile
- Pulsar 介紹與部署
- Docker Getting started with Java
- Iptables 介紹與使用
- Kubernetes 持久卷