Avviamo systemd nel contenitore

Seguiamo da tempo il tema dell'uso di systemd nei contenitori. Già nel 2014 il nostro ingegnere della sicurezza Daniel Walsh scrisse un articolo Esecuzione di systemd all'interno di un contenitore Docker, e qualche anno dopo un altro, intitolato Esecuzione di systemd in un contenitore non privilegiato, nel quale constatava che la situazione non era migliorata di molto. In particolare, scriveva che "sfortunatamente, anche due anni dopo, cercando 'Docker system', la prima cosa che appare è ancora il suo vecchio articolo. È tempo di cambiare qualcosa". Inoltre, abbiamo già parlato di un conflitto tra gli sviluppatori di Docker e systemd.

Avviamo systemd nel contenitore

In questo articolo mostreremo cosa è cambiato nel tempo e come Podman possa aiutarci in questo problema.

Ci sono molte ragioni per eseguire systemd all'interno di un contenitore, come ad esempio:

  1. Contenitori multi-servizio – molti vogliono estrarre le proprie applicazioni multi-servizio da macchine virtuali e eseguirle in contenitori. Ovviamente sarebbe meglio suddividere tali applicazioni in microservizi, ma non tutti sono in grado di farlo o semplicemente non hanno tempo. Quindi eseguire tali applicazioni sotto forma di servizi avviati da systemd tramite file di unità ha un senso.
  2. File di unità Systemd – la maggior parte delle applicazioni che funzionano all'interno dei contenitori sono composte da codice che era stato precedentemente eseguito su macchine virtuali o fisiche. Queste applicazioni hanno un file di unità, creato appositamente per esse, che sa come avviarle. Quindi è comunque meglio avviare i servizi utilizzando metodi supportati, piuttosto che hackerare il proprio servizio init.
  3. Systemd è un gestore di processi. Gestisce i servizi (termina, riavvia i servizi o uccide processi zombie) meglio di qualsiasi altro strumento.

D'altra parte, ci sono molte ragioni per non eseguire systemd nei contenitori. La principale è che systemd/journald controlla l'output dei contenitori, e strumenti come Kubernetes o OpenShift si aspettano che i contenitori scrivano i log direttamente in stdout e stderr. Quindi, se stai pensando di gestire i contenitori tramite strumenti di orchestrazione come quelli sopra citati, dovresti seriamente considerare l'uso di contenitori basati su systemd. Inoltre, gli sviluppatori di Docker e Moby sono stati spesso fortemente contrari all'uso di systemd nei contenitori.

L'avvento di Podman

Siamo lieti di annunciare che la situazione finalmente si è sbloccata. Il team di Red Hat responsabile del lancio dei container ha deciso di sviluppare il proprio motore di container. Ha ricevuto il nome Podman e offre la stessa interfaccia a riga di comando (CLI) di Docker. Praticamente tutti i comandi di Docker possono essere utilizzati in modo identico in Podman. Spesso organizziamo seminari, che ora si chiamano Passiamo da Docker a Podman, e la prima slide invita a scrivere: alias docker=podman.

Molti lo fanno.

Con il nostro Podman non siamo affatto contrari ai container basati su systemd. Infatti, systemd è frequentemente utilizzato come sistema init in Linux e non dare a esso la possibilità di funzionare normalmente nei container significa ignorare come migliaia di persone sono abituate a lanciare container.

Podman sa cosa fare affinché systemd funzioni correttamente in un container. Ha bisogno di cose come il montaggio di tmpfs su /run e /tmp. Gli piace quando è attivato l'ambiente "container" e attende i permessi di scrittura nella sua parte del catalogo cgroup e nella cartella /var/log/journald.

Quando avvii un container il cui primo comando è init o systemd, Podman configura automaticamente tmpfs e Cgroups affinché l'avvio di systemd avvenga senza problemi. Per bloccare questo avvio automatico, si utilizza l'opzione —systemd=false. Nota che Podman utilizza la modalità systemd solo quando rileva la necessità di eseguire un comando systemd o init.

Ecco un estratto dal manuale:

man podman run

–systemd=true|false

Avvia un container in modalità systemd. Attivata per impostazione predefinita.

Se un comando systemd o init viene eseguito all'interno del container, Podman configurerà i punti di montaggio tmpfs nelle seguenti directory:

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

Inoltre, SIGRTMIN+3 verrà utilizzato come segnale di arresto per impostazione predefinita.

Tutto ciò consente a systemd di funzionare in un container isolato senza alcuna modifica.

NOTA: systemd tenta di scrivere nel file system cgroup. Tuttavia, SELinux impedisce per impostazione predefinita ai container di farlo. Per consentire la scrittura, attiva il parametro booleano container_manage_cgroup:

setsebool -P container_manage_cgroup true

Ora vediamo come appare un Dockerfile per avviare systemd in un container utilizzando Podman:

# cat Dockerfile

FROM fedora

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

EXPOSE 80

CMD [ "/sbin/init" ]

Ecco tutto.

Adesso costruiamo il container:

# podman build -t systemd .

Diciamo a SELinux di consentire a systemd di modificare la configurazione dei Cgroups:

# setsebool -P container_manage_cgroup true

Molti, per dire la verità, dimenticano questo passaggio. Fortunatamente, è sufficiente farlo una sola volta e la configurazione viene salvata dopo il riavvio del sistema.

Ora basta avviare il container:

# 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.

Tutto, il servizio è avviato e funzionante:

$ curl localhost

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

…

</html>

NOTA: Non provate a ripetere questo su Docker! Ci vogliono ancora degli aggiustamenti per avviare questo tipo di container tramite il demone. (Saranno necessari campi e pacchetti aggiuntivi affinché tutto funzioni in modo fluido su Docker, oppure dovrete avviare in un container con privilegi. Maggiori dettagli in abbiamo chiarito il corretto completamento dei programmi che utilizzano il mediastreamer..)

Altre due cose interessanti su Podman e systemd

Podman funziona meglio di Docker nei file unit di systemd

Se i container devono essere avviati all'avvio del sistema, è possibile inserire semplicemente i comandi Podman appropriati nel file unit di systemd, che avvierà il servizio e lo monitorerà. Podman utilizza il modello standard di fork-exec. In altre parole, i processi dei container sono figli del processo di Podman, quindi systemd può facilmente monitorarli.

Docker utilizza il modello client-server e i comandi CLI di Docker possono essere posizionati direttamente nel file unit. Tuttavia, dopo che il client di Docker si connette al demone Docker, esso (il client) diventa un normale processo che gestisce stdin e stdout. Di conseguenza, systemd non ha idea della connessione tra il client di Docker e il container che opera sotto il demone Docker, e quindi, all'interno di questo modello, systemd non può monitorare il servizio.

Attivazione di systemd tramite socket

Podman gestisce correttamente l'attivazione tramite socket. Poiché Podman utilizza il modello fork-exec, può inoltrare il socket ai propri processi container figlio. Docker non può farlo, poiché utilizza il modello client-server.

Il servizio varlink, utilizzato da Podman per interagire con i client remoti e i container, viene attivato attraverso un socket. Il pacchetto cockpit-podman, scritto in Node.js e parte del progetto cockpit, consente agli utenti di interagire con i container Podman attraverso un'interfaccia web. Il demone web, su cui gira cockpit-podman, invia messaggi al socket varlink, che è in ascolto da systemd. Di conseguenza, systemd attiva il programma Podman per ricevere messaggi e iniziare a gestire i container. L'attivazione di systemd tramite socket consente di evitare un demone sempre attivo nella realizzazione di API remoti.

Inoltre, stiamo sviluppando un altro client per Podman chiamato podman-remote, che implementa lo stesso Podman CLI, ma invoca varlink per avviare i container. Podman-remote può funzionare su sessioni SSH, permettendo un'interazione sicura con i container su diverse macchine. Nel tempo, prevediamo di utilizzare podman-remote per supportare MacOS e Windows insieme a Linux, affinché gli sviluppatori su queste piattaforme possano avviare una macchina virtuale Linux con Podman varlink in esecuzione e avere la completa sensazione che i container vengano eseguiti sulla macchina locale.

SD_NOTIFY

Systemd consente di posticipare l'avvio dei servizi ausiliari fino a quando non viene avviato il servizio containerizzato di cui hanno bisogno. Podman può inoltrare il socket SD_NOTIFY al servizio containerizzato, affinché questo avvisi systemd della sua prontezza. E ancora, Docker, che utilizza un modello client-server, non lo fa.

In programma

Prevediamo di aggiungere il comando podman generate systemd CONTAINERID, che genererà un file unit di systemd per gestire un determinato container. Questo dovrebbe funzionare sia in modalità root che in modalità rootless per i container non privilegiati. Abbiamo anche visto una richiesta per la creazione di un ambiente di esecuzione compatibile con OCI systemd-nspawn.

Conclusione

Eseguire systemd in un container è una necessità comprensibile. E grazie a Podman, finalmente abbiamo un ambiente di esecuzione dei container che non è in conflitto con systemd, ma rende facile utilizzarlo.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster