软件平台:Ubuntu 14.04
容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好的在孤立的组之间有冲突的资源使用需求。与其它的虚拟化比較,这样既不须要指令级模拟。也不须要即时编译。
容器能够在寒心CPU本地运行指令,而不须要不论什么专门的解释机制。此外半虚拟化和系统调用替换的复杂性。
LXC的实现是基于内核中的namespace和cgroup实现的。
namespace:
和C++中的namespace概念类似。在Linux操作系统中,系统资源如:进程、用户账户、文件系统、网络都是属于某个namespace。
每个namespace下的资源对于其它的namespace资源是透明的,不可见的。由于在操作系统层上就会出现同样的pid的进程。多个同样uid的不同账号。
内核中的实现:
namespace是针对每个进程而言的,所以在task_struct结构的定义中有一个指向nsproxy的指针
1 |
/* namespaces */ |
2 |
struct nsproxy *nsproxy;
|
该结构体的定义例如以下:
01 |
/* |
02 |
* A structure to contain pointers to all per-process
|
03 |
* namespaces - fs (mount), uts, network, sysvipc, etc.
|
04 |
*
|
05 |
* The pid namespace is an exception -- it's accessed using
|
06 |
* task_active_pid_ns. The pid namespace here is the
|
07 |
* namespace that children will use.
|
08 |
*
|
09 |
* 'count' is the number of tasks holding a reference.
|
10 |
* The count for each namespace, then, will be the number
|
11 |
* of nsproxies pointing to it, not the number of tasks.
|
12 |
*
|
13 |
* The nsproxy is shared by tasks which share all namespaces.
|
14 |
* As soon as a single namespace is cloned or unshared, the
|
15 |
* nsproxy is copied.
|
16 |
*/
|
17 |
struct nsproxy {
|
18 |
atomic_t count;
|
19 |
struct uts_namespace *uts_ns;
|
20 |
struct ipc_namespace *ipc_ns;
|
21 |
struct mnt_namespace *mnt_ns;
|
22 |
struct pid_namespace *pid_ns_for_children;
|
23 |
struct net *net_ns;
|
24 |
}; |
当中第一个属性count表示的是该命名空间被进程引用的次数。后面的几个各自是不同类型的命名空间。以pid_namespace为例。
其结构例如以下所看到的:
01 |
struct pid_namespace {
|
02 |
struct kref kref; //引用计数
|
03 |
struct pidmap pidmap[PIDMAP_ENTRIES]; //用于标记空暇的id号
|
04 |
struct rcu_head rcu;
|
05 |
int last_pid; //上一次分配的id号
|
06 |
unsigned int nr_hashed;
|
07 |
struct task_struct *child_reaper; //相当于全局的init进程,用于对僵尸进程进行回收
|
08 |
struct kmem_cache *pid_cachep;
|
09 |
unsigned int level; //namespace的层级
|
10 |
struct pid_namespace *parent; //上一级namespace指针
|
11 |
#ifdef CONFIG_PROC_FS |
12 |
struct vfsmount *proc_mnt;
|
13 |
struct dentry *proc_self;
|
14 |
#endif |
15 |
#ifdef CONFIG_BSD_PROCESS_ACCT |
16 |
struct bsd_acct_struct *bacct;
|
17 |
#endif |
18 |
struct user_namespace *user_ns;
|
19 |
struct work_struct proc_work;
|
20 |
kgid_t pid_gid;
|
21 |
int hide_pid;
|
22 |
int reboot; /* group exit code if this pidns was rebooted */
|
23 |
unsigned int proc_inum;
|
24 |
}; |
内核中的pid结构表示:
1 |
struct pid
|
2 |
{ |
3 |
atomic_t count;
|
4 |
unsigned int level; //pid相应的级数
|
5 |
/* lists of tasks that use this pid */
|
6 |
struct hlist_head tasks[PIDTYPE_MAX]; //一个pid可能相应多个task_struct
|
7 |
struct rcu_head rcu;
|
8 |
struct upid numbers[1]; //该结构是namespace中的详细的pid。从1到level各级别的namesapce,这里相当于一个指针。仅仅只是不须要再分配空间
|
9 |
}; |
上面的结构体就是内核中进程的标示符,能够用于标识内核中的tasks、process groups和sessions。这个结构体和详细的task通过hash来关联。通过详细的task相应的pid的值能够获得绑定的pid结构体。
属于详细的namespace的pid结构upid:
1 |
struct upid {
|
2 |
/* Try to keep pid_chain in the same cacheline as nr for find_vpid */
|
3 |
int nr;
|
4 |
struct pid_namespace *ns;
|
5 |
struct hlist_node pid_chain;
|
6 |
}; |
该结构体是用来获得结构体pid的详细的id,它仅仅对特定的namespace可见。会通过函数find_pid_ns(int nr,pid_namespace *ns)函数来获得详细的PID结构。
总体结构例如以下图:
Cgroup:
Cgroup是control groups的缩写,是Linux内核提供的一种能够限制、记录、隔离进程组所使用的物理资源(CPU,内存,IO等等)的机制。Cgroup也是LXC位实现虚拟化所使用的资源管理的手段。
能够说没有Cgroup就没有LXC,也就没有Docker。
Cgroup提供的功能:
- 限制进程组能够使用的资源数量。