Wiele poleceń w dyrektywie Docker CMD

39

Nie rozumiem, co się dzieje, gdy próbuję wykonać dwa polecenia w czasie wykonywania przez dyrektywę CMD w `Dockerfile. Zakładałem, że to powinno działać:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

Ale to nie działa. Kontener nie został uruchomiony. Więc musiałem to zrobić w ten sposób:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Nie rozumiem. Dlaczego? Dlaczego pierwsza linia nie jest właściwa? Czy ktoś może mi wyjaśnić te „format powłoki CMD vs. format JSON itp.”. W prostych słowach.

Uwaga: to samo command:dotyczyło dyrektywy docker-compose.ymlzgodnie z oczekiwaniami.

Vladan
źródło

Odpowiedzi:

33

Uważam, że różnica może mieć związek z tym, że drugie polecenie wykonuje przetwarzanie powłoki, a drugie nie. Zgodnie z oficjalną dokumentacją istnieje execi shellforma, twoje pierwsze polecenie jest formularzem wykonania i nie rozszerza na przykład zmiennych środowiskowych, podczas gdy drugie. Jest więc możliwe, że przy użyciu formularza exec polecenie może się nie powieść z powodu jego zależności od przetwarzania powłoki. Możesz to sprawdzić, uruchamiającdocker logs CONTAINERID

Twoje drugie polecenie, forma powłoki, jest równoważne z -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Fragmenty dokumentacji -

Uwaga: W przeciwieństwie do formularza powłoki, formularz exec nie wywołuje powłoki poleceń. Oznacza to, że normalne przetwarzanie powłoki nie ma miejsca. Na przykład CMD [ "echo", "$HOME" ]nie dokona zamiany zmiennych na $HOME. Jeśli chcesz shell przetwarzanie następnie albo użyć formularza powłoki lub powłokę wykonać bezpośrednio, na przykład: CMD [ "sh", "-c", "echo", "$HOME" ].

Daniel t.
źródło
Prawdopodobnie polecenie nie powiodło się z powodu zmiennych środowiskowych. Czy nadal powinienem używać tego execformularza, ponieważ jest to preferowany? Dlaczego jest to preferowane? Czy powinienem użyć prostszego shellformularza?
Vladan
Nie powiodło się, ponieważ wykonywanie jednego polecenia po drugim jest funkcją powłoki. Zmienne środowiskowe to czerwony śledź.
Bryan
Jeśli korzystasz z wielu usług w Docker, polecam skorzystanie z menedżera procesów, takiego jak przełożony. W ten sposób uruchomisz tylko nadzór w sekcji CMD, a on zajmie się uruchomieniem usług. Możesz sprawdzić szczegóły tutaj - docs.docker.com/articles/using_supervisord
Daniel t.
To jest dokładnie ten artykuł, który właśnie czytałem :) Dzięki.
Vladan
Nadal nie rozumiem, dlaczego musisz to zrobić CMD [ "sh", "-c", "echo", "$HOME"]. Dlaczego nie CMD ["sh", "-c", "echo $HOME"]lub, jeśli o to chodzi CMD ["sh -c echo $HOME"],?
sixty4bit
4

Nie utrudniaj sobie. Wystarczy utworzyć plik bash „start.sh”:

#!/bin/bash

/usr/bin/command2 param1
/usr/bin/commnad1

w swoim pliku Docker wykonaj:

ADD start.sh /

CMD ["/start.sh"]
Digital Human
źródło
2

Składnia JSON CMD(a RUNi ENTRYPOINT) przekazywać argumenty do jądra bezpośrednio jako exec syscall. Nie ma oddzielania polecenia od argumentów spacjami, unikania cudzysłowów, przekierowywania IO, podstawiania zmiennych, łączenia między poleceniami, uruchamiania wielu poleceń itp. W syscall exec. Syscall pobiera tylko plik wykonywalny do uruchomienia i listę argumentów przekazywanych do tego pliku wykonywalnego i uruchamia go.

Znaki takie jak $rozszerzanie zmiennych, ;oddzielanie poleceń, (spacja) oddzielanie argumentów &&i ||łączenie poleceń, >przekierowywanie danych wyjściowych |, przechodzenie między poleceniami itp., Są cechami powłoki i wymagają czegoś podobnego /bin/shlub /bin/bashich interpretacji i implementacji.


Jeśli przełączysz się na składnię ciągu CMD, doker wykona polecenie z powłoką:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

W przeciwnym razie druga składnia robi dokładnie to samo:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Zauważ, że nie polecam wykonywania wielu poleceń w ten sposób w kontenerze, ponieważ nie ma obsługi błędów, jeśli pierwsze polecenie nie powiedzie się, szczególnie jeśli działa w tle. Zostawiasz również powłokę działającą jako pid 1 wewnątrz kontenera, co przerwie obsługę sygnału, co spowoduje 10-sekundowe opóźnienie i niesforne zabicie twojego kontenera przez dokera. Obsługę sygnałów można złagodzić za pomocą execpolecenia powłoki :

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

Jednak obsługa procesów, które cicho zawodzą w tle, wymaga przejścia do jakiegoś menedżera wieloprocesowego, takiego jak nadzór, lub najlepiej rozbicia aplikacji na wiele kontenerów i wdrożenia ich z czymś w rodzaju dokowania-komponowania.

BMitch
źródło
1

Wydaje mi się, że pierwsze polecenie kończy się niepowodzeniem, ponieważ w formie DOCKER CMD wykonywany jest tylko pierwszy parametr, reszta jest wprowadzana do tego polecenia.

Drugi formularz działa, ponieważ wszystkie polecenia są rozdzielone znakiem „;” są wprowadzane do polecenia sh, które je wykonuje.

devrimbaris
źródło
1

Nie sądzę, że powinieneś wstawić przecinek po „starcie”

zamiast używać

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

próbować

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

ponieważ okno dokowane używa „sh -c”, powyższe polecenie zostanie wykonane jak poniżej

/etc/init.d/nullmailer start
/etc/init.d/nullmailer /usr/sbin/php5-fpm
wedat
źródło
Składnia json nie uruchamia poleceń z powłoką, nie ma tego sh -cw tym scenariuszu.
BMitch