来源:云原生指北
作者: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.json

Pipy 会每隔 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 镜像相关推荐

  1. 推荐一款自动更新 Docker 镜像与容器的神器 Watchtower

    公众号关注 「奇妙的 Linux 世界」 设为「星标」,每天带你玩转 Linux ! 前言 Docker 容器的部署有一种在手机上装 App 的感觉,但 Docker 容器并不会像手机 App 那样会 ...

  2. 安装威锋替换的镜像源

    转自: http://bbs.weiphone.com/read-htm-tid-826313.html 安装威锋替换的镜像源 ==================================== ...

  3. R语言使用R基础安装中的glm函数构建乳腺癌二分类预测逻辑回归模型、分类预测器(分类变量)被自动替换为一组虚拟编码变量、summary函数查看检查模型、使用table函数计算混淆矩阵评估分类模型性能

    R语言使用R基础安装中的glm函数构建乳腺癌二分类预测逻辑回归模型(Logistic regression).分类预测器(分类变量)被自动替换为一组虚拟编码变量.summary函数查看检查模型.使用t ...

  4. 使用TS自动抓取镜像

    原文地址:[url]http://www.deployvista.com/Home/tabid/36/EntryID/77/language/en-US/Default.aspx[/url] 偶然搜了 ...

  5. 替换RubyGems 镜像

    替换RubyGems 镜像 更换gem的源: [root@tvm-rpm ~]# gem sources --remove http://rubygems.org/ [root@tvm-rpm ~]# ...

  6. Excel 取消Internet及网络路径自动替换为超链接

    Excel 取消Internet及网络路径自动替换为超链接: 1.文件 =>选项 =>校对 点击自动更正选项 2. 自动更正 配置修改 点击"键入时自动套用格式"tab ...

  7. <img src=“图片引用失败“ onerror=“自动替换默认图片“> - 代码篇

    img图片引用失败,自动替换默认图片(半句代码搞定) 图片引用失败,显示默认图片: <!--代码定义如下:--> <img src="图片引用失败" onerro ...

  8. [watchtower] 自动更新 Docker 镜像与容器

    自动更新 Docker 镜像与容器 pull镜像 运行 更新docker镜像 参数解释 更新镜像列表文件 pull镜像 根据自己的系统架构选择,都是为最新版镜像 docker pull contain ...

  9. PLSQL DEVELOPER编辑器的自动替换文件

    PLSQL DEVELOPER的编辑器的自动替换文件: 1 s=Select * From 2 w=Where 3 ins=Insert Into 4 sc=Select Count(*) From ...

最新文章

  1. java反射(reflect)机制模拟javabean的实现
  2. 微信版花呗“分付”要来了!花呗,白条你们怎么看?
  3. php找不到库,64位系统下编译PHP找不到库文件问题 | 学步园
  4. WIDOWS 7全家桶(很详细)
  5. Hadoop连载系列之六:Hadoop数据仓库工具Hive
  6. Python程序设计经典题库及答案
  7. Java同步三种实现方式
  8. FlashFXP注册码-FlashFXP密钥
  9. UVA 11137 Ingenuous Cubrency(dp)
  10. 计算机博士美国高校雅思要求,雅思8分成功申堪萨斯大学博士(助研全奖)
  11. JavaSE方法(构造方法)与方法重载基础练习题
  12. Visual Paradigm简单教程(1):绘制状态机图
  13. 计算机上的aece代表什么意思,Myristicaceae是什么意思
  14. 你真的了解TCP/IP吗
  15. HTML5中制作彩色圆环的代码,HTML5 五彩圆环Loading加载动画实现教程
  16. Cesium实践(4)——空间数据加载
  17. 四川师范大学Java期末_四川师范大学2008-2009第一学期常微分方程期末试题A英文版(含答案)精选.pdf...
  18. 洗衣店小程序v2.6.5+小程序前端全开源版安装教程
  19. 中图分类号和UDC查询
  20. Java 17新特性,快到起飞?惊呆了!

热门文章

  1. linux挂载cifs磁盘_linux使用windows磁盘,挂载共享目录
  2. 安装版mysql错误2_【gem安装】mysql2错误
  3. java三目运算_Java中的三目运算符 详解
  4. 智能照明控制系统电路图_咻享智能|学校教室智能照明控制系统怎么理解
  5. long转string mybatis_Spring+Mybatis类型转换的问题,oracle数据库中有一个clob类型,怎样在查询以后转换为String类型?...
  6. 基金本子提交在即!这11个问题现在改还来得及
  7. 六十五年来,他的祖国向他道歉了三次
  8. 概率论公式,你值得拥有
  9. 区块链跟银行有什么关系?
  10. 宇宙的最原始状态是个什么样子