Heim > Artikel > Betrieb und Instandhaltung > Sie müssen Linux-Namespaces verstehen
Dieser Artikel vermittelt Ihnen relevantes Wissen über Linux-Namespaces, die es uns ermöglichen, die globalen Eigenschaften des laufenden Systems aus verschiedenen Blickwinkeln zu betrachten.
– Namespace (Linux-Namespace) ist eine Funktion des Linux-Kernels zur Implementierung der Containervirtualisierung. Jeder von uns erstellte Container verfügt über einen eigenen Namensraum und die darin ausgeführten Anwendungen laufen so, als würden sie in einem unabhängigen Betriebssystem ausgeführt. Der Namensraum stellt sicher, dass sich die Container nicht gegenseitig beeinflussen.
Der Namespace-Mechanismus von Linux bietet eine Lösung für die Ressourcenisolation. Systemressourcen wie PID, IPC und Netzwerk sind nicht mehr global, sondern gehören zu einem bestimmten Namespace. Namespace ist eine Art Kapselung und Isolierung globaler Systemressourcen, sodass Prozesse in verschiedenen Namespaces über unabhängige globale Systemressourcen verfügen. Das Ändern von Systemressourcen in einem Namespace wirkt sich nur auf Prozesse im aktuellen Namespace aus und hat keine Auswirkungen auf Prozesse in anderen Namespaces.
Traditionell werden in Linux und anderen Derivaten von UNIX viele Ressourcen global verwaltet. Beispielsweise werden alle Prozesse im System herkömmlicherweise durch PID identifiziert, was bedeutet, dass der Kernel eine globale Liste von PIDs verwalten muss. Darüber hinaus sind die systembezogenen Informationen (einschließlich des Systemnamens und einiger Informationen über den Kernel), die von allen Aufrufern über den Systemaufruf uname zurückgegeben werden, dieselben. Benutzer-IDs werden auf ähnliche Weise verwaltet, d. h. jeder Benutzer wird durch eine weltweit eindeutige UID-Nummer identifiziert.
Mit der globalen ID kann der Kernel bestimmte Berechtigungen selektiv zulassen oder verweigern. Während der Root-Benutzer mit UID 0 grundsätzlich alles tun darf, sind andere Benutzer-IDs eingeschränkt. Beispielsweise darf der Benutzer mit der UID n den Prozess des Benutzers m (m≠ n) nicht beenden. Dies hindert die Benutzer jedoch nicht daran, sich gegenseitig zu sehen, d. h. Benutzer n kann sehen, dass auch ein anderer Benutzer m auf dem Computer aktiv ist. Solange Benutzer nur ihre eigenen Prozesse manipulieren können, ist dies in Ordnung, da es keinen Grund gibt, warum Benutzern nicht erlaubt werden sollte, die Prozesse anderer Benutzer zu sehen.
In manchen Fällen kann dieser Effekt jedoch unerwünscht sein. Wenn der Anbieter von Webhosting beabsichtigt, Benutzern vollen Zugriff auf einen Linux-Computer einschließlich Root-Rechten zu gewähren. Traditionell war hierfür für jeden Benutzer ein Computer erforderlich, was unerschwinglich teuer war. Die Verwendung der von KVM oder VMWare bereitgestellten Virtualisierungsumgebung ist eine Möglichkeit, das Problem zu lösen, die Ressourcenzuweisung ist jedoch nicht sehr gut. Jeder Benutzer des Computers benötigt einen separaten Kernel und einen vollständig installierten Satz unterstützender Anwendungen auf Benutzerebene.
Namespaces bieten eine andere Lösung, die weniger Ressourcen erfordert. In einem virtualisierten System kann ein physischer Computer mehrere Kerne und möglicherweise mehrere verschiedene Betriebssysteme parallel ausführen. Der Namespace verwendet nur einen Kernel für den Betrieb auf einem physischen Computer, und alle oben genannten globalen Ressourcen werden über den Namespace abstrahiert. Dadurch ist es möglich, eine Reihe von Prozessen in voneinander isolierten Containern zu platzieren. Durch die Isolation können Mitglieder eines Containers keine Beziehung zu anderen Containern haben. Sie können die Trennung zwischen Containern aber auch verringern, indem Sie ihnen erlauben, bestimmte Informationsmengen gemeinsam zu nutzen. Beispielsweise kann ein Container so eingerichtet werden, dass er seinen eigenen Satz von PIDs verwendet, aber dennoch Teile des Dateisystems mit anderen Containern teilt.
Die Implementierung des Namespace erfordert zwei Teile: die Namespace-Struktur jedes Subsystems, die alle vorherigen globalen Komponenten in den Namespace einschließt; und den Mechanismus, der einen bestimmten Prozess jedem Namespace zuordnet, zu dem er gehört.
Frühere globale Eigenschaften von Subsystemen sind jetzt in Namespaces gekapselt und jeder Prozess ist einem ausgewählten Namespace zugeordnet. Jedes Namespace-fähige Kernel-Subsystem muss eine Datenstruktur bereitstellen, die alle als Namespaces bereitgestellten Objekte sammelt. struct nsproxy wird verwendet, um Zeiger auf subsystemspezifische Namespace-Wrapper zusammenzustellen. In der Datei nsproxy.h gibt es:
/* * A structure to contain pointers to all per-process * namespaces - fs (mount), uts, network, sysvipc, etc. * * The pid namespace is an exception -- it's accessed using * task_active_pid_ns. The pid namespace here is the * namespace that children will use. * * 'count' is the number of tasks holding a reference. * The count for each namespace, then, will be the number * of nsproxies pointing to it, not the number of tasks. * * The nsproxy is shared by tasks which share all namespaces. * As soon as a single namespace is cloned or unshared, the * nsproxy is copied. */struct nsproxy { atomic_t count; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; struct pid_namespace *pid_ns_for_children; struct net *net_ns; struct time_namespace *time_ns; struct time_namespace *time_ns_for_children; struct cgroup_namespace *cgroup_ns;};
Die folgenden Bereiche des aktuellen Kernels können den Namespace erkennen
1. Der UTS-Namespace enthält den Namen, die Version, den zugrunde liegenden Architekturtyp und andere Informationen des laufenden Kernels. UTS ist die Abkürzung für UNIX Timesharing System.
2. Alle Informationen zur Interprozesskommunikation (IPC) werden in der Struktur ipc_namespace gespeichert.
3. Die Ansicht des gemounteten Dateisystems ist in der Struktur mnt_namespace angegeben.
4. Informationen über die Prozess-ID werden von der Struktur pid_namespace bereitgestellt.
5. Die von struct user_namespace gespeicherten Informationen werden verwendet, um die Ressourcennutzung jedes Benutzers zu begrenzen.
6. struct net_ns enthält alle netzwerkbezogenen Namespace-Parameter.
Wenn ich das entsprechende Subsystem bespreche, werde ich den Inhalt jedes Namespace-Containers vorstellen. Da fork beim Erstellen eines neuen Prozesses zum Einrichten eines neuen Namensraums verwendet werden kann, müssen entsprechende Flags bereitgestellt werden, um dieses Verhalten zu steuern. Jeder Namespace verfügt über ein entsprechendes Flag, das sich in der Datei sched.h befindet:
#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ #define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ #define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ #define CLONE_NEWUSER 0x10000000 /* New user namespace */ #define CLONE_NEWPID 0x20000000 /* New pid namespace */ #define CLONE_NEWNET 0x40000000 /* New network namespace */
Die Funktionen verschiedener Arten von Namespaces:
IPC:用于隔离进程间通讯所需的资源( System V IPC, POSIX message queues),PID命名空间和IPC命名空间可以组合起来用,同一个IPC名字空间内的进程可以彼此看见,允许进行交互,不同空间进程无法交互
Network:Network Namespace为进程提供了一个完全独立的网络协议栈的视图。包括网络设备接口,IPv4和IPv6协议栈,IP路由表,防火墙规则,sockets等等。一个Network Namespace提供了一份独立的网络环境,就跟一个独立的系统一样。
Mount:每个进程都存在于一个mount Namespace里面, mount Namespace为进程提供了一个文件层次视图。如果不设定这个flag,子进程和父进程将共享一个mount Namespace,其后子进程调用mount或umount将会影响到所有该Namespace内的进程。如果子进程在一个独立的mount Namespace里面,就可以调用mount或umount建立一份新的文件层次视图。
PID::linux通过命名空间管理进程号,同一个进程,在不同的命名空间进程号不同!进程命名空间是一个父子结构,子空间对于父空间可见。
User:用于隔离用户
UTS:用于隔离主机名
每个进程都关联到自身的命名空间视图,在任务定义的结构体task_struct中有如下定义:
struct task_struct {.../* 命名空间 */struct nsproxy *nsproxy;...}
因为使用了指针,多个进程可以共享一组子命名空间。这样,修改给定的命名空间,对所有属于该命名空间的进程都是可见的。
init_nsproxy定义了初始的全局命名空间,其中维护了指向各子系统初始的命名空间对象的指针。在kernel/nsproxy.c文件内有
struct nsproxy init_nsproxy = { .count = ATOMIC_INIT(1), .uts_ns = &init_uts_ns,#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) .ipc_ns = &init_ipc_ns,#endif .mnt_ns = NULL, .pid_ns_for_children = &init_pid_ns,#ifdef CONFIG_NET .net_ns = &init_net,#endif#ifdef CONFIG_CGROUPS .cgroup_ns = &init_cgroup_ns,#endif#ifdef CONFIG_TIME_NS .time_ns = &init_time_ns, .time_ns_for_children = &init_time_ns,#endif};
UTS命名空间几乎不需要特别的处理,因为它只需要简单量,没有层次组织。所有相关信息都汇集到下列结构的一个实例中。在utsname.h文件内:
struct uts_namespace { struct new_utsname name; struct user_namespace *user_ns; struct ucounts *ucounts; struct ns_common ns;} __randomize_layout;
uts_namespace所提供的属性信息本身包含在struct new_utsname中:
struct oldold_utsname { char sysname[9]; char nodename[9]; char release[9]; char version[9]; char machine[9];};#define __NEW_UTS_LEN 64struct old_utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65];};struct new_utsname { char sysname[__NEW_UTS_LEN + 1]; char nodename[__NEW_UTS_LEN + 1]; char release[__NEW_UTS_LEN + 1]; char version[__NEW_UTS_LEN + 1]; char machine[__NEW_UTS_LEN + 1]; char domainname[__NEW_UTS_LEN + 1];}
各个字符串分别存储了系统的名称( Linux…)、内核发布版本、机器名,等等。使用uname工具可以取得这些属性的当前值,也可以在/proc/sys/kernel/中看到
z@z-virtual-machine:~$ cat /proc/sys/kernel/ostype Linux z@z-virtual-machine:~$ cat /proc/sys/kernel/osrelease5.3.0-40-generic
初始设置保存在init_uts_ns中,在init/version.c文件内:
struct uts_namespace init_uts_ns = { .ns.count = REFCOUNT_INIT(2), .name = { .sysname = UTS_SYSNAME, .nodename = UTS_NODENAME, .release = UTS_RELEASE, .version = UTS_VERSION, .machine = UTS_MACHINE, .domainname = UTS_DOMAINNAME, }, .user_ns = &init_user_ns, .ns.inum = PROC_UTS_INIT_INO,#ifdef CONFIG_UTS_NS .ns.ops = &utsns_operations,#endif};
相关推荐:《Linux视频教程》
Das obige ist der detaillierte Inhalt vonSie müssen Linux-Namespaces verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!