CD 之 Pull Mode 介紹: Keel
上篇文章中,我們探討了不同類型的部署架構,今天我們就針對最後一種 Pull 的方式來進行一個介紹,同時使用開源專案 keel 來展示一
下這種模式下的操作過程與結果
本文中的圖片都節錄自 Keel官網
介紹
Keel 的官網介紹如下
Keel - automated Kubernetes deployments for the rest of us
Keel 是一款 CD 部署的工具,其實作方式除了我們介紹的 Pull Mode 之外,他也支援 Push Mode 的方式,讓 Container Registry 主動通知 Keel 去進行自動部署。
下圖是一個最快理解 Keel 的運作流程,該圖片有五個步驟,分別是
- 修改程式碼推到 Github
- 透過 CI pipeline 來產生最後的 Container Image,並且把 Container Image 給推到遠方 Registry
- Container Registry 知道有新版出現後,透過 relay 的方式把 web hook 的資訊往下傳遞
- 當 Webhook 最終到達 Keel 的 Controller 後, Keel 根據設定來準備更新相關資源
- 將差異性更新到 Kubernetes 內
上述的運作方式跟我們前篇提到的 Pull-Mode 不太一樣,因為還是透過 webhook 的方式主動通知 Keel 去更新,但是 Keel 本身也有提供別的機制來實現不同的架構,如同其官方內的文章介紹
Polling
Since only the owners of docker registries can control webhooks - it's often convenient to use polling. Be aware that registries can be rate limited so it's a good practice to set up reasonable polling intervals. While configuration for each provider can be slightly different - each provider has to accept several polling parameters:
如圖上篇文章所說,不是每個 container registry 都能去控管 web hooks 的架構,我們等等的示範中會使用 docker registry 配上 Polling 的機制來實現這種稍微被動一點的更新
此外,相對於 Push mode, Pull 則是透過定期詢問的方式去確認有沒有新版本,因此更新的速度上可能會比 webhook 還來得慢一點。
下圖是比較完整的架構,用來敘述 Keel 整個專案的架構
整個架構圖非常簡單,首先右邊代表的是 Keel Controller 以及控管的 Kubernetes Cluster,其中可以 Keel 下方還有 Helm 的標誌,這意
味者 Keel 對於應用程式可以支援原生的 Yaml 也可以支援用 Helm 控管的應用程式
左邊有三個框架,最上面代表的是 KEEL 支援的 Kubernetes 版本,不論是官方原生, Rancher 或者 Openshift 都支援。
下面則是所支援的 Container Registry 版本,譬如是 Quay, Harbor, Docker 或是其他公有雲的 Cloud Registry。
最下面則是一些通知系統,包含 Slack, Mattermost, Hipchat 等,此外 keel 還可以支援審核機制,當要部署的時候會發通知到 slack 等系統,需要有人按下同意後,才會繼續執行後續的動作。
有更多的興趣可以參閱官方網站
安裝
安裝方面提供兩種做法,可以透過 helm
去安裝或是直接透過 kubectl
安裝原生 yaml 檔案
$ helm repo add keel https://charts.keel.sh
"keel" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "keel" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm upgrade --install keel --namespace=kube-system keel/keel
Release "keel" does not exist. Installing it now.
NAME: keel
LAST DEPLOYED: Sun Sep 13 03:28:06 2020
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. The keel is getting provisioned in your cluster. After a few minutes, you can run the following to verify.
To verify that keel has started, run:
kubectl --namespace=kube-system get pods -l "app=keel"
到這邊完畢我們就將 Keel Controller 安裝到 Kubernetes 叢集內了,接下來就來試試看如何使用 Keel 來完成自動部署
示範
接下來的示範流程如下
- 透過 Deployment 準備一個自己準備的 Container Image
- 讓 Keel 幫忙部署該應用程式
- 手動於別的畫面更新 Container Image
- 觀察 Keel 的 log 以及 Kubernetes 狀況,確認該 container 有更新
首先,因為 Keel 本身沒有額外的 CRD 去告訴 Keel 到底哪些應用程式想要被 Keel 控管,因此控制的方式就是在應用程式的 Yaml 內增加 label,然後 Keel 的 controller 就會去監聽所有有設定這些規則的應用程式,再根據應用程式的內容來決定如何更新
下面是一個簡單的 deployment 的範例,該範例中我們於 metadata.labels 裡面增加兩個關於 keel 的敘述
apiVersion: apps/v1
kind: Deployment
metadata:
name: ithome
namespace: default
labels:
name: "ithome"
keel.sh/policy: all
keel.sh/trigger: poll
spec:
replicas: 3
selector:
matchLabels:
app: ithome
template:
metadata:
name: ithome
labels:
app: ithome
spec:
containers:
- image: hwchiu/netutils:3.4.5
name: ithome
- keel.sh/policy:
這邊描述怎樣的 image tag 的變化是認可為有新版,keel 會希望image tag的版本都可以根據 SemVer 的方式使用 $major.$minor.$patch 來描述。 而今天我們使用
all
的含義是三者有任何一個版本更新,我們就會更新,預設會使用最新的版本。 - keel.sh/trigger 這邊描述我們不使用 webhook 的方式,而是改用去定期詢問遠方 image 是否有更新
接下來我們就來部署看看
$ kubectl apply -f deployment.yaml
$ kubectl get deployment ithome -o jsonpath='{.spec.template.spec.containers[0].image}'
hwchiu/netutils:3.4.5
接下來開啟其他視窗,嘗試部署一個全新的 image tag, 其版本必須大於 3.4.5,譬如我們使用 4.5.6 試試看
$ docekr push hwchiu/netutils:4.5.6
....
Successfully tagged hwchiu/netutils:4.5.6
The push refers to repository [docker.io/hwchiu/netutils]
de527d59ee7c: Layer already exists
0c98ba7dbe5c: Layer already exists
64d2e4aaa54c: Layer already exists
0d3833376c2f: Layer already exists
4a048ea09024: Layer already exists
b592b5433bbf: Layer already exists
4.5.6: digest: sha256:f2956ee6b5aafb43ec22aeeda10cfd20b92b3d01d9048908a25ef4430671b8a3 size: 1569
$ kubectl get deployment ithome -o jsonpath='{.spec.template.spec.containers[0].image}'
hwchiu/netutils:4.5.6
不久後就可以觀察到系統上的 image 已經被改變了,此時去觀察中間層的 replicaset,就可以看到有 4.5.6
的出現
$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
ithome-7d44545847 3 3 3 2m49s ithome hwchiu/netutils:4.5.6 app=ithome,pod-template-hash=7d44545847
ithome-7d5fb6757f 0 0 0 12m ithome hwchiu/netutils:3.4.5 app=ithome,pod-template-hash=7d5fb6757f
透過這樣的 Demo 過程,我們算是跑了一個基本的 Pull Mode 的更新,我們透過 Container Image 版本的更新來自動更新 Kubernetes 內部資源的狀態,這中間沒有牽扯到任何 CD Pipeline 的運作。
實際上這種運作模式後來也有一種更好的架構,稱為 GitOps,下篇開始我們就來認真學習一下 GitOps 的概念!