ARG 或 ENV,在这种情况下使用哪一个?

Posted

技术标签:

【中文标题】ARG 或 ENV,在这种情况下使用哪一个?【英文标题】:ARG or ENV, which one to use in this case? 【发布时间】:2017-06-14 10:59:36 【问题描述】:

这可能是一个微不足道的问题,但阅读 ARG 和 ENV 的文档并没有让我明白。

我正在构建一个 php-FPM 容器,我希望能够根据用户需求启用/禁用某些扩展。

如果这可以在 Dockerfile 中通过添加条件并在构建命令上传递标志来完成,那就太好了,但不支持 AFAIK。

就我而言,我个人的做法是在容器启动时运行一个小脚本,如下所示:

#!/bin/sh   
set -e

RESTART="false"

# This script will be placed in /config/init/ and run when container starts.
if  [ "$INSTALL_XDEBUG" == "true" ]; then
    printf "\nInstalling Xdebug ...\n"
    yum install -y  php71-php-pecl-xdebug
    RESTART="true"
fi
...   
if  [ "$RESTART" == "true" ]; then
    printf "\nRestarting php-fpm ...\n"
    supervisorctl restart php-fpm
fi

exec "$@"

这就是我的Dockerfile 的样子:

FROM reynierpm/centos7-supervisor
ENV TERM=xterm \
    PATH="/root/.composer/vendor/bin:$PATH" \
    INSTALL_COMPOSER="false" \
    COMPOSER_ALLOW_SUPERUSER=1 \
    COMPOSER_ALLOW_XDEBUG=1 \
    COMPOSER_DISABLE_XDEBUG_WARN=1 \
    COMPOSER_HOME="/root/.composer" \
    COMPOSER_CACHE_DIR="/root/.composer/cache" \
    SYMFONY_INSTALLER="false" \
    SYMFONY_PROJECT="false" \
    INSTALL_XDEBUG="false" \
    INSTALL_MONGO="false" \
    INSTALL_REDIS="false" \
    INSTALL_HTTP_REQUEST="false" \
    INSTALL_UPLOAD_PROGRESS="false" \
    INSTALL_XATTR="false"

RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
                   https://rpms.remirepo.net/enterprise/remi-release-7.rpm
RUN yum install -y  \
        yum-utils \
        git \
        zip \
        unzip \
        nano \
        wget \
        php71-php-fpm \
        php71-php-cli \
        php71-php-common \
        php71-php-gd \
        php71-php-intl \
        php71-php-json \
        php71-php-mbstring \
        php71-php-mcrypt \
        php71-php-mysqlnd \
        php71-php-pdo \
        php71-php-pear \
        php71-php-xml \
        php71-pecl-apcu \
        php71-php-pecl-apfd \
        php71-php-pecl-memcache \
        php71-php-pecl-memcached \
        php71-php-pecl-zip && \
        yum clean all && rm -rf /tmp/yum*

RUN ln -sfF /opt/remi/php71/enable /etc/profile.d/php71-paths.sh && \
    ln -sfF /opt/remi/php71/root/usr/bin/pear,pecl,phar,php,php-cgi,phpize /usr/local/bin/. && \
    mv -f /etc/opt/remi/php71/php.ini /etc/php.ini && \
    ln -s /etc/php.ini /etc/opt/remi/php71/php.ini && \
    rm -rf /etc/php.d && \
    mv /etc/opt/remi/php71/php.d /etc/. && \
    ln -s /etc/php.d /etc/opt/remi/php71/php.d

COPY container-files /
RUN chmod +x /config/bootstrap.sh
WORKDIR /data/www
EXPOSE 9001

目前这是可行的,但是...如果我想添加 20 个(随机数)扩展或任何其他可以启用|禁用的功能,那么我将以 20 个不必要的 ENV 结尾(因为 Dockerfile不支持 .env 文件)定义,其唯一目的是设置此标志,以便让脚本知道该做什么......

这是正确的做法吗? 我应该为此使用ENV 吗?

如果您有不同的方法来实现这一点,我愿意接受想法,请告诉我

【问题讨论】:

如果这些扩展/功能会因一个构建与另一个构建不同,那么您应该使用ARG 为每个构建使用--build-arg 设置不同的值,并且您仍然可以使用默认值在 Dockerfile 中。如果您使用ENV,则需要为每个构建编辑 Dockerfile 本身以设置不同的值 另见vsupalov.com/docker-arg-vs-env 【参考方案1】:

来自Dockerfile reference:

ARG 指令定义了一个变量,用户可以在构建时通过 docker build 命令使用--build-arg <varname>=<value> 标志将其传递给构建器。

ENV 指令将环境变量<key> 设置为值<value>。 当容器从生成的镜像运行时,使用ENV 设置的环境变量将保持不变。

因此,如果您需要构建时间自定义,ARG 是您的最佳选择。 如果您需要运行时自定义(以不同的设置运行相同的图像),ENV 非常适合。

如果我想添加 20 个(随机数)扩展或任何其他可以启用|禁用的功能

考虑到所涉及的组合数量,最好在运行时使用ENV 设置这些功能。

但是你可以combine both by:

使用特定的ARG 构建映像 使用ARG 作为ENV

也就是说,使用 Dockerfile 包括:

ARG var
ENV var=$var

然后,您可以在构建时构建具有特定 var 值的映像 (docker build --build-arg var=xxx),或者运行具有特定运行时值 (docker run -e var=yyy) 的容器

【讨论】:

很好,但是那些ARG 可以从我在容器启动时运行的脚本中访问?如果有怎么办?您能否通过添加一个关于如何从 bash 脚本访问这些内容的小示例来改进您的答案? @ReynierPM 您可以通过在您的 Dockerfile(构建时间)中声明,在ARGaddition 中添加ENV var=$var:参见***.com/a/33936014/6309。两者都用。 如果我使用你的方法,那么无论如何我都会在容器启动时得到一个var ENV 变量,我是对的吗?否则我根本不关注你。记住这一点:脚本从本地文件夹复制到容器,并在容器初始化时使用,这就是我使用 ENV 而不是 ARG 的原因,因为我不知道容器何时启动 ARG 是否仍然存在并且可以从内部访问一个 bash 脚本。 @ReynierPM 好的。见***.com/a/33936014/6309。如该答案所述,添加ARGENV @HardeepSingh 两者:ENV (***.com/a/33836848/6309) 和 ARG (***.com/a/41593407/6309)【参考方案2】:

因此,如果想为每次构建设置不同的环境变量值,那么我们可以在构建期间传递这些值,而无需每次都更改 docker 文件。

虽然ENV,一旦设置不能通过命令行值覆盖。所以,如果我们想让我们的环境变量对不同的构建有不同的值,那么我们可以使用ARG 并在我们的 docker 文件中设置默认值。当我们想要覆盖这些值时,我们可以在每次构建时使用--build-args 来实现,而无需更改我们的 docker 文件。

更多详情可以参考this。

【讨论】:

以上是关于ARG 或 ENV,在这种情况下使用哪一个?的主要内容,如果未能解决你的问题,请参考以下文章

Dockerfiles ENV和ARG的应用

Dockerfiles ENV和ARG的应用

在 spark RDD 中应该使用哪种方法来处理这种情况。解释?

Angular 指令:在这种情况下我应该使用结构还是属性?

在这种情况下使用 Tasklet 或 Chunk

我应该在通知系统中使用哪种设计模式?