1. 程式人生 > >Contour 學習筆記(一):使用 Contour 接管 Kubernetes 的南北流量

Contour 學習筆記(一):使用 Contour 接管 Kubernetes 的南北流量

> 原文連結:Contour 學習筆記(一):使用 Contour 接管 Kubernetes 的南北流量

在 Kubernetes 中執行大規模以 Web 為中心的工作負載,最關鍵的需求之一就是在 L7 層實現高效流暢的入口流量管理。自從第一批 Kubernetes Ingress Controller 開發完成以來,Envoy(由 Matt Klein 和 Lyft 團隊開發)已經成為雲原生生態系統中的新生力量。Envoy 之所以受到支援,因為它是一個 CNCF 託管的專案,與整個容器圈和雲原生架構有著天然的支援。

容器公司 Heptio 開源的專案 Contour 使用 Envoy

作為 Kubernetes 的 Ingress Controller 實現,為大家提供了一條新的 Kubernetes 外部負載均衡實現思路。

官方部落格介紹,Heptio Contour 可以為使用者提供以下好處:

  • 一種簡單的安裝機制來快速部署和整合 Envoy。
  • 與 Kubernetes 物件模型的整合。
  • Ingress 配置的動態更新,而無需重啟底層負載均衡器。
  • 專案成熟後,將允許使用 Envoy 一些強大的功能,如熔斷器、外掛式的處理器鏈,以及可觀測性和可除錯性,可以非常方便地對接監控系統。
  • IngressRoute 之間可以級聯,用來做藍綠部署非常方便。

下面我們就來試用一下。

1. 安裝步驟

Contour Ingress controller 由兩個元件組成:

  • Envoy : 提供高效能反向代理。
  • Contour : 充當 Envoy 的控制平面,為 Envoy 的路由配置提供統一的來源。

官方文件提供了三種部署方法:

  1. 通過 DaemonSet 來部署,每個節點上跑一個 Contour 例項(Contour 與 Envoy 在同一個 Pod 中)。
  2. 通過 Deployment 來部署,總共跑兩個 Contour 例項(Contour 與 Envoy 在同一個 Pod 中)。
  3. 通過 Deployment 來部署 Contour,總共跑兩個 Contour 例項;通過 DaemonSet 來部署 Envoy,每個節點上跑一個 Envoy 例項。

經過老夫目測,第三種方案比較妙,這樣可以讓 Contour 和 Envoy 這兩個元件解耦,可以分別按需對不同的元件進行擴充套件,具體的優勢如下:

  • Envoy 以 Daemonset 的形式執行,具有很強的擴充套件性,後續可通過 ipvskeepalived 等工具來實現其負載均衡和高可用。
  • Envoy 執行的網路模式是 hostNetwork,減少了額外的網路效能損耗。
  • Contour 與 Envoy 之間通過雙向認證的自簽名證書進行通訊,大大增強了安全性。
  • 升級 Contour 不需要重啟 Envoy。

聽起來好像不錯的樣子。

我們就採用第三種方案來部署,首先克隆官方倉庫,進入 manifest 清單目錄:

$ git clone https://github.com/heptio/contour
$ cd contour/examples/ds-hostnet-split

為了便於檢視 envoy 的配置,修改 03-envoy.yaml,將 envoy 的 admin-adress 設定為 0.0.0.0,並暴露 9001 埠:

...省略...
initContainers:
- args:
  - bootstrap
  - --admin-address=0.0.0.0
  - /config/contour.json
...省略...

將 Envoy Service 的型別改為 ClusterIP

$ cat 02-service-envoy.yaml
apiVersion: v1
kind: Service
metadata:
 name: envoy
 namespace: heptio-contour
 annotations:
   service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
 externalTrafficPolicy: Local
 ports:
 - port: 80
   name: http
   protocol: TCP
 - port: 443
   name: https
   protocol: TCP
 selector:
   app: envoy
 type: ClusterIP

部署:

$ kubectl apply ./

檢視狀態:

$ kubectl -n heptio-contour get pod
NAME                       READY   STATUS      RESTARTS   AGE
contour-767fd99989-27qjw   0/1     Running     0          21s
contour-767fd99989-kcjxz   0/1     Running     0          21s
contour-certgen-29nqs      0/1     Completed   0          21s
envoy-cnzvm                0/1     Running     0          21s
envoy-lb8mm                0/1     Running     0          21s
envoy-qzmt4                0/1     Running     0          21s

$ kubectl -n heptio-contour get job
NAME              COMPLETIONS   DURATION   AGE
contour-certgen   1/1           2s         4m42s

contour-certgen 是一個 Job,它會生成有效期為一年的 mTLS(雙向認證)證書,並將其掛載到 Contour 和 Envoy 的容器中。如果你想自定義證書,可以參考官方文件

> 如果你還沒有部署 Kubernetes 叢集怎麼辦?廢話,當然是用 sealos 啊!分分鐘搞起一個高可用叢集。

2. Ingress 測試

安裝結束後,我們就可以來測試 Ingress 了。在 examples/example-workload 目錄下包含一個示例應用,可以直接使用:

$ kubectl apply -f examples/example-workload/kuard-ingressroute.yaml

檢視建立好的資源:

$ kubectl get po,svc,ingressroute -l app=kuard
NAME                         READY   STATUS    RESTARTS   AGE
pod/kuard-67789b8754-5c4w7   1/1     Running   0          63s
pod/kuard-67789b8754-fpdfb   1/1     Running   0          63s
pod/kuard-67789b8754-fx9bn   1/1     Running   0          63s

NAME            TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kuard   ClusterIP   10.97.46.79   <none>        80/TCP    63s

NAME                                    FQDN          TLS SECRET   FIRST ROUTE   STATUS   STATUS DESCRIPTION
ingressroute.contour.heptio.com/kuard   kuard.local                /             valid    valid IngressRoute

將域名加入本地電腦的 hosts:

$ echo "$INGRESS_HOST kuard.local" &gt;&gt; /etc/hosts

其中 $INGRESS_HOST 是任意執行 Envoy 節點的 IP。

現在我們就可以在瀏覽器中輸入域名 kuard.local 訪問應用了:

3. Contour 工作原理

Contour 同時支援 Ingress 資源物件和 IngressRoute 資源物件(通過 CRD 建立),這些物件都是為進入叢集的請求提供路由規則的集合。這兩個物件的結構和實現方式有所不同,但它們的核心意圖是相同的,都是為進入叢集的請求提供路由規則。如不作特殊說明,後面當我們描述 “Ingress” 時,它將同時適用於 IngressIngressRoute 物件。

通常情況下,當 Envoy 配置了 CDS 的 endpoint 時,它會定期輪詢端點,然後將返回的 JSON 片段合併到其執行配置中。如果返回到 Envoy 的叢集配置代表當前的 Ingress 物件的集合,則可以將 Contour 視為從 Ingress 物件到 Envoy 叢集配置的轉換器。隨著 Ingress 物件的新增和刪除,Envoy 會動態新增並刪除相關配置,而無需不斷重新載入配置。

在實踐中,將 Ingress 物件轉換為 Envoy 配置更加微妙,需要將 Envoy 中的 xDS 配置(包括 CDSEDSRDS)對映到 Kubernetes 中。Contour 至少需要觀察 IngressServiceEndpoint 這幾個資源物件以構建這些服務的響應,它通過 client-gocache/informer 機制免費獲得這些 watchers。這些 watchers 提供新增,更新和刪除物件的邊緣觸發通知,也可以通過 watch API 在本地快取快取物件,以便後續查詢。

Contour 將收集到的這些物件處理為虛擬主機及其路由規則的有向非迴圈圖(DAG),這表明 Contour 將有權構建路由規則的頂級檢視,並將群集中的相應服務和TLS祕鑰連線在一起。一旦構建了這個新的資料結構,我們就可以輕鬆實現 IngressRoute 物件的驗證,授權和分發。改資料結構匯出的 png 圖片如下圖所示:

<center>![](https://oscimg.oschina.net/oscnet/5f97e86a7acfb149548de8a86779eb4f648.jpg)</center>

Envoy API 呼叫和 Kubernetes API 資源之間的對映關係如下:

  • CDS : 叢集發現服務。對映為 Kubernetes 中的 Service 以及一部分 Ingress 物件的 TLS 配置。

  • EDS : 服務發現服務。對映為 Kubernetes 中的 Endpoint。Envoy 使用 EDS 自動獲取 Cluster 成員,這與 Endpoint 物件中包含的資訊非常匹配。Envoy 使用 Contour 在 EDS 響應中返回的名稱查詢 EDS

  • RDS : 路由發現服務。對映為 Kubernetes 中的 Ingress。提供了虛擬主機名和字首路由資訊的 RDS 與 Ingress 匹配得更好。

4. 對映關係詳情

CDS

CDS 更像是 Kubernetes 中的 Service 資源,因為 Service 是具體 Endpoint(Pods)的抽象,Envoy Cluster 是指 Envoy 連線到的一組邏輯上相似的上游主機(參考下文的 RDS)。其中 TLS 配置也是 CDS 的一部分,而 Kubernetes 中的 TLS 資訊由 Ingress 提供,所以這部分之間的對映關係會有些複雜。

EDS

EDS 更像是 Kubernetes 中的 Endpoint 資源,這部分對映關係的實現最簡單。Contour 將 Endpoint 的響應物件轉換為 EDS 的 { address: [] } json 配置塊。

RDS

RDS 更像是 Kubernetes 中的 Ingress 資源。RDS 將字首,路徑或正則表示式之一路由到 Envoy 群集。Envoy 叢集的名稱可以從 Ingress 的 IngressSpec 的配置項中獲取(比如:namespace/serviceName_servicePort),因為這是一個選擇器,它會匹配 Service 物件被轉換後返回的 CDS 物件。

5. Contour 架構分析

Contour Ingress controller 由兩個元件組成:

  • Envoy : 提供高效能反向代理。
  • Contour : 充當 Envoy 的控制平面,為 Envoy 的路由配置提供統一的來源。

以本文的部署方式為例,在 Envoy 的 Pod 初始化期間,Contour 作為 Init 容器執行,並將 bootstrap(初始化)配置寫入一個 temporary volume。該 Volume 被傳遞給 Envoy 容器並告訴 Envoy 將另一個 Deployment 中的 Contour 容器視為控制平面。

初始化完成後,Envoy 容器啟動,檢索 Contour 寫入的 bootstrap 配置,並開始輪詢 Contour 以熱更新配置。如果控制平面無法訪問,Envoy 將會進行優雅重試。

Contour 相當於 Kubernetes API 的客戶端。它監視 IngressServiceEndpoint 物件,並通過將其物件快取轉換為相關的 JSON 欄位來充當其 Envoy 的控制平面。

從 Kubernetes 到 Contour 的資訊轉換是通過 SharedInformer 框架 watching API 來完成的;而從 Contour 到 Envoy 的資訊轉換是通過 Envoy 定期輪詢來實現的。

6. IngressRoute 介紹

Ingress 物件從 Kubernetes 1.1 版本開始被引進,用來描述進入叢集的請求的 HTTP 路由規則。但迄今為止 Ingress 物件還停留在 beta 階段,不同的 Ingress Controller 外掛為了新增 HTTP 路由的額外屬性,只能通過新增大量的 annotation 來實現,而且每個外掛的 annotation 都不一樣,非常混亂。

IngressRoute CRD 的目標就是擴充套件 Ingress API 的功能,以便提供更豐富的使用者體驗以及解決原始設計中的缺點。

**目前 Contour 是唯一支援 IngressRoute CRD 的 Kubernetes Ingress Controller。**下面就來看看它與 Ingress 相比的優點:

  • 安全地支援多團隊 Kubernetes 叢集,能夠限制哪些名稱空間可以配置虛擬主機和 TLS 憑據。
  • 允許將路徑或域名的路由配置分發給另一個名稱空間。
  • 接受單個路由中的多個服務,並對它們之間的流量進行負載均衡。
  • 無需通過新增 annotation 就可以定義服務權重和負載均衡策略。
  • 在建立時驗證 IngressRoute 物件,並在建立後報告驗證是否有效。

從 Ingress 到 IngressRoute

一個基本的 Ingress 物件如下所示:

# ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: basic
spec:
  rules:
  - host: foo-basic.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80

這個 Ingress 物件名為 basic,它將傳入的 HTTP 流量路由到標頭檔案中 Host: 欄位值為 foo-basic.bar.com 且埠為 80 的 s1 服務。該路由規則通過 IngressRoute 來實現如下:

# ingressroute.yaml
apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
  name: basic
spec:
  virtualhost:
    fqdn: foo-basic.bar.com
  routes:
    - match: /
      services:
        - name: s1
          port: 80

對應關係很簡單,我就不再詳細介紹了,更多功能配置可以參考官方倉庫的文件:IngressRoute

7. Envoy 初始配置檔案

Contour 會根據啟動引數和 K8S API Server 中的配置資訊生成 Envoy 的初始配置檔案,可以使用下面的命令將 Envoy Pod 中的配置檔案匯出來檢視其中的內容:

$ kubectl -n heptio-contour exec envoy-lb8mm -- cat /config/envoy.json &gt; envoy.json

開啟網站 https://www.bejson.com/jsonviewernew/,將配置檔案內容複製貼上進去,可以看到配置檔案的結構如圖所示:

其中各個配置節點的內容如下:

Dynamic_resources

配置動態資源,這裡配置了 LDS 和 RDS 伺服器。

"dynamic_resources": {
  "lds_config": {
    "api_config_source": {
      "api_type": "GRPC",
      "grpc_services": [
        {
          "envoy_grpc": {
            "cluster_name": "contour"
          }
        }
      ]
    }
  },
  "cds_config": {
    "api_config_source": {
      "api_type": "GRPC",
      "grpc_services": [
        {
          "envoy_grpc": {
            "cluster_name": "contour"
          }
        }
      ]
    }
  }
}

Static_resources

配置靜態資源,包括了 contourservice-stats 兩個 cluster,其中 contour cluster 對應前面 dynamic_resources 中的 LDS 和 RDS 配置,指明瞭 Envoy 用於獲取動態資源的伺服器地址。

"static_resources": {
  "clusters": [
    {
      "name": "contour",
      "alt_stat_name": "heptio-contour_contour_8001",
      "type": "STRICT_DNS",
      "connect_timeout": "5s",
      "load_assignment": {
        "cluster_name": "contour",
        "endpoints": [
          {
            "lb_endpoints": [
              {
                "endpoint": {
                  "address": {
                    "socket_address": {
                      "address": "contour",
                      "port_value": 8001
                    }
                  }
                }
              }
            ]
          }
        ]
      },
      "circuit_breakers": {
        "thresholds": [
          {
            "priority": "HIGH",
            "max_connections": 100000,
            "max_pending_requests": 100000,
            "max_requests": 60000000,
            "max_retries": 50
          },
          {
            "max_connections": 100000,
            "max_pending_requests": 100000,
            "max_requests": 60000000,
            "max_retries": 50
          }
        ]
      },
      "tls_context": {
        "common_tls_context": {
          "tls_certificates": [
            {
              "certificate_chain": {
                "filename": "/certs/tls.crt"
              },
              "private_key": {
                "filename": "/certs/tls.key"
              }
            }
          ],
          "validation_context": {
            "trusted_ca": {
              "filename": "/ca/cacert.pem"
            },
            "verify_subject_alt_name": [
              "contour"
            ]
          }
        }
      },
      "http2_protocol_options": {}
    },
    {
      "name": "service-stats",
      "alt_stat_name": "heptio-contour_service-stats_9001",
      "type": "LOGICAL_DNS",
      "connect_timeout": "0.250s",
      "load_assignment": {
        "cluster_name": "service-stats",
        "endpoints": [
          {
            "lb_endpoints": [
              {
                "endpoint": {
                  "address": {
                    "socket_address": {
                      "address": "0.0.0.0",
                      "port_value": 9001
                    }
                  }
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

Admin

配置 Envoy 的日誌路徑以及管理埠。

"admin": {
  "access_log_path": "/dev/null",
  "address": {
    "socket_address": {
      "address": "0.0.0.0",
      "port_value": 9001
    }
  }
}

結合 Envoy 的初始化配置檔案和第 5 節的分析,我們可以大致看到 Contour 通過 Envoy 來實現南北流量管理的基本原理。即控制平面將 xDS server 資訊通過 static resource 的方式配置到 Envoy 的初始化配置檔案中,Envoy 啟動後通過 xDS server 獲取到 dynamic resource,包括叢集中的 service 資訊及路由規則。

Envoy 配置初始化流程:

  1. Envoy initContainer 根據啟動引數和 K8S API Server 中的配置資訊生成 Envoy 的初始配置檔案 envoy.json,該檔案告訴 Envoy 從 xDS server 中獲取動態配置資訊,並配置了 xDS server 的地址資訊,即控制平面的 Contour
  2. Envoy 使用配置檔案 envoy.json 啟動。
  3. Envoy 根據獲取到的動態配置啟動 Listener,並根據 Listener 的配置,結合 Route 和 Cluster 對進入的流量進行處理。

8. IngressRoute 配置對映

通過上節的分析我們知道,Envoy 中實際生效的配置是由初始化配置檔案中的靜態配置和從 Contour 獲取的動態配置一起組成的,我們可以通過 Envoy 的管理介面來獲取 Envoy 的完整配置,先開啟 Envoy 的管理介面:

然後點選 config_dump,就能看到 Envoy 的完整配置:

我們在第二節建立了一個 ingressroute,現在來看看它是怎麼對映到 Envoy 的配置檔案中的。你可以到 config_dump 中查詢相關配置,但還有更好的辦法,我們可以通過 Contour 的命令列工具直接呼叫 Contour 的 xDS gRPC 介面來分別檢視 Envoy 的 Listener、Route、Cluster 和 Endpoint 配置。

Contour 總共有兩個例項,通過選舉來實現高可用,被選中的例項作為 leader 來對外提供服務。

$ kubectl -n heptio-contour get pod -l app=contour

NAME                       READY   STATUS    RESTARTS   AGE
contour-767fd99989-27qjw   1/1     Running   0          14h
contour-767fd99989-kcjxz   0/1     Running   0          14h

看看哪個是 leader:

可以看到該例項不是 leader,我們到另一個例項中去檢視 Envoy xDS 配置。

Listener

Envoy 採用 listener 來接收並處理 downstream 發過來的請求,listener 的處理邏輯是外掛式的,可以通過配置不同的 filter 來插入不同的處理邏輯。Listener 可以繫結到 IP Socket 或者 Unix Domain Socket 上,也可以不繫結到一個具體的埠上,而是接收從其他 listener 轉發來的資料。

Listener 的配置可以通過下面的命令檢視:

$ kubectl -n heptio-contour exec -it contour-767fd99989-27qjw -- contour cli --cafile=/ca/cacert.pem --cert-file=/certs/tls.crt --key-file=/certs/tls.key lds

可以看到 Listener 被繫結到了 80 埠上,同時通過 RDS 配置了一個路由規則 ingress_http,在路由規則中再根據不同的請求目的地對請求進行處理。

Route

Route 用來配置 Envoy 的路由規則,根據 host 來對請求進行路由分發。

Route 的配置可以通過下面的命令檢視:

$ kubectl -n heptio-contour exec -it contour-767fd99989-27qjw -- contour cli --cafile=/ca/cacert.pem --cert-file=/certs/tls.crt --key-file=/certs/tls.key rds

上面是 ingress_http 的路由配置,對應了兩個 virtual host,其中一個是預設路由(圖中省略),上面展示的是 kuard 的路由,對應到 Cluster default/kuard/80/da39a3ee5e。其中 domains: "kuard.local:*" 表示允許訪問的域名為 kuard.local,埠可以是任意值。

Cluster

Cluster 是一個服務叢集,Cluster 中包含一個到多個 endpoint,每個 endpoint 都可以提供服務,Envoy 根據負載均衡演算法將請求傳送到這些 endpoint 中。

Cluster 的配置可以通過下面的命令檢視:

$ kubectl -n heptio-contour exec -it contour-767fd99989-27qjw -- contour cli --cafile=/ca/cacert.pem --cert-file=/certs/tls.crt --key-file=/certs/tls.key cds

cluster_name: "contour" 表示通過 xDS 介面從 contour 控制平面動態獲取 Endpoint 資訊。獲取到的 Endpoint 是 default/kuard

Endpoint

Endpoint 就對應到 Kubernetes 中的 Endpoint 資源,對應的即是 Pod 的 IP+Port

Cluster 的配置可以通過下面的命令檢視:

$ kubectl -n heptio-contour exec -it contour-767fd99989-27qjw -- contour cli --cafile=/ca/cacert.pem --cert-file=/certs/tls.crt --key-file=/certs/tls.key eds|grep "default/kuard" -A 34 -B 2

驗證一下:

$ kubectl get ep -l app=kuard

NAME    ENDPOINTS                                                     AGE
kuard   100.118.117.18:8080,100.119.55.150:8080,100.91.147.204:8080   17h

9. 對接監控

Contour 和 Envoy 都暴露一些監控指標可以被 Prometheus 抓取,官方也提供了 Prometheus 和 Grafana 的部署模板,但一般情況下我們都會有自己的監控系統,比如 prometheus-operator,只需要將官方的 Grafana 模板匯入自己的 Grafana 中就可以了,後續會探討詳細步驟。

Envoy Metrics

Envoy 預設通過 admin 介面暴露監控指標,為了避免暴露 admin 介面,Contour 建立了一個靜態 Listener,只將訪問路徑為 /stats 的流量轉發到 service-stats Cluster,即 admin 介面,其他所有請求一律拒絕訪問。

> 本文只是為了方便檢視,才將 admin 介面的 IP 改為 0.0.0.0,生產環境建議不要改,預設值為 127.0.0.1

所以 Envoy 在 8002 埠暴露監控指標,路徑為 /stats/prometheus

Contour Metrics

Contour 在 8000 埠上暴露監控指標,路徑為 /metrics。包含以下監控指標:

  • contour_ingressroute_total (gauge) : IngressRoute 的總數量,包括狀態為 Valid / Invalid / Orphaned 的 IngressRoute。
  • contour_ingressroute_orphaned_total (gauge) : 狀態為 Orphaned 的 IngressRoute 數量。
  • contour_ingressroute_root_total (gauge) : Root IngressRoute 的數量(每個 vhost 只有一個 Root IngressRoute)。
  • contour_ingressroute_valid_total (gauge) : 狀態為 Valid 的 IngressRoute 數量。
  • contour_ingressroute_invalid_total (gauge) : 狀態為 Invalid 的 IngressRoute 數量。
  • contour_ingressroute_dagrebuild_timestamp (gauge) : 最近一次重建 DAG 的時間戳。

下面就來教大家怎麼將 Contour 接入 Prometheus-Operator,對 Prometheus-Operator 不熟的同學,推薦看一下張館長的這篇文章:全手動部署prometheus-operator監控Kubernetes叢集遇到的坑

RBAC 授權

為了讓 Prometheus 能夠 list 其他 namespace 中的 pod,我們需要賦予它相應的許可權,首先進入 kube-prometheus 專案的 manifests 目錄:

$ cd kube-prometheus/manifests

$ ll *SpecificNamespace*
4 -rw-r--r-- 1 root root  988 8月  27 05:22 prometheus-roleBindingSpecificNamespaces.yaml
4 -rw-r--r-- 1 root root 1078 8月  27 05:15 prometheus-roleSpecificNamespaces.yaml

修改 prometheus-roleSpecificNamespaces.yaml,向其中新增如下的 Role:

- apiVersion: rbac.authorization.k8s.io/v1
  kind: Role
  metadata:
    name: prometheus-k8s
    namespace: heptio-contour
  rules:
  - apiGroups:
    - ""
    resources:
    - services
    - endpoints
    - pods
    verbs:
    - get
    - list
    - watch

修改 prometheus-roleBindingSpecificNamespaces.yaml,向其中新增如下的 RoleBinding:

- apiVersion: rbac.authorization.k8s.io/v1
  kind: RoleBinding
  metadata:
    name: prometheus-k8s
    namespace: heptio-contour
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: prometheus-k8s
  subjects:
  - kind: ServiceAccount
    name: prometheus-k8s
    namespace: monitoring

然後建立相應的 RoleRoleBinding

$ kubectl apply -f prometheus-roleSpecificNamespaces.yaml
$ kubectl apply -f prometheus-roleBindingSpecificNamespaces.yaml

修改 Contour manifest 檔案

Prometheus 監控的物件被叫做 Target,Target 通過 Cluster 中的 Endpoint 資源來定義,每個監控物件都有一個對應的 Endpoint。而 ServiceMonitor 是 Target 的抽象,ServiceMonitor 通過標籤來找到對應的 Endpoint,然後將相應的 Target 新增到 Prometheus 的監控列表中。

預設情況下 Contour 的 Service 是沒有打標籤的,所以我們需要修改 yaml 檔案,加上相應的標籤。首先修改 Contour Deployment 的 yaml 檔案:

# 03-contour.yaml
ports:
- containerPort: 8001
  name: xds
  protocol: TCP
- containerPort: 8000
  name: http-metrics # 將 name 改為 http-metrics
  protocol: TCP

再修改 Contour Service 的 yaml 檔案:

# 02-service-envoy.yaml
ports:
- port: 80
  name: http
  protocol: TCP
- port: 443
  name: https
  protocol: TCP
# 新增新埠
- port: 8002
  name: http-metrics
  protocol: TCP

Envoy 類似,先修改 Envoy Deployment 的 yaml 檔案:

# 03-envoy.yaml
ports:
- containerPort: 80
  hostPort: 80
  name: http
  protocol: TCP
- containerPort: 443
  hostPort: 443
  name: https
  protocol: TCP
# 新增新埠
- containerPort: 8002
  hostPort: 8002
  name: http-metrics
  protocol: TCP

再修改 Envoy Service 的 yaml 檔案:

# 02-service-envoy.yaml
ports:
- port: 80
  name: http
  protocol: TCP
- port: 443
  name: https
  protocol: TCP
# 新增新埠
- port: 8002
  name: http-metrics
  protocol: TCP

最後重新 apply 一下:

# 在 contour/examples/ds-hostnet-split 目錄下
$ kubectl apply -f ./

建立 ServiceMonitor

接下來就是建立相應的 ServiceMonitor 來抓取指標資料,沒什麼好說的,自己看 yaml 檔案:

$ cat prometheus-serviceMonitorContour.yaml

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app: contour
  name: contour
  namespace: monitoring
spec:
  endpoints:
  - interval: 30s
    port: http-metrics
  jobLabel: app
  namespaceSelector:
    matchNames:
    - heptio-contour
  selector:
    matchLabels:
      app: contour
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app: envoy
  name: envoy
  namespace: monitoring
spec:
  endpoints:
  - interval: 30s
    path: /stats/prometheus
    port: http-metrics
  namespaceSelector:
    matchNames:
    - heptio-contour
  selector:
    matchLabels:
      app: envoy

建立 IngressRoute

為了檢視 PrometheusGrafana 的 Dashboard,我們需要為它們建立相應的 IngressRoute,yaml 檔案內容如下:

# ingressroute-prometheus.yaml
apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
  labels:
    app: grafana
  name: grafana
  namespace: monitoring
spec:
  virtualhost:
    fqdn: grafana.sealos.io
  routes:
    - match: /
      services:
        - name: grafana
          port: 3000
---
apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
  labels:
    app: prometheus
  name: prometheus
  namespace: monitoring
spec:
  virtualhost:
    fqdn: prometheus.sealos.io
  routes:
    - match: /
      services:
        - name: prometheus-k8s
          port: 9090

直接 apply:

$ kubectl apply -f ingressroute-prometheus.yaml

將域名寫入本地電腦的 hosts 中:

$ echo "$INGRESS_HOST grafana.sealos.io" &gt;&gt; /etc/hosts
$ echo "$INGRESS_HOST prometheus.sealos.io" &gt;&gt; /etc/hosts

其中 $INGRESS_HOST 是任意執行 Envoy 節點的 IP。

現在我們可以在瀏覽器中輸入域名 prometheus.sealos.io 來檢視 Prometheus Target 狀態。

可以看到這兩個 Target 已經被抓取到了。

匯入 Grafana 模板

前面提到 Contour 官方倉庫中提供了 Grafana Dashboard 模板,現在我們要做的事就是把這個模板匯入到自己的 Grafana 中。官方的 Grafana Dashboard 模板定義在 contour/examples/grafana 目錄下的 ConfigMap 檔案中,可以先把它匯出來:

# 假設 contour 專案在你的 $HOME 目錄
$ sed '/---/,$d' ~/contour/examples/grafana/02-grafana-configmap.yaml \
  sed 's/grafana-dashs/grafana-dashboard-contour/' \
  sed 's/contour-monitoring/monitoring/' \
  sed 's/kubernetes_pod_name/pod/g' \
  sed 's/ingress_http_update/update/g' \
  kubectl apply -f -
  
configmap/grafana-dashboard-contour created

建立了 ConfigMap 後,還要再掛載到 Grafana 的 Dashboard 中,所以需要修改 Grafana Deployment 的 yaml 檔案:

# ~/kube-prometheus/manifests/grafana-deployment.yaml
        volumeMounts:
        - mountPath: /var/lib/grafana
          name: grafana-storage
          readOnly: false
        ...省略...
        # 新增掛載
        - mountPath: /grafana-dashboard-definitions/0/contour
          name: grafana-dashboard-contour
          readOnly: false
        ...省略...
      volumes:
      - emptyDir: {}
        name: grafana-storage
      ...省略...
      # 新增 ConfigMap
      - configMap:
          name: grafana-dashboard-contour
        name: grafana-dashboard-contour

重新 apply 一下:

$ kubectl apply -f grafana-deployment.yaml

現在在瀏覽器中輸入域名 grafana.sealos.io,就可以看到 Contour 和 Envoy 的 Dashboard 了。

對接監控到這裡就結束了,剩下的大家可以自己去探索,總體來說難度還是稍微有點大,希望我的細心講解能夠幫助到你。

微信公眾號

掃一掃下面的二維碼關注微信公眾號,在公眾號中回覆◉加群◉即可加入我們的雲原生交流群,和孫巨集亮、張館長、陽明等大佬一起探討雲原生技術