ARG ou ENV, lequel utiliser dans ce cas?

122

Cela pourrait être peut-être une question triviale, mais la lecture de documents pour ARG et ENV ne me clarifie pas les choses.

Je construis un conteneur PHP-FPM et je souhaite donner la possibilité d'activer / désactiver certaines extensions en fonction des besoins des utilisateurs.

Ce serait formidable si cela pouvait être fait dans le Dockerfile en ajoutant des conditions et en passant des indicateurs sur la commande de construction peut-être, mais AFAIK n'est pas pris en charge.

Dans mon cas et mon approche personnelle est d'exécuter un petit script au démarrage du conteneur, quelque chose comme ce qui suit:

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

Voici à quoi Dockerfileressemble mon :

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

Voici le référentiel complet si vous avez besoin de regarder en profondeur pour comprendre comment je fais les choses

Actuellement, cela fonctionne mais ... Si je veux ajouter, disons, 20 (un nombre aléatoire) d'extensions ou toute autre fonctionnalité qui peut être activée | désactiver, je ENVfinirai par 20 non nécessaires (car Dockerfile ne prend pas en charge .env files) définition dont le seul but serait de définir cet indicateur pour que le script sache quoi faire alors ...

  • Est-ce que c'est la bonne façon de le faire?
  • Dois-je utiliser ENVà cette fin?

Je suis ouvert aux idées si vous avez une approche différente pour y parvenir s'il vous plaît laissez-moi savoir

ReynierPM
la source
Si ces extensions / fonctionnalités sont différentes d'une build à l'autre, vous devez les utiliser ARGpour les définir avec des valeurs différentes avec chaque build en utilisant --build-arg, et vous pouvez toujours utiliser les valeurs par défaut dans le Dockerfile. Si vous utilisez ENV, vous devrez modifier le Dockerfile lui-même pour chaque build afin de définir des valeurs différentes
AA

Réponses:

216

À partir de la référence Dockerfile :

  • L' ARGinstruction définit une variable que les utilisateurs peuvent transmettre au générateur au moment de la construction avec la commande docker build à l'aide de l' --build-arg <varname>=<value>indicateur.

  • L' ENVinstruction définit la variable d'environnement <key>sur la valeur <value>.
    Les variables d'environnement définies à l'aide de ENVpersisteront lorsqu'un conteneur est exécuté à partir de l'image résultante.

Donc, si vous avez besoin d'une personnalisation au moment de la construction , ARGc'est votre meilleur choix.
Si vous avez besoin d'une personnalisation au moment de l'exécution (pour exécuter la même image avec des paramètres différents), ENVc'est bien adapté.

Si je veux ajouter, disons 20 (un nombre aléatoire) d'extensions ou toute autre fonctionnalité qui peut être activée | désactivée

Compte tenu du nombre de combinaisons impliquées, il ENVest préférable d' utiliser pour définir ces fonctionnalités au moment de l'exécution.

Mais vous pouvez combiner les deux en:

  • construire une image avec un ARG
  • en utilisant cela ARGcomme unENV

Autrement dit, avec un Dockerfile comprenant:

ARG var
ENV var=${var}

Vous pouvez ensuite soit créer une image avec une varvaleur spécifique au moment de la construction ( docker build --build-arg var=xxx), soit exécuter un conteneur avec une valeur d'exécution spécifique ( docker run -e var=yyy)

VonC
la source
1
Génial, mais ceux- ARGci sont accessibles à partir du script que j'exécute au démarrage du conteneur? Si c'est le cas, comment? Pourriez-vous améliorer votre réponse en ajoutant un petit exemple sur la façon dont ceux-ci sont accessibles à partir d'un script bash?
ReynierPM
@ReynierPM vous pouvez, en déclarant dans votre Dockerfile (temps de construction), en plus de ARG, un ENV var=${var}: voir stackoverflow.com/a/33936014/6309 . Utilise les deux.
VonC
Si j'utilise votre approche, peu importe ce que je vais finir avec une varvariable ENV sur le conteneur au démarrage, j'ai raison? Sinon, je ne te suis pas du tout. Rappelez-vous ceci: le script est copié d'un dossier local vers le conteneur et il est utilisé lors de l'initialisation du conteneur, c'est pourquoi j'utilise ENV au lieu d'ARG car je ne sais pas si lorsque le conteneur démarre, l'ARG est toujours en vie et est accessible de l'intérieur un script bash.
ReynierPM
J'ai ajouté mon Dockerfile pour que vous puissiez y jeter un œil et savoir ce que je fais actuellement
ReynierPM
1
@HardeepSingh Both: ENV ( stackoverflow.com/a/33836848/6309 ) et ARG ( stackoverflow.com/a/41593407/6309 )
VonC
0

Donc, si vous souhaitez définir la valeur d'une variable d'environnement sur quelque chose de différent pour chaque construction, nous pouvons transmettre ces valeurs pendant la construction et nous n'avons pas besoin de changer notre fichier docker à chaque fois.

Alors ENVqu'une fois défini, il ne peut pas être écrasé par les valeurs de ligne de commande. Donc, si nous voulons que notre variable d'environnement ait des valeurs différentes pour différentes versions, nous pourrions utiliser ARGet définir des valeurs par défaut dans notre fichier docker. Et lorsque nous voulons écraser ces valeurs, nous pouvons le faire --build-argsà chaque build sans changer notre fichier docker.

Pour plus de détails, vous pouvez vous référer à ceci .

user2719152
la source