istio內置資源和sidecar注入初探

目錄

Gateway(gw)

VirtualService(vs)

DestinationRule(dr)

ServiceEntry(se)

sidecar注入以及流量劫持

sidecar注入過程

sidecar注入原理

sidecar注入結果


Gateway(gw)

istio中gateway資源可以將網格內部的服務暴露給網格外部的服務,供網格外部的服務調用,該資源描述了需要公開的端口、端口的協議類型、以及域名等。

下面是服務的gw資源配置文件示例。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

apiVersion: networking.istio.io/v1alpha3

kind: Gateway

metadata:

  name: mis-gateway-gateway

  namespace: lyl

spec:

  selector:

    istio: ingressgateway # use istio default controller

  servers:

  - port:

      number: 80

      name: http

      protocol: HTTP

    hosts:

    - "*"

 

selector標明瞭該gateway選擇用的pod,ingressgateway實際上是一個istio-proxy,這裏gateway用label關聯了istio的ingressgateway。

我們可以用命令查找出該pod:

kubectl get po -l istio=ingressgateway -n istio-system

我們查看該pod的配置,發現該pod有一個container,名稱爲istio-proxy,該服務負責從網格外轉發請求到網格內。

istio-proxy實際上是envoy + 管理envoy的父進程pilot-agent。

kubectl get po -l istio=ingressgateway -n istio-system -o json

VirtualService(vs)

virtualService用來與Gateway綁定,實現服務訪問路由控制、服務版本與流量的控制。

下面是服務的vs配置示例:

apiVersion: networking.istio.io/v1alpha3

kind: VirtualService

metadata:

  name: go-center-mis-gateway-vs

  namespace: lyl

spec:

  hosts:

  - "*"

  gateways:

  - mis-gateway-gateway

  http:

  - match:

    - uri:

        exact: /

    route:

    - destination:

        host: go-center-mis-gateway

        subset: v1

      weight: 80

    - destination:

        host: go-center-mis-gateway

        subset: v2

      weight: 20

  1. gateways表示與哪些gateway綁定,可以綁定多個gateway資源,這裏我們綁定了上面創建的gateway資源。
  2. match與route搭配可實現路由控制,上面是將path / 下的請求全部路由到兩個destination上。
  3. destination中描述了目標服務的具體信息,包含host服務域名、服務版本、版本權重等。
  4. virtual service與destination rule結合,可以實現服務版本的流量控制,新版本的灰度發佈可以根據這個來實現。

協議支持:

http協議流量規則:

DestinationRule(dr)

外部請求經過VirtualService的路由規則後,如果目標服務設置了dr,那麼dr配置的目標服務策略會生效。

下面是服務的dr配置示例:

apiVersion: networking.istio.io/v1alpha3

kind: DestinationRule

metadata:

  name: go-center-mis-gateway-dr

  namespace: lyl

spec:

  host: go-center-mis-gateway

  trafficPolicy:

    loadBalancer:

      simple: ROUND_ROBIN

  subsets:

  - name: v1

    labels:

      version: v1

  - name: v2

    labels:

      version: v2

  1. host是服務的域名
  2. trafficPolicy是對於服務pod的流量規則,比較重要的如loadBalancer、connectionPool、outlierDetection

    loadBalancer simple規則:

    http connectionPool規則:

    outlierDetection可實現異常點檢測與熔斷:

  3. subset描述了服務的子集,該子集由帶有標籤(version: v2)的pod組成,不同的子集也可以設置不同的trafficPolicy,如下面的例子,默認lb策略是least_conn,而v3版本則是輪詢策略。

    apiVersion: networking.istio.io/v1alpha3

    kind: DestinationRule

    metadata:

      name: bookinfo-ratings

    spec:

      host: ratings.prod.svc.cluster.local

      trafficPolicy:

        loadBalancer:

          simple: LEAST_CONN

      subsets:

      - name: testversion

        labels:

          version: v3

        trafficPolicy:

          loadBalancer:

            simple: ROUND_ROBIN

ServiceEntry(se)

功能:

  1. 將網格外的服務加到服務發現中,就像是網格內的服務一樣被治理(成爲k8s中的一個service),如網格外的mysql、redis等服務,或是部署在物理機上未加入網格內部的服務。

機制:

  1. 將ServiceEntry描述的service加到服務發現中,對這些服務的outbound流量進行攔截,從而進行治理。
  2. 當ServiceEntry描述的service有endpoint變化時,我們可以監聽其變化,利用k8s基建,創建或者刪除k8s該service的endpoint,由於istio的服務發現依賴於k8s,該變化會被istio pilot-discovery感知到,並通過xDs通知envoy。
  3. istio服務發現概覽:
  4. TODO:serviceEntry其他配置文件等待補充……

sidecar注入以及流量劫持

sidecar模式:

Sidecar 連接到父應用並且爲其添加擴展或者增強功能。

使用sidecar的優勢:

  • 將與應用業務邏輯無關的功能抽象到共同基礎設施,降低了微服務代碼的複雜度。
  • 因爲不再需要編寫相同的第三方組件配置文件和代碼,所以能夠降低微服務架構中的代碼重複度。
  • Sidecar 可獨立升級,降低應用程序代碼和底層平臺的耦合度。

sidecar注入過程

在創建namespace lyl時,我們使用了istio的自動注入:

kubectl label namespace lyl istio-injection=enabled --overwrite

注入以後,我們看下namespace的配置,多了一個label,istio-injection=enable

sidecar注入原理

sidecar注入依賴於Kubernetes 的准入控制器。

來自 Kubernetes 文檔:

准入控制器是一段代碼,會攔截 Kubernetes API Server 收到的請求,攔截髮生在認證和鑑權完成之後,對象進行持久化之前。可以定義兩種類型的 Admission webhook:Validating 和 Mutating。Validating 類型的 Webhook 可以根據自定義的准入策略決定是否拒絕請求;Mutating 類型的 Webhook 可以根據自定義配置來對請求進行編輯。

簡單來說,sidecar的注入是在api-server接收到deployment pod的請求之後,寫入etcd之前做的事情。

對於 sidecar 自動注入,Istio 依賴於 Mutating Admission Webhook。讓我們來看看 istio-sidecar-injector 中的配置詳情。

kubectl get mutatingwebhookconfiguration istio-sidecar-injector -o yaml

apiVersion: admissionregistration.k8s.io/v1beta1

kind: MutatingWebhookConfiguration

metadata:

  annotations:

    kubectl.kubernetes.io/last-applied-configuration: |

      {"apiVersion":"admissionregistration.k8s.io/v1beta1","kind":"MutatingWebhookConfiguration","metadata":{"annotations":{},"labels":{"app":"istio-sidecar-injector","chart":"sidecarInjectorWebhook-1.0.1","heritage":"Tiller","release":"istio-remote"},"name":"istio-sidecar-injector","namespace":""},"webhooks":[{"clientConfig":{"caBundle":"","service":{"name":"istio-sidecar-injector","namespace":"istio-system","path":"/inject"}},"failurePolicy":"Fail","name":"sidecar-injector.istio.io","namespaceSelector":{"matchLabels":{"istio-injection":"enabled"}},"rules":[{"apiGroups":[""],"apiVersions":["v1"],"operations":["CREATE"],"resources":["pods"]}]}]}

  creationTimestamp: 2018-12-10T08:40:15Z

  generation: 2

  labels:

    app: istio-sidecar-injector

    chart: sidecarInjectorWebhook-1.0.1

    heritage: Tiller

    release: istio-remote

  name: istio-sidecar-injector

  .....

webhooks:

- clientConfig:

    service:

      name: istio-sidecar-injector

      namespace: istio-system

      path: /inject

  name: sidecar-injector.istio.io

  namespaceSelector:

    matchLabels:

      istio-injection: enabled

  rules:

  - apiGroups:

    - ""

    apiVersions:

    - v1

    operations:

    - CREATE

    resources:

    - pods

在配置文件中,我們看到有namespaceSelector配置,matchLabels表明如果namespace滿足有label:istio-injection=enable(上面截圖可以看到我們的namespace lyl已經滿足這個條件),並且滿足下面列的rules:v1 version,且動作是pod的創建,那麼mutatingWebhook會執行istio-sidecar-injector這個service,給創建的pod注入配置。

sidecar注入結果

sidecar注入以後,查看服務啓動的pod信息

可以看到,每個pod都有兩個ready的容器,一個是我們的服務容器,另一個就是sidecar容器。

查看下第一個pod具體的配置信息:

kubectl get po $(kubectl get po -n lyl | grep v1 | awk '{print $1}') -n lyl -o json

 

 

發現有兩個containers,具體展開可以看到一個是我們自己服務的容器,第二個是istio-proxy容器,也就是sidecar容器,之前說到istio-proxy實際上是pilot-agent + envoy兩個父子進程,pilot負責管理envoy,所以實際上服務的sidecar就是envoy。

同時,在配置下方,我們還發現了另一個container,叫作istio-init container,這個init容器在pod初始化時創建,pod初始化完成就自動銷燬了,從配置的command中可以看出,init容器主要用來創建iptables規則。istio-iptables的代碼位於istio代碼倉庫的tools/istio-iptables目錄。

 

所以,Istio 給應用 Pod 注入的配置主要包括:

  • Init 容器 istio-init:用於 pod 中設置 iptables 端口轉發。
  • Sidecar 容器 istio-proxy:運行 sidecar 代理,即envoy。

iptables注入解析(以下iptables規則引用自這裏,本文不在詳述):

# 查看 NAT 表中規則配置的詳細信息。

$ iptables -t nat -L -v

# PREROUTING 鏈:用於目標地址轉換(DNAT),將所有入站 TCP 流量跳轉到 ISTIO_INBOUND 鏈上。

Chain PREROUTING (policy ACCEPT 2701 packets, 162K bytes)

 pkts bytes target     prot opt in     out     source               destination

 2701  162K ISTIO_INBOUND  tcp  --  any    any     anywhere             anywhere

 

# INPUT 鏈:處理輸入數據包,非 TCP 流量將繼續 OUTPUT 鏈。

Chain INPUT (policy ACCEPT 2701 packets, 162K bytes)

 pkts bytes target     prot opt in     out     source               destination

 

# OUTPUT 鏈:將所有出站數據包跳轉到 ISTIO_OUTPUT 鏈上。

Chain OUTPUT (policy ACCEPT 79 packets, 6761 bytes)

 pkts bytes target     prot opt in     out     source               destination

   15   900 ISTIO_OUTPUT  tcp  --  any    any     anywhere             anywhere

 

# POSTROUTING 鏈:所有數據包流出網卡時都要先進入POSTROUTING 鏈,內核根據數據包目的地判斷是否需要轉發出去,我們看到此處未做任何處理。

Chain POSTROUTING (policy ACCEPT 79 packets, 6761 bytes)

 pkts bytes target     prot opt in     out     source               destination

 

# ISTIO_INBOUND 鏈:將所有入站流量重定向到 ISTIO_IN_REDIRECT 鏈上,目的地爲 15090(mixer 使用)和 15020(Ingress gateway 使用,用於 Pilot 健康檢查)端口的流量除外,發送到以上兩個端口的流量將返回 iptables 規則鏈的調用點,即 PREROUTING 鏈的後繼 POSTROUTING。

Chain ISTIO_INBOUND (1 references)

 pkts bytes target     prot opt in     out     source               destination

    0     0 RETURN     tcp  --  any    any     anywhere             anywhere             tcp dpt:ssh

    2   120 RETURN     tcp  --  any    any     anywhere             anywhere             tcp dpt:15090

 2699  162K RETURN     tcp  --  any    any     anywhere             anywhere             tcp dpt:15020

    0     0 ISTIO_IN_REDIRECT  tcp  --  any    any     anywhere             anywhere

 

# ISTIO_IN_REDIRECT 鏈:將所有的入站流量跳轉到本地的 15006 端口,至此成功的攔截了流量到 sidecar 中。

Chain ISTIO_IN_REDIRECT (3 references)

 pkts bytes target     prot opt in     out     source               destination

    0     0 REDIRECT   tcp  --  any    any     anywhere             anywhere             redir ports 15006

 

# ISTIO_OUTPUT 鏈:選擇需要重定向到 Envoy(即本地) 的出站流量,所有非 localhost 的流量全部轉發到 ISTIO_REDIRECT。爲了避免流量在該 Pod 中無限循環,所有到 istio-proxy 用戶空間的流量都返回到它的調用點中的下一條規則,本例中即 OUTPUT 鏈,因爲跳出 ISTIO_OUTPUT 規則之後就進入下一條鏈 POSTROUTING。如果目的地非 localhost 就跳轉到 ISTIO_REDIRECT;如果流量是來自 istio-proxy 用戶空間的,那麼就跳出該鏈,返回它的調用鏈繼續執行下一條規則(OUTPUT 的下一條規則,無需對流量進行處理);所有的非 istio-proxy 用戶空間的目的地是 localhost 的流量就跳轉到 ISTIO_REDIRECT。

Chain ISTIO_OUTPUT (1 references)

 pkts bytes target     prot opt in     out     source               destination

    0     0 RETURN     all  --  any    lo      127.0.0.6            anywhere

    0     0 ISTIO_IN_REDIRECT  all  --  any    lo      anywhere            !localhost            owner UID match 1337

    0     0 RETURN     all  --  any    lo      anywhere             anywhere             ! owner UID match 1337

   15   900 RETURN     all  --  any    any     anywhere             anywhere             owner UID match 1337

    0     0 ISTIO_IN_REDIRECT  all  --  any    lo      anywhere            !localhost            owner GID match 1337

    0     0 RETURN     all  --  any    lo      anywhere             anywhere             ! owner GID match 1337

    0     0 RETURN     all  --  any    any     anywhere             anywhere             owner GID match 1337

    0     0 RETURN     all  --  any    any     anywhere             localhost

    0     0 ISTIO_REDIRECT  all  --  any    any     anywhere             anywhere

 

# ISTIO_REDIRECT 鏈:將所有流量重定向到 Sidecar(即本地) 的 15001 端口。

Chain ISTIO_REDIRECT (1 references)

 pkts bytes target     prot opt in     out     source               destination

    0     0 REDIRECT   tcp  --  any    any     anywhere             anywhere             redir ports 15001

 

 

 

參考資料:

https://jimmysong.io/blog/sidecar-injection-iptables-and-traffic-routing/

https://istio.io/zh/docs/reference/config/networking/destination-rule/#OutlierDetection

 

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