Dockerfiles中的命令行模板

时间:2017-07-24 18:42:00

标签: docker metaprogramming dockerfile

我正在尝试构建一个Dockerfile,为多个基础映像构建我的项目(例如,Ubuntu 17.10用于多种架构)

我希望能够写出类似

的内容
FROM {{ ARCH }}/ubuntu:17.10
...

让它在构建时解析为ubuntu:17.10ppc64le/ubuntu:17.10。有没有办法做到这一点?

另外一个单独的解决方案可能是有两个docker文件,但不知何故将文件的公共部分包含在docker文件中。

4 个答案:

答案 0 :(得分:1)

您可以使用build argument并使用docker build --build-arg foo=bar来构建图片。

答案 1 :(得分:1)

我的第一个想法是编写一个模板脚本,将您的变量值替换为当时所需的值。当从环境变量调用或获取时,可以将此值传递给脚本。

我正在考虑使用python的string.Template模块并使用分隔符$而不是{,因为{可能在您的Dockerfile中使用。 $string.Template的默认分隔符。另外,我会用不同的扩展名来命名这个模板文件,因为Docker将无法使用里面的模板化变量来构建它。

假设你的Dockerfile.template看起来像这样:

FROM $ARCH/ubuntu:17.10
...

然后您可以在会话中设置环境变量ARCH=ppc64le并运行如下的简短脚本:

import os
import string

with open('Dockerfile.template', 'r') as f:
    template = string.Template(f.read())

with open('Dockerfile', 'w') as f:
    args = {key: value.strip() for (key, value) in os.environ.items()}
    f.write(template.substitute(**args))

这两行读取您的模板文件并创建一个string.Template对象。 string.Template的默认分隔符为$,因此它符合您的模板。

with open('Dockerfile.template', 'r') as f:
    template = string.Template(f.read())

这只是让我们创建并写入您的实际Dockerfile

with open('Dockerfile', 'r') as f:

这条奇特的线条是环境变量发挥作用的地方。 os.environ是os的环境变量的映射对象。 os.environ.items()将每对解包为其各自的键:值元组。 value.strip()只是清理价值,以确保没有奇怪的whitespacing。所有这些都包含在字典理解中,其中变量key是环境变量的名称,在本例中是模板化变量,它映射了此变量的值

args = {key: value.strip() for (key, value) in os.environ.items()}

最后我们有这条线。 template.substitute()接受映射对象并尝试用其值替换所有键。 **args扩展字典。

f.write(template.substitute(**args))

答案 2 :(得分:0)

官方docker库操作系统的现代标签现在倾向于多体系结构。只需根据体系结构上的FROM ubuntu:17.10构建就可以获取正确的图像。

例如:

docker run ubuntu:17.10 uname -a
Unable to find image 'ubuntu:17.10' locally
17.10: Pulling from library/ubuntu
c3cef7a7aa54: Pull complete 
8cbf0d1d8127: Pull complete 
1b5d7d7519b4: Pull complete 
855c347561ac: Pull complete 
ec1530a7444c: Pull complete 
Digest: sha256:3b811ac794645dfaa47408f4333ac6e433858ff16908965c68f63d5d315acf94
Status: Downloaded newer image for ubuntu:17.10
Linux 93a4440468e9 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:22:24 UTC 2018 ppc64le ppc64le ppc64le GNU/Linux

答案 3 :(得分:0)

TL; DR-不幸的是,Docker不支持此功能。这意味着,您需要自己做这些事情。

有一些专门为此任务编写的库:

dockerfile-template 允许您在Dockerfile中编写类似的内容:

FROM %%BASE%%:%%TAG%%
...

然后使用给定的值处理此docker-template文件,以生成最终的Dockerfile。但是,它实际上并不支持多行替换,而是使用Javascript编写的(原文如此!)。

另一种解决方案是编写自己的简单模板程序,如@Ricky Barillas建议(如果需要更多功能,也可以使用jinja之类的现有模板引擎)。

请注意所有此类自制解决方案的缺点是您的Dockertemplate文件将超出Dockerfile的语法,因此您将无法再使用Dockerfile linters / validators (仅在最终输出中)。此外,就构建映像而言,它们将不再那么“便携”,因为它不仅需要基础Docker,还需要模板脚本。