Jak uruchomić wiele usług w jednym kontenerze Docker
Opublikowany: 2022-06-30Docker to technologia pakowania elementów stosu jako izolowanych pojemników. Powszechną praktyką jest uruchamianie każdego z procesów we własnym kontenerze, tworząc czysty podział między komponentami. Zwiększa to modułowość i umożliwia dostęp do korzyści związanych ze skalowalnością konteneryzacji.
Nadal mogą istnieć sytuacje, w których chcesz uruchomić wiele usług w jednym kontenerze. Chociaż nie jest to naturalne w ekosystemie platformy Docker, pokażemy kilka różnych podejść, których można użyć do tworzenia kontenerów z więcej niż jednym długotrwałym procesem.
Identyfikacja problemu
Kontenery platformy Docker uruchamiają jeden proces na pierwszym planie. Jest to określone w instrukcjach ENTRYPOINT
i CMD
obrazu. ENTRYPOINT
jest ustawiony w pliku Dockerfile
obrazu, podczas gdy CMD
można zastąpić podczas tworzenia kontenerów. Kontenery zatrzymują się automatycznie po zakończeniu ich procesu na pierwszym planie.
Możesz uruchomić inne procesy z CMD
, ale kontener będzie działał tylko wtedy, gdy oryginalny proces na pierwszym planie będzie działał. Utrzymanie kontenera w działaniu przez łączną żywotność dwóch niezależnych usług nie jest bezpośrednio możliwe przy użyciu mechanizmu ENTRYPOINT/CMD
.
Zawijanie wielu procesów w jednym punkcie wejścia
Skrypty opakowujące to najprostsze rozwiązanie tego problemu. Możesz napisać skrypt, który uruchamia wszystkie twoje procesy i czeka na ich zakończenie. Ustawienie skryptu jako Docker ENTRYPOINT
spowoduje uruchomienie go jako procesu pierwszego planu kontenera, utrzymując działanie kontenera do momentu zamknięcia jednego z opakowanych skryptów.
#!/kosz/bash /opt/pierwszy proces & /opt/drugi proces & czekaj - n wyjść $?
Ten skrypt uruchamia pliki binarne /opt/first-process
i /opt/second-process
wewnątrz kontenera. Użycie &
umożliwia kontynuację działania skryptu bez czekania na zakończenie każdego procesu. wait
jest używany do zawieszenia skryptu do czasu zakończenia jednego z procesów. Skrypt następnie kończy działanie z kodem stanu wydanym przez gotowy skrypt.
Ten model powoduje, że kontener uruchamia zarówno first-process
jak i second-process
dopóki jeden z nich nie zostanie zamknięty. W tym momencie kontener zostanie zatrzymany, mimo że drugi proces może nadal działać.
Aby użyć tego skryptu, zmodyfikuj ENTRYPOINT
i CMD
obrazu Docker, tak aby był to proces pierwszego planu kontenera:
PUNKT WEJŚCIA ["/bin/sh"] CMD ["./ścieżka/do/skryptu.sh"]
Opcja kontenera --init
Jednym z wyzwań związanych z zarządzaniem procesami kontenerowymi jest skuteczne sprzątanie po ich wyjściu. Docker uruchamia Twój CMD
jako proces o identyfikatorze 1, czyniąc go odpowiedzialnym za obsługę sygnałów i eliminację zombie. Jeśli Twój skrypt nie ma tych możliwości, możesz skończyć z osieroconymi procesami podrzędnymi, które będą trwać w Twoim kontenerze.
Polecenie docker docker run
ma flagę --init
, która modyfikuje punkt wejścia tak, aby używał tini
jako PID 1. Jest to minimalna implementacja procesu init, która uruchamia CMD
, obsługuje przekazywanie sygnałów i nieustannie zbiera zombie.
Warto użyć --init
, jeśli spodziewasz się, że będzie pojawiać się wiele procesów i nie chcesz ręcznie zajmować się czyszczeniem. Tini to lekki smak init przeznaczony do pojemników. Jest znacznie mniejszy niż w pełni rozwinięte alternatywy, takie jak systemd
i upstart
.
Korzystanie z dedykowanego menedżera procesu
Ręczne skrypty szybko stają się nieoptymalne, gdy trzeba zarządzać wieloma procesami. Przyjęcie menedżera procesów to kolejny sposób uruchamiania kilku usług w kontenerach Dockera. Kierownik procesu staje się ENTRYPOINT
i odpowiada za uruchamianie, konserwację i czyszczenie po procesach pracowniczych.
Przy wdrażaniu tego podejścia dostępnych jest kilka opcji. supervisord
to popularny wybór, który można łatwo skonfigurować za pomocą pliku /etc/supervisor/conf.d/supervisord.conf
:
[program:apache2] polecenie=/usr/sbin/apache2 -PRZEDZIEMIE [program:mysqld] polecenie=/usr/sbin/mysqld_safe
Ten plik konfiguracyjny konfiguruje supervisord
do uruchamiania Apache i MySQL. Aby użyć go w kontenerze Docker, dodaj wszystkie wymagane pakiety do obrazu, a następnie skopiuj plik konfiguracyjny supervisord
do właściwej lokalizacji. Ustaw supervisord
jako CMD
obrazu, aby uruchamiał go automatycznie po uruchomieniu kontenerów.
Z ubuntu: najnowsze URUCHOM apt-get install -y apache2 mysql-server nadzorca KOPIUJ supervisor.conf /etc/supervisor/conf.d/supervisord.conf PUNKT WEJŚCIA ["/bin/sh"] CMD ["/usr/bin/nadzorca"]
Ponieważ narzędzie supervisord
działa w sposób ciągły, nie jest możliwe zatrzymanie kontenera po zamknięciu jednego z monitorowanych procesów. Alternatywną opcją jest s6-overlay
, która ma taką możliwość. Używa deklaratywnego modelu usług, w którym umieszczasz skrypty usług bezpośrednio w /etc/services.d
:
# Dodaj s6-overlay do swojego obrazu DODAJ https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz /tmp URUCHOM tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz URUCHOM printf "#!/bin/shn/usr/sbin/apache2 -DFOREGROUND" > /etc/services.d/first-service/run URUCHOM chmod +x /etc/services.d/first-service/run # Użyj s6-overlay jako punktu wejściowego obrazu PUNKT WEJŚCIOWY ["/początek"]
Możesz dodać wykonywalny skrypt finish
w swoich katalogach usług, aby obsłużyć zatrzymywanie kontenera za pomocą docker stop
. s6-overlay
automatycznie uruchomi te skrypty, gdy jego proces otrzyma sygnał TERM
z powodu polecenia stop
.
Skrypty kończące otrzymują kod zakończenia swojej usługi jako pierwszy argument. Kod jest ustawiony na 256, gdy usługa zostanie zabita z powodu nieprzechwyconego sygnału. Skrypt musi napisać ostateczny kod wyjścia do /run/s6-linux-init-container-results/exitcode
; s6-overlay odczytuje ten plik i kończy działanie z wartością w obrębie, powodując, że ten kod jest używany jako kod zatrzymania kontenera.
#!/kosz/sz echo "$1" > /run/s6-linux-init-container-results/exitcode
Kiedy należy uruchamiać wiele procesów w kontenerze?
Ta technika najlepiej sprawdza się w przypadku ściśle powiązanych procesów, których nie można rozdzielić w celu uruchomienia jako niezależnych kontenerów. Możesz mieć program, który opiera się na narzędziu pomocniczym w tle lub monolitycznej aplikacji, która samodzielnie zarządza poszczególnymi procesami. Przedstawione powyżej techniki mogą pomóc w konteneryzacji tego typu oprogramowania.
W miarę możliwości należy unikać uruchamiania wielu procesów w kontenerze. Trzymanie się jednego procesu na pierwszym planie maksymalizuje izolację, zapobiega wzajemnemu zakłócaniu się komponentów i poprawia zdolność do debugowania i testowania określonych elementów. Składniki można skalować indywidualnie przy użyciu koordynatorów kontenerów, co zapewnia elastyczność uruchamiania większej liczby wystąpień procesów wymagających największej ilości zasobów.
Wniosek
Kontenery mają zwykle jeden proces na pierwszym planie i działają tak długo, jak żyją. Ten model jest zgodny z najlepszymi praktykami w zakresie konteneryzacji i pozwala czerpać największe korzyści z technologii.
W niektórych sytuacjach może być konieczne uruchomienie wielu procesów w kontenerze. Ponieważ wszystkie obrazy ostatecznie mają jeden punkt wejścia, musisz napisać skrypt opakowujący lub dodać menedżera procesów, który bierze odpowiedzialność za uruchamianie docelowych plików binarnych.
Menedżerowie procesów zapewniają wszystko, czego potrzebujesz, ale powiększają obrazy dodatkowymi pakietami i konfiguracją. Skrypty opakowujące są prostsze, ale mogą wymagać połączenia z flagą --init
, aby zapobiec rozprzestrzenianiu się procesów zombie.