【问题标题】:Docker Swarm Service - force update of latest image already runningDocker Swarm Service - 强制更新已经运行的最新镜像
【发布时间】:2016-12-20 14:20:28
【问题描述】:

环境

  • 码头工人 1.12
  • 在 Ubuntu 16.04 上集群

如果服务更新未更改任何参数但 docker hub 映像已更新,是否有办法强制滚动更新已运行的 docker swarm 服务?

示例:我部署了服务:

docker service create --replicas 1 --name servicename --publish 80:80 username/imagename:latest

我的构建过程已经更新了 docker hub 上的最新镜像,现在我想再次拉取最新的。

我试过跑步:

docker service update --image username/imagename:latest servicename

当我按照这个过程进行操作时,docker 不会拉最新的,我猜它假设因为我想要最新的并且 docker 已经拉了一个图像:最新的,所以没有什么可做的。

我唯一的解决方法是删除服务 servicename 并重新部署。

【问题讨论】:

  • 这不起作用。我向 Docker 提出了一个问题:github.com/docker/docker/issues/26978 解决方法是添加无意义的元数据或部署信息等,就像之前评论的那样: > 我能够通过使用容器标签来触发滚动更新。我添加了 --container-label-add deploy="1.0.1"。所以每次我更改标签时,每个服务都会拉取并重新部署服务。 – longday 8 月 14 日 15:53

标签: docker docker-swarm


【解决方案1】:

仅供参考:

Docker 1.13 为service update 添加了--force 标志:

--force: 即使不需要更改也强制更新

如下使用:

docker service update --force service_name

【讨论】:

  • 我在 Azure 上使用 Docker Swarm (17.04.0-ce),仅使用 --force 不会将映像更新到最新版本。我必须将摘要添加到图像标签:docker service update --image registry.co/image:latest@sha256:109ca... service。然后它将图像更新为最新推送。我错过了什么吗?
  • IIRC,如果您的服务设置为使用特定的摘要,则更新它将继续拉取相同的图像。您可以尝试docker service update --force --image registry.co/image service 来删除摘要固定,然后一个--force 应该可以解决问题。
  • 感谢您的回复!我做了一些繁重的测试,但--force 标志没有运气。我尝试了一个私有 Docker Registry(使用registry:2)和官方 Docker Hub(认为注册表可能是原因)。在更新期间我从未指定任何摘要(在 service createservice update 上),但 Docker 始终使用摘要。 service inspect 也显示了摘要,自动回滚也考虑了。也许这是预期的行为(在17.05.0-ce, build 89658be 上测试)?
  • 我怀疑service update 之前的pull 是问题所在。它似乎欺骗 update 认为你已经在使用 latest 标签(当服务更新真的应该比较摘要时)
【解决方案2】:

Docker 不会自动从 DockerHub(或私有注册表)拉取您在本地已有的 image:tag。

如果您在docker service update 之前执行了手动拉取,或者在本地删除了图像,则可以。

你也可以链接命令:

docker pull image:tag && docker service update --image username/imagename:latest servicename

您可以通过数字标记图像并使用更新的标记来避免这种情况。 username/imagename:1.1.0

【讨论】:

  • 我尝试对经理进行拉取和服务更新,但没有成功。然后尝试对每个节点进行拉取,并从管理器进行服务更新,但没有成功。
  • 我能够通过使用容器标签触发滚动更新。我添加了 --container-label-add deploy="1.0.1"。所以每次我更改标签时,每个服务都会拉取并重新部署服务。
  • docker pull before update 没有帮助,容器基本上与没有最新标签的图像链接,并且有一个带有标签的新标签,但仍然没有做任何更改。所以只有 --force 帮助
  • 为什么这不是公认的答案? :)
【解决方案3】:

您可以像这样使用图像 ID 代替 username/imagename:latest

docker service update --image \
$(docker inspect --type image --format '{{.Id}}' username/imagename:latest) \
servicename

但在这种情况下,您的所有节点都必须在服务更新之前提取此图像。否则,容器将仅在存在具有该 ID 的映像的那些节点上更新。幸运的是,没有这个镜像的节点会停止他们的容器,所以如果一些节点拉不上新版本的镜像也没有什么不好。

更新:或者您可以使用以下图像摘要:

docker service update --image \
$(docker inspect --type image --format '{{index .RepoDigests 0}}' username/imagename:latest) \
servicename

docker inspect --type image --format '{{index .RepoDigests 0}}' IMAGE 返回图像摘要,其中包括注册表 v2 生成的图像的唯一哈希。因此,必须从注册表中提取图像,否则摘要将不可用。

使用摘要允许您不要在所有节点上提取图像(具有指定摘要的图像将自动从必要节点上的注册表中提取)。但是您必须在服务更新之前在管理器节点上拉一次新版本的图像。

顺便说一句,最后一种方式将是默认的since Docker 1.13

【讨论】:

    【解决方案4】:

    如果你想更新 docker 服务镜像,你可以简单地做docker service update --image myimage:tag servicename。例如docker service update --image traefik:1.7.5 traefik_proxy 另外,通过不使用myimage:latest 标签,它可以确保您不会无意中更新到最新更新的主要/次要版本而不是补丁版本。

    参考:https://github.com/moby/moby/issues/30951#issuecomment-279479589

    【讨论】:

      【解决方案5】:

      我做的是

      1. 先拉图片
      2. 使用新的时间戳标签运行更新命令

      docker 服务更新 --container-label-add last_deployed=$(date -u +%Y-%m-%dT%H:%M:%S) service_name_or_id

      【讨论】:

        【解决方案6】:

        我在 2020 年写这篇文章,我希望这个脚本能帮助那些想要一种干净的方式来拉取和重新启动堆栈上的容器,而无需每次都在新标签上发布新图像的人!

        #!/bin/bash -e
        if [ $# -lt 1 ]
        then
          echo "this command needs the name of the container and the branch you want to use"
          echo "Syntax: ./update.sh <microservice> <version>"
          echo "Syntax: ./update.sh mymicroservice develop"
          exit 1
        fi
        declare -r STACK_NAME="mystack" # this should be generated or asked to user
        declare -r REPO="192.168.1.100" # this should be generated or asked to user
        
        echo "Pull the image ${REPO}/${1}:${2}"
        # Pull latest image on the swarm master
        docker pull ${REPO}/${1}:${2}
        # Get the ID of that image
        declare -r imageSha256=`docker image inspect --format '{{ .Id }}' ${REPO}/${1}:${2}`
        declare -r image="${REPO}/${1}@${imageSha256}"
        
        # Update the server and the image used
        docker service update --image ${image} ${STACK_NAME}_${1}
        echo "Update succeeded !"
        

        【讨论】:

          【解决方案7】:

          根据https://github.com/moby/moby/issues/34153

          更新需要凭据来拉取映像的服务时,您 需要通过--with-registry-auth。为服务提取的图像需要 与常规 docker pull 不同的路径,因为实际的 pull 是 在部署实例的集群中的每个节点上执行。到 拉取图像,swarm 集群需要存储凭据 (以便凭据可以传递到它执行的节点 拉上)。

          即使在这种情况下“节点”是您的本地节点,swarm 相同的方法(否则它只能拉图像 在本地节点上,但不在任何其他节点上)。

          设置 --with-registry-auth 选项会传递您本地存储的 守护进程的凭据,并将它们存储在 raft 存储中。后 即,图像摘要被解析(使用这些凭据),并且 图像被拉到任务安排的节点上(再次, 使用存储在服务中的凭据)。

          【讨论】:

            猜你喜欢
            • 2020-12-09
            • 2018-06-03
            • 1970-01-01
            • 2015-07-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-22
            • 1970-01-01
            相关资源
            最近更新 更多