01.docker原理
# 01.namespace
# 1.1 namespace介绍
namespace(命名空间)
是Linux提供的一种内核级别环境隔离的方法,为了实现资源能够在不同的命名空间里有相同的名称- linux支持namespace有Network,IPC,PID, Mount, UTC, User,创建不同类型的namespace就相当于从不同资源维度在主机上作隔离
- 譬如在
A命名空间
有个pid为1的进程,而在B命名空间
中也可以有一个pid为1的进程 - 有了
namespace
就可以实现基本的容器功能,著名的Docker
也是使用了 namespace 来实现资源隔离的
# 1.2 Linux支持6种资源的 namespace
Type | Parameter | Linux Version |
---|---|---|
Mount namespaces | CLONE_NEWNS | Linux 2.4.19 |
UTS namespaces | CLONE_NEWUTS | Linux 2.6.19 |
IPC namespaces | CLONE_NEWIPC | Linux 2.6.19 |
PID namespaces | CLONE_NEWPID | Linux 2.6.24 |
Network namespaces | CLONE_NEWNET | Linux 2.6.24 |
User namespaces | CLONE_NEWUSER | Linux 2.6.23 |
# 02.namespace实现原理
# 2.1 struct nsproxy结构体
- 为了让每个进程都可以从属于某一个namespace,Linux内核为进程描述符添加了一个
struct nsproxy
的结构 - Linux为每种不同类型的资源定义了不同的命名空间结构体进行管理
- 比如对于
pid命名空间
定义了struct pid_namespace
结构来管理
struct task_struct {
...
/* namespaces */
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 user_namespace *user_ns;
struct net *net_ns;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2.2 struct pid_namespace
结构
- 因为
struct pid_namespace
结构主要用于为当前pid命名空间
分配空闲的pid,所以定义比较简单kref
成员是一个引用计数器,用于记录引用这个结构的进程数pidmap
成员用于快速找到可用pid的位图last_pid
成员是记录最后一个可用的pidlevel
成员记录当前pid命名空间
所在的层次parent
成员记录当前pid命名空间
的父命名空间
struct pid_namespace {
struct kref kref;
struct pidmap pidmap[PIDMAP_ENTRIES];
int last_pid;
struct task_struct *child_reaper;
struct kmem_cache *pid_cachep;
unsigned int level;
struct pid_namespace *parent;
#ifdef CONFIG_PROC_FS
struct vfsmount *proc_mnt;
#endif
};
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 由于
pid命名空间
是分层的,也就是说新创建一个pid命名空间
时会记录父级pid命名空间
到parent
字段中 - 所以随着
pid命名空间
的创建,在内核中会形成一颗pid命名空间
的树- 第0层的
pid命名空间
是init
进程所在的命名空间。 - 如果一个进程所在的
pid命名空间
为N
,那么其在0 ~ N 层pid命名空间
都有一个唯一的pid号。 - 也就是说
高层pid命名空间
的进程对低层pid命名空间
的进程是可见的 - 但是
低层pid命名空间
的进程对高层pid命名空间
的进程是不可见的
- 第0层的
# 03.CGroup
# 3.1 CGroup介绍
cgroup:为了不让某个进程一家独大,而其他进程饿死,所以它的作用就是控制各进程分配的CPU,Memory,IO等。
CGroup 是将任意进程进行分组化管理的 Linux 内核功能。
CGroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。
这些具体的资源管理功能称为 CGroup 子系统或控制器。
CGroup 子系统有控制内存的 Memory 控制器、控制进程调度的 CPU 控制器等。
运行中的内核可以使用的 Cgroup 子系统由/proc/cgroup 来确认。
CGroup 提供了一个 CGroup 虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。
要使用 CGroup,必须挂载 CGroup 文件系统。
# 3.2 Cgroups提供功能
1.限制进程组可以使用的资源数量(Resource limiting )
- 比如:memory子系统可以为进程组设定一个memory使用上限
- 一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。
2.进程组的优先级控制(Prioritization )
- 比如:可以使用cpu子系统为某个进程组分配特定cpu share。
3.记录进程组使用的资源数量(Accounting )
- 比如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
4.进程组隔离(Isolation)
- 比如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的
- 不同的进程组有各自的进程、网络、文件系统挂载空间。
5.进程组控制(Control)
- 比如:使用freezer子系统可以将进程组挂起和恢复。
# 3.3 CGroup 相关概念解释
1、任务(task):在 cgroups 中,任务就是系统的一个进程;
2、控制族群(control group)
- 控制族群就是一组按照某种标准划分的进程,Cgroups 中的资源控制都是以控制族群为单位实现。
- 一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。
- 一个进程组的进程可以使用 cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制;
3、层级(hierarchy)
- 控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。
- 控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性;
4、子系统(subsystem)
- 一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu 时间分配的一个控制器。
- 子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。
上次更新: 2024/3/13 15:35:10