本教程已加入 Istio 系列:https://istio.whuanle.cn
5,出入口網關
Istio 可以管理集羣的出入口流量,當客戶端訪問集羣內的應用時, Istio 可以將經過 istio-ingressgateway 的流量實現負載均衡和熔斷等一系列功能。
可是,如果集羣內的一個應用要訪問 google.com ,那麼我們可以給內部所有請求了 google.com 的流量設置負載均衡嗎?答案是可以,Istio 提供了 istio-egressgateway 實現這種功能。因爲 Pod 中的容器要訪問網絡時,會被 Envoy 攔截,Envoy 可以很容易地分析這些請求,然後通過一系列手段影響着請求的行爲。
在本章中,將會簡單說一下 istio-ingressgateway 和 istio-egressgateway。
istio-ingressgateway
入口網關指的是從外部經過 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
然後創建一個 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-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"]
。- ports: 一個描述外部服務使用的端口的列表。每個端口都有以下屬性:
number
: 端口號,例如:80。name
: 端口的名稱,例如:http
。protocol
: 使用的協議,例如:HTTP
、TCP
、HTTPS
等。
location
: 服務的位置。可以是MESH_EXTERNAL
(表示服務在網格外部)或MESH_INTERNAL
(表示服務在網格內部,但不屬於任何已知服務)。resolution
: 用於確定服務實例地址的解析方法。可以是NONE
(默認值,表示不解析地址),STATIC
(表示使用addresses
字段中的IP地址),DNS
(表示使用DNS解析主機名)或MESH_EXTERNAL
。- endpoints: (可選)外部服務的端點列表。每個端點都有以下屬性:
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/