Build Kuberntes GRPC Health Probe with Pack
在 Kubernetes Pod 完整的生命周期包含了三個部份: Iinit container Pod Hook 健康檢查。這三部都會影響到 Pod 的生命周期,而本篇文章說明如何使用 pack 打包 grpc-health-probe 來支援 GRPC 健康檢查
Kubernetes livenessProbe & readinessProbe
Configure Liveness, Readiness and Startup Probes | Kubernetes
在 Kubernetes cluster 中我們可以通過配置 livenessProbe 及 readinessProbe 二個探針來影響容器的生命周期
livenessProbe: 簡單的來說就是 Kubectl 通過livenessProbe來判斷容器是否存活 (Running),如果 livenessProbe 探針偵測到容器不健康,Kubectl 就會刪除容器,並依據容器的重啟策略來處理,如果容器不包含 livenessProbe 探針,Kubectl 預設就會認定 livenessProbe 探針回傳值永遠為 SuccessreadinessProbe: 簡單的來說就是 Kubectl 通過livenessProbe來判斷容器的可用性 (Ready),只有 Pod 下面所有容器的狀態都是就緒時,Kubectl 才會認定該 Pod 已經處於可工作狀態。如果該 Pod 執行過期中 Ready 狀態變成 False,系統會將其從 Service 的後端 Endpoints 列表中移除,等待 Pod Ready 狀態再度成為 True 時加為 Service Endpoints 列表,這樣可以確認流量不會被導至不可用的 Pod
在配置 livenessProbe 及 readinessProbe 都有三種指定方式
ExecAction: 在容器中執行指令,回傳值為 0 表示健康TCPSocketAction: 透過容器的 IP 及 Port 進行檢查,如果可以建立 TCP 連線表示健康HTTPGetAction: 透過容器的 IP 及 Port 進行 HTTP GET 檢查,如果回傳狀態碼介於 200 - 400 表示健康
Health checking gRPC servers on Kubernetes

本篇文章因為要檢查 GRPC 服務是否健康,則屬於第一種 ExecAction 的範籌。Health checking gRPC servers on Kubernetes | Kubernetes 文章也說明如何使用 grpc-health-probe 工具來檢查 GRPC 是否健康
在 Pod 中我們可以配置 readinessProbe 及 livenessProbe
| |
在 exec ommand 中 grpc_health_probe 的執行檔是 /layers/cage1016_github-assets-cnb/github-assets/bin/grpc_health_probe 而非 grpc-health-probe 中看到的 /bin/grpc_health_probe 則是本篇的重點,我們慢慢說明
GPRC Server 健康檢查準備
| |
在要使用 grpc_health_probe 來檢查 GRCP 狀態是否健康,在 Server 端也需要進行一些配合,實作二個方法 Check 及 Watch
| |
我們直接使用 google.golang.org/grpc/health 提供的方法進行配置就可以快速完成 GRPC Server 端的準備工具,詳細的程式碼可以至 cage1016/ms-demo/cmd/add/main.go#L76-L77 及 cage1016/ms-demo/cmd/add/main.go#L190-L192
GPRC client 健康檢查準備
| |
在 local 的部份可以下載 grpc_health_probe 進行測試
建構 Container Image
本篇文章的重點就是如何使用
Pack來建構含有grpc_health_probe功能的 container image
方法一 Dockerfile
| |
在建構 Container image 時下載 grpc_health_probe 執行檔至 /bin/grpc_health_probe,所以在 Kubernetes Pod livenessProbe 及 readinessProbe 中的 command 才會是 command: ["/grpc_health_probe", "-addr=:5000"]
在之前的文章
都有分享使用 Pack 來建構 container image。那我們如何使用 Pack 提供的方式在建構 container image 時如同寫 Dockerfile 去下載我們所需的 grpc_health_probe 檔案呢?
Github Asset Buildpack
cage1016/github-assets-cnb: A Cloud Native Buildpack that Download Github Assets
buildpack cage1016/[email protected] 提供了一個簡易的方式讓你透過 pack 建構 container image 時動態下載所需的 Github Assets,在這一次的使用情境也派上了用場
建立一個
project.toml並配置 buildpackcage1016/github-assets-cnb所需的參數repo: Github Repoasset: Github Repo asset nametag: Release tag name, default set to “latest”token_env: (optional), Please assign ENV name for private repodestination: download asset destination path to,bin/<your-asset>forapplication/x-executableassetstrip_components:x-tar,gzip,x-zxsuuport StripComponents feature.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23cat <<EOF >> project.toml # assign token [[build.env]] name = "APITEST_TOOLCHAIN_TOKEN" value = "<github-token>" [[metadata.githubassets]] repo = "kkdai/youtube" asset = "youtubedr_2.7.0_linux_arm64.tar.gz" destination = "bin" [[metadata.githubassets]] repo = "qeek-dev/apitest-toolchain" token_env = "APITEST_TOOLCHAIN_TOKEN" asset = "apitest-toolchain-linux-amd64" destination = "bin/apitest-toolchain" tag = "v0.1.0" [[metadata.githubassets]] repo = "stedolan/jq" asset = "jq-linux64" destination = "bin/jq" EOF明確的指定所需的 buildpack 給
Pack指令。一般來說,Pack 會跟據 builder 中的配置自動偵測目標目錄下需要載入那幾個 buildpacksbuildpacks/builder.toml at main · GoogleCloudPlatform/buildpacks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25###### # Go # ###### [[order]] [[order.group]] id = "google.go.runtime" [[order.group]] id = "google.go.functions-framework" [[order.group]] id = "google.go.build" [[order.group]] id = "google.config.entrypoint" optional = true [[order.group]] id = "google.go.clear_source" optional = true [[order.group]] id = "google.utils.label"以 GoogleCloudPlatform/buildpacks builder.toml 所定義的來說,針對 Golang 語言定義了 6 個 buildpack,而這些 buildpack 也會在 builder 動態偵測目標目錄所需,並不是 Golang 就一定是 6 個
1 2 3 4 5 6 7 8 9 10 11 12 13 14... Status: Image is up to date for gcr.io/buildpacks/gcp/run:v1 ===> DETECTING 3 of 6 buildpacks participating google.go.runtime 0.9.1 google.go.build 0.9.0 google.utils.label 0.0.1 ===> ANALYZING ===> RESTORING ===> BUILDING === Go - Runtime ([email protected]) === Using runtime version from go.mod: 1.14 Installing Go v1.14 ...我們可以看到使用
gcr.io/buildpacks/builder:v1作為 builder 對 Golang 言語基本上就會載入 3 個 buildpack,google.go.runtimegoogle.go.buildgoogle.utils.label最後因為我們沒有客製自己的 builder,所以必需明確指定 buildpack,加上下載 Github Asset 用的
cage1016/github-assets-cnb,原來google.go.runtimegoogle.go.buildgoogle.utils.label共記 4 個在
project.toml增加明確指定所需要的 4 個 buildpack 及 Github Asset 相關的 metadata1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22cat <<EOF >> project.toml [[build.buildpacks]] id = "google.go.runtime" version = "0.9.1" [[build.buildpacks]] id = "google.go.build" version = "0.9.0" [[build.buildpacks]] id = "google.utils.label" version = "0.0.1" [[metadata.githubassets]] repo = "grpc-ecosystem/grpc-health-probe" asset = "grpc_health_probe-linux-amd64" destination = "bin/grpc_health_probe" [[build.buildpacks]] id = "cage1016/github-assets-cnb" version = "2.1.1" EOF1 2 3pack build aa -B gcr.io/buildpacks/builder:v1 \ -d=project.toml \ --env GOOGLE_BUILDABLE=cmd/add/main.go我們可以看到
DETECTING的階段有正確偵測到我們明確指定的 4 個 buildpack,並在BUILDING階段也有正確下載 Github grpc-ecosystem/grpc-health-probe asset 至 container image 中
grpc-health-probe asset container image 而依照
cage1016/github-assets-cnb中實作 buildpack sepc 所提供的目錄為/layers/cage1016_github-assets-cnb/grpc-ecosystem_grpc-health-prob/bin/grpc_health_probe如圖所示,而這個路徑也是我們在 Kubernetes Pod 在livenessProbe及readinessProbe探針指令執行檔所在基本上二種方式的結果都是一樣的,就看你喜歡那一種
心得
在 Dockerfile 中使用 wget 動態去下載所需要的檔案算是一種常規的作法。反之在 buildapck 的架構之下要下載一個檔案卻有一點複雜,也是常常有需要下載 Github Assets 的剛性需求,特別寫了一個符合 Cloud Native Buildpack 的 cage1016/github-assets-cnb buildpack 來滿足這個需求,當這一個生態越來越豐富時,就會慢慢感覺像是在疊責木一樣
如同 cage1016/ms-demo 這個 gokit microserives demo 一樣,Add 及 Tictac 服務基本上都改用 pack 來建構 container image,為了在 Kubernetes Pod 新增 livenessProbe 及 readinessProbe 探針並使用 grpc_health_probe 來檢查 GRPC 服務的健康狀況,其實就是新增了 project.toml
| |
及
| |
剩下的都不用動,Pack 就會操作 builder 按照所載入的 buildpack 完成對應的動作。慢慢體會這種抽換的方便性

