在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
任何人都知道正确的方法
- 在docker文件中创build一个variables
-
对该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”版本,它似乎仍然没有拿起$sname
variables的值。
我会避免在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”的原因。
请注意,没有RUN
和ENTRYPOINT
。 它是如何工作的?
你需要深入的文档。 首先RUN
( https://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"]
同样的事情适用于ENTRYPOINT
和CMD
除非在容器启动期间只有运行时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,这似乎是这样的。