ARG ou ENV, qual usar neste caso?

122

Esta pode ser uma questão trivial, mas ler documentos para ARG e ENV não deixa as coisas claras para mim.

Estou construindo um contêiner PHP-FPM e desejo habilitar / desabilitar algumas extensões de acordo com as necessidades do usuário.

Seria ótimo se isso pudesse ser feito no Dockerfile adicionando condicionais e passando sinalizadores no comando de construção, talvez, mas AFAIK não é suportado.

No meu caso e minha abordagem pessoal é executar um pequeno script quando o contêiner é iniciado, algo como o seguinte:

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

É assim que meu se Dockerfileparece:

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

Aqui está o repositório completo, se você precisar dar uma olhada em profundidade para entender como estou fazendo as coisas

Atualmente, isso está funcionando, mas ... Se eu quiser adicionar, digamos, 20 (um número aleatório) de extensões ou qualquer outro recurso que possa ser habilitado | desabilitado, terminarei com 20 não necessários ENV(porque o Dockerfile não oferece suporte a .env arquivos) definição cujo único propósito seria definir este sinalizador para permitir que o script saiba o que fazer então ...

  • Esse é o jeito certo de fazer?
  • Devo usar ENVpara esse fim?

Estou aberto a ideias, se você tiver uma abordagem diferente para conseguir isso, por favor me informe sobre isso

ReynierPM
fonte
Se essas extensões / recursos forem diferentes de uma compilação para outra, você deve usar ARGpara defini-los com valores diferentes com cada compilação usando --build-arg, e você ainda pode usar os valores padrão no Dockerfile. Se você usar ENV, precisará editar o próprio Dockerfile para cada construção para definir valores diferentes
AA

Respostas:

217

Da referência do Dockerfile :

  • A ARGinstrução define uma variável que os usuários podem passar no momento da construção para o construtor com o comando docker build usando o --build-arg <varname>=<value>sinalizador.

  • A ENVinstrução define a variável de ambiente <key>para o valor <value>.
    As variáveis ​​de ambiente definidas usando ENVpersistirão quando um contêiner for executado a partir da imagem resultante.

Portanto, se você precisar de personalização em tempo de construção , ARGé sua melhor escolha.
Se você precisa de personalização em tempo de execução (para executar a mesma imagem com configurações diferentes), ENVé adequado.

Se eu quiser adicionar, digamos, 20 (um número aleatório) de extensões ou qualquer outro recurso que possa ser habilitado | desabilitado

Dado o número de combinações envolvidas, usar ENVpara definir esses recursos em tempo de execução é melhor aqui.

Mas você pode combinar ambos :

  • construir uma imagem com um específico ARG
  • usando isso ARGcomo umENV

Ou seja, com um Dockerfile incluindo:

ARG var
ENV var=${var}

Você pode então construir uma imagem com um varvalor específico em tempo de construção ( docker build --build-arg var=xxx) ou executar um contêiner com um valor de tempo de execução específico ( docker run -e var=yyy)

VonC
fonte
1
Ótimo, mas eles ARGpodem ser acessados ​​a partir do script que estou executando na inicialização do contêiner? Se sim, como? Você poderia melhorar sua resposta adicionando um pequeno exemplo sobre como eles podem ser acessados ​​a partir de um script bash?
ReynierPM
@ReynierPM você pode, declarando em seu Dockerfile (tempo de compilação), além de ARGum ENV var=${var}: consulte stackoverflow.com/a/33936014/6309 . Use ambos.
VonC
Se eu usar sua abordagem, não importa o que aconteça, vou acabar com uma varvariável ENV no contêiner quando ele iniciar, estou certo? Caso contrário, não estou te seguindo de forma alguma. Lembre-se disso: o script é copiado de uma pasta local para o contêiner e é usado na inicialização do contêiner, é por isso que estou usando ENV em vez de ARG porque não sei se quando o contêiner inicia o ARG ainda está vivo e pode ser acessado de dentro um script bash.
ReynierPM
Eu adicionei meu Dockerfile para que você possa dar uma olhada nele e saber o que estou fazendo atualmente
ReynierPM
1
@HardeepSingh Ambos: ENV ( stackoverflow.com/a/33836848/6309 ) e ARG ( stackoverflow.com/a/41593407/6309 )
VonC
0

Portanto, se quisermos definir o valor de uma variável de ambiente para algo diferente para cada construção, podemos passar esses valores durante o tempo de construção e não precisamos alterar nosso arquivo docker todas as vezes.

Enquanto ENV, uma vez definido, não pode ser substituído por meio de valores de linha de comando. Portanto, se quisermos que nossa variável de ambiente tenha valores diferentes para diferentes compilações, podemos usar ARGe definir os valores padrão em nosso arquivo docker. E quando quisermos sobrescrever esses valores, podemos fazer isso usando--build-args em cada compilação, sem alterar nosso arquivo docker.

Para mais detalhes, você pode consultar isto .

user2719152
fonte