【问题标题】:How to keep docker images up to date?如何使 docker 镜像保持最新?
【发布时间】:2021-04-08 14:37:18
【问题描述】:

我对 docker 还很陌生,并尝试实现自动化部署。 据我了解,容器永远不应该更新。在更新的情况下,需要创建新图像 (1) 并且需要用新实例替换正在运行的容器 (2)。

我通过使用 containerrrr/watchtower 解决了挑战 2。这似乎是唯一(?)仍然维护的自动更新我的容器的软件。

挑战 1 有点复杂。对于直接来自 docker hub 的图像,除了希望包维护者定期更新之外,我无能为力。但是在某些情况下,来自 docker hub 的图像是不够的,通常建议创建派生图像。有时一开始就没有维护图像。对于这两个用例,我都设置了 Jenkins 管道,这些管道构建图像并将它们推送到我的私有 docker 存储库中,由瞭望塔监控。 到目前为止,一切顺利。

但是如何在我的 Jenkins 管道上设置触发器以使其保持最新状态?

可能的来源:

  • VCS (SVN/GIT):由 Jenkins 轻松处理。
  • Docker Hub(对于派生图像或基础):我发现的唯一解决方法是创建一个带有虚拟 Github 存储库的虚拟 Docker Hub 存储库,自动构建存储库链接(“启用基础映像”),然后我的 Jenkins 实例的网络挂钩(“CloudbDocker Hub/Registry Notification 插件”)
  • 包更新(安装在 docker 文件中。例如通过 apk/apt):这里我还没有找到任何解决方案。

我很惊讶没有关于这个主题的更多信息。关于如何初始设置 docker 和 Jenkins 有很多很棒的指南,它们显示了入门是多么容易,但没有关于如何长时间运行容器的内容。 对于许多开发人员来说,我认为这不是问题,因为源代码中有许多更新会经常触发更新,但是所有定制图像呢?

这是一个实际的差距还是我错过了重要的信息?

【问题讨论】:

  • 源代码通常在 apt/yum 命令之后添加到容器中,因此在使用源代码更改重建图像时,这些层不会得到更新
  • 如果您希望始终拥有最新的基础镜像,只需每天重建您的容器即可。如果基础映像没有更改,则构建将与前一个相同,并且不会发生任何变化。然而,这不是生产系统的工作方式。您通常从基础映像的固定版本构建以确保稳定性,而不是从最新版本构建。
  • @OneCricketeer 您可以在没有缓存的情况下构建,以确保您始终拥有最新的软件包。然而,这是一项昂贵的重建任务。
  • @BurakSerdar 许多官方存储库提供标签以避免兼容性问题。每天在没有缓存的情况下重建容器是唯一可行的解​​决方案,但是由于这会产生很多不必要的开销,因为无论是否有更改,所有容器都会每天更新

标签: docker jenkins docker-registry


【解决方案1】:

据我所知,容器永远不应该更新。在更新的情况下,需要创建新图像 (1) 并且需要用新实例替换正在运行的容器。

我们先简单介绍一下docker:

Docker 提供了在称为容器的松散隔离环境中打包和运行应用程序的能力。隔离和安全性允许您在给定主机上同时运行多个容器。欲了解更多信息:Docker documentation

将容器视为虚拟机是一种常见的误解,但 docker 不是一种虚拟化技术,它是一种应用程序交付技术。容器的抽象就是你的应用运行的服务,一旦进程结束,docker容器就停止了。

每个容器都有自己的隔离环境,为服务运行的需要做好准备。 This is one of the main benefits of docker, you can REPLICATE the environment of the application to run. 进行此快速介绍是为了了解 docker 的这种好处,作为澄清您的问题的基础。考虑到这一点,让我们看看你的问题:

  1. 对于直接来自 docker hub 的图像,除了希望包维护者定期更新之外,我无能为力

为什么需要直接从 docker hub 中更新正在运行的容器?

假设您正在使用 postgres 映像在服务器中运行数据库。其他容器需要与这个 postgres 容器通信,所以它需要访问这个 db。您的应用程序使用当前图像版本按预期工作。有一个新的可用版本的 postgres 映像,您的系统更新了容器,并且由于某种原因,容器的行为与以前的版本不同,并且一旦更新了容器,您的应用程序就会由于某种原因失败。

这里的主要内容是更新容器应该遵循标准,了解您的应用程序的需求,并始终有办法测试这个更新版本是否按照您期望的方式运行。另一方面,如果您在没有任何标准且没有先前断言整个应用程序的情况下自动更新,则您没有利用环境复制。

  1. 但在某些情况下,来自 docker hub 的图像不够用,通常建议创建派生图像

这与第一点密切相关。由于我想为应用程序需求创建我的隔离环境,我需要选择合适的基础镜像来构建我的最终镜像。我只会在特定条件下更新此基础映像。

想象一下,我想为 java 应用程序创建一个容器。我将使用官方 java 镜像作为基础镜像。我会选择适合我项目的 sdk 的镜像版本。如果此映像自动更新为更新的 sdk,则可能会破坏应用程序的当前行为。

但是如何在我的 Jenkins 管道上设置触发器以使其保持最新状态?

根据之前所有的说明,答案是:这应该是一个手动步骤,根据容器服务需求的标准完成,并且有办法测试这个新的镜像版本,作为最终镜像的基础镜像,或者是直接在您的系统中使用,不会破坏您的应用程序或系统行为。

我使用环境复制 docker 优势来回答您的问题,但还有许多其他 docker 功能、标准流程和其他发挥重要作用的其他功能,可以使答案变得更长。我希望这可以很好地介绍您的问题。

我鼓励您阅读有关编写 docker 映像的最佳实践以及其他有关 docker 的有趣博客,以更好地了解使用此技术的好处,并获得知识以使答案更有意义。我将在下面留下几个有趣的链接:

  1. https://www.docker.com/blog/intro-guide-to-dockerfile-best-practices/
  2. https://www.docker.com/blog/containers-are-not-vms/

【讨论】:

  • 感谢 JandaTheMan 的广泛回答。兼容性是一个非常重要的因素。但是,让我来举一下您的 PostgreSQL 示例。它有不同版本的多个标签。假设我的应用程序与版本 12 有一些固定的兼容性,因此我将使用 docker 标签“12”,并且由于我需要自定义语言环境,因此我创建了自定义图像。如果有从 12.5 到 12.6 的更新,我想自动切换到较新的版本。这只是一个带有错误修正的小更新。我还可以实现一个预生产环境来自动测试应用程序的兼容性。
  • 由于您正在创建自定义映像,这意味着对 Dockerfile 进行了修改。一个好的做法是有一个管道作业,它为您的自定义 Docker 映像创建一个新标记,并将这个新标记的映像从一个源代码项目存储到您的私有注册表,该源代码项目具有所需最终映像的 Dockerfile 以及构建此映像的上下文。这个过程应该自动化吗? (1/2)
  • 想象生产环境是一个基于 docker-compose 的项目,我必须在其中指定要使用的映像版本。有了这个,应该实现一个自动修改 Dockerfile 以创建新图像标签的系统,以及另一个使用新图像标签修改 docker-compose 的系统。听起来不好吗?我认为更新镜像版本的过程应该是手动的,你决定的时间来轮询基础镜像的注册表以检查是否有新的标签要使用。希望能帮助到你! (2/2)
  • 是的,如上所述,我通过 Jenkins 在我的私人注册表中创建自定义图像。这个过程是自动化的。这不是问题所在。我只是没有任何可能根据 apt 或 apk 包的更新来触发我的 Jenkins 重建过程。此外,Docker hub webhook 只能在私有存储库中进行配置。所以我必须创建虚拟存储库,它只复制基本映像,然后触发我的 Jenkins 管道。我还通过 compose 设置了我的应用程序。但是,如上所述,我使用基于兼容性的标签。
  • Eg."postgres:13" 而不是 "postgres@sha256:5b56f67..." 因为我的应用程序与版本 13 兼容。我想在发布后自动将我的 postgres 容器更新到版本 13.2无需手动按下 Jenkins 中的按钮。如果不需要这种需求 containerrr/watchtower 以及“CloudBees Docker Hub/Registry Notification plugin”就不会存在。我只是错过了 APT 和 APK 的部分
猜你喜欢
  • 2015-07-14
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 2021-09-16
  • 2018-04-05
相关资源
最近更新 更多