Uruchamianie skryptu w kontenerze Dockera przy użyciu skryptu powłoki

86

Próbuję stworzyć skrypt powłoki do konfigurowania kontenera dockera. Mój plik skryptu wygląda następująco:

#!bin/bash

docker run -t -i -p 5902:5902 --name "mycontainer" --privileged myImage:new /bin/bash

Uruchomienie tego pliku skryptu spowoduje uruchomienie kontenera w nowo wywołanym bash.

Teraz muszę uruchomić plik skryptu (test.sh), który jest już w kontenerze z podanego powyżej skryptu powłoki. (Np .: cd /path/to/test.sh && ./test.sh) Jak to zrobić?

zappy
źródło
1
Dlaczego nie użyć WORKDIRi CMD?
Dharmit
1
Prawdopodobnie nie chcesz tutaj używać --privileged. Zobacz: stackoverflow.com/questions/36425230/…
CMP

Odpowiedzi:

121

Możesz uruchomić polecenie w działającym kontenerze za pomocą docker exec [OPTIONS] CONTAINER COMMAND [ARG...]:

docker exec mycontainer /path/to/test.sh

Aby uruchomić z sesji bash:

docker exec -it mycontainer /bin/bash

Stamtąd możesz uruchomić swój skrypt.

Javier Cortejoso
źródło
6
co, jeśli najpierw muszę wejść do / bin / bash, a następnie uruchomić polecenie w tym bashu?
zappy
45
Możesz również uruchomić skrypt lokalny bezpośrednio z hosta. docker exec -i mycontainer bash < mylocal.sh Czyta skrypt lokalnego hosta i uruchamia go w kontenerze. Możesz to zrobić z innymi rzeczami (takimi jak pliki .tgz przesłane potokiem do tar) - po prostu użyj '-i', aby przesłać potok do wejścia standardowego procesu kontenera.
Marvin
@Marvin, jaki jest odpowiednik w PowerShell? znak „<” nie jest rozpoznawany.
Nicekiwi
1
Nie jestem guru PowerShell (na szczęście), ale wędrowałem po SO i znalazłem stackoverflow.com/a/11788475/500902 . Więc może Get-Content mylocal.sh | docker exec -i mycontainer bash. Nie wiem, czy to działa.
Marvin
97

Zakładając, że Twój kontener Docker jest uruchomiony i działa, możesz uruchamiać polecenia jako:

docker exec mycontainer /bin/sh -c "cmd1;cmd2;...;cmdn"
cyklop
źródło
2
Podoba mi się ta odpowiedź; nie musisz logować się do kontenera Dockera, aby wykonać polecenie lub zestaw poleceń. Dziękuję Ci!
Hatem Jaber
Czy wiesz, jak pójść o krok dalej i przekazać całe polecenie ( /bin/sh -c "cmd1; cmd2; ...; cmdn") jako wartość zmiennej powłoki? Pytam, ponieważ „docker run” wydaje się oczekiwać pojedynczego polecenia i pojedynczych niecytowanych argumentów, a nie cytowanego ciągu.
davidA
@meowsqueak: Ta odpowiedź mówi, jak uruchamiać wiele poleceń w już utworzonym i działającym kontenerze bez logowania się do tego kontenera, co jest pomocne w automatyzacji. Jeśli jednak chcesz uruchomić wiele poleceń w momencie tworzenia kontenera (PS: docker run command tworzy i uruchamia kontener), możesz to osiągnąć, postępując zgodnie z odpowiedziami w tym samym wątku stackoverflow.com/a/41363989/777617
Cyclops
W miejscu cmd1, muszę zdać się na całej pętli - ale spodziewa się ;po pętli oświadczenia i zrobić oświadczenie. Jak mogę uruchomić całą pętlę for jako jedno polecenie, tj. cmd1? Czy to możliwe?
Nicholas K
18

Szukałem odpowiedzi na to samo pytanie i znalazłem ENTRYPOINT w rozwiązaniu Dockerfile .

Dockerfile

...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash

Teraz skrypty są wykonywane, kiedy uruchamiam kontener, a po wykonaniu skryptów pojawia się monit bash.

tojo
źródło
6

Możesz także zamontować katalog lokalny w obrazie Dockera i umieścić skrypt w swoim .bashrc. Nie zapominaj, że skrypt musi składać się z funkcji, chyba że chcesz, aby był wykonywany na każdej nowej powłoce. (To jest nieaktualne, zobacz informację o aktualizacji).

Używam tego rozwiązania, aby móc zaktualizować skrypt poza instancją dockera. W ten sposób nie muszę ponownie uruchamiać obrazu, jeśli nastąpią zmiany, po prostu otwieram nową powłokę. (Pozbyłem się ponownego otwierania powłoki - zobacz informację o aktualizacji)

Oto jak wiążesz swój bieżący katalog:

docker run -it -v $PWD:/scripts $my_docker_build /bin/bash

Teraz twój bieżący katalog jest powiązany /scriptsz twoją instancją dockera.

(Nieaktualne) Aby zapisać .bashrczmiany, zatwierdź obraz roboczy za pomocą tego polecenia:

docker commit $container_id $my_docker_build

Aktualizacja

Aby rozwiązać problem otwierania nowej powłoki dla każdej zmiany, teraz wykonuję następujące czynności:

W samym dockerfile dodaję RUN echo "/scripts/bashrc" > /root/.bashrc". Wewnątrz zshrceksportuję katalog skryptów do ścieżki. Katalog scripts zawiera teraz wiele plików zamiast jednego. Teraz mogę bezpośrednio wywoływać wszystkie skrypty bez otwierania powłoki podrzędnej przy każdej zmianie.

BTW, możesz również zdefiniować plik historii poza kontenerem. W ten sposób nie jest już konieczne zatwierdzanie zmiany bash.

Devpool
źródło
Za późno..! @javier już pokazuje proste rozwiązanie !! Czuję, że jest jeszcze lepszy.
zappy
2
@zappy rozwiązanie od javier nie rozwiązało tego problemu wygodnie dla mnie - ale moje rozwiązanie tak, pomyślałem, że będzie interesujące dla tych, którzy mieli podobny problem, w którym nie chcą ponownie uruchamiać obrazów dockera, aby zaktualizować przeglądać potrzebne im funkcje. Na przykład, jeśli używasz wielu obrazów dockera jednocześnie, aby uruchomić klaster deweloperski, nie chcesz ich ciągle uruchamiać ponownie.
Devpool
3

Jeśli nie chcesz (lub nie masz) uruchomionego kontenera, możesz wywołać swój skrypt bezpośrednio za pomocą runpolecenia.

Usuń iteracyjne -i -targumenty tty i użyj tego:

    $ docker run ubuntu:bionic /bin/bash /path/to/script.sh

To zadziała (nie testowane) również dla innych skryptów:

    $ docker run ubuntu:bionic /usr/bin/python /path/to/script.py
Thomio
źródło
0

Jeśli chcesz uruchomić to samo polecenie w wielu instancjach, możesz to zrobić:

for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done
DMin
źródło