Urmărim de multă vreme subiectul utilizării systemd în containere. În 2014, inginerul nostru de securitate Daniel Walsh a scris un articol
Î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:
- 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.
- 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.
- 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
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
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
Î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