本教學已加入 Istio 系列:https://istio.whuanle.cn
Istio 可以管理叢集的出入口流量,當用戶端存取叢集內的應用時, Istio 可以將經過 istio-ingressgateway 的流量實現負載均衡和熔斷等一系列功能。
可是,如果叢集內的一個應用要存取 google.com ,那麼我們可以給內部所有請求了 google.com 的流量設定負載均衡嗎?答案是可以,Istio 提供了 istio-egressgateway 實現這種功能。因為 Pod 中的容器要存取網路時,會被 Envoy 攔截,Envoy 可以很容易地分析這些請求,然後通過一系列手段影響著請求的行為。
在本章中,將會簡單說一下 istio-ingressgateway 和 istio-egressgateway。
入口閘道器指的是從外部經過 istio-ingressgateway 流入叢集的流量,需要建立 Gateway 繫結流量。
關於 istio-ingressgateway 經過前面幾章的學習,大家應該不陌生了。
istio-ingressgateway 由 Pod 和 Service 組成。 istio-ingressgateway 本身就是一個閘道器應用,你可以把它當作 Nginx、Apisix、Kong ,你可以從各種各種閘道器應用中找到與 istio-ingressgateway 類似的概念。
作為一個應用,它需要對外開放一些埠,只有當流量經過這些埠時, istio-ingressgateway 才會起作用。為了在 Kubernetes 中暴露埠, istio-ingressgateway 還有一個 Service 物件。
有了 istio-ingressgateway 之後,我們可以通過 Istio Gateway 監控一些域名或IP,然後暴露叢集內部的服務 。
Gateway 的概念跟 Nginx 有很多相似之處。
比如從設定上看, Gateway 跟 Nginx 如果要監控某個入口流量,它們的設定如下:
Nginx:
server {
listen 80;
server_name example.org www.example.org;
#...
}
Gateway:
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- example.org
- www.example.org
這些設定指定了 Gateway 和 Nginx 只監控哪些流量。
緊接著,監控到指定入口的流量之後,需要將流量轉發到叢集內的應用中。
Nginx 可以直接在同一個組態檔裡面設定:
server {
listen 80;
server_name example.org www.example.org;
#...
}
location /some/path/ {
proxy_pass http:/bookinfo:9080/;
}
而 Gateway 需要使用 VirtualService 指定流量轉發到哪裡,並且 VirtualService 還可以進一步篩選入口地址。
spec:
hosts:
- "www.example.org"
gateways:
# 繫結 Gateway
- mygateway
http:
route:
- destination:
host: bookinfo
port:
number: 9080
所以總結起來,Istio 的做法是 Gateway 監控入口流量,通過 VirtualService 設定流量進入的策略,並指向 Service。而 DestinationRule 則定義了流量流向 Pod 的策略。
下面我們將使用 httpbin 服務作為範例,如何一步步設定在外部存取 httpbin 服務。
首先部署一個 httpbin 服務,這個 httpbin 服務很簡單,包含了 Service 和 Deployment 。
httpbin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
kubectl -n bookinfo apply -f httpbin.yaml
然後建立一個 Gateway ,指定監聽哪些入口流量。
httpbin_gw.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.s1.whuanle.cn"
- "*"
這一步為了大家能夠通過域名更加直觀地瞭解 Gateway,大家可以修改
httpbin.s1.whuanle.cn
替換為自己的域名。然後在自己的電腦中開啟
C:\Windows\System32\drivers\etc\hosts
增加一條記錄 ,將 IP 指向自己的伺服器。
kubectl -n bookinfo apply -f httpbin_gw.yaml
現在,我們已經讓 istio-ingressgateway 幫我們關注 httpbin.s1.whuanle.cn 這個地址,如果有人存取了 httpbin.s1.whuanle.cn,那麼這個流量將會流入到 httpbin-gateway。
接下來我們將要為 Gateway 設定服務地址,並設定外部允許存取的地址字尾。
設定 VistualService:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
當 Gateway 和 VirtualService 埠只有一個時,不需要設定埠繫結。
kubectl -n bookinfo apply -f httpbin_vs.yaml
找到 istio-ingressgateway 對外暴露的埠。
kubectl get svc istio-ingressgateway -n istio-system
httpbin 是一個 http 測試程式,我們可以通過使用 /status/{狀態碼}
獲取對應的 http 請求狀態。
例如:
如果我們不希望這個服務被外界存取到,我們可以先把 /status
刪除。
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
此時你將無法存取 status
路徑。但是我們還可以存取 /delay
路徑。
httpbin 的 /delay
路徑用於測試延遲 http 請求響應使用,/delay/{秒數}
可以指定伺服器在多久之後才會返回響應。
例如 http://192.168.3.150:32309/delay/5 將在 5 秒後響應。
httpbin 還有很多路由介面,我們可以通過 VirtualService 設定放通哪些路徑。
如果需要全部放通,可以使用:
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 8000
host: httpbin
subset: v1
EOF
第四章中進行版本路由實驗時使用到,可以將流量匯入到不同的版本之中。
kubectl -n bookinfo apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
subsets:
- name: v1
labels:
version: v1
EOF
首先是使用 DestinationRule 指向一個 Service:
host: httpbin
當然,我們也可以寫成
host: httpbin.bookinfo.svc.cluster.local
通過 host 可以識別到對應的 Kubernetes Service,然後從 Service 對應的 Endpoints 中獲得所有 Pod 列表。
通過 Endpoints 獲得所有 Pod 之後,檢視每個 Pod 的描述資訊。當有一個請求到達時,根據 DestinationRule 中的標籤選擇器,選擇合適的 Pod 進行存取。
- name: v1
labels:
version: v1
istio-egressgateway 也是 Istio 中的一種元件,需要自行安裝。安裝 istio-egressgateway 命令:
helm install istio-egressgateway istio/gateway -n istio-system
在叢集中,如果 A 應用存取的地址屬於叢集中的應用,那麼 Istio 可以給這些請求注入各種行為,實現負載均衡和熔斷等。
可是,如果叢集內部要存取外部的一個服務時,需要設定存取地址,如 aaa.com,我們應該如何實現負載均衡和熔斷這些功能呢?
Istio ServiceEntry 是一種資源,允許將外部服務(即不在 Istio 服務網格中的服務)納入Istio服務網格。通過將外部服務新增到網格,可以使用 Istio 的流量管理和策略功能來控制與這些外部服務的互動。
以下是一個ServiceEntry範例,將外部HTTP服務 www.google.com
新增到Istio服務網格:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: google
spec:
hosts:
- www.google.com
addresses:
- 192.168.1.1
ports:
- number: 80
name: http
protocol: HTTP
location: MESH_EXTERNAL
resolution: DNS
endpoints:
- address: "www.google.com"
ports:
http: 80
locality: "us-west1/zone1"
exportTo:
- "*"
在此範例中,我們建立了一個名為httpbin-ext
的ServiceEntry資源。指定的主機為httpbin.org
,埠號為80,協定為HTTP。此外,我們將resolution
設定為DNS
,將location
設定為MESH_EXTERNAL
,表示該服務位於網格之外。
要將此ServiceEntry應用到叢集,請將其儲存到一個YAML檔案(例如:httpbin-ext.yaml
),然後執行以下命令:
kubectl apply -f httpbin-ext.yaml
現在,Istio 服務網格中的服務存取 www.google.com
時仍受Istio策略的控制。例如,可以為此 ServiceEntry 建立 VirtualService 以應用流量管理規則,或者為其建立 DestinationRule 以設定負載均衡和連線池設定。
spec
: 包含ServiceEntry的具體設定的物件。
hosts
: 一個包含要匯入的外部服務的主機名(FQDN)的列表。例如:["httpbin.org"]
。addresses
: (可選)與外部服務關聯的虛擬IP地址的列表。例如:["192.168.1.1"]
。number
: 埠號,例如:80。name
: 埠的名稱,例如:http
。protocol
: 使用的協定,例如:HTTP
、TCP
、HTTPS
等。location
: 服務的位置。可以是MESH_EXTERNAL
(表示服務在網格外部)或MESH_INTERNAL
(表示服務在網格內部,但不屬於任何已知服務)。resolution
: 用於確定服務範例地址的解析方法。可以是NONE
(預設值,表示不解析地址),STATIC
(表示使用addresses
欄位中的IP地址),DNS
(表示使用DNS解析主機名)或MESH_EXTERNAL
。address
: 端點的IP地址或主機名。ports
: 一個包含埠名稱和埠號的對映,例如:{"http": 8080}
。labels
: (可選)應用於端點的標籤。locality
: (可選)端點的地理位置,例如:us-west1/zone1
。exportTo
: (可選)一個包含名稱空間名稱的列表,指定可以存取此ServiceEntry的名稱空間。可以使用星號(*
)表示所有名稱空間。預設值為*
。subjectAltNames
: (可選)用於驗證伺服器證書主題替代名(SANs)的列表。讀者可以從官方檔案中瞭解更多:
https://istio.io/latest/zh/docs/tasks/traffic-management/egress/egress-control/