首頁  >  文章  >  運維  >  你必須了解Linux的命名空間

你必須了解Linux的命名空間

WBOY
WBOY轉載
2022-01-25 17:37:453910瀏覽

這篇文章為大家帶來了關於linux命名空間的相關知識,命名空間提供了虛擬化的一種輕量級形式,使得我們可以從不同的方面來查看運行系統的全局屬性,希望對大家有幫助。

你必須了解Linux的命名空間

一、基本概念

  命名空間(Linux namespace)是linux核心針對實作容器虛擬化映入的特性。我們創建的每個容器都有自己的命名空間,運行在其中的應用程式都像是在獨立的作業系統中運作一樣,命名空間保證了容器之間互不影響。

  Linux的命名空間機制提供了一個資源隔離的解決方案。 PID,IPC,Network等系統資源不再是全域性的,而是屬於特定的Namespace。 Namespace是對全域系統資源的一種封裝隔離,使得處於不同namespace的程序擁有獨立的全域系統資源,改變一個namespace中的系統資源只會影響目前namespace裡的進程,對其他namespace中的進程沒有影響。

  傳統上,在Linux以及其他衍生的UNIX變體中,許多資源是全域管理的。例如,系統中的所有程序按照慣例是透過PID標識的,這表示核心必須管理一個全域的PID清單。而且,所有呼叫者透過uname系統呼叫傳回的系統相關資訊(包括系統名稱和有關核心的一些資訊)都是相同的。使用者ID的管理方式類似,即個別使用者是透過一個全域唯一的UID號識別。

  全域ID使得核心可以選擇性地允許或拒絕某些特權。雖然UID為0的root使用者基本上允許做任何事,但其他使用者ID則會受到限制。例如UID為n的用戶,不允許殺死屬於用戶m的進程( m≠ n)。但這不能防止使用者看到彼此,即使用者n可以看到另一個使用者m也在電腦上活動。只要用戶只能操縱自己的進程,這就沒什麼問題,因為沒有理由不允許用戶看到其他用戶的進程。

  但有些情況下,這種效果可能是不想要的。如果提供Web主機的供應商打算提供Linux電腦的全部存取權限,包括root權限在內。傳統上,這需要為每個使用者準備一台計算機,代價太高。使用KVM或VMWare提供的虛擬化環境是一種解決問題的方法,但資源分配做得不是非常好。電腦的各個使用者都需要一個獨立的內核,以及一份完全安裝好的配套的使用者層應用程式。

  命名空間提供了不同的解決方案,所需資源較少。在虛擬化的系統中,一台實體電腦可以運行多個內核,可能是並行的多個不同的作業系統。而命名空間則只使用一個核心在一台實體電腦上運作,前述的所有全域資源都透過命名空間抽象化。這使得可以將一組進程放置到容器中,各個容器彼此隔離。隔離可以使容器的成員與其他容器毫無關係。但也可以透過允許容器進行一定的共享,來降低容器之間的分隔。例如,容器可以設定為使用自身的PID集合,但仍與其他容器共用部分檔案系統。

二、實作

  命名空間的實作需要兩個部分:每個子系統的命名空間結構,將先前所有的全域元件包裝到命名空間中;將給定程序關聯到所屬各命名空間的機制。

  子系統先前的全域屬性現在封裝到命名空間中,每個程序關聯到一個選定的命名空間。每個可以感知命名空間的內核子系統都必須提供一個資料結構,將所有透過命名空間形式提供的物件集中起來。 struct nsproxy用於匯集指向特定於子系統的命名空間包裝器的指標。在檔案nsproxy.h中有:

/*
 * 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;};

  目前核心的以下範圍可以感知到命名空間

  1、 UTS命名空間包含了運行核心的名稱、版本、底層體系結構類型等資訊. UTS是UNIXTimesharing System的簡稱。

  2、保存在struct ipc_namespace中的所有與進程間通訊( IPC)有關的資訊。

  3、 已經載入的檔案系統的視圖,在struct mnt_namespace中給出。

  4、 有關進程ID的信息,由struct pid_namespace提供。

  5、 struct user_namespace保存的用於限制每個使用者資源使用的資訊。

  6、struct net_ns包含所有網路相關的命名空間參數。

  當我討論對應的子系統時,會介紹各個命名空間容器的內容。在由於在建立新進程時可使用fork建立一個新的命名空間,因此必須提供控制該行為的適當的標誌。每個命名空間都有一個對應的標誌,在sched.h檔案內:

#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 */

  不同類型的命名空間的作用:

  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命名空间

  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视频教程

以上是你必須了解Linux的命名空間的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除