Czy mogę uruchamiać wiele programów w kontenerze Docker?

150

Próbuję owinąć głowę Dockerem od momentu wdrożenia aplikacji, która ma działać na komputerach użytkowników. Moja aplikacja to po prostu aplikacja internetowa z kolbami i baza danych mongo. Zwykle zainstalowałbym zarówno na maszynie wirtualnej, jak i przekazałbym port hosta do aplikacji internetowej gościa. Chciałbym spróbować Docker, ale nie jestem pewien, jak mam używać więcej niż jednego programu. Dokumentacja mówi, że może być tylko ENTRYPOINT, więc jak mogę mieć Mongo i moją aplikację na kolbę. A może muszą znajdować się w oddzielnych kontenerach, w takim przypadku jak rozmawiają ze sobą i jak to ułatwia dystrybucję aplikacji?

nickponline
źródło
2
Spot on: sprawia, że ​​zastanawiam się, dlaczego docker był tak popularny ... (pojedynczy proces ...?) - ale zobaczmy, co powiedzą nam odpowiedzi ...
javadba

Odpowiedzi:

120

Może istnieć tylko jeden punkt ENTRYPOINT, ale tym celem jest zwykle skrypt, który uruchamia tyle programów, ile potrzeba. Możesz dodatkowo użyć np. Supervisorda lub podobnego, aby zadbać o uruchomienie wielu usług w jednym kontenerze. To jest przykład kontenera Dockera z uruchomionymi mysql, apache i wordpress w jednym kontenerze .

Powiedzmy, że masz jedną bazę danych, która jest używana przez jedną aplikację internetową. Wtedy prawdopodobnie łatwiej będzie uruchomić oba w jednym kontenerze.

Jeśli masz udostępnioną bazę danych, która jest używana przez więcej niż jedną aplikację, lepiej byłoby uruchomić bazę danych w jej własnym kontenerze, a aplikacje każda w swoich własnych kontenerach.

Istnieją co najmniej dwie możliwości, w jaki sposób aplikacje mogą się ze sobą komunikować, gdy działają w różnych kontenerach:

  1. Użyj odsłoniętych portów IP i łącz się za ich pośrednictwem.
  2. Najnowsze wersje dockera obsługują łączenie .
vesako
źródło
1
Wygląda na to, że nowa wersja Dockera obsługuje teraz sieci kontenerów Docker .
jpierson
Docker obsługuje teraz uruchamianie Supervisor, umożliwiając oddzielenie zachowania dla każdego procesu, takiego jak autorestart = true, stdout_logfile, stderr_logfile itp. Spójrz na docs.docker.com/engine/admin/using_supervisord
Andreas Lundgren
4
Zdecydowanie nie polecam uruchamiania aplikacji internetowej i mongodb w tym samym kontenerze w tym przykładzie. Istnieją dobre przypadki użycia superwizora lub podobnych procesów init w Dockerze, ale ten nie jest ich częścią. O wiele prostsze jest użycie docker-compose, aby po prostu uruchomić dwie usługi w oddzielnych kontenerach.
nicolas-van
@ nicolas-van dlaczego to jest prostsze? Czy to dlatego, że jeśli baza danych umrze, mogę ponownie uruchomić kontener bazy danych zamiast ponownego uruchamiania całej rzeczy?
brillout
Aplikacje na tym samym komputerze mogą również komunikować się za pośrednictwem gniazd domeny Unix . Gwarancja najwyższej wydajności.
Sceptyczny Jule
21

Miałem podobne wymaganie, aby uruchomić stos LAMP, Mongo DB i własne usługi

Docker to wirtualizacja oparta na systemie operacyjnym, dlatego izoluje swój kontener wokół działającego procesu, dlatego wymaga co najmniej jednego procesu działającego w FOREGROUND.

Więc dostarczasz swój własny skrypt startowy jako punkt wejścia, w ten sposób twój skrypt startowy staje się rozszerzonym skryptem obrazu Dockera, w którym możesz układać dowolną liczbę usług, o ile ROZPOCZĘŁA SIĘ CO NAJMNIEJ JEDNA WCZESNA USŁUGA, KTÓRA ZBYT KU KOŃCA

Więc mój plik obrazu Dockera ma dwie linie poniżej na samym końcu:

COPY myStartupScript.sh /usr/local/myscripts/myStartupScript.sh
CMD ["/bin/bash", "/usr/local/myscripts/myStartupScript.sh"]

W moim skrypcie uruchamiam wszystkie MySQL, MongoDB, Tomcat itp. Na koniec uruchamiam Apache jako wątek pierwszego planu.

source /etc/apache2/envvars
/usr/sbin/apache2 -DFOREGROUND

Dzięki temu mogę uruchomić wszystkie moje usługi i utrzymać kontener przy życiu, przy czym ostatnia usługa zaczyna być na pierwszym planie

Mam nadzieję, że to pomoże

AKTUALIZACJA : Odkąd ostatnio odpowiedziałem na to pytanie, pojawiły się nowe rzeczy, takie jak Docker Compose , który może pomóc w uruchamianiu każdej usługi w osobnym kontenerze, a jednocześnie powiązać je wszystkie razem jako zależności między tymi usługami, spróbuj dowiedzieć się więcej o docker-compose i użyj go, jest bardziej elegancki, chyba że twoja potrzeba mu nie pasuje.

Basav
źródło
6

Zdecydowanie nie zgadzam się z niektórymi wcześniejszymi rozwiązaniami, które zalecały uruchamianie obu usług w tym samym kontenerze. W dokumentacji jest jasno określone, że nie jest to zalecane :

Generalnie zaleca się oddzielenie problematycznych obszarów przy użyciu jednej usługi na kontener. Ta usługa może podzielić się na wiele procesów (na przykład serwer WWW Apache uruchamia wiele procesów roboczych). Dobrze jest mieć wiele procesów, ale aby uzyskać jak największe korzyści z platformy Docker, unikaj jednego kontenera odpowiedzialnego za wiele aspektów ogólnej aplikacji. Możesz połączyć wiele kontenerów za pomocą sieci zdefiniowanych przez użytkownika i udostępnionych woluminów.

Istnieją dobre przypadki użycia dla nadzorcy lub podobnych programów, ale uruchomienie aplikacji internetowej + bazy danych nie jest ich częścią.

W tym celu zdecydowanie powinieneś użyć docker-compose i zaaranżować wiele kontenerów z różnymi obowiązkami.

nicolas-van
źródło
2
To jest komentarz, a nie odpowiedź. Prosimy o rozważenie dodania wyjaśnienia i / lub linków wspierających to stanowisko. W przeciwnym razie nie jest to pomocne.
Iwan Iwanow
1
Jest to odpowiedź w tym sensie, że najlepszym zaleceniem, jakie mogę dać w takim przypadku użycia, jest użycie docker-compose. W każdym razie masz rację, że mogę podać więcej linków do oficjalnych zaleceń. Zaktualizuję to.
nicolas-van
Pytanie dotyczy uruchomienia 2 procesów w jednym kontenerze, więc nie dba o najlepsze praktyki. Podam ci przykład: musiałem uruchomić rabbitmq wewnątrz obrazu opartego na PhotonOS i proces java ... Więc użyłem skryptu wejściowego i użyłem go jako ENTRYPOINT :)
Vallerious
Pierwotne pytanie nie jest ogólnym pytaniem o techniczną wykonalność uruchamiania dwóch procesów w kontenerze Dockera. Określa konkretny przypadek użycia, którym jest wdrożenie aplikacji Python wraz z bazą danych MongoDB. W tym przypadku najlepszym zaleceniem jest zniechęcenie do używania pojedynczego kontenera i zalecenie użycia docker-compose.
nicolas-van
5

Mogą znajdować się w osobnych kontenerach i rzeczywiście, jeśli aplikacja miałaby działać również w większym środowisku, prawdopodobnie tak by się stało.

System z wieloma kontenerami wymagałby trochę więcej orkiestracji, aby móc przywołać wszystkie wymagane zależności, chociaż w Docker v0.6.5 + dostępna jest nowa funkcja, która pomaga z tym wbudowanym w sam Docker - Łączenie . Jednak w przypadku rozwiązania obejmującego wiele maszyn nadal jest to coś, co trzeba zorganizować spoza środowiska Dockera.

W przypadku dwóch różnych kontenerów obie części nadal komunikują się przez TCP / IP, ale chyba że porty zostały specjalnie zablokowane (niezalecane, ponieważ nie można uruchomić więcej niż jednej kopii), musiałbyś przekazać nowy port że baza danych została ujawniona jako aplikacja, aby mogła komunikować się z Mongo. To znowu coś, w czym Linking może pomóc.

W przypadku prostszej, małej instalacji, w której wszystkie zależności znajdują się w tym samym kontenerze, możliwe jest również uruchomienie zarówno bazy danych, jak i środowiska wykonawczego Pythona przez program, który początkowo był nazywany ENTRYPOINT. Może to być tak proste, jak skrypt powłoki lub inny kontroler procesu - Supervisord jest dość popularny, a wiele przykładów istnieje w publicznych plikach Dockerfile.

Alister Bulman
źródło
3

Zgadzam się z innymi odpowiedziami, że używanie dwóch kontenerów jest lepsze, ale jeśli masz serce nastawione na pakowanie wielu usług w jednym kontenerze, możesz użyć czegoś w rodzaju nadzorcy.

w Hipache Na przykład, zawarte Dockerfile biegnie supervisord oraz określa plik supervisord.conf zarówno dla hipache i Redis-serwer do uruchomienia.

ben schwartz
źródło
2

Docker zawiera kilka przykładów, jak to zrobić. Lekka opcja to:

Umieść wszystkie swoje polecenia w skrypcie opakowującym, wraz z informacjami dotyczącymi testowania i debugowania. Uruchom skrypt opakowania jako plik CMD. To bardzo naiwny przykład. Najpierw skrypt opakowujący:

#!/bin/bash

# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_first_process: $status"
  exit $status
fi

# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_second_process: $status"
  exit $status
fi

# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container will exit with an error
# if it detects that either of the processes has exited.
# Otherwise it will loop forever, waking up every 60 seconds

while /bin/true; do
  ps aux |grep my_first_process |grep -q -v grep
  PROCESS_1_STATUS=$?
  ps aux |grep my_second_process |grep -q -v grep
  PROCESS_2_STATUS=$?
  # If the greps above find anything, they will exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit -1
  fi
  sleep 60
done

Następnie plik Dockerfile:

FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh
OzNetNerd
źródło
2

Możesz uruchomić 2 procesy na pierwszym planie, używając wait. Po prostu utwórz skrypt bash z następującą zawartością. Np . start.sh:

# runs 2 commands simultaneously:

mongod & # your first application
P1=$!
python script.py & # your second application
P2=$!
wait $P1 $P2

W swoim pliku Dockerfile zacznij od

CMD bash start.sh
Sam
źródło
0

Jeśli dedykowany skrypt wydaje się być zbyt dużym narzutem, możesz jawnie utworzyć oddzielne procesy za pomocą sh -c. Na przykład:

CMD sh -c 'mini_httpd -C /my/config -D &' \
 && ./content_computing_loop
Raphael
źródło