我希望服务器上所有正在运行的容器始终使用最新版本的官方基础映像,例如node:16.3
以获取安全更新。为了实现这一点,我使用 CI 工作流为注册表中的所有容器映像实现了映像更新机制,该工作流具有如下所述的一些限制。
我已经阅读了这个问题的答案,但它们涉及在目标服务器上构建或检查图像,我想避免这样做。
我想知道是否有更简单的方法来实现容器映像更新或减轻我遇到的一些警告。
当前映像更新机制
我使用FROM
指令构建容器映像,其中包含我想使用的次要版本:
FROM node:16.13
COPY . .
此映像将作为my-app:1.0
推送到注册表。
为了检查与构建my-app:1.0
映像时相比,node:16.3
图像的变化,我定期将node:16.3
层的SHA256摘要与前n=(node:16.3
层数)my-app:1.0
层的摘要进行比较,如本答案所示。我用docker manifest inpect <image>:<tag> -v
检索 SHA256 摘要。
如果它们不同,我会重建my-app:1.0
并将其推送到我的注册表,从而确保my-app:1.0
始终使用最新的node:16.3
基础映像。
我通过使用 cron 作业定期在服务器上运行docker pull my-app:1.0
来使服务器上正在运行的容器保持最新。
局限性
- 检查更新时,我需要下载所有容器映像及其基础映像的清单。对于托管在 Docker Hub 上的映像,不幸的是,这会影响下载速率限制。
- 由于我总是
my-app:1.0
更新相同的映像,因此很难跟踪服务器上当前正在运行的版本。当更新过程中断服务时,此信息尤其重要。我通过记录 cron 作业中docker pull
命令的输出来跟踪更新。 - 为了能够在服务器上恢复容器映像,我还必须保留以前版本的
my-app:1.0
映像。我通过将增量补丁版本标签以及my-app:1.0
标签推送到我的注册表来做到这一点,例如my-app:1.0.1
,my-app:1.0.2
, ... - 由于比较基本映像和应用映像的图层的方式,因此无法检测到仅删除最上层的基本映像中的更改。但是,我预计这种情况不会经常发生。
感谢您的帮助!
我会做几件事来简化这一点。
docker pull
基本上已经执行了您描述的顺序,即下载映像的清单,然后下载您还没有的图层。 如果您docker build
具有相同基础映像、相同 Dockerfile 和相同COPY
源文件的新映像,则它实际上不会生成新映像,只需在现有映像 ID 上输入新名称即可。 因此,可以按计划无条件docker build --pull
图像,并且不会真正占用额外的空间。 (如果基础映像和应用程序均未更改,则可能会导致更多重新部署。
[...]不幸的是,这符合下载速率限制。
除了运行自己的 Docker Hub 镜像或确保您的 CI 系统具有 Docker Hub 登录名之外,您无能为力。
由于我总是更新相同的图像my-app:1.0,因此很难跟踪服务器上当前正在运行的版本。[...] 为了能够还原服务器上的容器映像 [...]
我建议每次构建始终使用唯一的图像标记。 您现在使用的顺序构建 ID、日期戳或源代码管理提交 ID 通常也很容易想出。 进行部署时,请始终使用完整的映像标记,而不是缩写标记。
docker pull registry.example.com/my-app:1.0.5
docker stop my-app
docker rm my-app
docker run -d ... registry.example.com/my-app:1.0.5
docker rmi registry.example.com/my-app:1.0.4
现在,您绝对可以确定服务器正在运行哪个版本,并且如果需要,可以轻松还原。
(如果你使用 Kubernetes 作为你的部署环境,这一点尤其重要。 更改部署对象的image:
字段的文本值会触发 Kubernetes 的滚动更新机制。 这种方法比尝试确保每个节点具有相同版本的共享标记要容易得多。