名稱空間(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名稱空間幾乎不需要特別的處理,因為它只需要簡單量,沒有層次組織。所有相關資訊都彙集到下列結構的一個範例中。在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的名稱空間的詳細內容,更多請關注TW511.COM其它相關文章!