Linux Namespace系列(01):Namespace概述

Namespace是對全局系統資源的一種封裝隔離,使得處於不一樣namespace的進程擁有獨立的全局系統資源,改變一個namespace中的系統資源只會影響當前namespace裏的進程,對其餘namespace中的進程沒有影響。html

下面的全部例子都在ubuntu-server-x86_64 16.04下執行經過node

Linux內核支持的namespaces

目前,Linux內核裏面實現了7種不一樣類型的namespace。linux

名稱        宏定義             隔離內容
Cgroup      CLONE_NEWCGROUP   Cgroup root directory (since Linux 4.6)
IPC         CLONE_NEWIPC      System V IPC, POSIX message queues (since Linux 2.6.19)
Network     CLONE_NEWNET      Network devices, stacks, ports, etc. (since Linux 2.6.24)
Mount       CLONE_NEWNS       Mount points (since Linux 2.4.19)
PID         CLONE_NEWPID      Process IDs (since Linux 2.6.24)
User        CLONE_NEWUSER     User and group IDs (started in Linux 2.6.23 and completed in Linux 3.8)
UTS         CLONE_NEWUTS      Hostname and NIS domain name (since Linux 2.6.19)

注意: 因爲Cgroup namespace在4.6的內核中才實現,而且和cgroup v2關係密切,如今普及程度還不高,好比docker如今就尚未用它,因此在namespace這個系列中不會介紹Cgroup namespace。docker

查看進程所屬的namespaces

系統中的每一個進程都有/proc/[pid]/ns/這樣一個目錄,裏面包含了這個進程所屬namespace的信息,裏面每一個文件的描述符均可以用來做爲setns函數(後面會介紹)的參數。ubuntu

#查看當前bash進程所屬的namespace
dev@ubuntu:~$ ls -l /proc/$$/ns     
total 0
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 cgroup -> cgroup:[4026531835] #(since Linux 4.6)
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 ipc -> ipc:[4026531839]       #(since Linux 3.0)
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 mnt -> mnt:[4026531840]       #(since Linux 3.8)
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 net -> net:[4026531957]       #(since Linux 3.0)
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 pid -> pid:[4026531836]       #(since Linux 3.8)
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 user -> user:[4026531837]     #(since Linux 3.8)
lrwxrwxrwx 1 dev dev 0 7月 7 17:24 uts -> uts:[4026531838]       #(since Linux 3.0)
  • 上面每種類型的namespace都是在不一樣的Linux版本被加入到/proc/[pid]/ns/目錄裏去的,好比pid namespace是在Linux 3.8才被加入到/proc/[pid]/ns/裏面,但這並非說到3.8才支持pid namespace,其實pid namespace在2.6.24的時候就已經加入到內核了,在那個時候就能夠用pid namespace了,只是有了/proc/[pid]/ns/pid以後,使得操做pid namespace更方便了segmentfault

  • 雖說cgroup是在Linux 4.6版本才被加入內核,但是在Ubuntu 16.04上,儘管內核版本才4.4,但也支持cgroup namespace,估計應該是Ubuntu將4.6的cgroup namespace這部分代碼patch到了他們的4.4內核上。bash

  • 以ipc:[4026531839]爲例,ipc是namespace的類型,4026531839是inode number,若是兩個進程的ipc namespace的inode number同樣,說明他們屬於同一個namespace。這條規則對其餘類型的namespace也一樣適用。dom

  • 從上面的輸出能夠看出,對於每種類型的namespace,進程都會與一個namespace ID關聯。socket

跟namespace相關的API

和namespace相關的函數只有三個,這裏簡單的看一下,後面介紹UTS namespace的時候會有詳細的示例函數

clone: 建立一個新的進程並把他放到新的namespace中

int clone(int (*child_func)(void *), void *child_stack
            , int flags, void *arg);

flags: 
    指定一個或者多個上面的CLONE_NEW*(固然也能夠包含跟namespace無關的flags), 
    這樣就會建立一個或多個新的不一樣類型的namespace, 
    並把新建立的子進程加入新建立的這些namespace中。

setns: 將當前進程加入到已有的namespace中

int setns(int fd, int nstype);

fd: 
    指向/proc/[pid]/ns/目錄裏相應namespace對應的文件,
    表示要加入哪一個namespace

nstype:
    指定namespace的類型(上面的任意一個CLONE_NEW*):
    1. 若是當前進程不能根據fd獲得它的類型,如fd由其餘進程建立,
    並經過UNIX domain socket傳給當前進程,
    那麼就須要經過nstype來指定fd指向的namespace的類型
    2. 若是進程能根據fd獲得namespace類型,好比這個fd是由當前進程打開的,
    那麼nstype設置爲0便可

unshare: 使當前進程退出指定類型的namespace,並加入到新建立的namespace(至關於建立並加入新的namespace)

int unshare(int flags);

flags:
    指定一個或者多個上面的CLONE_NEW*,
    這樣當前進程就退出了當前指定類型的namespace並加入到新建立的namespace

clone和unshare的區別

clone和unshare的功能都是建立並加入新的namespace, 他們的區別是:

  • unshare是使當前進程加入新的namespace

  • clone是建立一個新的子進程,而後讓子進程加入新的namespace,而當前進程保持不變

其它

當一個namespace中的全部進程都退出時,該namespace將會被銷燬。固然還有其餘方法讓namespace一直存在,假設咱們有一個進程號爲1000的進程,以ipc namespace爲例:

  1. 經過mount --bind命令。例如mount --bind /proc/1000/ns/ipc /other/file,就算屬於這個ipc namespace的全部進程都退出了,只要/other/file還在,這個ipc namespace就一直存在,其餘進程就能夠利用/other/file,經過setns函數加入到這個namespace

  2. 在其餘namespace的進程中打開/proc/1000/ns/ipc文件,並一直持有這個文件描述符不關閉,之後就能夠用setns函數加入這個namespace。

參考

相關文章
相關標籤/搜索