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

Container von Hand bauen:Der PID-Namespace

Als Fortsetzung der Namespaces-Serie behandelt dieser Artikel die PID Namensraum. Wenn Sie einen allgemeinen Überblick über alle Namespaces wünschen, lesen Sie den ersten Artikel. Zuvor haben Sie ein neues mnt erstellt Namensraum. Interessanterweise, wie Sie festgestellt haben, sogar nach dem Erstellen eines neuen mnt Namespace hatten Sie immer noch Zugriff auf die Prozess-IDs (PIDs) des ursprünglichen Hosts. Als Sie versucht haben, die Datei /proc bereitzustellen Namespace erhalten Sie die ziemlich verwirrende Berechtigung verweigert Fehler, wie unten zu sehen:

root@new-mnt$ mount -t proc proc /proc
mount: permission denied (are you root?)

root@new-mnt$ whoami
root

Während Sie alle Arten von Mounts im neuen Mount-Namespace erstellen konnten, konnten Sie /proc nicht interagieren oder ändern . In diesem Artikel gehe ich Schritt für Schritt durch die PID Namespace und demonstrieren Sie, wie Sie ihn zusammen mit dem mnt verwenden können Namespace, um Ihren noch jungen Container weiter zu sichern.

[ Den Lesern gefiel auch:Wie Linux-PID-Namespaces mit Containern funktionieren ]

Was sind Prozess-IDs?

Bevor Sie direkt in die PID springen Namensraum, ich denke, es ist eine gute Idee, nur ein wenig Hintergrund zu geben, warum dieser Namensraum wichtig ist.

Wenn ein Prozess auf den meisten Unix-ähnlichen Betriebssystemen erstellt wird, erhält er eine bestimmte numerische Kennung, die als Prozess-ID bezeichnet wird (PID). Diese PID hilft dabei, einen Prozess eindeutig zu identifizieren, selbst wenn es zwei Prozesse gibt, die denselben menschenlesbaren Namen haben. Wenn beispielsweise mehrere SSH-Sitzungen auf einem System aktiv sind und Sie eine bestimmte Verbindung schließen müssen, bietet die PID dem Administrator eine Möglichkeit, sicherzustellen, dass die richtige Sitzung geschlossen wird.

Alle diese Prozesse werden in einem speziellen Dateisystem namens procfs verfolgt . Während dieses Dateisystem technisch gesehen überall gemountet werden kann, erwarten die meisten Tools (und Konventionen) die procfs unter /proc einzuhängen . Wenn Sie eine Auflistung von /proc machen , sehen Sie einen Ordner für jeden Prozess, der derzeit auf Ihrem System ausgeführt wird. In diesem Ordner befinden sich alle Arten von speziellen Dateien, die zum Verfolgen verschiedener Aspekte des Prozesses verwendet werden. Für die Zwecke dieses Artikels sind diese Dateien nicht wichtig. Es genügt zu wissen, dass /proc Hier speichern die meisten Unix-ähnlichen Systeme Informationen zu Prozessen auf einem laufenden System.

Der PID-Namensraum

Einer der Hauptgründe für die PID Namespace soll eine Prozessisolierung ermöglichen. Genauer gesagt, wie die Manpage sagt:

PID-Namensräume isolieren den Prozess-ID-Nummernraum, was bedeutet, dass Prozesse in verschiedenen PID-Namensräumen dieselbe PID haben können.

Dies ist wichtig, da dadurch garantiert werden kann, dass Prozesse keine widersprüchliche PID mit anderen Prozessen haben. Bei Betrachtung eines einzelnen Systems besteht natürlich keine Möglichkeit, dass PIDs in Konflikt geraten, da das System die Prozess-ID-Nummer kontinuierlich erhöht und niemals dieselbe Nummer zweimal zuweist. Beim Umgang mit Containern auf mehreren Computern wird dieses Problem deutlicher. Wie in der Manpage beschrieben:

PID-Namespaces ermöglichen es Containern, Funktionen wie das Anhalten/Fortsetzen der Reihe von Prozessen im Container und das Migrieren des Containers auf einen neuen Host bereitzustellen, während die Prozesse innerhalb des Containers dieselben PIDs beibehalten.

Abgesehen von der Isolierung funktioniert das PID-System fast identisch mit dem außerhalb des Namensraums. Die Prozess-IDs innerhalb des neuen Namespace beginnen bei 1 , wobei der erste Prozess als init betrachtet wird Prozess. Die init Der Prozess wird ganz anders gehandhabt als alle anderen PIDs auf einem Host. Dies hat besondere Auswirkungen auf das laufende System, die außerhalb des Rahmens dieser Serie liegen. Wenn Sie an weiteren Informationen interessiert sind, lesen Sie den Abschnitt "Signale und der Init-Prozess" des Artikels LWN-Namespaces.

Bemerkenswert ist jedoch, dass jeder Prozess die PID 1 hat ist entscheidend für die Langlebigkeit der Namespaces. Wenn PID 1 aus irgendeinem Grund beendet wird, sendet der Kernel ein SIGKILL zu allen verbleibenden Prozessen im Namespace, wodurch dieser Namespace effektiv heruntergefahren wird.

Erkunden von PID-Namespaces

Wenn Sie sich wie ich fragen, ob Sie PID verschachteln können Namespaces, lautet die Antwort ja. Tatsächlich macht der Kernel Platz für bis zu 32 verschachtelte PID Namensräume. Dies wird als einseitige Beziehung betrachtet. Das bedeutet, dass der Elternteil die PIDs von Kindern, Enkelkindern usw. sehen kann. Er kann jedoch keine der PIDs seiner Vorfahren sehen. Beachten Sie Folgendes:

[user@localhost ~] sudo unshare -fp /bin/bash
[root@localhost ~] sleep 90000 &

[root@localhost ~] ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
[truncated ]
.....
root       11627   11620  0 09:16 pts/0    00:00:00 sudo unshare -fp /bin/bash
root       11633   11627  0 09:17 pts/0    00:00:00 unshare -fp /bin/bash
root       11634   11633  0 09:17 pts/0    00:00:00 /bin/bash
root       11639   11634  0 09:17 pts/0    00:00:00 sleep 90000
root       11641   11634  0 09:17 pts/0    00:00:00 ps -ef

[root@localhost ~] sudo unshare -fp /bin/bash
[root@localhost ~] sleep 8000 &

[root@localhost ~] ps -ef
[truncated ]
.....

UID          PID    PPID  C STIME TTY          TIME CMD
root       11650   11634  0 09:17 pts/0    00:00:00 sudo unshare -fp /bin/bash
root       11654   11650  0 09:17 pts/0    00:00:00 unshare -fp /bin/bash
root       11655   11654  0 09:17 pts/0    00:00:00 /bin/bash
root       11661   11655  0 09:17 pts/0    00:00:00 sleep 8000
root       11671   11655  0 09:17 pts/0    00:00:00 ps -ef

Sie werden feststellen, dass ich die Ausgabe abgeschnitten habe, weil die PID Namespace erscheint vollen Zugriff auf alle PIDs in /proc zu haben . Beobachten Sie, was passiert, wenn Sie versuchen, einen Prozess zu stoppen, der sich in einem Vorfahren befindet:

[root@localhost ~] kill -9 11361
bash: kill: (11361) - No such process

Warum ist das? Einfach gesagt, herkömmliche Tools wie ps sind nicht namespace-bewusst und werden tatsächlich aus /proc gelesen Verzeichnis. Wenn Sie ein ls /proc gemacht haben , würden Sie immer noch alle Ordner und Dateien von vorher sehen, weil, wie im letzten Artikel besprochen, die PID Namespace erbt alle mnt Namespace-Mounts. Auf diese Situation gehe ich später ein. Kehren Sie zunächst zum vorliegenden Beispiel zurück.

Identifizieren Sie in einer anderen Shell die Schlafprozesse:

[user@localhost ~] ps -ef |grep sleep
root       11639   11634  0 09:17 pts/0    00:00:00 sleep 90000
root       11661   11655  0 09:17 pts/0    00:00:00 sleep 8000

Wenn Sie überprüfen möchten, ob sich diese Prozesse in unterschiedlichen Namespaces befinden, müssen Sie die bash finden PID verarbeiten. Denken Sie daran, da Sie sudo unshare -fp /bin/bash ausgeführt haben , die bash Prozess ist die init Prozess im neuen Namensraum. Daher wird die PID mit der Namensraum-ID verknüpft. Nehmen wir die PIDs:

[root@localhost ~] ps -ef |grep bash
root       11627   11620  0 09:16 pts/0    00:00:00 sudo unshare -fp /bin/bash
root       11633   11627  0 09:17 pts/0    00:00:00 unshare -fp /bin/bash
root       11634   11633  0 09:17 pts/0    00:00:00 /bin/bash
root       11650   11634  0 09:17 pts/0    00:00:00 sudo unshare -fp /bin/bash
root       11654   11650  0 09:17 pts/0    00:00:00 unshare -fp /bin/bash
root       11655   11654  0 09:17 pts/0    00:00:00 /bin/bash

Sie können die PIDs 11634 sehen und 11655 in der Ausgabe. Wenn Sie dies mit der Ausgabe von lsns vergleichen (Namespaces auflisten), sehen Sie Folgendes:

[root@localhost ~] lsns |grep bash
        NS TYPE   NPROCS    PID USER             COMMAND
4026532952 pid         4 11634 root             /bin/bash
4026532954 pid         4 11655 root             /bin/bash

Wie Sie sehen können, sind die Namespace-IDs unterschiedlich, und daher befinden sich die Prozesse in unterschiedlichen Namespaces.

Nachdem Sie nun festgestellt haben, dass die Namespaces tatsächlich unterschiedlich sind, schauen wir uns die zuvor erwähnte PID-Abstammung an. Sie können dies tun, indem Sie die NSpid identifizieren Attribut einer gegebenen PID in /proc Verzeichnis, wie unten zu sehen:

sudo cat /proc/11655/status |grep NSpid
NSpid:    11655    6    1

Die Spalten werden von links nach rechts gelesen und geben die PID in ihren jeweiligen Namespaces an. Die PID ganz links ist der primäre oder Root-Namespace. In diesem Fall hat es eine PID von 11655 , eine sekundäre PID von 6 und eine tertiäre PID von 1 . Da die Namespaces jede untergeordnete PID besitzen Namensraum, können Sie sich das so vorstellen:

  • Auf dem Host die bash Prozess, der sleep 8000 ausführt Befehl hat eine PID von 11655 .
  • Innerhalb des ersten "Containers", der bash Prozess, der sleep 8000 ausführt Befehl hat eine PID von 6 .
  • Innerhalb des verschachtelten zweiten "Containers" ist die PID 1 . Dies ist der Container, der den Prozess tatsächlich gestartet hat.

Jede dieser bash Befehle wurde innerhalb seines eigenen Namespace erstellt, ist aber für das übergeordnete Element (in diesem Fall das Root) sichtbar Namensraum).

/proc, PID und nicht privilegierte Benutzer

Dem aufmerksamen Leser wäre aufgefallen, dass ein normaler Benutzer in den letzten beiden Artikeln beide Benutzer erstellen konnte und mnt Namensräume. In diesem Artikel habe ich den sudo verwendet Befehl. Dies liegt daran, dass Sie keine PID erstellen können Namespace allein mit einem nicht privilegierten Benutzer. Die Antwort darauf besteht darin, mehrere Namespace-Kreationen zu einem Ereignis zusammenzufassen. Es gibt ein paar verschiedene Lösungen zum Mounten von /proc als nicht privilegierter Benutzer.

Wenn Sie einfach versuchen, einen neuen Nutzer zu erstellen Namespace erhalten Sie ein seltsames Ergebnis:

[ user@localhost ~] unshare -Urp
-bash: fork: Cannot allocate memory
-bash-5.1# ps -ef
-bash: fork: Cannot allocate memory
-bash-5.1# ls
-bash: fork: Cannot allocate memory

Was passiert hier? Denken Sie daran, wie der erste Prozess innerhalb einer neuen PID Namespace wird zum init Prozess? In diesem Fall kann die aktuelle Shell keine Namespaces verschieben. Es existiert im Root Namespace und wann Sie eine neue PID erstellt haben Namespace, das System wusste nicht, wie es damit umgehen sollte. Die Lösung dafür ist die Prozessverzweigung selbst. Dadurch kann die aktuelle Shell ein untergeordneter Prozess von unshare werden Befehl. Mit dem -f Flag bewirkt, dass der Namensraum erstellt wird:

[ user@localhost ~] unshare -Urfp
[ root@localhost ~]

Sie sehen jedoch immer noch eine Kontamination von /proc Einhängepunkt. Dafür gibt es zwei Lösungen. Zuerst könnten Sie ein neues mnt erstellen namespace und mounten Sie dann /proc neu selbst:

[ user@localhost  ~]$ unshare -Urpmf
[ root@localhost ~]# mount -t proc proc /proc
[ root@localhost ~]# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 09:31 pts/0    00:00:00 -bash
root          10       1  0 09:31 pts/0    00:00:00 ps -ef

In der Tat war dies viele Jahre lang die einzige Option, aber ein Flag --mount-proc wurde vor einiger Zeit erstellt, um dies in einem einzigen Schritt zu tun. Die Manpage lautet:

Mounten Sie kurz vor dem Ausführen des Programms das proc-Dateisystem am Einhängepunkt (Standard ist /proc). Dies ist nützlich, wenn Sie einen neuen PID-Namespace erstellen. Es impliziert auch, einen neuen Mount-Namespace zu erstellen, da der /proc-Mount ansonsten vorhandene Programme auf dem System durcheinander bringen würde. Das neue proc-Dateisystem wird ausdrücklich als privat gemountet (mit MS_PRIVATE|MS_REC).

Daher sehen Sie möglicherweise Verweise auf den folgenden Befehl:

unshare -Urpf --mount-proc

Dadurch wird ein neues mnt erstellt Namespace beim Mounten von /proc für dich.

Namespace eingeben

Um die Komplexität zu reduzieren, habe ich die zuvor erstellten Namespaces verlassen. Ich habe mit dem folgenden Befehl einen neuen Namensraum erstellt:

unshare -Urfp --mount-proc

Ich habe auch eine andere erstellt sleep nur um den Namensraum zu identifizieren. Da ich nur einen einzigen neuen Namespace habe, kann ich den lsns verwenden Befehl, um die richtige PID zu ermitteln:

[ user@localhost  ~]$ lsns |grep bash
4026532965 pid         2 13142 user -bash

Führen Sie dann nsenter aus Befehl:

sudo nsenter -t 13142 -a

Das -a Flag teilt dem nsenter mit Befehl, um alle Namespaces dieser PID einzugeben. sudo wird mit dem -a benötigt andernfalls können Sie nicht zu allen entsprechenden Namespaces wechseln. Sie sollten jetzt alle PIDS in diesem NS auflisten können:

[ root@localhost  ~]$ ps -ef

UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 09:54 pts/0    00:00:00 -bash
root           8       1  0 09:54 pts/0    00:00:00 sleep 99999
root          25       0  0 10:15 pts/1    00:00:00 -bash
root          31      25  0 10:15 pts/1    00:00:00 ps -ef

[ Lernen Sie die Grundlagen der Verwendung von Kubernetes in diesem kostenlosen Spickzettel. ] 

Abschluss

Die PID Namespace ist ein wichtiger Name, wenn es darum geht, isolierte Umgebungen zu erstellen. Es ermöglicht Prozessen, unabhängig vom Hostsystem ihre eigenen PIDs zu haben. In einer Welt, in der mehrere Hosts an der Orchestrierung isolierter Umgebungen (Container) beteiligt sein können, wird es entscheidend, über eine Einrichtung zu verfügen, die eindeutige PIDs beim Einfrieren und Migrieren von Prozessen garantiert. Darüber hinaus wird aus Sicherheitsgründen, wenn Sie Namespaces zur Anwendungsisolierung ausführen, die PID Namespace ist wichtig, um Informationslecks zu verhindern, durch die Prozesse auf einem Host ausgeführt werden können.

In Kombination mit dem Benutzer und mnt Namespaces, die PID Namespace bietet ein hohes Maß an Schutz, ohne dass Root-Rechte erforderlich sind. Moderne Browser wie Firefox und Vivaldi verwenden Namespaces, um Browser-Sandboxing bereitzustellen. Im nächsten Artikel werde ich das Netz demonstrieren Namespace und sehen Sie, wie Sie Ihren Container weiterhin manuell erstellen können, indem Sie diskrete Netzwerkkomponenten hinzufügen.


Linux
  1. Warum ist die PGID der untergeordneten Prozesse nicht die PGID des übergeordneten Prozesses?

  2. Der maximale Wert der Prozess-ID?

  3. Bestimmen des bestimmten Prozessors, auf dem ein Prozess läuft

  4. Finden Sie die PID des Prozesses mit einem bestimmten Port?

  5. Wie erhalte ich die PID eines Prozesses und rufe im Shell-Skript kill -9 darauf auf?

Erstellen eines Containers von Hand unter Verwendung von Namespaces:Der Mount-Namespace

So finden Sie die PID und PPID eines Prozesses in Linux

Wie finde ich die Prozess-ID in Ubuntu?

Bleibt eine Prozess-PID garantiert gleich, solange der Prozess nicht stirbt?

Wenn ich die PID-Nummer eines Prozesses kenne, wie erhalte ich seinen Namen?

So finden Sie die .pid-Datei für einen bestimmten Prozess