Λειτουργία συστήματος σε δοχείο

Παρακολουθούμε εδώ και πολύ καιρό το θέμα της χρήσης του systemd σε κοντέινερ. Το 2014, ο μηχανικός ασφαλείας μας Daniel Walsh έγραψε ένα άρθρο Λειτουργία συστήματος μέσα σε ένα Docker Container, και μερικά χρόνια αργότερα - ένα άλλο, το οποίο ονομάστηκε Εκτέλεση του συστήματος σε μη προνομιακό κοντέινερ, στην οποία ανέφερε ότι η κατάσταση δεν έχει βελτιωθεί ιδιαίτερα. Συγκεκριμένα, έγραψε ότι «δυστυχώς, ακόμη και δύο χρόνια αργότερα, αν google-ρίξεις το «Docker system», το πρώτο πράγμα που προκύπτει είναι το ίδιο παλιό άρθρο του. Ήρθε λοιπόν η ώρα να αλλάξει κάτι». Επιπλέον, έχουμε ήδη μιλήσει για διένεξη μεταξύ του Docker και των προγραμματιστών του συστήματος.

Λειτουργία συστήματος σε δοχείο

Σε αυτό το άρθρο θα δείξουμε τι έχει αλλάξει με την πάροδο του χρόνου και πώς μπορεί να μας βοηθήσει το Podman σε αυτό το θέμα.

Υπάρχουν πολλοί λόγοι για να τρέξετε το systemd μέσα σε ένα κοντέινερ, όπως:

  1. Εμπορευματοκιβώτια πολλαπλών υπηρεσιών – Πολλοί άνθρωποι θέλουν να βγάλουν τις εφαρμογές πολλαπλών υπηρεσιών τους από εικονικές μηχανές και να τις εκτελούν σε κοντέινερ. Θα ήταν καλύτερα, φυσικά, να χωρίσουμε τέτοιες εφαρμογές σε μικροϋπηρεσίες, αλλά δεν γνωρίζουν όλοι πώς να το κάνουν ακόμα ή απλά δεν έχουν το χρόνο. Επομένως, η εκτέλεση τέτοιων εφαρμογών ως υπηρεσιών που εκκινούνται από το systemd από αρχεία μονάδας είναι απολύτως λογικό.
  2. Συστημικά αρχεία μονάδας – Οι περισσότερες εφαρμογές που εκτελούνται μέσα σε κοντέινερ είναι κατασκευασμένες από κώδικα που προηγουμένως εκτελούνταν σε εικονικές ή φυσικές μηχανές. Αυτές οι εφαρμογές έχουν ένα αρχείο μονάδας που γράφτηκε για αυτές τις εφαρμογές και κατανοεί πώς πρέπει να εκκινηθούν. Επομένως, είναι ακόμα καλύτερο να ξεκινήσετε τις υπηρεσίες χρησιμοποιώντας υποστηριζόμενες μεθόδους, αντί να παραβιάζετε τη δική σας υπηρεσία init.
  3. Ο Systemd είναι διαχειριστής διεργασιών. Διαχειρίζεται τις υπηρεσίες (κλείνει, επανεκκινεί υπηρεσίες ή σκοτώνει διαδικασίες ζόμπι) καλύτερα από οποιοδήποτε άλλο εργαλείο.

Τούτου λεχθέντος, υπάρχουν πολλοί λόγοι για να μην εκτελείτε το systemd σε κοντέινερ. Το κυριότερο είναι ότι το systemd/journald ελέγχει την έξοδο των κοντέινερ και εργαλείων όπως Kubernetes ή openshift περιμένουμε τα κοντέινερ να γράφουν το αρχείο καταγραφής απευθείας στα stdout και stderr. Επομένως, εάν πρόκειται να διαχειριστείτε κοντέινερ μέσω εργαλείων ενορχήστρωσης όπως αυτά που αναφέρθηκαν παραπάνω, θα πρέπει να σκεφτείτε σοβαρά τη χρήση κοντέινερ που βασίζονται στο σύστημα. Επιπλέον, οι προγραμματιστές Docker και Moby έχουν συχνά αντιταχθεί σθεναρά στη χρήση του systemd σε κοντέινερ.

Ο ερχομός του Πόντμαν

Είμαστε στην ευχάριστη θέση να αναφέρουμε ότι η κατάσταση επιτέλους έχει προχωρήσει. Η ομάδα που είναι υπεύθυνη για τη λειτουργία κοντέινερ στο Red Hat αποφάσισε να αναπτυχθεί τον δικό σας κινητήρα κοντέινερ. Πήρε όνομα Πόντμαν και προσφέρει την ίδια διεπαφή γραμμής εντολών (CLI) με το Docker. Και σχεδόν όλες οι εντολές Docker μπορούν να χρησιμοποιηθούν στο Podman με τον ίδιο τρόπο. Συχνά πραγματοποιούμε σεμινάρια, τα οποία ονομάζονται πλέον Αλλαγή Docker σε Podman, και η πρώτη κιόλας διαφάνεια απαιτεί γραφή: ψευδώνυμο docker=podman.

Πολλοί άνθρωποι κάνουν ακριβώς αυτό.

Το Podman μου και εγώ δεν είμαστε σε καμία περίπτωση κατά των δοχείων που βασίζονται στο σύστημα. Σε τελική ανάλυση, το Systemd είναι το πιο συχνά χρησιμοποιούμενο υποσύστημα init Linux και το να μην του επιτρέπεται να λειτουργεί σωστά σε κοντέινερ σημαίνει ότι αγνοούμε πώς χιλιάδες άνθρωποι έχουν συνηθίσει να τρέχουν κοντέινερ.

Ο Podman ξέρει τι πρέπει να κάνει για να κάνει το systemd να λειτουργεί σωστά σε ένα δοχείο. Χρειάζεται πράγματα όπως η τοποθέτηση tmpfs στο /run και /tmp. Της αρέσει να έχει ενεργοποιημένο το περιβάλλον "containerized" και αναμένει δικαιώματα εγγραφής στο μέρος του καταλόγου cgroup και στο φάκελο /var/log/journald.

Όταν ξεκινάτε ένα κοντέινερ στο οποίο η πρώτη εντολή είναι init ή systemd, το Podman διαμορφώνει αυτόματα τα tmpfs και τα Cgroups για να διασφαλίσει ότι το systemd ξεκινά χωρίς προβλήματα. Για να αποκλείσετε αυτήν τη λειτουργία αυτόματης εκκίνησης, χρησιμοποιήστε την επιλογή --systemd=false. Λάβετε υπόψη ότι το Podman χρησιμοποιεί τη λειτουργία systemd μόνο όταν βλέπει ότι πρέπει να εκτελέσει μια εντολή systemd ή init.

Εδώ είναι ένα απόσπασμα από το εγχειρίδιο:

άνθρωπος podman τρέξιμο
...

–systemd=true|false

Εκτέλεση ενός κοντέινερ σε λειτουργία systemd. Ενεργοποιημένο από προεπιλογή.

Εάν εκτελείτε μια εντολή systemd ή init μέσα σε ένα κοντέινερ, το Podman θα διαμορφώσει τα σημεία προσάρτησης tmpfs στους ακόλουθους καταλόγους:

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

Επίσης το προεπιλεγμένο σήμα διακοπής θα είναι το SIGRTMIN+3.

Όλα αυτά επιτρέπουν στο systemd να λειτουργεί σε κλειστό δοχείο χωρίς καμία τροποποίηση.

ΣΗΜΕΙΩΣΗ: Το systemd επιχειρεί να γράψει στο σύστημα αρχείων cgroup. Ωστόσο, το SELinux εμποδίζει τα κοντέινερ να το κάνουν αυτό από προεπιλογή. Για να ενεργοποιήσετε τη γραφή, ενεργοποιήστε τη δυαδική παράμετρο container_manage_cgroup:

setsebool -P container_manage_cgroup true

Τώρα δείτε πώς φαίνεται το Dockerfile για την εκτέλεση του systemd σε ένα κοντέινερ χρησιμοποιώντας το Podman:

# cat Dockerfile

FROM fedora

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

EXPOSE 80

CMD [ "/sbin/init" ]

Αυτό είναι όλο.

Τώρα συναρμολογούμε το δοχείο:

# podman build -t systemd .

Λέμε στο SELinux να επιτρέψει στο systemd να τροποποιήσει τη διαμόρφωση των Cgroups:

# setsebool -P container_manage_cgroup true

Παρεμπιπτόντως, πολλοί άνθρωποι ξεχνούν αυτό το βήμα. Ευτυχώς, αυτό χρειάζεται να γίνει μόνο μία φορά και η ρύθμιση αποθηκεύεται μετά την επανεκκίνηση του συστήματος.

Τώρα ξεκινάμε απλώς το δοχείο:

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

Αυτό είναι όλο, η υπηρεσία είναι σε λειτουργία:

$ curl localhost

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

…

</html>

ΣΗΜΕΙΩΣΗ: Μην το δοκιμάσετε στο Docker! Εκεί πρέπει ακόμα να χορέψετε με ένα ντέφι για να ρίξετε αυτά τα είδη δοχείων μέσα από τον δαίμονα. (Θα απαιτηθούν πρόσθετα πεδία και πακέτα για να λειτουργήσουν όλα απρόσκοπτα στο Docker ή θα πρέπει να εκτελεστούν σε ένα προνομιακό κοντέινερ. Για λεπτομέρειες, βλ. άρθρο.)

Κάποια ακόμα ωραία πράγματα για το Podman και το systemd

Το Podman λειτουργεί καλύτερα από το Docker σε αρχεία μονάδων systemd

Εάν τα κοντέινερ πρέπει να ξεκινήσουν κατά την εκκίνηση του συστήματος, τότε μπορείτε απλώς να εισαγάγετε τις κατάλληλες εντολές Podman στο αρχείο της μονάδας systemd, το οποίο θα ξεκινήσει την υπηρεσία και θα την παρακολουθήσει. Το Podman χρησιμοποιεί το τυπικό μοντέλο fork-exec. Με άλλα λόγια, οι διεργασίες κοντέινερ είναι παιδιά της διαδικασίας Podman, επομένως το systemd μπορεί εύκολα να τις παρακολουθεί.

Το Docker χρησιμοποιεί ένα μοντέλο πελάτη-διακομιστή και οι εντολές Docker CLI μπορούν επίσης να τοποθετηθούν απευθείας σε ένα αρχείο μονάδας. Ωστόσο, μόλις ο πελάτης Docker συνδεθεί με τον δαίμονα Docker, (ο πελάτης) γίνεται απλώς μια άλλη διεργασία που επεξεργάζεται το stdin και το stdout. Με τη σειρά του, το systemd δεν έχει ιδέα για τη σύνδεση μεταξύ του προγράμματος-πελάτη Docker και του κοντέινερ που λειτουργεί υπό τον έλεγχο του δαίμονα του Docker, και επομένως, σε αυτό το μοντέλο, το systemd ουσιαστικά δεν μπορεί να παρακολουθήσει την υπηρεσία.

Ενεργοποίηση του συστήματος μέσω πρίζας

Το Podman χειρίζεται σωστά την ενεργοποίηση μέσω υποδοχής. Επειδή το Podman χρησιμοποιεί το μοντέλο fork-exec, μπορεί να προωθήσει την υποδοχή στις διαδικασίες του θυγατρικού κοντέινερ. Το Docker δεν μπορεί να το κάνει αυτό επειδή χρησιμοποιεί ένα μοντέλο πελάτη-διακομιστή.

Η υπηρεσία varlink που χρησιμοποιεί το Podman για να επικοινωνεί με απομακρυσμένους πελάτες σε κοντέινερ ενεργοποιείται στην πραγματικότητα μέσω μιας πρίζας. Το πακέτο cockpit-podman, γραμμένο στο Node.js και μέρος του έργου cockpit, επιτρέπει στους ανθρώπους να αλληλεπιδρούν με κοντέινερ Podman μέσω μιας διεπαφής ιστού. Ο διαδικτυακός δαίμονας που τρέχει το cockpit-podman στέλνει μηνύματα σε μια υποδοχή varlink που το systemd ακούει. Στη συνέχεια, το Systemd ενεργοποιεί το πρόγραμμα Podman για να λαμβάνει μηνύματα και να ξεκινήσει τη διαχείριση κοντέινερ. Η ενεργοποίηση του systemd μέσω μιας υποδοχής εξαλείφει την ανάγκη για έναν δαίμονα που τρέχει συνεχώς κατά την εφαρμογή απομακρυσμένων API.

Επιπλέον, αναπτύσσουμε έναν άλλο πελάτη Podman που ονομάζεται podman-remote, ο οποίος υλοποιεί το ίδιο Podman CLI αλλά καλεί το varlink για να τρέξει κοντέινερ. Το Podman-Remote μπορεί να τρέχει πάνω από τις περιόδους λειτουργίας SSH, επιτρέποντάς σας να αλληλεπιδράτε με ασφάλεια με κοντέινερ σε διαφορετικά μηχανήματα. Με την πάροδο του χρόνου, σχεδιάζουμε να ενεργοποιήσουμε το podman-remote για υποστήριξη MacOS και Windows παράλληλα με το Linux, έτσι ώστε οι προγραμματιστές σε αυτές τις πλατφόρμες να μπορούν να εκτελούν μια εικονική μηχανή Linux με το Podman varlink να εκτελείται και να έχουν την πλήρη εμπειρία ότι τα κοντέινερ εκτελούνται στον τοπικό υπολογιστή.

SD_NOTIFY

Το Systemd σάς επιτρέπει να αναβάλλετε την έναρξη των βοηθητικών υπηρεσιών έως ότου ξεκινήσει η υπηρεσία κοντέινερ που απαιτούν. Το Podman μπορεί να προωθήσει την υποδοχή SD_NOTIFY στην υπηρεσία κοντέινερ, έτσι ώστε η υπηρεσία να ειδοποιεί το σύστημα ότι είναι έτοιμο να λειτουργήσει. Και πάλι, το Docker, το οποίο χρησιμοποιεί ένα μοντέλο πελάτη-διακομιστή, δεν μπορεί να το κάνει αυτό.

Στα σχέδια

Σκοπεύουμε να προσθέσουμε την εντολή podman generate systemd CONTAINERID, η οποία θα δημιουργήσει ένα αρχείο μονάδας systemd για τη διαχείριση ενός συγκεκριμένου κοντέινερ. Αυτό θα πρέπει να λειτουργεί και σε λειτουργίες root και χωρίς root για μη προνομιούχα κοντέινερ. Έχουμε δει ακόμη και ένα αίτημα για χρόνο εκτέλεσης systemd-nspawn συμβατό με OCI.

Συμπέρασμα

Η λειτουργία του συστήματος σε ένα κοντέινερ είναι μια κατανοητή ανάγκη. Και χάρη στο Podman, επιτέλους έχουμε έναν χρόνο εκτέλεσης κοντέινερ που δεν έρχεται σε αντίθεση με το systemd, αλλά τον κάνει εύκολο στη χρήση.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο