Docker學習總結(一)—— namespace,cgroup機制

1.namespace:css

  Linux Namespaces機制提供一種資源隔離方案。PID,IPC,Network等系統資源再也不是全局性的,而是屬於特定的Namespace。每一個node

Namespace裏面的資源對其餘Namespace都是不可見的,要建立新的Namespace,只須要在調用clone時指定相應的flag。Linux數組

Namespaces機制爲實現基於容器的虛擬化技術提供了很好的基礎,容器正是利用這一特性實現了資源的隔離。不一樣container內的網絡

進程屬於不一樣的Namespace,彼此透明,互不干擾。數據結構

  Linux很早就實現了一個系統調用chroot,該系統調用可以爲進程提供一個限制的文件系統。chroot提供了一種簡單的隔離模式:chrootatom

內部的文件系統沒法訪問外部的內容。Linux Namespace在此基礎上,提供了對UTS、IPC、mount、PID、network的隔離機制。spa

  UTS: 包含了運行內核的名稱,版本,底層體系結構的信息線程

  IPC: 包含了全部與進程間通訊有關的信息指針

  PID: 就是進程ID繼承

  mount: 包含了文件系統的視圖

  NET: 網絡訪問

  1.1 task_struct中的結構:
struct task_struct { 
... 
struct nsproxy *nsproxy; 
... 
};

 

<——————將給定進程關聯到所屬的各個命名空間——————>
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; 
struct net *net_ns; 
}; 

1.2 建立命名空間的方式

  1.2.1. clone建立新進程時,能夠設置選項,使新進程與父進程共享命名空間,仍是新進程建立一個獨立的命名空間.

  1.2.2. unshare系統調用,能夠將進程的某些部分從父進程分離,其中也包括命名空間。

1.3 PID

  PID命名空間按層次組織,在建立一個新的pid namespace,該命名空間中全部的pid都對父命名空間可見,可是子命名空間

看不到父命名空間的pid,所以進程在不一樣的pid namespace中具備不一樣的pid,只要能看到該進程的namespace都有一個PID。

  對於全部的進程來講,都有兩種ID:一個是全局的ID(包含PID、TGID、PGRP、SID),保存在task_struct->pid中;

另外一個是局部的ID,即屬於某個特定的命名空間的ID,對應task_struct->pids數組,能夠經過task_struct->pids[pid_type]->pid

來找到對應的pid結構。pid_type:PIDTYPE_PID,PIDTYPE_PGID,PIDTYPE_SID,PIDTYPE_MAX

struct pid 

atomic_t count; //計數
unsigned int level; //對應多少namespace
struct hlist_head tasks[PIDTYPE_MAX]; //指回task_struct
struct rcu_head rcu; //rcu是將全部struct pid組織起來的輔助結構
struct upid numbers[1]; //numbers成員中存儲的是struct upid結構,該結構是pid與pid_namespace相關聯的結構。
}

upid
struct upid { 
int nr; 
struct pid_namespace *ns; 
struct hlist_node pid_chain; 
};

全部的upid都保存在一個散列表中,經過upid->pid_chain組織。

static struct hlist_head *pidhash;
};
pid_namespace
struct pid_namespace { 
struct kref kref; 
struct pidmap pidmap[PIDMAP_ENTRIES]; //保存該namespace中pid的分配狀況
int last_pid; //保存上一個分配的pid
struct task_struct *child_reaper; //每一個namespace都有一個進程來扮演Linux中init進程的角色,child_reaper指向這個進程
struct kmem_cache *pid_cachep; 
unsigned int level; //表示該namespace在整個命名空間的層次
struct pid_namespace *parent; //父namespace
struct vfsmount *proc_mnt; 
struct bsd_acct_struct *bacct; 
};

 

2.cgroups:限制被namespaces隔離起來的資源,爲資源設置權重,計算使用量,操控任務啓停。

  特色:cgroups經過僞文件系統方式實現

             組織管理操做單元細粒度到線程級別,用戶也能夠建立銷燬cgroup實現資源再分配

            資源管理的功能都已子系統方式實現,接口統一

            子任務建立之初與副任務同出一個cgroups

  做用:資源限制:對任務使用的資源總額進行限制

             優先級分配:經過分配CPU時間片,IO帶寬等來控制任務優先級

             資源統計:CPU使用時長,內存用量等

             任務控制:任務掛起,恢復等

  相互關係:  cgroups具備層級結構,每一個層級經過綁定對應的子系統進行資源控制,cgoups層級能夠包含0或1個子節點。子節點繼承

父節點掛載的子系統。

  1.一個子系統能附加到多個層級,前提是目標層級只有惟一一個子系統

  2.一個層級能夠附加多個子系統

  3.一個任務能夠是多個cgroup的成員,可是這些cgroup必須在不一樣的層級。

  4.系統中的進程(任務)建立子進程(任務)時,該子任務自動成爲其父進程所在 cgroup 的成員。而後可根據須要將該子任務移動到不

同的 cgroup 中,但開始時它老是繼承其父任務的cgroup。

   Cgroups子系統:

    blkio -- 這個子系統爲塊設備設定輸入/輸出限制,好比物理設備(磁盤,固態硬盤,USB 等等)。

    cpu -- 這個子系統使用調度程序提供對 CPU 的 cgroup 任務訪問。

    cpuacct -- 這個子系統自動生成 cgroup 中任務所使用的 CPU 報告。

    cpuset -- 這個子系統爲 cgroup 中的任務分配獨立 CPU(在多核系統)和內存節點。

    devices -- 這個子系統可容許或者拒絕 cgroup 中的任務訪問設備。

    freezer -- 這個子系統掛起或者恢復 cgroup 中的任務。

    memory -- 這個子系統設定 cgroup 中任務使用的內存限制,並自動生成由那些任務使用的內存資源報告。

    net_cls -- 這個子系統使用等級識別符(classid)標記網絡數據包,可容許 Linux 流量控制程序(tc)識別從具體 cgroup 中生成的數據包。

     ns -- 名稱空間子系統。  

  cgroups數據結構:

task_struct中與cgroups有關的:

    struct css_set *cgroups;

    struct list_head cg_list;

其中cgroups指針指向了一個css_set結構,而css_set存儲了與進程相關的cgroups信息。cg_list是一個list_head結構,用於將連到同一個css_set的進程組織成一個鏈表。

struct css_set {

    atomic_t refcount; //該css_set的引用數

    struct hlist_node hlist; //用於把全部css_set組織成一個hash表,這樣內核能夠快速查找特定的css_set

    struct list_head tasks; //指向全部連到此css_set的進程連成的鏈表

    struct list_head cg_links; //指向一個由struct cg_cgroup_link連成的鏈表

    struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; //subsys是一個數組,存儲一組指向cgroup_subsys_state的指針。

};

一個cgroup_subsys_state就是進程與一個特定子系統相關的信息。經過這個指針數組,進程就能夠得到相應的cgroups控制信息了

struct cgroup_subsys_state {

    struct cgroup *cgroup;

    atomic_t refcnt;

    unsigned long flags;

    struct css_id *id;

};

    cgroup指針指向了一個cgroup結構,也就是進程屬於的cgroup。進程受到子系統的控制,其實是經過加入到特定的cgroup實現的,由於cgroup在特定的層級上,而子系統又是附加到層級上的。經過以上三個結構,進程就能夠和cgroup鏈接起來了:task_struct->css_set->cgroup_subsys_state->cgroup。

    cgroup和css_set是一個多對多的關係,一個進程對應一個css_set,一個css_set就存儲了一組進程(有可能被幾個進程共享)跟各個子系統相關的信息,並且一個進程能夠同時屬於幾個cgroup,只要這些cgroup不在同一個層級。一個cgroup中能夠有多個進程,並且這些進程的css_set不必定都相同,由於有些進程可能還加入了其餘cgroup。

struct cg_cgroup_link {

    struct list_head cgrp_link_list;

    struct cgroup *cgrp; 

    struct list_head cg_link_list;

    struct css_set *cg;

};

   cg_cgroup_link做爲一箇中間結構將 cgroup和css_set聯繫起來,cgrp_link_list和cg_link_list分別指向cgroup和css_set所在的鏈表。每一個進程都會指向一個css_set,與這個css_set關聯的全部進程都會鏈入到css_set->tasks鏈表,cgroup經過中間結構cg_cgroup_link來尋找全部與之關聯的全部css_set,從而能夠獲得與cgroup關聯的全部進程。

  mount -t cgroup 查看當前系統全部根層級,進入到跟層級目錄下,mkdir [名稱]就能夠建立一個cgroup,新建立的cgroup下的tasks文件爲空的,表示當前cgroup無進程,根層級目錄下的tasks文件內包含當前系統全部進程。

相關文章
相關標籤/搜索