Cum să rulați mai multe servicii într-un singur container Docker

Publicat: 2022-06-30

Ilustrație care arată sigla Docker

Docker este o tehnologie pentru ambalarea componentelor stivei dvs. ca containere izolate. Este o practică obișnuită să rulați fiecare dintre procesele dvs. în propriul container, creând o diferență clară între componente. Acest lucru îmbunătățește modularitatea și vă permite să accesați beneficiile de scalabilitate ale containerizării.

Pot exista în continuare situații în care doriți să rulați mai multe servicii într-un singur container. Deși acest lucru nu vine de la sine în ecosistemul Docker, vom arăta câteva abordări diferite pe care le puteți folosi pentru a crea containere cu mai mult de un proces de lungă durată.

Identificarea Problemei

Containerele Docker rulează un singur proces în prim-plan. Acest lucru este definit de instrucțiunile ENTRYPOINT și CMD ale imaginii. ENTRYPOINT este setat în Dockerfile al unei imagini, în timp ce CMD poate fi suprascris la crearea containerelor. Containerele se opresc automat când procesul lor din prim-plan iese.

Puteți lansa alte procese din CMD , dar containerul va rămâne în funcțiune doar cât timp procesul inițial din prim-plan este activ. Menținerea containerului operațional pe durata de viață combinată a două servicii independente nu este direct posibilă folosind mecanismul ENTRYPOINT/CMD .

Încheierea mai multor procese într-un singur punct de intrare

Scripturile Wrapper sunt cea mai simplă soluție la problemă. Puteți scrie un script care începe toate procesele și așteaptă ca acestea să se termine. Setarea scriptului ca Docker ENTRYPOINT va rula ca proces din prim-plan al containerului, menținând containerul să ruleze până când unul dintre scripturile împachetate iese.

 #!/bin/bash

/opt/first-process &

/opt/al doilea proces &

așteptați -n

ieșire din $?

Acest script pornește binarele /opt/first-process și /opt/second-process din interiorul containerului. Utilizarea & permite script-ului să continue fără a aștepta ieșirea fiecărui proces. wait este folosit pentru a suspenda scriptul până când unul dintre procese se încheie. Scriptul iese apoi cu codul de stare emis de scriptul terminat.

Acest model are ca rezultat containerul care rulează atât first-process cât și second-process până când unul dintre ele iese. În acel moment, containerul se va opri, chiar dacă celălalt proces poate fi încă în curs de desfășurare.

Pentru a utiliza acest script, modificați ENTRYPOINT -ul și CMD -ul imaginii Docker pentru a deveni procesul din prim-plan al containerului:

 ENTRYPOINT ["/bin/sh"]
CMD ["./path/to/script.sh"]

Opțiunea Container --init

O provocare cu gestionarea proceselor containerelor este curățarea eficientă pe măsură ce acestea ies. Docker rulează CMD -ul dvs. ca ID de proces 1, făcându-l responsabil pentru gestionarea semnalelor și eliminarea zombi. Dacă scriptul dvs. nu are aceste capacități, puteți ajunge cu procese copil orfane care persistă în containerul dvs.

Comanda docker docker run are un --init care modifică punctul de intrare pentru a utiliza tini ca PID 1. Aceasta este o implementare minimă a procesului de inițializare care rulează CMD -ul dvs., gestionează transmiterea semnalului și culege continuu zombi.

Merită să folosiți --init dacă vă așteptați să generați multe procese și nu doriți să vă ocupați manual de curățare. Tini este o aromă inițială ușoară, concepută pentru recipiente. Este mult mai mic decât alternativele cu drepturi depline, cum ar fi systemd și upstart .

Utilizarea unui manager de proces dedicat

Crearea manuală de scripturi devine rapid sub-optimă atunci când aveți o mulțime de procese de gestionat. Adoptarea unui manager de proces este o altă modalitate de a rula mai multe servicii în interiorul containerelor Docker. Managerul de proces devine ENTRYPOINT -ul tău și are responsabilitatea de a porni, întreține și curăța după procesele lucrătorului tău.

Există mai multe opțiuni disponibile la implementarea acestei abordări. supervisord este o alegere populară care este ușor de configurat printr-un fișier /etc/supervisor/conf.d/supervisord.conf :

 [program:apache2]
command=/usr/sbin/apache2 -DFOREGROUND

[program:mysqld]
command=/usr/sbin/mysqld_safe

Acest fișier de configurare configurează supervisord pentru a porni Apache și MySQL. Pentru a-l folosi într-un container Docker, adăugați toate pachetele necesare la imaginea dvs., apoi copiați fișierul de configurare supervisord în locația corectă. Setați supervisord ca CMD al imaginii pentru a o rula automat când containerele pornesc.

 DIN ubuntu:latest
RUN apt-get install -y apache2 mysql-server supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ENTRYPOINT ["/bin/sh"]
CMD ["/usr/bin/supervisord"]

Deoarece supervisord rulează continuu, nu este posibil să opriți containerul atunci când unul dintre procesele dvs. monitorizate iese. O opțiune alternativă este s6-overlay , care are această capacitate. Utilizează un model de serviciu declarativ în care plasați scripturi de serviciu direct în /etc/services.d :

 # Adăugați s6-overlay la imaginea dvs
ADAUGĂ https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz

RUN printf "#!/bin/shn/usr/sbin/apache2 -DFOREGROUND" > /etc/services.d/first-service/run
RUN chmod +x /etc/services.d/first-service/run

# Utilizați s6-overlay ca punct de intrare al imaginii dvs
ENTRYPOINT ["/init"]

Puteți adăuga un script de finish executabil în directoarele dvs. de servicii pentru a gestiona oprirea containerului cu docker stop . s6-overlay va rula automat aceste scripturi atunci când procesul său primește un semnal TERM din cauza comenzii de stop .

Scripturile Finish primesc codul de ieșire al serviciului lor ca prim argument. Codul este setat la 256 atunci când serviciul este oprit din cauza unui semnal necaptat. Scriptul trebuie să scrie codul de ieșire final în /run/s6-linux-init-container-results/exitcode ; s6-overlay citește acest fișier și iese cu valoarea din interior, ceea ce face ca acel cod să fie utilizat ca cod de oprire al containerului.

 #!/bin/sh
echo „$1” > /run/s6-linux-init-container-results/exitcode

Când ar trebui să rulați mai multe procese într-un container?

Această tehnică este utilizată cel mai bine cu procese strâns cuplate pe care nu le puteți separa pentru a le rula ca containere independente. S-ar putea să aveți un program care se bazează pe un utilitar de ajutor de fundal sau pe o aplicație monolitică care realizează propriul management al proceselor individuale. Tehnicile prezentate mai sus vă pot ajuta să containerizați aceste tipuri de software.

Rularea mai multor procese într-un container ar trebui totuși evitată ori de câte ori este posibil. Aderarea la un singur proces din prim-plan maximizează izolarea, previne interferența componentelor între ele și îmbunătățește capacitatea de a depana și testa anumite piese. Puteți scala componentele individual utilizând orchestratoare de containere, oferindu-vă flexibilitatea de a rula mai multe instanțe ale proceselor dvs. cele mai mari consumatoare de resurse.

Concluzie

Containerele au de obicei un proces în prim-plan și rulează atâta timp cât este în viață. Acest model se aliniază cu cele mai bune practici de containerizare și vă permite să obțineți cele mai multe beneficii de pe urma tehnologiei.

În unele situații, este posibil să aveți nevoie de mai multe procese pentru a rula într-un container. Deoarece toate imaginile au în cele din urmă un singur punct de intrare, trebuie să scrieți un script wrapper sau să adăugați un manager de proces care își asumă responsabilitatea pentru pornirea fișierelor binare țintă.

Managerii de proces vă oferă tot ceea ce aveți nevoie, dar umflați-vă imaginile cu pachete și configurații suplimentare. Scripturile Wrapper sunt mai simple, dar poate fi necesar să fie asociate cu semnalul Docker --init pentru a preveni proliferarea procesului zombi.