Istio 入門(七):出入口網關 - 負載均衡和熔斷等一系列功能

本教程已加入 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 類似的概念。

image-20230526194223740

image-20230526194154234

作爲一個應用,它需要對外開放一些端口,只有當流量經過這些端口時, istio-ingressgateway 纔會起作用。爲了在 Kubernetes 中暴露端口, istio-ingressgateway 還有一個 Service 對象。

image-20230526194139225

有了 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 指向自己的服務器。

image-20230515193213923

kubectl -n bookinfo apply -f httpbin_gw.yaml

現在,我們已經讓 istio-ingressgateway 幫我們關注 httpbin.s1.whuanle.cn 這個地址,如果有人訪問了 httpbin.s1.whuanle.cn,那麼這個流量將會流入到 httpbin-gateway。

image-20230515190518804

接下來我們將要爲 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

1683287785674

httpbin 是一個 http 測試程序,我們可以通過使用 /status/{狀態碼} 獲取對應的 http 請求狀態。

例如:

image-20230505200437890

image-20230505200444999

image-20230515193314909image-20230515193301641

如果我們不希望這個服務被外界訪問到,我們可以先把 /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 配置放通哪些路徑。

image-20230505201156220

如果需要全部放通,可以使用:

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 列表。

image-20230515194105645

1684151025350

通過 Endpoints 獲得所有 Pod 之後,查看每個 Pod 的描述信息。當有一個請求到達時,根據 DestinationRule 中的標籤選擇器,選擇合適的 Pod 進行訪問。

  - name: v1
    labels:
      version: v1

1684151265603

istio-egressgateway

istio-egressgateway 也是 Istio 中的一種組件,需要自行安裝。安裝 istio-egressgateway 命令:

helm install istio-egressgateway istio/gateway -n istio-system

在集羣中,如果 A 應用訪問的地址屬於集羣中的應用,那麼 Istio 可以給這些請求注入各種行爲,實現負載均衡和熔斷等。

可是,如果集羣內部要訪問外部的一個服務時,需要配置訪問地址,如 aaa.com,我們應該如何實現負載均衡和熔斷這些功能呢?

image-20230515195151940

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: 使用的協議,例如:HTTPTCPHTTPS等。
  • 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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章