在Docker中使用string中的variables插值

我在创build和使用Dockerfile中的variables时遇到困难 – 我使用以下命令通过Dockerfile构buildDocker镜像:

$ docker build --build-arg s=scripts/a.sh -ta . 

(所以,因为我使用–build-arg,$ s将是Dockerfile中可用的参数,这部分工作)

Dockerfile是这样的:

 ARG s RUN echo $s RUN useradd -ms /bin/bash newuser USER newuser WORKDIR /home/newuser ENV fn=$(filename $s) # fails on this line COPY $s . ENTRYPOINT ["/bin/bash", "/home/newuser/$fn"] 

我遇到的问题是Docker构build在上面指出的行上失败。

 Error response from daemon: Syntax error - can't find = in "$s)". Must be of the form: name=value 

如果我改变这一行:

 RUN fn=$(filename $s) 

我得到这个错误:

 Error: Command failed: docker build --build-arg s=scripts/a.sh -ta . The command '/bin/sh -c fn=$(filename $s)' returned a non-zero code: 127 

任何人都知道正确的方法

  1. 在docker文件中创build一个variables
  2. 对该variables使用string插值,以便可以像ENTRYPOINT参数中那样引用variables:

    ENTRYPOINT [“/ bin / bash”,“/ home / newuser / $ var”]

即使我这样做:

 ARG s ARG sname RUN echo $s # works as expected RUN echo $sname # works as expected RUN useradd -ms /bin/bash newuser USER newuser WORKDIR /home/newuser COPY $s . # works as expected (I believe) ENTRYPOINT /bin/bash /home/newuser/$sname # does not work as expected 

即使我正在使用ENTRYPOINT的“非JSON”版本,它似乎仍然没有拿起$snamevariables的值。

我会避免在ENTRYPOINT中使用variables。 这是棘手的,需要深刻理解发生了什么。 容易被意外打破。 只要考虑下列之一。

使用已知名称为您的启动脚本创build链接。

 RUN ln -s /home/newuser/$sname /home/newuser/docker_entrypoint.sh ENTRYPOINT ["/home/newuser/docker_entrypoint.sh"] 

或编写独立的入口点脚本来运行你所需要的。

但是如果你想知道你的问题的解决scheme是如何工作的,只要继续阅读。

首先是一些定义。

  • ENV – 是构build时( docker build )和运行时( docker run )期间可用的环境variables。
  • ARG – 仅在构build时可用的环境variables

如果您查看https://docs.docker.com/engine/reference/builder/#environment-replacement,则会看到直接支持这些环境variables的dockerfile指令列表。 正如你所说,这就是COPY “拿起variables”的原因。

请注意,没有RUNENTRYPOINT 。 它是如何工作的?

你需要深入的文档。 首先RUNhttps://docs.docker.com/engine/reference/builder/#run )。 有两种forms。 第一个通过shell执行命令,这个shell可以访问buildtime环境variables。

 # this works because it is called as /bin/sh -c 'echo $sname' # the /bin/sh replace $sname for you RUN echo $sname # this does NOT work. There is no shell process to do $sname replacement # for you RUN ["echo", "$sname"] 

同样的事情适用于ENTRYPOINTCMD除非在容器启动期间只有运行时variables可用。

 # first you need to make some runtime variable from builtime one ENV sname $sname # Then you can use it during container runtime # docker runs `/bin/sh -c '/bin/bash /home/newuser/$sname'` for you # and this `/bin/sh` proces interprets `$sname` ENTRYPOINT /bin/bash /home/newuser/$sname # but this does NOT work. There is no process to interpolate `$sname` # docker runs what you describe. ENTRYPOINT ["/bin/bash", "/home/newuser/$sname"] 

编辑2017-04-03 :更新链接到docker文件和轻微的改名,以避免混淆,我从其他答案和意见。

我要求维勒姆回答,他的回答是非常明确的,但以下内容将起作用(只是不是一个稳定的解决scheme)。 他的回答基本上是说这个答案不是一个好办法:

 ARG s # passed in via --build-arg s=foo ARG sname # passed in via --build-arg sname=bar RUN echo $s RUN echo $sname ENV sname $sname # this is the key part RUN useradd -ms /bin/bash newuser USER newuser WORKDIR /home/newuser COPY $s . ENTRYPOINT /bin/bash /home/newuser/$sname # works, but is not stable! 

不要问我为什么COPY命令拿起通过ARG声明的variables,但是ENTRYPOINT命令似乎没有拿起通过ARG声明的variables,而只是拾取通过ENV声明的variables。 至less,这似乎是这样的。