【问题标题】:How to use multiple image tags with docker-compose如何在 docker-compose 中使用多个图像标签
【发布时间】:2018-04-29 21:25:01
【问题描述】:

根据thisthis GitHub 问题,目前在使用docker-compose 构建一个或多个图像时,没有原生方法如何为服务的图像提供多个标签。

我的用例是构建在 docker-compose.yml 文件中定义的图像,并使用一些自定义标签(例如,一些构建编号或日期或类似标签)标记它们一次,然后将它们标记为 latest

虽然这可以通过使用docker tag 的普通docker 轻松实现,但docker-compose 只允许在image key 中设置一个标签。将docker tagdocker-compose 一起使用对我来说不是一个选项,因为我想将所有与docker 相关的定义保留在docker-compose.yml 文件中,而不是将它们复制到我的构建脚本中。

docker-compose 设置多个标签而不需要先硬编码/复制图像名称是一种体面的解决方法?

【问题讨论】:

    标签: docker tags docker-compose


    【解决方案1】:

    我有一些使用环境变量的漂亮而干净的解决方案(默认变量值的 bash 语法,在我的例子中是 latest 但你可以使用任何东西),这是我的作文:

    version: '3'
    services:
      app:
        build: .
        image: myapp-name:${version:-latest}
    

    使用默认标签构建和推送(如果需要推送到注册表),使用环境变量更改版本并再次构建和推送:

    docker-compose build
    docker-compose push
    export version=0.0.1
    docker-compose build
    docker-compose push
    

    【讨论】:

    • 我会为版本环境变量使用不同的名称。但除此之外,这看起来很干净。这里描述了环境变量替换的详细信息:docs.docker.com/compose/compose-file/#variable-substitution
    • 真的很漂亮,但我同意@CharlieReitzel 关于使用更好的变量名
    • 现在可能是我们能做的最好的事情了。不过,它确实构建了两次。我知道,我知道,缓存的图像第二次用于构建,但仍然如此。如果 compose 文件支持多个标签,那就更好了。
    【解决方案2】:

    您还可以采取以下方法:

    # build is your actual build spec
    build:
      image: myrepo/myimage
      build:
      ...
      ...
    # these extend from build and just add new tags statically or from environment variables or 
    version_tag:
      extends: build
      image: myrepo/myimage:v1.0
    some_other_tag:
      extends: build
      image: myrepo/myimage:${SOME_OTHER_TAG}
    

    然后您可以运行 docker-compose builddocker-compose push,您将构建并推送正确的标记图像集

    【讨论】:

    • 很遗憾它只适用于撰写文件版本
    • 同意,docker-compose.yml 不再支持此语法。 @Maoz Zadok 在下面有正确的方法。如果只是为了清楚起见,请使用您自己的不与任何 Docker 关键字冲突的环境变量(例如 version)。
    • @whoan 支持 3.4+ 文件格式的扩展字段。您可以使用它来执行相同的步骤,尽管 YAML 格式更加模糊。参考:docs.docker.com/compose/compose-file/#extension-fields
    • @JordanDeyton 好主意,我已经根据您的建议发布了an answer。谢谢!
    【解决方案3】:

    我想出了几个不同复杂度的变通办法。它们都依赖于${IMAGE_TAG} 存储代表例如的自定义标签的假设。一个版本号。我们想用这个标签以及latest来标记所有服务的图像。

    grep docker-compose.yml 文件中的图像名称

    images=$(cat docker-compose.yml | grep 'image: ' | cut -d':' -f 2 | tr -d '"')
    for image in $images
    do
      docker tag "${image}":"${IMAGE_TAG}" "${image}":latest
    done
    

    但是,如果有人在 docker-compose.yml 中添加评论,这很容易出错,例如看起来像# Purpose of this image: do something useful...

    构建两次

    使用${IMAGE_TAG} 作为docker-compose.yml 文件中的环境变量,如here in the first example 所述。

    然后,只需运行构建过程两次,每次将 ${IMAGE_TAG} 替换为不同的值:

    IMAGE_TAG="${IMAGE_TAG}" docker-compose build
    IMAGE_TAG=latest docker-compose build
    

    第二个构建过程应该比第一个快得多,因为所有图像层仍然应该从第一次运行开始缓存。

    这种方法的缺点是它会为每个单独的服务使用两个后续构建过程来淹没您的日志输出,这可能会使通过它搜索有用的东西变得更加困难。

    此外,如果您的 Dockerfile 中有任何命令总是刷新构建缓存(例如,ADD 命令从远程位置获取并自动更新 last-modified 标头,添加由外部进程等),那么额外的构建可能会显着减慢速度。

    使用一些内联 Python 代码从 docker-compose.yml 文件中解析图像名称

    在 Python 中使用真正的 yaml 解析器(或任何其他语言,例如 Rubyperl 或您系统上安装的任何其他语言)比第一次提到的 grep 方法更强大,因为它不会得到被 cmets 或编写 yml 文件的奇怪但有效的方式弄糊涂了。

    在 Python 中,这可能如下所示:

    images=$(python3 <<-EOF # make sure below to indent with tabs, not spaces; or omit the "-" before "EOF" and use no indention at all
        import yaml
        content = yaml.load(open("docker-compose.build.yml"))
        services = content["services"].values()
        image_names = (service["image"].split(":")[0] for service in services)
        print("\n".join(image_names))
    EOF
    )
    
    for image in ${images}
    do
    docker tag ${image}:${IMAGE_TAG} ${image}:latest
    done
    

    这种方法的缺点是执行构建的机器必须安装 Python3 以及 PyYAML 库。如前所述,此模式同样可以与 Python2 或任何其他已安装的编程语言一起使用。

    结合一些docker命令获取图片名称

    以下使用一些本机 dockerdocker-compose 命令(使用 go-templates)的方法编写起来有点复杂,但效果也很好。

    # this should be set to something unique in order to avoid conflicts with other running docker-compose projects
    compose_project_name=myproject.tagging
    
    # create containers for all services without starting them
    docker-compose --project-name "${compose_project_name}" up --no-start
    
    # get image names without tags for all started containers
    images=$(docker-compose --project-name "${compose_project_name}" images -q | xargs docker inspect --format='{{ index .RepoTags 0}}' | cut -d':' -f1)
    
    # iterate over images and re-tag
    for image in ${images}
    do
        docker tag "${image}":"${IMAGE_TAG}" "${image}":latest
    done
    
    # clean-up created containers again
    docker-compose --project-name "${compose_project_name}" down
    

    虽然此方法没有任何外部依赖项并且比 grep 方法更安全,但在创建和删除容器的大型设置上执行可能需要几秒钟的时间(但通常不是问题)。

    【讨论】:

    • 您可以在第一个示例中运行 docker-compose config,这将剥离所有 cmets 并仅保留配置语句。 IE。 docker-compose config | grep 'image: ' | awk -F ':' '{ print "image "$2", tag "$3 }' 为我做。
    • docker-compose images &lt;service_name&gt; 输出Container | Repository | Tag | Image Id | Size,其值类似于project_foo_1 | project_foo | latest | 590caffee098 | 1.1 GB。 (添加了| 以适应这种乱码的行布局。)也许可以用来改进最后一个示例并使--project-name 不再需要。
    【解决方案4】:

    正如@JordanDeyton 所建议的,extends 不能再在 Compose 文件格式中使用 &gt; 3 并且在版本 3.4 中添加的 Extension fields 功能可以替换它以实现相同的目标。这是一个例子。

    version: "3.4"
    # Define common behavior
    x-ubi-httpd:
      &default-ubi-httpd
      build: ubi-httpd
      # Other settings can also be shared
      image: ubi-httpd:latest
    
    # Define one service by wanted tag
    services:
      # Use the extension as is
      ubi-httpd_latest:
        *default-ubi-httpd
      # Override the image tag
      ubi-httpd_major:
        << : *default-ubi-httpd
        image: ubi-httpd:1
      ubi-httpd_minor:
        << : *default-ubi-httpd
        image: ubi-httpd:1.0
      # Using an environment variable defined in a .env file for e.g.
      ubi-httpd_patch:
        << : *default-ubi-httpd
        image: "ubi-httpd:${UBI_HTTPD_PATCH}"
    

    现在可以使用所有定义的标签构建图像

    $ docker-compose build
    # ...
    
    $ docker images | grep ubi-httpd
    # ubi-httpd  1       8cc412411805  3 minutes ago  268MB
    # ubi-httpd  1.0     8cc412411805  3 minutes ago  268MB
    # ubi-httpd  1.0.1   8cc412411805  3 minutes ago  268MB
    # ubi-httpd  latest  8cc412411805  3 minutes ago  268MB
    

    【讨论】:

    • 对于那些阅读,对文件格式版本 3.4 的支持已添加到 docker-compose 1.17.0 per github.com/docker/compose/releases/tag/1.17.0-rc1 撰写文件参考页面包括格式矩阵和 Docker 引擎版本,但它是我永远不清楚如何将 Docker 引擎版本映射到 docker-compose 版本。
    • 好吧,这对我来说在构建两个标签时很有用,但它有两个缺陷:它构建了两次(没什么大不了的),但它还创建了第二个服务,该服务在“docker-compose”上启动up”,这当然不是预期的目标。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多