自动替换 Kubernetes 镜像
來源:云原生指北
作者:Addo Zhang
最近萌生了個想法,維護一個后網絡友好的倉庫鏡像,在 Pod 創建時將鏡像倉庫切換到自維護的倉庫,從自維護的倉庫拉取鏡像。
前幾天體驗了極狐Gitlab 的容器鏡像庫,便是為這個想法做的準備。當然其他的云廠商也有提供針對個人版的免費鏡像倉庫和企業版倉庫。
正好?Pipy 作為策略引擎,非常適合實現這種策略的執行。
實現思路
Admission Webhook
Kubernetes 動態準備控制的?MutatingWebhookConfiguration?可以 hook Pod 的創建或者更新,然后調用目標服務對 Pod 資源對象進行 patch 操作。
策略引擎
Pipy 作為應用的核心,也就是?MutatingWebhookConfiguration?的目標服務,以策略引擎的角色完成策略的執行。
Pipy 支持從文件或者 HTTP 地址加載腳本,這里為了便于策略的更新,使用了后者。
對于從 HTTP 地址加載腳本,HTTP 地址返回內容的第一行會作為 Pipy 的主腳本,Pipy 啟動時會加載主腳本,其他的文件也會被緩存到內存中。
#地址 http://localhost:6080/repo/registry-mirror/ $ curl http://localhost:6080/repo/registry-mirror/ /main.js /config.jsonPipy 會每隔 5s 檢查腳本和配置文件的?etag(就是文件的最后更新時間),假如與當前文件的 etag 不一致,則會緩存并重新加載。
利用 Pipy 的這個特性,便可以策略和配置的準實時更新。
策略
對于策略的部分,我們將其邏輯和配置進行了分離。配置部分,配置了需要進行替換的鏡像的前綴,以及替換成的內容;而邏輯,這是對?MutatingWebhookConfiguration?的?AdmissionReview?的對象進行檢查。
配置:
{ "registries":{ "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd":"registry.gitlab.cn/flomesh/registry-mirror/tekton-pipeline" } }比如說,對于鏡像?gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/controller:v0.28.1,將?gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd?替換成?registry.gitlab.cn/addozhang/registry-mirror/tekton-pipeline。
Demo
本文使用所有的源碼都已上傳到了 github。
腳本服務器
既然選用了 HTTP 方式加載 Pipy 的腳本,那就需要實現一個腳本服務器。實現的方式有兩種:使用腳本實現腳本服務器和使用 Pipy 內置的 Codebase。
使用腳本實現腳本服務器
根據需求定義兩種路由:
?/repo/registry-mirror/:返回腳本和配置的文件列表?/repo/registry-mirror/[File Name]:返回對應的文件的內容,同時需要在響應頭添加?etag,值是文件的更新時間
具體腳本如下:
#repo.js pipy({_serveFile:(req, type, filename)=>(filename = req.head.path.substring(22),os.stat(filename)?( newMessage( {bodiless: req.head.method ==='HEAD',headers:{ 'etag': os.stat(filename)?.mtime |0, 'content-type': type, }, },req.head.method ==='HEAD'?null: os.readFile(filename), ) ):( newMessage({ status:404},`file ${filename} not found`) ) ),_router:new algo.URLRouter({ '/repo/registry-mirror/':()=>newMessage('/main.js\n/config.json'), '/repo/registry-mirror/*': req => _serveFile(req,'text/plain') }), }) .listen(6080) .serveHTTP(req => _router.find(req.head.path)(req) )%$ pipy repo.js 2021-10-0521:40:25[info][config] 2021-10-0521:40:25[info][config]Module/repo.js 2021-10-0521:40:25[info][config]=============== 2021-10-0521:40:25[info][config] 2021-10-0521:40:25[info][config][Listen on :::6080] 2021-10-0521:40:25[info][config]----->| 2021-10-0521:40:25[info][config]| 2021-10-0521:40:25[info][config] serveHTTP 2021-10-0521:40:25[info][config]| 2021-10-0521:40:25[info][config]<-----| 2021-10-0521:40:25[info][config] 2021-10-0521:40:25[info][listener]Listening on port 6080 at ::檢查路由:
$ curl http://localhost:6080/repo/registry-mirror/ /main.js /config.json $ curl http://localhost:6080/repo/registry-mirror/main.js #省略 main.js 的內容 $ curl http://localhost:6080/repo/registry-mirror/config.json #省略 config.json 的內容使用 Pipy 內置的 Codebase
在最新發布的 Pipy 內置了一個 Codebase,大家可以理解成腳本倉庫,但是比單純的倉庫功能更加強大(后面會有文檔介紹該特性)。
目前版本的 Codebase 還未支持持久化的存儲,數據都是保存在內存中。后續會提供 KV store 或者 git 類型的持久化支持。
啟動 Pipy 的 Codebase很簡單:
$ pipy 2021-10-0521:49:08[info][codebase]Starting codebase service... 2021-10-0521:49:08[info][listener]Listening on port 6060 at ::對于新的 Codebase 控制臺的使用,這里不做過多的介紹,直接使用 REST API 完成腳本的寫入:
#創建 registry-mirror codebase,會自動創建一個空的 main.js $ curl -X POST http://localhost:6060/api/v1/repo/registry-mirror #更新 main.js $ curl -X POST 'http://localhost:6060/api/v1/repo/registry-mirror/main.js'--data-binary '@scripts/main.js' #創建 config.json $ curl -X POST 'http://localhost:6060/api/v1/repo/registry-mirror/config.json'--data-binary '@scripts/config.json' #檢查 codebase 的版本 $ curl -s http://localhost:6060/api/v1/repo/registry-mirror | jq -r .version #更新版本 $ curl -X POST 'http://localhost:6060/api/v1/repo/registry-mirror'--data-raw '{"version":2}'安裝
進入到項目的根目錄中,執行:
$ helm install registry-mirror ./registry-mirror -n default NAME: registry-mirror LAST DEPLOYED:TueOct522:19:262021 NAMESPACE:default STATUS: deployed REVISION:1 TEST SUITE:None查看 webhook:
$ kubectl get mutatingwebhookconfigurations NAME WEBHOOKS AGE registry-mirror-webhook 12m6s檢查 pod 的啟動日志:
$ kubectl logs -n pipy -l app=pipy 2021-10-0514:19:28[info][codebase] GET http://192.168.1.101:6060/repo/registry-mirror/ -> 21 bytes 2021-10-0514:19:28[info][codebase] GET /repo/registry-mirror/main.js ->2213 bytes 2021-10-0514:19:28[info][codebase] GET /repo/registry-mirror/config.json ->149 bytes 2021-10-0514:19:28[info][config] 2021-10-0514:19:28[info][config]Module/main.js 2021-10-0514:19:28[info][config]=============== 2021-10-0514:19:28[info][config] 2021-10-0514:19:28[info][config][Listen on :::6443] 2021-10-0514:19:28[info][config]----->| 2021-10-0514:19:28[info][config]| 2021-10-0514:19:28[info][config] acceptTLS 2021-10-0514:19:28[info][config]| 2021-10-0514:19:28[info][config]|-->[tls-offloaded] 2021-10-0514:19:28[info][config] decodeHTTPRequest 2021-10-0514:19:28[info][config] replaceMessage 2021-10-0514:19:28[info][config] encodeHTTPResponse -->| 2021-10-0514:19:28[info][config]| 2021-10-0514:19:28[info][config]<---------------------------------| 2021-10-0514:19:28[info][config] 2021-10-0514:19:28[info][listener]Listening on port 6443 at ::測試
$ kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.28.1/release.yaml $ kubectl get pod -n tekton-pipelines NAME READY STATUS RESTARTS AGE tekton-pipelines-controller-75974fbfb8-f62dv 1/1Running07m36s tekton-pipelines-webhook-6cc478f7ff-mm5l9 1/1Running07m36s檢查結果:
$ kubectl get pod -o json -n tekton-pipelines -l app=tekton-pipelines-controller | jq -r '.items[].spec.containers[].image' registry.gitlab.cn/flomesh/registry-mirror/tekton-pipeline/controller:v0.28.1 $ kubectl get pod -o json -n tekton-pipelines -l app=tekton-pipelines-webhook | jq -r '.items[].spec.containers[].image' registry.gitlab.cn/flomesh/registry-mirror/tekton-pipeline/webhook:v0.28.1從上面的結果可以看到結果是符合預期的。
總結
整個實現的策略部分加上配置,只有 70 多行的代碼。并且實現了邏輯與配置的分離之后,后續的配置也都可以做到實時的更新而無需修改任何邏輯代碼,更無需重新部署。
但是目前的實現,是需要手動把鏡像推送的自維護的鏡像倉庫中。實際上理想的情況是檢查自維護的倉庫中是否存在鏡像(比如通過 REST API),如果未發現鏡像,先把鏡像拉取到本地,tag?后再推送到自維護的倉庫。不過這種操作,還是需要網絡的暢通。當然也嘗試過通過 REST API 觸發 CICD Pipeline 的執行拉取鏡像并 tag,但是極狐Gitlab 是部署在某云的環境上,同樣也受困于網絡問題。
引用鏈接
Kubernetes 動態準備控制:?https://kubernetes.io/zh/docs/reference/access-authn-authz/extensible-admission-controllers/
源碼:?https://github.com/addozhang/registry-mirror
往期推薦
移動云亮相2021 IDC年度盛典
數學在左,人生在右
Redis很厲害,使用規范來啦
低代碼會讓程序員更加內卷嗎?
點分享
點收藏
點點贊
點在看
總結
以上是生活随笔為你收集整理的自动替换 Kubernetes 镜像的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 飞桨企业版重磅发布智能边缘控制台 5分钟
- 下一篇: 2017双11技术揭秘—分布式缓存服务T