Docker run aracılığıyla bağımsız değişkenleri Shell Script'e iletme


133

Liman işçisi dünyasında yeniyim. Docker kapsayıcısından komut satırı argümanlarını alan bir kabuk betiğini çağırmalıyım. Ör: Kabuk betiğim şöyle görünüyor:

#!bin/bash
echo $1

Dockerfile şuna benzer:

FROM ubuntu:14.04
COPY ./file.sh /
CMD /bin/bash file.sh

Kapsayıcıyı çalıştırırken bağımsız değişkenleri nasıl geçireceğimden emin değilim

Yanıtlar:


62

Aynısını kullan file.sh

#!/bin/bash
echo $1

Mevcut Dockerfile kullanarak görüntüyü oluşturun:

docker build -t test .

Görüntüyü argümanlarla abcveya xyzbaşka bir şeyle çalıştırın.

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz

27
Son kullanıcının file.sh hakkında doğrudan bilgi sahibi olmasını istemiyorsanız, ENTRYPOINT'in gitmenin yolu olduğunu düşünüyorum.
greg.kindel

Böyle bir senaryoya nasıl başlayabilirsin docker run -ti test /file.sh abc? Betiğin çalışması gerektiği için çalışmayacağını hissediyorum docker run -ti test sh /file.sh abc. sh veya / bin / sh doğru çalıştıracaktır.
Vamsidhar Muggulla

1
Buraya gelen başkaları için. / Usr / bin / env numarası, isteğe bağlı stil tercihidir, bunun işe yaraması için bir gereklilik değildir. Ayrıca #! satırı hangi tercümanın satın alma varsayılanını kullanacağını gösterir. Böylece sadece komut dosyasını çağırarak çalışabilir.
2018

166

bu komut dosyası ile file.sh

#!/bin/bash
echo Your container args are: "$@"

ve bu Dockerfile

FROM ubuntu:14.04
COPY ./file.sh /
ENTRYPOINT ["/file.sh"]

yapabilmelisin:

% docker build -t test .
% docker run test hello world
Your container args are: hello world

9
Eğer benim yaptığım gibi /file.sh "" etrafını "unutursanız, işe yaramaz.
kev

6
bazı nedenlerden dolayı bu çalışmıyorENTRYPOINT ./file.sh
phil294

6
chmod +x file.shYürütülebilir bayrağı ayarlamayı unutmayın .
18'i

1
@kev, neden böyle olduğunu biliyor musun? arasındaki fark nedir ["/file.sh"]ve /file.shhatta[/file.sh]
Nitzankin

1
@Nitzankin neden uygun json biçimlendirmesinin gerekli olduğuna dair cevabımı görüyor.
BMitch

60

Docker ile, bu tür bilgileri iletmenin uygun yolu ortam değişkenlerinden geçer.

Dolayısıyla, aynı Dockerfile ile komut dosyasını

#!/bin/bash
echo $FOO

Oluşturduktan sonra aşağıdaki docker komutunu kullanın:

docker run -e FOO="hello world!" test

20
Bu neden en yüksek oyu alan cevap? Env değişkenleri, bilgi aktarmanın başka bir yoludur, ancak OP'nin istediği şey değildir. Ve elbette, OP'nin konteynere argümanlar iletme arzusunda kesinlikle uygunsuz hiçbir şey yoktur.
Parçalı Bulutlu

8
@PartlyCloudy Bence insanlar bunu seviyor çünkü açıkça yanlış olmasına rağmen "doğru" cevabı vermeyi iddia ediyor. Docker'ın temel tasarım ilkelerinden biri, dogmayı sağduyuya göre önceliklendirmektir.
augurar

1
@augurar: Bu cevabı iyileştirmek için, belki bu cevabın neden "açıkça yanlış" olduğunu düşündüğünüzü açıklarsınız?
Emil Stenström

2
SO'da sorulan bir sürü XY sorunu var. OP, Docker için yeni olduklarını belirttiğinden, son derece makul bir cevap, bir hedefe ulaşmak için önerilen yolu gösterir. Böylece bunu harika bir cevap yapıyor.
colm.anseo

1
Değişkenleri derleme argümanları ve tüm bu karmaşa olarak geçirmek yerine işi halletmenin en basit yolu. Sırları ortam değişkenleri olarak geçirmek için çok kullanışlıdır.
Arvind Sridharan

32

Burada etkileşimde olan birkaç şey var:

  1. docker run your_image arg1 arg2değerini CMDile değiştirir arg1 arg2. Bu, CMD'nin tamamen yerine geçmiştir, ona daha fazla değer eklemeyecektir. Bu nedenle docker run some_image /bin/bash, kapta sık sık bir bash kabuğu çalıştırmayı görürsünüz .

  2. Hem bir ENTRYPOINT hem de bir CMD değeri tanımladığınız zaman, docker, ikisini birleştirip bu birleştirilmiş komutu çalıştırarak konteyneri başlatır. Dolayısıyla, giriş noktanızı olarak tanımlarsanız file.sh, artık kapsayıcıyı bağımsız değişkenler olarak iletilecek ek bağımsız değişkenlerle çalıştırabilirsiniz file.sh.

  3. Docker'daki giriş noktaları ve Komutlar iki sözdizimine sahiptir, bir kabuğu başlatan bir dize sözdizimi ve bir yürütme gerçekleştirecek bir json sözdizimi. Kabuk, IO yeniden yönlendirme, birden fazla komutu bir arada zincirleme (gibi şeyler &&), değişken ikame vb. Gibi şeyleri işlemek için kullanışlıdır. bir kap, bu genellikle nedenidir) ve bir giriş noktası ile komutu bir araya getirerek. Giriş noktanızı bir dizge olarak tanımlarsanız, çalışır /bin/sh -c "file.sh", ki bu tek başına iyidir. Ancak dizge olarak tanımlanan bir komutunuz varsa /bin/sh -c "file.sh" /bin/sh -c "arg1 arg2", komutun konteynerinizin içinde başlatılması gibi bir şey göreceksiniz , o kadar iyi değil. Bu iki seçeneğin nasıl etkileşim kurduğu hakkında daha fazla bilgi için buradaki tabloya bakın

  4. Kabuk -cseçeneği yalnızca tek bir argüman alır. Bundan sonra her şey olarak geçirilen alacağı $1, $2açıkça args geçti sürece tek argüman için değil, gömülü bir kabuk komut dosyası içine, vb. Yani çalışırdı /bin/sh -c "file.sh $1 $2" "arg1" "arg2", ama /bin/sh -c "file.sh" "arg1" "arg2"o zamandan beri file.shargümansız çağrılmayacaktı.

Tüm bunları bir araya getirirsek, ortak tasarım şudur:

FROM ubuntu:14.04
COPY ./file.sh /
RUN chmod 755 /file.sh
# Note the json syntax on this next line is strict, double quotes, and any syntax
# error will result in a shell being used to run the line.
ENTRYPOINT ["file.sh"]

Ve sonra bunu şununla çalıştırırsınız:

docker run your_image arg1 arg2

Bununla ilgili biraz daha fazla ayrıntı var:


1
["bash", "--login", "-c"]Görüntüdeki / etc / profile kaynağını almak için giriş noktamı ayarlamayı denedim , ancak daha sonra docker çalışmasına geçirilen bir kabuk betiğine neden hiçbir argüman aktarılmayacağını merak ettim ... Cevabınız bunu açıklığa kavuşturdu, teşekkür ederim !
Apteryx

23

Sahip olduğum şey, gerçekten bir şeyler çalıştıran bir komut dosyası. Bu komut dosyası dosyası nispeten karmaşık olabilir. Buna "run_container" diyelim. Bu komut dosyası, komut satırından argümanlar alır:

run_container p1 p2 p3

Basit bir run_container şöyle olabilir:

#!/bin/bash
echo "argc = ${#*}"
echo "argv = ${*}"

Yapmak istediğim şey, bunu "dockering" yaptıktan sonra, bu konteyneri docker komut satırındaki aşağıdaki gibi parametrelerle başlatabilmek istiyorum:

docker run image_name p1 p2 p3

ve run_container betiğinin parametreler olarak p1 p2 p3 ile çalıştırılmasını sağlayın.

Bu benim çözümüm:

Dockerfile:

FROM docker.io/ubuntu
ADD run_container /
ENTRYPOINT ["/bin/bash", "-c", "/run_container \"$@\"", "--"]

7
Üçüncü değer değiştirilmesi ENTRYPOINTile dizi "/run_container \"$@\""boşluk içeren araçlar bağımsız değişkenleri (örneğin, doğru bir şekilde düzenlendiğinden docker run image_name foo 'bar baz' quux).
davidchambers

Bash dosyama anahtar / durum ifadeleri ekledikten sonra, ENTRYPOINT ["run_container.sh"] artık benim için çalışmadı, ancak ENTRYPOINT ["sh", "-c", "run_container.sh"] artık parametrelerimi kabul etmeyecek. Bu çözüm (@davidchambers önerisiyle) benim için çalıştı.
rhamilton

10

@Build time çalıştırmak istiyorsanız:

CMD /bin/bash /file.sh arg1

@run zamanında çalıştırmak istiyorsanız:

ENTRYPOINT ["/bin/bash"]
CMD ["/file.sh", "arg1"]

Sonra ana bilgisayar kabuğunda

docker build -t test .
docker run -i -t test

2
ENTRYPOINTbu, çalışma zamanı istediğini düşündüğüm OP için iyi bir cevap, ancak gerçekten zaman değişkenleri oluşturmak istiyorsanız, bu cevap sadece geçersiz. ARGVe docker build --build-arg docs.docker.com/engine/reference/builder/#arg
greg.kindel

0

Başka seçenek...

Bunun işe yaraması için

docker run -d --rm $IMG_NAME "bash:command1&&command2&&command3"

dockerfile'da

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh içinde

#!/bin/sh

entrypoint_params=$1
printf "==>[entrypoint.sh] %s\n" "entry_point_param is $entrypoint_params"

PARAM1=$(echo $entrypoint_params | cut -d':' -f1) # output is 1 must be 'bash' it     will be tested    
PARAM2=$(echo $entrypoint_params | cut -d':' -f2) # the real command separated by     &&

printf "==>[entrypoint.sh] %s\n" "PARAM1=$PARAM1"
printf "==>[entrypoint.sh] %s\n" "PARAM2=$PARAM2"

if [ "$PARAM1" = "bash" ];
then
    printf "==>[entrypoint.sh] %s\n" "about to running $PARAM2 command"
    echo $PARAM2 | tr '&&' '\n' | while read cmd; do
        $cmd
    done    
fi

":" ile bazı açıklamalar ve sınırlamalar .... komutu cut -d ':' de değişiklik gerektiriyor ve docker run -d --rm $ IMG_NAME "bash: echo $ PATH" gibi komutlar ana bilgisayar yerine ana bilgisayar yolu değerini gösterecek one
wagnermarques
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.