我有dockerfile
FROM centos:7
ENV foo=42
然后我建立它
docker build -t my_docker .
然后运行它。
docker run -it -d my_docker
是否可以从命令行传递参数,并在Dockerfile中使用if else ?我的意思是
FROM centos:7
if (my_arg==42)
{ENV=TRUE}
else:
{ENV=FALSE}
用这个论证来构建。
docker build -t my_docker . --my_arg=42
我看到了很多可能的解决方案,但没有一个适合我今天面临的问题。所以,我正在花时间用另一个对我有用的可能的解决方案来回答这个问题。
在我的例子中,我利用了众所周知的if ["$VAR" == "this"];然后重复“do that”;fi。警告是Docker,我不知道为什么,在这种情况下不喜欢双等号。所以我们需要这样写if ["$VAR" = "this"];然后重复“do that”;fi。
这里有一个完整的例子,适用于我的情况:
FROM node:16
# Let's set args and envs
ARG APP_ENV="dev"
ARG NPM_CMD="install"
ARG USER="nodeuser"
ARG PORT=8080
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV PATH=$PATH:/home/node/.npm-global/bin
ENV NODE_ENV=${APP_ENV}
# Let's set the starting point
WORKDIR /app
# Let's build a cache
COPY package*.json .
RUN date \
# If the environment is production or staging, omit dev packages
# If any other environment, install dev packages
&& if [ "$APP_ENV" = "production" ]; then NPM_CMD="ci --omit=dev"; fi \
&& if [ "$APP_ENV" = "staging" ]; then NPM_CMD="ci --omit=dev"; fi \
&& npm ${NPM_CMD} \
&& usermod -d /app -l ${USER} node
# Let's add the App
COPY . .
# Let's expose the App port
EXPOSE ${PORT}
# Let's set the user
USER ${USER}
# Let's set the start App command
CMD [ "node", "server.js" ]
因此,如果用户传递了正确的build参数,docker build命令将为生产应用创建一个映像。如果没有,它将创建一个带有dev Node.js包的应用程序映像。
为了让它工作,你可以这样调用:
# docker build --build-arg APP_ENV=production -t app-node .
出于某种原因,这里的大多数答案都没有帮助我(可能与Dockerfile中的From图像有关)
所以我更喜欢在我的工作空间中结合——build-arg创建一个bash脚本,以便在Docker构建时通过检查参数是否为空来处理if语句
Bash脚本:
#!/bin/bash -x
if test -z $1 ; then
echo "The arg is empty"
....do something....
else
echo "The arg is not empty: $1"
....do something else....
fi
Dockerfile:
FROM ...
....
ARG arg
COPY bash.sh /tmp/
RUN chmod u+x /tmp/bash.sh && /tmp/bash.sh $arg
....
码头工人构建:
docker build --pull -f "Dockerfile" -t $SERVICE_NAME --build-arg arg="yes" .
注意:这将被用于bash脚本中的else (false)
docker build --pull -f "Dockerfile" -t $SERVICE_NAME .
备注:这将进入if (true)
编辑1:
经过几次尝试,我找到了下面的文章和这一篇
这让我明白了两件事:
1) FROM之前的ARG在构建之外
2)默认shell是/bin/sh,这意味着if else在docker构建中有一点不同。例如,你只需要一个“=”而不是“==”来比较字符串。
你可以在Dockerfile里面做这个
ARG argname=false #default argument when not provided in the --build-arg
RUN if [ "$argname" = "false" ] ; then echo 'false'; else echo 'true'; fi
在docker构建中:
docker build --pull -f "Dockerfile" --label "service_name=${SERVICE_NAME}" -t $SERVICE_NAME --build-arg argname=true .
对于上述提出的解决方案,有一个有趣的替代方案,它使用单个Dockerfile,每个条件构建只需要调用一次docker构建,并避免bash。
解决方案:
下面的Dockerfile解决了这个问题。复制粘贴,自己试试。
ARG my_arg
FROM centos:7 AS base
RUN echo "do stuff with the centos image"
FROM base AS branch-version-1
RUN echo "this is the stage that sets VAR=TRUE"
ENV VAR=TRUE
FROM base AS branch-version-2
RUN echo "this is the stage that sets VAR=FALSE"
ENV VAR=FALSE
FROM branch-version-${my_arg} AS final
RUN echo "VAR is equal to ${VAR}"
Dockerfile说明:
我们首先得到一个基本图像(在您的例子中是centos:7),并将其放入自己的阶段。基本阶段应该包含在条件之前要做的事情。在那之后,我们还有两个阶段,代表我们的条件的分支:branch-version-1和branch-version-2。我们两个都做了。最终阶段根据my_arg选择其中一个阶段。条件Dockerfile。好了。
运行时输出:
(我把它缩写了一下…)
my_arg = = 2
docker build --build-arg my_arg=2 .
Step 1/12 : ARG my_arg
Step 2/12 : ARG ENV
Step 3/12 : FROM centos:7 AS base
Step 4/12 : RUN echo "do stuff with the centos image"
do stuff with the centos image
Step 5/12 : FROM base AS branch-version-1
Step 6/12 : RUN echo "this is the stage that sets VAR=TRUE"
this is the stage that sets VAR=TRUE
Step 7/12 : ENV VAR=TRUE
Step 8/12 : FROM base AS branch-version-2
Step 9/12 : RUN echo "this is the stage that sets VAR=FALSE"
this is the stage that sets VAR=FALSE
Step 10/12 : ENV VAR=FALSE
Step 11/12 : FROM branch-version-${my_arg}
Step 12/12 : RUN echo "VAR is equal to ${VAR}"
VAR is equal to FALSE
my_arg = = 1
docker build --build-arg my_arg=1 .
...
Step 11/12 : FROM branch-version-${my_arg}
Step 12/12 : RUN echo "VAR is equal to ${VAR}"
VAR is equal to TRUE
感谢Tõnis提供这个惊人的想法!