Dockerfile中的条件ENV


77

是否可以ENV根据构建的值在Dockerfile中有条件地设置变量ARG

例如:类似

ARG BUILDVAR=sad
ENV SOMEVAR=if $BUILDVAR -eq "SO"; then echo "hello"; else echo "world"; fi

更新:基于Mario答案的当前用法:

ARG BUILD_ENV=prod
ENV NODE_ENV=production
RUN if [ "${BUILD_ENV}" = "test" ]; then export NODE_ENV=development; fi

但是,先运行--build-arg BUILD_ENV=test然后进入主机,我仍然可以

docker run -it mycontainer bin/bash
[root@brbqw1231 /]# echo $NODE_ENV
production

1
尝试RUN if [ "$BUILD_ENV" = "test" ]; then export NODE_ENV=development; fi。注意空格。不要删除它们
Alkis Kalogeris

@alkis似乎没有帮助虽然赶上好使用=的,而不是eq
马修·赫布斯特

映像构建期间的导出变量不会在容器运行时扩展,而是使用RUN if [ "${BUILD_ENV}" = "test" ] ;then echo BUILD_ENV=development >>/etc/environment ; fi
kyb

Answers:


48

是的,可以,但是您需要使用build参数作为标志。您可以使用Shell的参数扩展功能来检查条件。这是概念验证的Docker文件:

FROM debian:stable
ARG BUILD_DEVELOPMENT
# if --build-arg BUILD_DEVELOPMENT=1, set NODE_ENV to 'development' or set to null otherwise.
ENV NODE_ENV=${BUILD_DEVELOPMENT:+development}
# if NODE_ENV is null, set it to 'production' (or leave as is otherwise).
ENV NODE_ENV=${NODE_ENV:-production}

测试版本:

docker build --rm -t env_prod ./
...
docker run -it env_prod bash
root@2a2c93f80ad3:/# echo $NODE_ENV 
production
root@2a2c93f80ad3:/# exit
docker build --rm -t env_dev --build-arg BUILD_DEVELOPMENT=1 ./
...
docker run -it env_dev bash
root@2db6d7931f34:/# echo $NODE_ENV
development

1
这似乎是最好的解决方案,尤其是当构建类似Nuxt.js / next.js之类的东西时,需要在构建时而非运行时设置NODE_ENV。
尼克·鲍尔斯

经过更多使用之后,对ARG有一些警告,它仅用于下一阶段(dockerfile中的行),因此,如果要多次使用它,则必须多次包含它。docs.docker.com / engine / reference / builder /#using-arg-variables
Nick Bolles

1
@ Sup3rb0wlz该警告是关于多阶段构建的,即多条“ FROM ...”行。如果您不使用它们,那么ARG将继续在Dockerfile的所有以后的代码行中使用。
亚瑟·塔卡

1
请注意,Dockerfiles中的变量仅允许扩展类型有限子集,而不允许该链接中的整个列表(用于bash,不适用于docker)。基本上,只允许使用两种形式:+形式和–形式,如答案所示。
亚瑟塔卡

14

您不能直接在Dockerfile中运行bash代码,但必须使用RUN命令。因此,举例来说,你可以改变ENVRUN和输出变量的if,象下面这样:

ARG BUILDVAR=sad 
RUN if [ "$BUILDVAR" == "SO" ]; \
    then export SOMEVAR=hello; \
    else export SOMEVAR=world; \
    fi 

我没有尝试过,但应该可以。


15
请注意,带有的环境变量RUN export将不会保留在生成的图像中
Bastien Libersa,

1
@BastienLibersa导出的变量甚至不会在此RUN语句之外持续存在,因为它被视为单独的层。
Ruslan Kabalin '18

1
@holms等。-请记住,对于基于某些Linux发行版的映像,例如ubuntu,您必须使用single=而不是==
Jakub Kukul

3
这行不通Step 9/11 : RUN if [ "$version" = "show"]; then export runCMD=hello; else export runCMD=world; fi ---> Running in 160b291ca7e4 /bin/sh: 1: [: missing ]
Peter Weyand

1
@PeterWeyand最有可能在结束括号之前丢失空间]
Andre Miras

4

虽然您无法设置条件ENV变量,但是您可以使用RUN命令和空值合并环境变量来完成操作:

RUN node /var/app/current/index.js --env ${BUILD_ENV:-${NODE_ENV:-"development"}}

我喜欢这样,但是它限于可以在容器外部(在运行时)确定的条件,这就是为什么我不接受它作为“答案”的原因。我认为对此的完整解决方案应该可以在容器内部工作(除非可以证明这是不可能的)。不过,感谢您对bash中空合并的学习!
马修·赫伯斯特

3

您的逻辑实际上是正确的。这里的问题是,RUN export ...export命令在Dockerfile中将不起作用,因为该命令不会在映像之间持续存在。Dockerfile创建一个临时容器以为其生成映像,因此环境变量将不存在。

ENV另一方面,根据文档说明:

ENV从结果映像运行容器时,使用设置的环境变量将保留。

唯一的方法是在docker run命令期间从映像生成容器,并围绕该逻辑包装逻辑:

if [ "${BUILD_ENV}" = "test" ]; then
    docker run -e NODE_ENV=development myimage
else
    docker run myimage
fi

0

将值传递给Dockerfile,然后传递给入口点脚本

在命令行中输入所需的值(TARG)

docker run --env TARG=T1_WS01 -i projects/msbob

然后在你Dockerfile这样的东西

Dockerfile:
# if $TARG is not set then "entrypoint" defaults to Q0_WS01
CMD ./entrypoint.sh ${TARG} Q0_WS01

entrypoint.sh脚本只读取第一个参数

entrypoint.sh:
#!/bin/bash
[ $1 ] || { echo "usage: entrypoint.sh <$TARG>" ; exit ; }
target_env=$1

0

如果我们只在谈论环境变量,那么只需在生产环境中进行设置即可

ENV NODE_ENV prod

在开发容器的过程中,您可以使用-e NODE_ENV=dev

这样,映像始终是内置产品,但是本地容器是在开发中启动的。


-1

如果您只需要检查是否存在build-arg并要设置默认值,则此答案很好。为了改进此解决方案,如果您要使用build-arg传递的数据,可以执行以下操作:

FROM debian:stable
ARG BUILD_DEVELOPMENT=production
ENV NODE_ENV=$BUILD_DEVELOPMENT

神奇之处在于ARG的默认值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.