根据this和this GitHub问题,目前在使用docker-compose
构建一个或多个服务时,如何为服务的图像提供多个标记没有本机方式图像。
我的用例是构建docker-compose.yml
文件中定义的图像,并使用一些自定义标记(例如某些构建编号或日期或类似标记)标记一次,并将其标记为latest
。
虽然使用docker tag使用普通docker
可以轻松实现此目的,docker-compose
只允许在image key中设置一个标记。将docker tag
和docker-compose
一起使用对我来说不是一个选项,因为我想将所有与docker相关的定义保存在docker-compose.yml
文件中,而不是将它们复制到我的构建脚本中。
使用docker-compose
设置多个标签并且不必首先硬编码/复制图像名称会有什么好处?
答案 0 :(得分:8)
我提出了几个不同复杂程度的解决方法。它们都依赖于${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
命令,则添加文件通过外部流程等不断更新,然后额外的构建可能会显着降低速度。
docker-compose.yml
文件中解析图像名称
在Python中使用真正的yaml
解析器(或任何其他语言,如Ruby
或perl
或系统上安装的任何语言)比第一次提到的{{1}更强大因为它不会被评论或编写grep
文件的奇怪但有效的方式所迷惑。
在Python中,这可能如下所示:
yml
这种方法的缺点是执行构建的机器必须安装Python3以及PyYAML库。如前所述,此模式可以类似地与Python2或任何其他已安装的编程语言一起使用。
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
命令使用一些本地docker
和docker
命令(使用go-templates)的以下方法编写起来有点复杂,但也可以很好地工作。
docker-compose
虽然这种方法没有任何外部依赖性并且比# 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
方法更安全,但是在大型设置上执行以创建和删除容器可能需要几秒钟(尽管通常不是问题)
答案 1 :(得分:8)
如@JordanDeyton所建议,extends
不能再以Compose文件格式> 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
答案 2 :(得分:7)
您还可以采取以下方法:
# 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 build
和docker-compose push
,然后构建并推送标记为已成像的正确
答案 3 :(得分: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