我有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
使用Bash脚本和Alpine/Centos
Dockerfile
FROM alpine #just change this to centos
ARG MYARG=""
ENV E_MYARG=$MYARG
ADD . /tmp
RUN chmod +x /tmp/script.sh && /tmp/script.sh
script.sh
#!/usr/bin/env sh
if [ -z "$E_MYARG" ]; then
echo "NO PARAM PASSED"
else
echo $E_MYARG
fi
传递参数:
docker build -t test——build-arg MYARG="this is a test"。
....
Step 5/5 : RUN chmod +x /tmp/script.sh && /tmp/script.sh
---> Running in 10b0e07e33fc
this is a test
Removing intermediate container 10b0e07e33fc
---> f6f085ffb284
Successfully built f6f085ffb284
无参数:
Docker build -t test。
....
Step 5/5 : RUN chmod +x /tmp/script.sh && /tmp/script.sh
---> Running in b89210b0cac0
NO PARAM PASSED
Removing intermediate container b89210b0cac0
....
使用Bash脚本和Alpine/Centos
Dockerfile
FROM alpine #just change this to centos
ARG MYARG=""
ENV E_MYARG=$MYARG
ADD . /tmp
RUN chmod +x /tmp/script.sh && /tmp/script.sh
script.sh
#!/usr/bin/env sh
if [ -z "$E_MYARG" ]; then
echo "NO PARAM PASSED"
else
echo $E_MYARG
fi
传递参数:
docker build -t test——build-arg MYARG="this is a test"。
....
Step 5/5 : RUN chmod +x /tmp/script.sh && /tmp/script.sh
---> Running in 10b0e07e33fc
this is a test
Removing intermediate container 10b0e07e33fc
---> f6f085ffb284
Successfully built f6f085ffb284
无参数:
Docker build -t test。
....
Step 5/5 : RUN chmod +x /tmp/script.sh && /tmp/script.sh
---> Running in b89210b0cac0
NO PARAM PASSED
Removing intermediate container b89210b0cac0
....
出于某种原因,这里的大多数答案都没有帮助我(可能与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中有多行if条件,你可以把\放在每行的末尾(类似于你在shell脚本中的做法),并以;结尾每个命令。您甚至可以将set -eux之类的命令定义为第一个命令。
例子:
RUN set -eux; \
if [ -f /path/to/file ]; then \
mv /path/to/file /dest; \
fi; \
if [ -d /path/to/dir ]; then \
mv /path/to/dir /dest; \
fi
在你的情况下:
FROM centos:7
ARG arg
RUN if [ -z "$arg" ] ; then \
echo Argument not provided; \
else \
echo Argument is $arg; \
fi
然后使用:
docker build -t my_docker . --build-arg arg=42
我在容器上设置代理服务器时遇到了类似的问题。
我使用的解决方案是一个入口点脚本和另一个环境变量配置脚本。使用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
在Dockerfile中,配置:
# Base Image
FROM ubuntu:18.04
ARG user
ARG pass
USER root
# -z the length of STRING is zero
# [] are an alias for test command
# if $user is not empty, write credentials file
RUN if [ ! -z "$user" ]; then echo "${user} ${pass}">/root/proxy_credentials ; fi
#copy bash scripts
COPY configproxy.sh /root
COPY startup.sh .
RUN ["/bin/bash", "-c", ". /root/configproxy.sh"]
# Install dependencies and tools
#RUN apt-get update -y && \
# apt-get install -yqq --no-install-recommends \
# vim iputils-ping
ENTRYPOINT ["./startup.sh"]
CMD ["sh", "-c", "bash"]
在没有代理设置的情况下构建
docker build -t img01 -f Dockerfile .
使用代理设置构建
docker build -t img01 --build-arg user=<USER> --build-arg pass=<PASS> -f Dockerfile .
看看这里。
在可能的情况下,不要使用其他答案中描述的构建参数。这是一个古老的混乱的解决方案。Docker的target属性解决了这个问题。
目标的例子
Dockerfile
FROM foo as base
RUN ...
# Build dev image
FROM base as image-dev
RUN ...
COPY ...
# Build prod image
FROM base as image-prod
RUN ...
COPY ...
docker build --target image-dev -t foo .
version: '3.4'
services:
dev:
build:
context: .
dockerfile: Dockerfile
target: image-dev
现实世界中
dockerfile在现实世界中变得很复杂。使用buildkit & COPY——from可以获得更快、更可维护的dockerfile:
Docker在目标之上构建每个阶段,而不管它是否被继承。使用buildkit只构建继承的阶段。Docker必须是v19+。希望这很快会成为默认功能。
目标可以共享构建阶段。使用COPY——from来简化继承。
FROM foo as base
RUN ...
WORKDIR /opt/my-proj
FROM base as npm-ci-dev
# invalidate cache
COPY --chown=www-data:www-data ./package.json /opt/my-proj/package.json
COPY --chown=www-data:www-data ./package-lock.json /opt/my-proj/package-lock.json
RUN npm ci
FROM base as npm-ci-prod
# invalidate cache
COPY --chown=www-data:www-data ./package.json /opt/my-proj/package.json
COPY --chown=www-data:www-data ./package-lock.json /opt/my-proj/package-lock.json
RUN npm ci --only=prod
FROM base as proj-files
COPY --chown=www-data:www-data ./ /opt/my-proj
FROM base as image-dev
# Will mount, not copy in dev environment
RUN ...
FROM base as image-ci
COPY --from=npm-ci-dev /opt/my-proj .
COPY --from=proj-files /opt/my-proj .
RUN ...
FROM base as image-stage
COPY --from=npm-ci-prod /opt/my-proj .
COPY --from=proj-files /opt/my-proj .
RUN ...
FROM base as image-prod
COPY --from=npm-ci-prod /opt/my-proj .
COPY --from=proj-files /opt/my-proj .
RUN ...
开启实验模式。
sudo echo '{"experimental": true}' | sudo tee /etc/docker/daemon.json
启用buildkit进行构建。Buildkit默认构建时不带缓存-启用——build-arg BUILDKIT_INLINE_CACHE=1
CI构建工作。
DOCKER_BUILDKIT=1 \
docker build \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--target image-ci\
-t foo:ci
.
使用——cache-from从拉出的图像中缓存
生产工作
docker pull foo:ci
docker pull foo:stage
DOCKER_BUILDKIT=1 \
docker build \
--cache-from foo:ci,foo:stage \
--target image-prod \
-t prod
.