ARG o ENV, ¿cuál usar en este caso?

122

Esta podría ser una pregunta trivial, pero leer documentos para ARG y ENV no me aclara las cosas.

Estoy construyendo un contenedor PHP-FPM y quiero brindar la posibilidad de habilitar / deshabilitar algunas extensiones según las necesidades del usuario.

Sería genial si esto se pudiera hacer en el Dockerfile agregando condicionales y pasando banderas en el comando de compilación, pero AFAIK no es compatible.

En mi caso y mi enfoque personal es ejecutar un pequeño script cuando se inicia el contenedor, algo como lo siguiente:

#!/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 "$@"

Así es como se Dockerfileve mi :

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

Aquí está el repositorio completo si necesita echar un vistazo en profundidad para comprender cómo estoy haciendo las cosas

Actualmente esto funciona, pero ... Si quiero agregar, digamos 20 (un número aleatorio) de extensiones o cualquier otra característica que se pueda habilitar | deshabilitar, terminaré con 20 no necesarias ENV(porque Dockerfile no admite .env files) definición cuyo único propósito sería establecer esta bandera para que el script sepa qué hacer luego ...

  • ¿Esta es la manera correcta de hacerlo?
  • ¿Debo usar ENVpara este propósito?

Estoy abierto a ideas si tiene un enfoque diferente para lograr esto, hágamelo saber

ReynierPM
fuente
Si esas extensiones / características fueran diferentes de una compilación a otra, entonces debería usar ARGpara configurarlas con valores diferentes con cada compilación usando --build-arg, y aún puede usar valores predeterminados en el Dockerfile. Si lo usa ENV, necesitaría editar el Dockerfile para cada compilación para establecer diferentes valores
AA

Respuestas:

216

De la referencia de Dockerfile :

  • La ARGinstrucción define una variable que los usuarios pueden pasar en el momento de la compilación al constructor con el comando docker build usando la --build-arg <varname>=<value>marca.

  • La ENVinstrucción establece <key>el valor de la variable de entorno <value>.
    Las variables de entorno establecidas con ENVpersistirán cuando se ejecute un contenedor desde la imagen resultante.

Entonces, si necesita personalización en el tiempo de construcción , ARGes su mejor opción.
Si necesita personalización en tiempo de ejecución (para ejecutar la misma imagen con diferentes configuraciones), ENVes adecuado.

Si quiero agregar, digamos 20 (un número aleatorio) de extensiones o cualquier otra característica que se pueda habilitar | deshabilitar

Dada la cantidad de combinaciones involucradas, usar ENVpara configurar esas características en tiempo de ejecución es mejor aquí.

Pero puedes combinar ambos mediante:

  • construyendo una imagen con un especifico ARG
  • usando eso ARGcomo unENV

Es decir, con un Dockerfile que incluye:

ARG var
ENV var=${var}

A continuación, puede crear una imagen con un varvalor específico en el tiempo de compilación ( docker build --build-arg var=xxx) o ejecutar un contenedor con un valor de tiempo de ejecución específico ( docker run -e var=yyy)

VonC
fuente
1
Genial, pero ¿ ARGse puede acceder a ellos desde el script que estoy ejecutando al iniciar el contenedor? ¿Si es así, cómo? ¿Podría mejorar su respuesta agregando un pequeño ejemplo sobre cómo se puede acceder a ellos desde un script bash?
ReynierPM
@ReynierPM puede, declarando en su Dockerfile (tiempo de compilación), además de ARG, un ENV var=${var}: consulte stackoverflow.com/a/33936014/6309 . Utilice ambos.
VonC
Si utilizo su enfoque, no importa lo que termine con una varvariable ENV en el contenedor cuando comience, ¿tengo razón? De lo contrario, no te seguiré en absoluto. Recuerde esto: el script se copia de una carpeta local al contenedor y se usa después de la inicialización del contenedor, por eso estoy usando ENV en lugar de ARG porque no sé si cuando el contenedor se inicia, el ARG sigue vivo y se puede acceder desde adentro un guión bash.
ReynierPM
Agregué mi Dockerfile para que pueda echarle un vistazo y saber lo que estoy haciendo actualmente
ReynierPM
1
@HardeepSingh Ambos: ENV ( stackoverflow.com/a/33836848/6309 ) y ARG ( stackoverflow.com/a/41593407/6309 )
VonC
0

Entonces, si desea establecer el valor de una variable de entorno en algo diferente para cada compilación, entonces podemos pasar estos valores durante el tiempo de compilación y no es necesario que cambiemos nuestro archivo docker cada vez.

Mientras que ENV, una vez configurado, no se puede sobrescribir a través de los valores de la línea de comando. Entonces, si queremos que nuestra variable de entorno tenga diferentes valores para diferentes compilaciones, entonces podríamos usar ARGy establecer valores predeterminados en nuestro archivo docker. Y cuando queremos sobrescribir estos valores, podemos hacerlo usando --build-argsen cada compilación sin cambiar nuestro archivo docker.

Para obtener más detalles, puede consultar esto .

usuario2719152
fuente