GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Eine Geschichte der Low-Level-Laufzeiten von Linux-Containern

Bei Red Hat sagen wir gerne:„Container sind Linux – Linux ist Container.“ Hier ist, was das bedeutet. Herkömmliche Container sind Prozesse auf einem System, die normalerweise die folgenden drei Merkmale aufweisen:

1. Ressourcenbeschränkungen

Linux-Container

  • Was sind Linux-Container?
  • Eine Einführung in die Containerterminologie
  • Download:Einführung in Container
  • Kubernetes-Operatoren:Automatisierung der Container-Orchestrierungsplattform
  • eBook:Kubernetes-Muster zum Entwerfen cloudnativer Apps
  • Was ist Kubernetes?

Wenn Sie viele Container auf einem System ausführen, möchten Sie nicht, dass ein Container das Betriebssystem monopolisiert, also verwenden wir Ressourcenbeschränkungen, um Dinge wie CPU, Speicher, Netzwerkbandbreite usw. zu steuern. Der Linux-Kernel bietet die cgroups-Funktion, die kann konfiguriert werden, um die Ressourcen des Containerprozesses zu steuern.

2. Sicherheitsbeschränkungen

Normalerweise möchten Sie nicht, dass Ihre Container sich gegenseitig angreifen oder das Hostsystem angreifen können. Wir nutzen mehrere Funktionen des Linux-Kernels, um eine Sicherheitstrennung einzurichten, wie SELinux, seccomp, Capabilities usw.

3. Virtuelle Trennung

Containerprozesse sollten keine Sicht auf Prozesse außerhalb des Containers haben. Sie sollten sich in ihrem eigenen Netzwerk befinden. Containerprozesse müssen sich in verschiedenen Containern an Port 80 binden können. Jeder Container benötigt eine andere Ansicht seines Images, benötigt ein eigenes Root-Dateisystem (rootfs). In Linux verwenden wir Kernel-Namespaces, um eine virtuelle Trennung bereitzustellen.

Daher kann ein Prozess, der in einer Cgroup läuft, Sicherheitseinstellungen hat und in Namespaces läuft, als Container bezeichnet werden. Wenn Sie sich PID 1, systemd, auf einem Red Hat Enterprise Linux 7-System ansehen, sehen Sie, dass systemd in einer Kontrollgruppe läuft.

# tail -1 /proc/1/cgroup
1:name=systemd:/

Das ps zeigt Ihnen, dass der Systemprozess ein SELinux-Label hat ...

# ps -eZ | grep systemd
system_u:system_r:init_t:s0             1 ?     00:00:48 systemd

und Fähigkeiten.

# grep Cap /proc/1/status
...
CapEff: 0000001fffffffff
CapBnd: 0000001fffffffff
CapBnd:    0000003fffffffff

Schließlich, wenn Sie sich die Datei /proc/1/ns ansehen subdir sehen Sie den Namespace, in dem systemd läuft.

ls -l /proc/1/ns
lrwxrwxrwx. 1 root root 0 Jan 11 11:46 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Jan 11 11:46 net -> net:[4026532009]
lrwxrwxrwx. 1 root root 0 Jan 11 11:46 pid -> pid:[4026531836]
...

Wenn PID 1 (und wirklich jeder andere Prozess auf dem System) Ressourcenbeschränkungen, Sicherheitseinstellungen und Namespaces hat, behaupte ich, dass sich jeder Prozess auf dem System in einem Container befindet.

Container-Laufzeittools ändern lediglich diese Ressourceneinschränkungen, Sicherheitseinstellungen und Namespaces. Dann führt der Linux-Kernel die Prozesse aus. Nachdem der Container gestartet wurde, kann die Containerlaufzeit die PID 1 im Container oder die stdin des Containers überwachen /stdout – Die Container-Laufzeit verwaltet die Lebenszyklen dieser Prozesse.

Containerlaufzeiten

Sie könnten sich sagen, nun, systemd klingt ziemlich ähnlich wie eine Container-Laufzeitumgebung. Nun, nachdem wir mehrere E-Mail-Diskussionen darüber geführt haben, warum Container-Laufzeiten systemd-nspawn nicht verwenden Als Tool zum Starten von Containern entschied ich, dass es sich lohnen würde, Containerlaufzeiten zu diskutieren und einen historischen Kontext zu geben.

Docker wird oft als Container-Laufzeit bezeichnet, aber „Container-Laufzeit“ ist ein überladener Begriff. Wenn Leute von einer „Container-Laufzeit“ sprechen, sprechen sie in Wirklichkeit von übergeordneten Tools wie Docker, CRI-O und RKT, die mit Entwicklerfunktionen ausgestattet sind. Sie sind API-gesteuert. Dazu gehören Konzepte wie das Abrufen des Container-Images aus der Containerregistrierung, das Einrichten des Speichers und schließlich das Starten des Containers. Das Starten des Containers beinhaltet oft das Ausführen eines speziellen Tools, das den Kernel für die Ausführung des Containers konfiguriert, und diese werden auch als „Container-Laufzeiten“ bezeichnet. Ich werde sie als „low-level container runtimes“ bezeichnen. Daemons wie Docker und CRI-O sowie Kommandozeilen-Tools wie Podman und Buildah sollten stattdessen eher "Container-Manager" genannt werden.

Als Docker ursprünglich geschrieben wurde, startete es Container mit dem lxc Toolset, das älter ist als systemd-nspawn . Die ursprüngliche Arbeit von Red Hat mit Docker bestand darin, zu versuchen, libvirt zu integrieren (libvirt-lxc ) in Docker als Alternative zum lxc Tools, die in RHEL nicht unterstützt wurden. libvirt-lxc hat auch systemd-nspawn nicht verwendet . Damals sagte das Systemd-Team, dass systemd-nspawn war nur ein Tool zum Testen, nicht für die Produktion.

Gleichzeitig entschieden die Upstream-Docker-Entwickler, darunter einige Mitglieder meines Red Hat-Teams, dass sie eine Golang-native Möglichkeit zum Starten von Containern wollten, anstatt eine separate Anwendung zu starten. Die Arbeit an libcontainer als native Golang-Bibliothek zum Starten von Containern begann. Red Hat Engineering entschied, dass dies der beste Weg nach vorne sei und ließ libvirt-lxc fallen .

Später wurde die Open Container Initiative (OCI) gegründet, Partei, weil die Leute in der Lage sein wollten, Container auf zusätzliche Weise zu starten. Herkömmliche Namespace-getrennte Container waren beliebt, aber die Leute hatten auch den Wunsch nach Isolation auf Ebene der virtuellen Maschine. Intel und Hyper.sh arbeiteten an KVM-getrennten Containern, und Microsoft arbeitete an Windows-basierten Containern. Die OCI wollte eine Standardspezifikation, die definiert, was ein Container ist, also wurde die OCI Runtime Specification geboren.

Die OCI-Laufzeitspezifikation definiert ein JSON-Dateiformat, das beschreibt, welche Binärdatei ausgeführt werden soll, wie sie enthalten sein sollte und wo sich die rootfs des Containers befinden. Tools können diese JSON-Datei generieren. Dann können andere Tools diese JSON-Datei lesen und einen Container auf den rootfs ausführen. Die libcontainer-Teile von Docker wurden ausgebrochen und dem OCI gespendet. Die Upstream-Docker-Ingenieure und unsere Ingenieure haben geholfen, ein neues Frontend-Tool zu erstellen, um die JSON-Datei der OCI-Laufzeitspezifikation zu lesen und mit libcontainer zu interagieren, um den Container auszuführen. Dieses Tool namens runc , wurde ebenfalls dem OCI gespendet. Während runc kann die OCI-JSON-Datei lesen, Benutzer müssen sie selbst erstellen. runc ist seitdem zur beliebtesten Low-Level-Containerlaufzeit geworden. Fast alle Container-Management-Tools unterstützen runc , einschließlich CRI-O, Docker, Buildah, Podman und Cloud Foundry Garden. Seitdem haben auch andere Tools die OCI Runtime Spec implementiert, um OCI-konforme Container auszuführen.

Sowohl Clear Containers als auch runV von Hyper.sh Tools wurden entwickelt, um die OCI-Laufzeitspezifikation zum Ausführen von KVM-basierten Containern zu verwenden, und sie bündeln ihre Bemühungen in einem neuen Projekt namens Kata. Letztes Jahr hat Oracle eine Demonstrationsversion eines OCI-Laufzeittools namens RailCar erstellt, das in Rust geschrieben ist. Es ist zwei Monate her, dass das GitHub-Projekt aktualisiert wurde, daher ist unklar, ob es sich noch in der Entwicklung befindet. Vor ein paar Jahren arbeitete Vincent Batts daran, ein Tool hinzuzufügen, nspawn-oci , die eine OCI-Laufzeit-Spezifikationsdatei interpretiert und systemd-nspawn gestartet hat , aber niemand hat es wirklich aufgegriffen, und es war keine native Implementierung.

Falls jemand eine native systemd-nspawn --oci OCI-SPEC.json implementieren möchte und es vom systemd-Team zur Unterstützung akzeptieren lassen, dann könnten CRI-O, Docker und schließlich Podman es zusätzlich zu runc  verwenden und Clear Container/runV (Kata). (Niemand in meinem Team arbeitet daran.)

Unter dem Strich wollten die Upstream-Entwickler vor drei oder vier Jahren ein Low-Level-Golang-Tool zum Starten von Containern schreiben, und dieses Tool wurde schließlich zu runc . Diese Entwickler hatten damals ein C-basiertes Tool namens lxc, um dies zu tun und entfernte sich davon. Ich bin mir ziemlich sicher, dass sie zu dem Zeitpunkt, als sie die Entscheidung trafen, libcontainer zu bauen, kein Interesse an systemd-nspawn gehabt hätten oder jede andere nicht-native (golang) Art, "Namespace"-getrennte Container auszuführen.


Linux
  1. Analysieren des Bash-Verlaufs unter Linux

  2. 5 Gründe, warum Sie eine Linux-Container-Strategie entwickeln sollten

  3. 7 unterhaltsame Funktionen für Linux-Container/Image-Transporte

  4. Was ist der Unterschied zwischen einem Linux-Container und einem Image?

  5. So erstellen, listen und löschen Sie Docker-Container unter Linux

Verlaufsbefehl in Linux (Bash-Verlauf)

Verlaufsbefehl in Linux mit Beispielen

Einführung in die Verwaltung von Linux-Containern

So installieren Sie Mcfly unter Linux.

Verlaufsbefehl in Linux – Zeigen Sie den Verlauf des Linux-Terminals an

So verwalten Sie Docker-Container