Dockerfile if else koşul harici bağımsız değişkenlerle


132

Dockerfile'ım var

FROM centos:7
ENV foo=42

sonra onu inşa ederim

docker build -t my_docker .

ve çalıştırın.

docker run -it -d  my_docker

Dockerfile'da komut satırından argümanlar iletip başka if ile kullanmak mümkün müdür? Gibi bir şey demek istiyorum

FROM centos:7
if (my_arg==42)
     {ENV=TRUE}
else:
     {ENV=FALSE}

ve bu argümanla inşa edin.

 docker build -t my_docker . --my_arg=42

1
Bu muhtemelen bir yapı betiğinden ele alınmalıdır.
Snps

@ Зелёный bu yanlış. Aşağıdaki cevaba bakın, bu
--build

Kabul edilen yanıt, sorunun "aksi takdirde koşulluysa" kısmını kapsamaz. Koşul kontrolü bir gereklilik değilse, "Harici bağımsız değişkenlerle Dockerfile" olarak yeniden adlandırmak daha iyi olurdu.
Ruslan Kabalin

@RuslanKabalin - kabul edilen yanıtın hem "then" hem de "else" cümleleri vardır. Tek fark, "eğer durumu" nda test edilen şeydir . Kodu için söz konusu gösterilen: RUN if [ "$arg" == "42" ]; then ENV=TRUE; else ENV=FALSE; fi. Veya arg eksikse: RUN if [ "x$arg" == "x42" ]; then ...
ToolmakerSteve

Yanıtlar:


193

O kadar temiz görünmeyebilir, ancak Dockerfile (koşullu) dosyanızı aşağıdaki gibi alabilirsiniz:

FROM centos:7
ARG arg
RUN if [ "x$arg" = "x" ] ; then echo Argument not provided ; else echo Argument is $arg ; fi

ve sonra görüntüyü şu şekilde oluşturun:

docker build -t my_docker . --build-arg arg=45

veya

docker build -t my_docker .


20
Bunun [ "$arg" = "x" ]yerine olması gerekmiyor [ "x$arg" = "x" ]mu?
Quannt

4
Buradaki üçlü, belirli bir argümanı kontrol etmek yerine herhangi bir argüman sağlanıp sağlanmadığını kontrol etmektir. Olarak yeniden yazılırsa daha açık görünürdü, if [ $arg != "" ] ;ancak aşina olmadığım bir şeyler olduğundan eminim
myol

21
if [[ -n "$arg" ]]bir parametre boş değilse true, bir parametre boşsa if [[ -z "$arg" ]]true
acumartini

6
Çok satırlı if ifadesi nasıl yazılır?
Ashutosh Chamoli

12
@Quannt - hayır, bakın Neden kabuk betikleri ... [ "x$arg" = "x" ] iki alıntılanmış dizgiyi karşılaştırıyor gibi görünüyor, ama tırnaklar soyulmuş; Bu, sözdizimini doğru tutar. İyi: alıntı sıyırma sonra: if x = x ... Kötü: if = . ANCAK, bir parametrenin varlığını kontrol etmenin daha iyi yolları VARDIR: Giriş bağımsız değişkenlerinin varlığını kontrol edin .
ToolmakerSteve

21

Bazı nedenlerden dolayı buradaki yanıtların çoğu bana yardımcı olmadı (belki de Dockerfile'daki FROM resmimle ilgilidir)

Bu yüzden bir bash script--build-arg , Docker oluştururken bağımsız değişkenin boş olup olmadığını kontrol ederek if ifadesini işlemek için çalışma alanımda ile birleştirilmiş

Bash komut dosyası:

#!/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 Yapısı:

docker build --pull -f "Dockerfile" -t $SERVICE_NAME --build-arg arg="yes" .

Açıklama: Bu, bash betiğindeki diğerine (yanlış) gidecek

docker build --pull -f "Dockerfile" -t $SERVICE_NAME .

Açıklama: Bu, if (doğru)

Düzenleme 1:

Birkaç denemeden sonra aşağıdaki makaleyi buldum ve bu tane 2 şey anlamama yardım:

1) FROM'dan önceki ARG yapının dışında

2) Varsayılan kabuk / bin / sh'dir, bu, if else'in docker yapısında biraz farklı çalıştığı anlamına gelir. örneğin dizeleri karşılaştırmak için "==" yerine yalnızca bir "=" gerekir.

Böylece bunu içinde yapabilirsiniz Dockerfile

ARG argname=false   #default argument when not provided in the --build-arg
RUN if [ "$argname" = "false" ] ; then echo 'false'; else echo 'true'; fi

ve içinde docker build:

docker build --pull -f "Dockerfile" --label "service_name=${SERVICE_NAME}" -t $SERVICE_NAME --build-arg argname=true .


17

Önerilen çözümlerin için ilginç bir alternatif eserler bu vardır tek Dockerfile , sadece ihtiyaç liman işçisi sürüme tek çağrı koşullu yapı ve başına kaçınır bash .

Çözüm:

Aşağıdaki Dockerfilebu sorunu çözer. Kopyalayıp yapıştırın ve kendiniz deneyin.

ARG my_arg

FROM centos:7 AS base
RUN echo "do stuff with the centos image"

FROM base AS branch-version-1
RUN echo "this is the stage that sets VAR=TRUE"
ENV VAR=TRUE

FROM base AS branch-version-2
RUN echo "this is the stage that sets VAR=FALSE"
ENV VAR=FALSE

FROM branch-version-${my_arg} AS final
RUN echo "VAR is equal to ${VAR}"

Dockerfile açıklaması:

Önce bir basegörüntü ( centos:7sizin durumunuzda) alır ve kendi aşamasına koyarız. baseSahne koşulda önce yapmak istediğim şeyleri içermelidir. Bundan sonra, durumumuzun dallarını temsil eden iki aşama daha var: branch-version-1ve branch-version-2. İkisini de biz inşa ediyoruz. finalBu aşamaların seçer birden sahne dayalı my_arg. Koşullu Dockerfile. İşte gidiyorsun.

Çalışırken çıktı:

(Bunu biraz kısalttım ...)

my_arg==2

docker build --build-arg my_arg=2 .
Step 1/12 : ARG my_arg
Step 2/12 : ARG ENV
Step 3/12 : FROM centos:7 AS base
Step 4/12 : RUN echo "do stuff with the centos image"
do stuff with the centos image
Step 5/12 : FROM base AS branch-version-1
Step 6/12 : RUN echo "this is the stage that sets VAR=TRUE"
this is the stage that sets VAR=TRUE
Step 7/12 : ENV VAR=TRUE
Step 8/12 : FROM base AS branch-version-2
Step 9/12 : RUN echo "this is the stage that sets VAR=FALSE"
this is the stage that sets VAR=FALSE
Step 10/12 : ENV VAR=FALSE
Step 11/12 : FROM branch-version-${my_arg}
Step 12/12 : RUN echo "VAR is equal to ${VAR}"
VAR is equal to FALSE

my_var==1

docker build --build-arg my_arg=1 .
...
Step 11/12 : FROM branch-version-${my_arg}
Step 12/12 : RUN echo "VAR is equal to ${VAR}"
VAR is equal to TRUE

Bu harika fikir için Tõnis'e teşekkürler!


Şimdiye kadar en iyi yaklaşım.
Felipe Desiderati

Ben de öyle düşündüm, bu yüzden buraya gönderdim. Haberi duyur @FelipeDesiderati
User12547645

1
Bu, burada sunulanların en iyi çözümüdür, çünkü komut dosyaları / bash ile geçici çözümler kullanmanız gerekmez, ancak yalnızca Dockerfile bilgisini içeren bir yöntem kullanırsınız. Mükemmel cevap.
Akito

"ARG ENV" ne işe yarar? buna biraz ışık tutabilir misin? Teşekkürler.
Maksimum

@Max bunu belirttiğiniz için teşekkürler. Gerekli değil
Kullanıcı12547645

12

Bunu yapmak için doğrudan "test" ikili dosyasını kullanın. Ayrıca "else" koşulunu belirtmek istemiyorsanız noop komutunu ":" kullanmalısınız, böylece docker sıfırdan farklı bir dönüş değeri hatasıyla durmaz.

RUN test -z "$YOURVAR" || echo "var is set" && echo "var is not set"
RUN test -z "$YOURVAR" && echo "var is not set" || :
RUN test -z "$YOURVAR" || echo "var is set" && :

2
Aynı RUN [ -z "$YOURVAR" ] && ... || :, inanıyorum ki
OneCricketeer

4
Aşağıdaki ifade için, eğer var ayarlanmışsa, her iki yankı da çalıştırılır. RUN test -z "$YOURVAR" || echo "var is set" && echo "var is not set"
Harshad Vyawahare

Aslında. Bunların dallanmış koşullu bloklar olmadığını unutmayın, seri olarak uyguluyorlar, &&önüne koyuyorlar ||:test ! -z "$YOURVAR" && echo "var is set" || echo "var is not set"
Brandt

5

Diğerlerinin de söylediği gibi, kabuk betiği yardımcı olacaktır.

Sadece ek bir durum, IMHO'dan bahsetmeye değer (burada rastlanan, daha kolay bir dava arayan biri için), yani Çevre değişimi .

Ortam değişkenleri (deyimle bildirilen ENV), belirli komutlarda, tarafından yorumlanacak değişkenler olarak da kullanılabilir.Dockerfile .

${variable_name}Aşağıda belirtilen sözdizimi ayrıca standart bash değiştiricilerinin birkaç destekler:

  • ${variable:-word}eğer variableayarlanmışsa sonucun o değer olacağını belirtir. Eğer variableayarlanmamış sonra wordsonuç olacaktır.

  • ${variable:+word}eğer variableayarlanmışsa wordsonuç olacağını, aksi takdirde sonucun boş dizge olacağını belirtir .


5

Kabul edilen cevap soruyu çözebilir, ancak ifdockerfile'da çok satırlı koşullar istiyorsanız, bunu \her satırın sonuna yerleştirerek (bir kabuk betiğinde yaptığınız gibi) ve her komutu ile sonlandırabilirsiniz ;. Hatta bazı şeyleri set -eux1. komut gibi tanımlayabilirsiniz .

Misal:

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

Senin durumunda:

FROM centos:7
ARG arg
RUN if [ -z "$arg" ] ; then \
    echo Argument not provided; \
  else \
    echo Argument is $arg; \
  fi

Ardından şununla inşa edin:

docker build -t my_docker . --build-arg arg=42

4

Bash komut dosyası ve Alpine / Centos kullanma

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

Arg aktarılıyor: 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

Arg olmadan: 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
....
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.