【问题标题】:how to get docker-compose to use the latest image from repository如何让 docker-compose 使用存储库中的最新图像
【发布时间】:2016-06-07 17:24:19
【问题描述】:

我不知道自己做错了什么,但如果不先从系统中完全删除旧容器,我根本无法让 docker-compose up 使用我们注册表中的最新映像。尽管 docker-compose pull 获取了更新的图像,但 compose 似乎正在使用之前启动的图像。

我查看了How to get docker-compose to always re-create containers from fresh images?,这似乎与我的问题相似,但那里提供的解决方案都不适合我,因为我正在寻找可以在生产服务器上使用的解决方案,但我没有想要在再次启动它们之前移除所有容器(可能的数据丢失?)。我希望 compose 仅​​检测更改图像的新版本,拉取它们,然后使用这些新图像重新启动服务。

我为此创建了一个简单的测试项目,其中唯一的目标是让版本 nr 在每次新构建时增加。如果我浏览到创建的 nginx 服务器,则会显示版本 nr(这在本地按预期工作)。

码头工人版本:1.11.2 码头工人撰写版本:1.7.1 操作系统:使用 docker-toolbox 在 CentOS 7 和 OS X 10.10 上测试

我的 docker-compose.yml:

version: '2'
services:
  application:
    image: ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
    volumes:
      - /var/www/html
    tty: true

  nginx:
    build: nginx
    ports:
      - "80:80"
    volumes_from:
      - application
    volumes:
      - ./logs/nginx/:/var/log/nginx
  php:
    container_name: buildchaintest_php_1
    build: php-fpm
    expose:
      - "9000"
    volumes_from:
      - application
    volumes:
      - ./logs/php-fpm/:/var/www/logs

在我们的 jenkins 服务器上,我运行以下命令来构建和标记图像

cd $WORKSPACE && PROJECT_VERSION=$(cat VERSION)-dev
/usr/local/bin/docker-compose rm -f
/usr/local/bin/docker-compose build
docker tag ourprivate.docker.reg:5000/ourcompany/buildchaintest ourprivate.docker.reg:5000/ourcompany/buildchaintest:$PROJECT_VERSION
docker push ourprivate.docker.reg:5000/ourcompany/buildchaintest

这似乎正在做它应该做的事情,因为每次构建完成并且版本 nr 被碰撞时,我都会在我们的存储库中获得一个新的版本标签。

如果我现在跑步

docker-compose pull && docker-compose -f docker-compose.yml up -d

在我计算机上的一个文件夹中,其中的内容只有 docker-compose.yml 和构建 nginx 和 php 服务所需的 Dockerfiles,我得到的输出不是注册表中标记的最新版本号或显示在 docker-compose.yml (0.1.8) 中,但之前的版本是 0.1.7。但是,pull 命令的输出表明已获取了新版本的图像:

Pulling application (ourprivate.docker.reg:5000/ourcompany/buildchaintest:latest)...
latest: Pulling from ourcompany/buildchaintest
Digest: sha256:8f7a06203005ff932799fe89e7756cd21719cccb9099b7898af2399414bfe62a
Status: Downloaded newer image for docker.locotech.fi:5000/locotech/buildchaintest:0.1.8-dev

只有当我运行时

docker-compose stop && docker-compose rm -f

然后运行docker-compose up 命令是否可以让新版本按预期显示在屏幕上。

这是 docker-compose 的预期行为吗?即我是否应该在再次运行up 之前始终执行docker-compose rm -f,即使在生产服务器上也是如此?还是我在这里做一些违背粮食的事情,这就是为什么它不起作用?

我们的目标是让我们的构建过程构建并创建 docker-compose.yml 中所需图像的标记版本,将它们推送到我们的私有注册表,然后“发布到生产步骤”以简单地复制 docker -compose.yml 到生产服务器并运行docker-compose pull && docker-compose -f docker-compose.yml up -d 以使新图像开始生产。如果有人对此有提示或可以指出此类设置的最佳实践教程,也将不胜感激。

【问题讨论】:

  • docker-compose up -d --force-recreate 没用?
  • 为避免删除/重新创建容器时数据丢失的风险,请使用主机或命名卷。看起来您已经在为其他容器使用主机卷。当您第一次使用它时,一个空的命名卷将使用图像卷的内容进行初始化。
  • --force-recreated 不起作用,不 :( 我正在使用卷来存储数据,因此数据丢失部分可能不那么相关。但我仍然对拥有在重新启动容器之前做一个 docker-compose rm。不应该 up, 命令,特别是使用 force-recreate,注意通知一个新图像并使用它吗?我不得不强制感觉不对在生产服务器上删除
  • 如果--force-recreate 没有重新创建容器,那么您可能需要在docker-compose 上提交错误报告。请记住,使用新图像将重新创建容器,这将删除它。如果您在此过程中不删除任何特定于容器的卷,则可以在docker volume ls -f dangling=true 中获得一个相当长的悬空数据列表,您将不再使用这些数据。所以你的修复是 docker-compose 应该为你做的前半部分。
  • 好的,谢谢!我将不得不更多地摆弄以确保我了解该过程(在涉及 Docker 时仍然是新手),但看起来 docker-compose rm -f 在构建之前是我需要做的。

标签: docker build-process docker-compose


【解决方案1】:

为了确保您使用的是来自注册表(例如 docker hub)的最新版本的 :latest 标签,您还需要再次拉取最新标签。如果它发生变化,当你再次docker-compose up 时,将下载并启动差异。

所以这将是要走的路:

docker-compose stop
docker-compose rm -f
docker-compose pull   
docker-compose up -d

我将它粘贴到我运行以启动 docker-compose 并确保图像保持最新的图像中:https://hub.docker.com/r/stephanlindauer/docker-compose-updater/

【讨论】:

  • docker-compose pull && docker-compose up -d 就足够了。它会自动检查正在运行的容器是否已过时,如果是,则使用最新图像重新创建它们
  • @MindaugasVarkalys 这适用于 Linux,但不适用于 Mac,除非您添加 --force-recreate 选项。
  • pull_policy 也是如此:总是。它在 Mac 上实现,并拉取图像,但不会替换正在运行的容器。
【解决方案2】:

要获取最新的图像,请使用 docker-compose build --pull

我使用下面的命令,它实际上是 3 in 1

docker-compose down && docker-compose build --pull && docker-compose up -d

此命令将停止服务,拉取最新图像,然后启动服务。

【讨论】:

  • 也许您应该添加 docker-compose pull 来更新带有 image: 而不是 build: in docker-compose.yml 的服务的图像,或者 docker-compose build --pull 会这样做吗?
  • 我在使用 docker-compose build --pull 时得到nginx uses an image, skipping 因此没有更新图像。
  • 不要使用这个命令!或者至少要小心并知道你在做什么。docker-compose down 将删除所有匿名卷,如果你的 dokcer-compose.yml 中有数据库,可能会导致数据丢失!
【解决方案3】:

[编辑] 不要使用
以下是规范中的内容,但正如 cmets 中所指出的,尚未实施(docker-compose 1.29.2 和 2)。

自 2020-05-07 起,docker-compose 规范还定义了服务的“pull_policy”属性:

version: '3.7'

services:
  my-service:
    image: someimage/somewhere
    pull_policy: always

docker-compose spec 说:

pull_policy defines the decisions Compose implementations will make when it starts to pull images.

可能的值是(tl;dr,查看规范了解更多详情):

  • 总是:总是拉动
  • 从不:不要拉(如果找不到图像则中断)
  • 缺失:如果图像未缓存则拉取
  • 构建:始终构建或重建

【讨论】:

  • 你知道支持这个的最低版本的docker是什么吗?我试过了,它说无效。
  • @Neal 不,抱歉。我找不到任何相关信息。
  • 我不认为这是有效的。规范链接不是来自官方 Docker 存储库,pull_policy 在当前 docker-compose v1.29.2 和文件版本 3.8 中无效。只有建议的 docker-compose pull 才会实际提​​取图像,即使它们存在
  • @mitsos1os 我相信你是对的。谢谢提供信息。我现在将更新上面的条目。在1.29.2 的源代码中,您可以看到“pull_policy”键丢失,因此无效,即使它在规范中可用并因此通过验证。
  • “规范链接不是来自官方 Docker 仓库”。是的。在docs.docker.com/compose/compose-file 中,第一段说“Docker Compose 1.27.0+ 实现了 Compose 规范定义的格式。” Compose 规范是compose-spec.io,此答案链接到其 GitHub 存储库。
【解决方案4】:

即使我的容器正在运行并且它更新得很好,我也会使用以下内容。

docker-compose pull
docker-compose up -d

【讨论】:

  • 它工作正常,但你可能会在小型机器上出现 "no space left on device" 错误,因为 Docker 会保留运行容器的旧镜像层,即使调用到docker system prune
【解决方案5】:

为了结束这个问题,似乎有效的方法确实在运行

docker-compose stop
docker-compose rm -f
docker-compose -f docker-compose.yml up -d

即在再次运行 up 之前删除容器。

这样做时需要记住的是,如果您只运行rm -f,也会删除数据卷容器。为了防止我明确指定要删除的每个容器:

docker-compose rm -f application nginx php

正如我在问题中所说,我不知道这是否是正确的过程。但这似乎适用于我们的用例,所以在我们找到更好的解决方案之前,我们将继续使用这个解决方案。

【讨论】:

  • 如果要回滚到之前的容器版本怎么办?冲洗,重复?
  • 还没有尝试过,但是是的,我假设也是如此。由于容器版本应该在 docker-compose.yml 中定义(例如 myimage:2.0.1),如果您想回滚,您需要将 docker-compose.yml 更新为您想要回滚到的版本(例如 2.0 .0) 并再次执行相同的冲洗重复过程。
  • 如果我想回滚,我只是恢复提交,让 docker hub 构建,然后等待更新程序获取它。可能不是最复杂的系统,但它适用于我的业余项目。
  • 删除所有内容似乎不是一个解决方案,但更像是一个狡猾的解决方案。
  • 如果文件已被称为docker-compose.yml,则-f 标志是可选
【解决方案6】:

选项down解决这个问题

我运行我的撰写文件:

docker-compose -f docker/docker-compose.yml up -d

然后我删除所有down --rmi all

docker-compose -f docker/docker-compose.yml down --rmi all

Stops containers and removes containers, networks, volumes, and images
created by `up`.

By default, the only things removed are:

- Containers for services defined in the Compose file
- Networks defined in the `networks` section of the Compose file
- The default network, if one is used

Networks and volumes defined as `external` are never removed.

Usage: down [options]

Options:
    --rmi type          Remove images. Type must be one of:
                        'all': Remove all images used by any service.
                        'local': Remove only images that don't have a custom tag
                        set by the `image` field.
    -v, --volumes       Remove named volumes declared in the `volumes` section
                        of the Compose file and anonymous volumes
                        attached to containers.
    --remove-orphans    Remove containers for services not defined in the
                        Compose file

【讨论】:

    【解决方案7】:

    我花了半天时间解决这个问题。原因是一定要检查音量的记录位置。

    卷: - api-data:/src/patterns

    但事实是,在这个地方是我们更改的代码。但是在更新docker时,代码并没有改变。

    因此,如果您正在检查其他人的代码并且由于某种原因您没有更新,请检查此。

    所以一般来说这种方法是有效的:

    docker-compose down

    docker-compose 构建

    docker-compose up -d

    【讨论】:

      【解决方案8】:
      docker-compose pull
      docker-compose up -d
      docker image prune -af
      

      它对我有用。

      先拉最新的图片, 比更新容器, 最后清理我们不需要的图像。

      【讨论】:

        【解决方案9】:

        拉新图片:docker-compose pull

        使用新镜像重建 docker 容器:docker-compose up --force-recreate --build -d

        删除未使用的图像:docker image prune -f

        【讨论】:

          【解决方案10】:

          我已经在我们的 7-8 docker 生产系统中看到了这种情况。 在生产中对我有用的另一个解决方案是运行

          docker-compose down
          docker-compose up -d
          

          这会删除容器,并且似乎“组成”了从最新图像创建新容器。

          这还没有解决我的梦想,即每个更改的容器都向下+向上(连续,减少停机时间),但它可以强制“向上”更新容器。

          【讨论】:

          • docker-compose down afaik 还会删除链接到正在运行的容器的所有数据卷容器。因此,如果数据卷只包含可以从正在运行的容器中重新创建的内容,那也没问题。但是,如果卷包含您要保留的数据,您应该小心。
          • down 默认删除当前文档:容器、网络和默认网络。 Doc 说“永远不会删除定义为外部的网络和卷”。使用命名卷对我有用(我想命名网络也是如此)。
          【解决方案11】:

          如果 docker compose 配置在文件中,只需运行:

          docker-compose -f appName.yml down && docker-compose -f appName.yml pull && docker-compose -f appName.yml up -d
          

          【讨论】:

            【解决方案12】:

            但是

            https://docs.docker.com/compose/reference/up/ -quiet-pull 不打印进度信息的拉动

            docker-compose up --quiet-pull
            

            不工作?

            【讨论】:

              【解决方案13】:

              您的docker-compose.yml 使用image 指代ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev。这意味着运行docker-compose build 不会对ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev 执行任何操作。一定有类似下面的命令在某处运行:

              docker build -t ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
              docker push ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
              

              这会将版本化的构建放入您的存储库中。但它不会更新其最新标签。这仍然指向之前的版本(例如,0.1.7-dev)。

              然后,您在 jenkins 上运行其他命令:

              cd $WORKSPACE && PROJECT_VERSION=$(cat VERSION)-dev
              /usr/local/bin/docker-compose rm -f
              /usr/local/bin/docker-compose build
              docker tag ourprivate.docker.reg:5000/ourcompany/buildchaintest ourprivate.docker.reg:5000/ourcompany/buildchaintest:$PROJECT_VERSION
              docker push ourprivate.docker.reg:5000/ourcompany/buildchaintest
              

              作为docker-compose build 的一部分,您实际上是在您的服务器上运行docker pull ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev。但是,这并不能说明标签ourprivate.docker.reg:5000/ourcompany/buildchaintest:latest(您在命令docker tag ourprivate.docker.reg:5000/ourcompany/buildchaintest ourprivate.docker.reg:5000/ourcompany/buildchaintest:$PROJECT_VERSION 中引用的)是如何进入您的服务器的。如果latest 标记没有事先由其他东西定义,那么docker tag 命令会给出这个错误:No such image: ourprivate.docker.reg:5000/ourcompany/buildchaintest:latest。因此,在运行您显示的命令之前,您的 jenkins 服务器必须运行以下内容:

              docker pull ourprivate.docker.reg:5000/ourcompany/buildchaintest
              

              此命令将导致它拉取当时在您的存储库中设置为 latest 的任何内容。因为在运行上述docker pull 命令之前,您没有提供任何证据证明您曾经将新构建的buildchaintest:0.1.8-dev 推送为buildchaintest:latest,所以我们必须假设这是旧版本的来源。因此,您的 tag 命令有效地做到了这一点:

              docker tag ourprivate.docker.reg:5000/ourcompany/buildchaintest:latest ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
              docker push ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
              

              如果latest 指向0.1.7-dev 处的同一事物,则与执行相同:

              docker tag ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.7-dev ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
              docker push ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev
              

              然后,稍后,当您运行docker-compose pull && docker-compose up -d 时,它当然会拉取存储库中设置为ourprivate.docker.reg:5000/ourcompany/buildchaintest:0.1.8-dev 的内容,这应该是旧版本,因为您将0.1.7-dev 标记为0.1.8-dev。

              注意事项

              您似乎假设docker-compose build 做了一些与构建buildchaintest 有关的事情。但是,事实并非如此。您在docker-compose.yml 中设置了image,但没有设置build。这意味着docker-compose build不会构建buildchaintest docker 镜像——它只会直接拉取并运行docker 镜像标签。由于docker-compose build 不会尝试构建buildchaintest,因此在调用该图像后尝试标记或推送该图像是没有意义的。

              另外,docker-compose push 存在并且如果你同时指定buildimage 会做所有的标记和推送(因为image 用于通知docker-compose 它应该设置一个标签对于建造的东西)。这将推送正确的标签(并且对于您的 docker-compose.yml 文件正确无操作)。

              您的docker-compose 中包含build,但没有image。无论你在哪里运行docker-compose up,这些东西都会被构建。因此,在构建服务器上运行docker-compose build(除了测试构建运行完成之外)没有意义(除非您添加image 来设置标签并保存那些构建的图像并使用docker-compose push)。您不会为自己节省任何时间,也不会减少部署期间服务器执行的工作。您正在增加构建事物的次数以及系统中节点之间的可变性(因为构建服务器上构建的任何内容都将不同于服务器上运行的任何内容(例如,文件时间戳、更新的图像标签)。

              很遗憾,您的问题不可信。您使用命令,就好像它们具有与应有的行为不同的行为一样。很抱歉攻击你的问题,但我学到了一些关于 docker tagdocker-compose 如何工作的令人惊讶的事情(对我来说)。谢谢!

              tl;博士

              确保您实际标记并将正确的图像推送到您的存储库中!

              【讨论】:

                【解决方案14】:

                'up' 命令的 docker-compose 文档明确指出,如果自上次执行“up”后图像发生更改,它将更新容器:

                如果服务存在现有容器,并且服务的配置或映像在容器创建后发生更改,docker-compose up 通过停止和重新创建容器来获取更改(保留已安装的卷)。

                因此,通过使用“stop”,然后使用“pull”,然后使用“up”,这应该可以避免正在运行的容器丢失卷的问题,当然,对于镜像已更新的容器除外。

                我目前正在尝试此过程,并将很快将我的结果包含在此评论中。

                【讨论】:

                • 即使只是 docker-compose pull 后跟 docker-compose up 也可以在没有先停止的情况下工作
                【解决方案15】:

                我正在使用以下命令获取最新图像

                sudo docker-compose down -rmi all

                sudo docker-compose up -d

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-03-26
                  • 2018-08-25
                  • 2015-12-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-06-29
                  相关资源
                  最近更新 更多