Dockerfile中的条件环境

Dockerfile中的条件环境,docker,dockerfile,Docker,Dockerfile,是否可以基于生成ARG的值在Dockerfile中有条件地设置ENV变量 比如说 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_

是否可以基于生成
ARG
的值在Dockerfile中有条件地设置
ENV
变量

比如说

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

不能直接在Dockerfile中运行bash代码,但必须使用
run
命令。因此,例如,您可以使用
RUN
更改
ENV
,并在
if
中导出变量,如下所示:

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

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

虽然您不能设置条件
ENV
变量,但您可以使用
RUN
命令和环境变量完成所需的操作:

RUN node /var/app/current/index.js --env ${BUILD_ENV:-${NODE_ENV:-"development"}}
将值传递给Dockerfile,然后传递给entrypoint脚本 从命令行输入所需的值(TARG)

然后在你的
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
entrypoint.sh:
#!/bin/bash
[$1]|{echo”用法:entrypoint.sh;exit;}
目标环境=1美元

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

ENV
另一方面,根据州:

从生成的映像运行容器时,使用
ENV
设置的环境变量将保持不变

执行此操作的唯一方法是在从图像生成容器时运行
docker
命令,并围绕该命令包装您的逻辑:

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

是的,这是可能的,但是您需要使用构建参数作为标志。您可以使用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

如果我们只讨论环境变量,那么就用production设置它

ENV NODE_ENV prod
在开发中的容器启动期间,您可以使用
-e NODE\u ENV=dev

这样,映像总是内置于产品中,但本地容器是在开发过程中启动的。

如果您只需要检查是否存在构建参数,并且希望设置默认值,这将非常有用。 要改进此解决方案,如果要使用生成参数传递的数据,可以执行以下操作:

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

魔法来自ARG的默认值。

在容器上设置代理服务器时,我遇到了类似的问题

我使用的解决方案是一个入口点脚本和另一个用于环境变量配置的脚本。使用RUN,可以确保配置脚本在构建时运行,并在运行容器时运行ENTRYPOINT

--在命令行上使用build arg设置代理用户和密码

入口点脚本如下所示:

#!/bin/bash
# Load the script of environment variables
. /root/configproxy.sh
# Run the main container command
exec "$@"
configproxy.sh

#!/bin/bash

function start_config {
read u p < /root/proxy_credentials

export HTTP_PROXY=http://$u:$p@proxy.com:8080
export HTTPS_PROXY=https://$u:$p@proxy.com:8080

/bin/cat <<EOF > /etc/apt/apt.conf 
Acquire::http::proxy "http://$u:$p@proxy.com:8080";
Acquire::https::proxy "https://$u:$p@proxy.com:8080";
EOF
}

if [ -s "/root/proxy_credentials" ]
then
start_config
fi
不带代理设置的生成

docker build -t img01 -f Dockerfile . 
docker build -t img01 --build-arg user=<USER> --build-arg pass=<PASS> -f Dockerfile . 
使用代理设置生成

docker build -t img01 -f Dockerfile . 
docker build -t img01 --build-arg user=<USER> --build-arg pass=<PASS> -f Dockerfile . 
docker build-t img01--build arg user=--build arg pass=-f Dockerfile。

看看。

如果[“$BUILD_ENV”=“test”],请尝试
运行;然后导出节点_ENV=development;fi
。注意空格。不要移除them@alkis虽然在映像构建期间使用
=
而不是
eq
导出变量的好习惯在容器的运行时不会展开,但似乎没有帮助,而是在[“${build_ENV}”=“test”]时使用
run;然后echo BUILD_ENV=development>>/etc/environment;fi
我喜欢这样,但它仅限于可以在容器外部(运行时)确定的条件,这就是为什么我不接受它作为“答案”的原因。我认为一个完整的解决方案应该能够在容器内部工作(除非可以证明这是不可能的)。感谢您学习了bash中的空合并!请注意,带有
runexport
的环境变量集不会在结果中持久存在image@BastienLibersa导出的变量甚至不会在这个RUN语句之外持久存在,因为它被视为单独的层。@holms等人。-请记住,对于基于某些linux发行版(例如ubuntu)的图像,您必须使用单个
=
而不是
=
。这不起作用
步骤9/11:如果[“$version”=“show”]运行;然后导出runCMD=hello;else export runCMD=world;fi--->运行在160b291ca7e4/bin/sh:1:[:missing]
@PeterWey中,并且很可能在结束括号前缺少空格
]
这似乎是最好的解决方案,尤其是在构建Nuxt.js/next.js这样的东西时,其中节点_ENV需要在构建时设置,而不是在运行时,ARG有一些注意事项,它只用于下一个阶段(dockerfile中的行),因此如果您想多次使用它@Sup3rb0wlz,则必须多次包含它,警告是关于多阶段构建的,即多个“FROM…”行。如果不使用这些参数,则参数将在Dockerfile的所有未来行上继续。请注意,Dockerfile中的变量只允许一个,而不允许该链接中的整个列表(用于bash,而不是docker)。基本上,只允许使用+形式和–形式,如本答案所示。