Rularea systemd într-un container

Urmărim de multă vreme subiectul utilizării systemd în containere. În 2014, inginerul nostru de securitate Daniel Walsh a scris un articol Rularea systemd într-un container Docker, și câțiva ani mai târziu - altul, care a fost numit Rulează systemd într-un container neprivilegiat, în care a afirmat că situația nu s-a îmbunătățit prea mult. În special, el a scris că „din păcate, chiar și doi ani mai târziu, dacă căutați pe google „sistem Docker”, primul lucru care apare este același articol vechi. Așa că este timpul să schimbăm ceva.” În plus, am vorbit deja despre conflict între Docker și dezvoltatorii systemd.

Rularea systemd într-un container

În acest articol vom arăta ce s-a schimbat de-a lungul timpului și cum ne poate ajuta Podman în această problemă.

Există multe motive pentru a rula systemd în interiorul unui container, cum ar fi:

  1. Containere multiservicii – mulți oameni doresc să-și scoată aplicațiile multi-servicii din mașinile virtuale și să le ruleze în containere. Desigur, ar fi mai bine să împărțim astfel de aplicații în microservicii, dar nu toată lumea știe încă cum să facă acest lucru sau pur și simplu nu are timp. Prin urmare, rularea unor astfel de aplicații precum serviciile lansate de systemd din fișierele unitare are sens perfect.
  2. Fișiere de unitate Systemd – Majoritatea aplicațiilor care rulează în interiorul containerelor sunt construite din cod care rula anterior pe mașini virtuale sau fizice. Aceste aplicații au un fișier unitar care a fost scris pentru aceste aplicații și înțelege cum ar trebui să fie lansate. Prin urmare, este mai bine să începeți serviciile folosind metode acceptate, decât să vă spargeți propriul serviciu de init.
  3. Systemd este un manager de proces. Gestionează serviciile (închide, repornește serviciile sau ucide procesele zombie) mai bine decât orice alt instrument.

Acestea fiind spuse, există multe motive pentru a nu rula systemd în containere. Principalul este că systemd/journald controlează producția containerelor și instrumente precum Kubernetes sau tura deschisă așteptați ca containerele să scrie log direct în stdout și stderr. Prin urmare, dacă aveți de gând să gestionați containerele prin instrumente de orchestrare precum cele menționate mai sus, ar trebui să vă gândiți serios să utilizați containere bazate pe systemd. În plus, dezvoltatorii Docker și Moby s-au opus adesea cu fermitate utilizării systemd în containere.

Venirea lui Podman

Suntem bucuroși să raportăm că situația a avansat în sfârșit. Echipa responsabilă cu rularea containerelor la Red Hat a decis să se dezvolte propriul motor container. A primit un nume Podman și oferă aceeași interfață de linie de comandă (CLI) ca și Docker. Și aproape toate comenzile Docker pot fi folosite în Podman în același mod. Deseori ținem seminarii, care sunt acum numite Schimbarea Docker în Podman, iar primul slide solicită scriere: alias docker=podman.

Mulți oameni fac asta.

Eu și Podmanul meu nu suntem în niciun caz împotriva containerelor bazate pe systemd. La urma urmei, Systemd este cel mai frecvent utilizat subsistem Linux init, iar a nu-i permite să funcționeze corect în containere înseamnă a ignora modul în care mii de oameni sunt obișnuiți să ruleze containerele.

Podman știe ce să facă pentru ca systemd să funcționeze corect într-un container. Are nevoie de lucruri precum montarea tmpfs pe /run și /tmp. Îi place să aibă mediul „containerizat” activat și așteaptă permisiuni de scriere pentru partea ei din directorul cgroup și pentru folderul /var/log/journald.

Când porniți un container în care prima comandă este init sau systemd, Podman configurează automat tmpfs și Cgroups pentru a se asigura că systemd pornește fără probleme. Pentru a bloca acest mod de lansare automată, utilizați opțiunea --systemd=false. Vă rugăm să rețineți că Podman folosește modul systemd numai când vede că trebuie să ruleze o comandă systemd sau init.

Iată un extras din manual:

om podman alerga
...

–systemd=adevărat|fals

Rularea unui container în modul systemd. Activat implicit.

Dacă rulați o comandă systemd sau init în interiorul unui container, Podman va configura punctele de montare tmpfs în următoarele directoare:

/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal

De asemenea, semnalul de oprire implicit va fi SIGRTMIN+3.

Toate acestea permit sistemului systemd să ruleze într-un container închis fără nicio modificare.

NOTĂ: systemd încearcă să scrie în sistemul de fișiere cgroup. Cu toate acestea, SELinux împiedică containerele să facă acest lucru în mod implicit. Pentru a activa scrierea, activați parametrul boolean container_manage_cgroup:

setsebool -P container_manage_cgroup true

Acum uitați-vă la cum arată fișierul Docker pentru rularea systemd într-un container folosind Podman:

# cat Dockerfile

FROM fedora

RUN dnf -y install httpd; dnf clean all; systemctl enable httpd

EXPOSE 80

CMD [ "/sbin/init" ]

Asta e tot.

Acum asamblam recipientul:

# podman build -t systemd .

Îi spunem SELinux să permită systemd să modifice configurația Cgroups:

# setsebool -P container_manage_cgroup true

Apropo, mulți oameni uită de acest pas. Din fericire, acest lucru trebuie făcut o singură dată, iar setarea este salvată după repornirea sistemului.

Acum începem doar containerul:

# podman run -ti -p 80:80 systemd

systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid)

Detected virtualization container-other.

Detected architecture x86-64.

Welcome to Fedora 29 (Container Image)!

Set hostname to <1b51b684bc99>.

Failed to install release agent, ignoring: Read-only file system

File /usr/lib/systemd/system/systemd-journald.service:26 configures an IP firewall (IPAddressDeny=any), but the local system does not support BPF/cgroup based firewalling.

Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first loaded unit using IP firewalling.)

[  OK ] Listening on initctl Compatibility Named Pipe.

[  OK ] Listening on Journal Socket (/dev/log).

[  OK ] Started Forward Password Requests to Wall Directory Watch.

[  OK ] Started Dispatch Password Requests to Console Directory Watch.

[  OK ] Reached target Slices.

…

[  OK ] Started The Apache HTTP Server.

Gata, serviciul este în funcțiune:

$ curl localhost

<html  xml_lang="en" lang="en">

…

</html>

NOTĂ: Nu încercați acest lucru pe Docker! Acolo mai trebuie să dansezi cu o tamburină pentru a lansa astfel de containere prin demon. (Vor fi necesare câmpuri și pachete suplimentare pentru ca toate acestea să funcționeze fără probleme în Docker, sau va trebui să fie rulat într-un container privilegiat. Pentru detalii, consultați articol.)

Încă câteva lucruri interesante despre Podman și systemd

Podman funcționează mai bine decât Docker în fișierele de unitate systemd

Dacă containerele trebuie pornite atunci când sistemul pornește, atunci puteți pur și simplu să introduceți comenzile Podman corespunzătoare în fișierul unitar systemd, care va porni serviciul și îl va monitoriza. Podman folosește modelul standard fork-exec. Cu alte cuvinte, procesele container sunt copii ale procesului Podman, astfel încât systemd le poate monitoriza cu ușurință.

Docker folosește un model client-server, iar comenzile Docker CLI pot fi, de asemenea, plasate direct într-un fișier unitar. Cu toate acestea, odată ce clientul Docker se conectează la demonul Docker, acesta (clientul) devine doar un alt proces care gestionează stdin și stdout. La rândul său, systemd habar n-are despre conexiunea dintre clientul Docker și containerul care rulează sub controlul demonului Docker și, prin urmare, în cadrul acestui model, systemd în mod fundamental nu poate monitoriza serviciul.

Activarea sistemului prin socket

Podman gestionează corect activarea prin priză. Deoarece Podman folosește modelul fork-exec, poate redirecționa socket-ul către procesele containerului său copil. Docker nu poate face acest lucru deoarece folosește un model client-server.

Serviciul varlink pe care Podman îl folosește pentru a comunica cu clienții la distanță către containere este de fapt activat printr-un socket. Pachetul cockpit-podman, scris în Node.js și parte a proiectului cockpit, permite oamenilor să interacționeze cu containerele Podman printr-o interfață web. Daemonul web care rulează cockpit-podman trimite mesaje către un socket varlink pe care systemd ascultă. Systemd activează apoi programul Podman pentru a primi mesaje și pentru a începe gestionarea containerelor. Activarea systemd printr-un socket elimină necesitatea unui daemon care rulează constant atunci când implementați API-uri la distanță.

În plus, dezvoltăm un alt client Podman numit podman-remote, care implementează același Podman CLI, dar apelează varlink pentru a rula containere. Podman-remote poate rula peste sesiunile SSH, permițându-vă să interacționați în siguranță cu containerele de pe diferite mașini. De-a lungul timpului, intenționăm să permitem podman-remote să accepte MacOS și Windows alături de Linux, astfel încât dezvoltatorii de pe acele platforme să poată rula o mașină virtuală Linux cu Podman varlink rulând și să aibă experiența completă că containerele rulează pe mașina locală.

SD_NOTIFY

Systemd vă permite să amânați lansarea serviciilor auxiliare până când începe serviciul containerizat de care au nevoie. Podman poate redirecționa socket-ul SD_NOTIFY către serviciul containerizat, astfel încât serviciul să notifice systemd că este gata de funcționare. Și din nou, Docker, care utilizează un model client-server, nu poate face acest lucru.

În planuri

Intenționăm să adăugăm comanda podman generate systemd CONTAINERID, care va genera un fișier unitar systemd pentru a gestiona un anumit container specificat. Acest lucru ar trebui să funcționeze atât în ​​modul rădăcină, cât și în modul fără rădăcină pentru containerele neprivilegiate. Am văzut chiar și o solicitare pentru un sistem de rulare systemd-nspawn compatibil cu OCI.

Concluzie

Rularea systemd într-un container este o nevoie de înțeles. Și datorită Podman, avem în sfârșit un container de rulare care nu intră în conflict cu systemd, dar îl face ușor de utilizat.

Sursa: www.habr.com

Adauga un comentariu