本文將就namespace這個知識點,進行簡單的歸納總結,力求通俗易通。在資料匯總的過程中,參考了許多網上的博客資料,在文章尾部給出相關鏈接。
namespace,命名空間,從名字上看,應該是類似於包含許多名字的空間,打個比方,三年一班的小明和三年二班的小明,雖說他們名字是一樣的,但是所在班級不一樣,那么,在全年級排行榜上面,即使出現兩個名字一樣的小明,也會通過各自的學號來區分。對於學校來說,每個班級就相當於是一個命名空間,這個空間的名稱是班級號。班級號用於描述邏輯上的學生分組信息,至於什么學生分配到1班,什么學生分配到2班,那就由學校層面來統一調度。大致應該就是這么個意思,恩。
C++中的命名空間
命名空間這個概念不僅僅在kernel中有使用,在其他語言中也有所體現。例如在C++中,標准C++庫中所包含的所有內容(包括常量、變量、結構、類和函數)都被定義在命名空間std中。我們可以定義有名命名空間,也可以定義無名命名空間,命名空間可以嵌套定義,
1: 有名的命名空間:
2:
3: namespace 命名空間名 {
4:
5: 聲明序列可選
6:
7: }
8:
9: 無名的命名空間:
10:
11: namespace {
12:
13: 聲明序列可選
14:
15: }
16:
在C++中,如果代碼的最前面沒有使用 using namespace std 的話,對於輸入輸出流,就必須指定所在的命名空間(std::cout <<),否則編譯器會找不到他們的具體實現。可以這么說,命名空間是對全局作用域的細分。
Linux中的namespace
在Linux系統中,可以同時存在多用戶多進程,那么對他們的運行協調管理,通過進程調度和進度管理可以解決,但是,整體資源是有限的,怎么把有限的資源(進程號、通信資源、網絡資源等等)合理分配給各個用戶所在的進程?Linux中提出了namespace機制,這是一種輕量級的虛擬化形式。再次之前,Linux中很多資源是全局管理的,例如,系統中所有進程,都是通過PID來標識的,就像每個學生的學號一樣,在整個學校范圍內,肯定是唯一標識這個學生的。用戶的ID管理,各個用戶通過全局為UID來標識,每個學校的校長也只有有一個,它的UID為0,權利最大,可以對學校內全部老師和學生發起命令。每個學生可以看到其他學生的活動,但是無權把他們趕出學校,這是可以理解的。這種集中統一的管理方式,很適合大規模人群的管理。
隨着大數據、虛擬化的興起,Linux為了提供更加精細的資源分配管理機制,給出了namespace機制解決方法。
命名空間建立系統的不同視圖, 對於每一個命名空間,從用戶看起來,應該像一台單獨的Linux計算機一樣,有自己的init進程(PID為0),其他進程的PID依次遞增,A和B空間都有PID為0的init進程,子容器的進程映射到父容器的進程上,父容器可以知道每一個子容器的運行狀態,而子容器與子容器之間是隔離的。
Linux中有chroot的系統調用,該方法將進程限制到文件系統的某一部分,是一種簡單的命名空間機制。
在task_struct結構體中,有struct nsproxy *nsproxy 這個成員變量,
1: /*
2: * A structure to contain pointers to all per-process
3: * namespaces - fs (mount), uts, network, sysvipc, etc.
4: *
5: * 'count' is the number of tasks holding a reference.
6: * The count for each namespace, then, will be the number
7: * of nsproxies pointing to it, not the number of tasks.
8: *
9: * The nsproxy is shared by tasks which share all namespaces.
10: * As soon as a single namespace is cloned or unshared, the
11: * nsproxy is copied.
12: */
13: struct nsproxy {
14: atomic_t count;
15: spinlock_t nslock;
16: struct uts_namespace *uts_ns;
17: struct ipc_namespace *ipc_ns;
18: struct mnt_namespace *mnt_ns;
19: struct pid_namespace *pid_ns;
20: };
uts_ns:UTS為Unix Timesharing System的簡稱,包含內存名稱、版本、底層體系結構等信息。
ipc_ns:保存所有與進程間通訊(IPC)有關的信息。
mnt_ns: 當前裝載的文件系統
pid_ns: 有關進程ID的信息
在高級版本上,還有net_ns的網絡信息,user_ns的資源配額的信息等。
下面以uts命名空間為例子,介紹如何創建用戶空間。
從上面的框架圖可以看出,所謂的子空間,就是父進程fork一個子進程出來,然后子進程與父進程不共享某些資源,那么,就可以說,這個子進程在它自己的那個命名空間內。
要達到這種效果,就必須對fork的行為進行精確控制,內核提供的如下參數來設置:
UTS命名空間沒有層次結構,所有信息都匯集到如下結構:
,kref是引用計數器,用於跟蹤內核中有多少地方使用uts_namespace的實例。它提供的屬性信息如下:
,從名字上,可以得知uts包含系統名稱、版本號、機器名稱等等。使用uname -a可以查看這些信息。
系統初始默認值保持在init/version.c 中的init_uts_ns全局變量中,在系統初始化task時,配置init_task。
用戶可以在fork時,傳入CLONE_NEWUTS標准,創建新的UTS命名空間。執行此操作,會生成先前uts_namespace的一份副本,當前進程內部的nsproxy指向此副本,然后就可以修改了。父子進程對nx_prosy的修改不會相互影響。
由於最初的父命名空間需要掌握所有子命名空間的所有pid信息,所有,在各級層次的命名空間的fork中,pid的分配是需要統一協調控制,對於各級子命名空間中的task_struct來說,同一個pid在不同命名空間看到的是不一樣的。
同一個進程可以屬於多個namespace,多個進程可以使用同一個namespace,
參考鏈接: