Docker 核心技术
Docker 核心技术
简介
- 基于 Linux 内核的 Cgroup,Namespace,以及 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术,由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
- 最初实现是基于 LXC,从 0.7 以后开始去除 LXC,转而使用自行开发的 Libcontainer,从 1.11 开始,则 进一步演进为使用 runC 和 Containerd。
- Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容 器的创建和维护,使得 Docker 技术比虚拟机技术更为轻便、快捷。
Docker 原理
Namespace
介绍
Linux Namespace 是一种 Linux Kernel 提供的资源隔离方案:
- 系统可以为进程分配不同的 Namespace
- 并保证不同的 Namespace 资源独立分配、进程彼此隔离,即不同的 Namespace 下的进程互不干扰
Linux 内核代码中 Namespace 的实现
Linux 对 Namespace 操作方法
-
clone
在创建新进程的系统调用时,可以通过 flags 参数指定需要新建的 Namespace 类型:
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg)
-
setns
该系统调用可以让调用进程加入某个已经存在的 Namespace 中:
Int setns(int fd, int nstype)
-
unshare
该系统调用可以将调用进程移动到新的 Namespace 下:
int unshare(int flags)
Namespace 的隔离性
Namespace 类型 | 隔离资源 | Kernel 版本 |
---|---|---|
IPC | System V IPC 和 POSIX 消息队列 | 2.6.19 |
Network | 网络设备、网络协议栈、网络端口等 | 2.6.29 |
PID | 进程 | 2.6.14 |
Mount | 挂载点 | 2.4.19 |
UTS | 主机名和域名 | 2.6.19 |
USR | 用户和用户组 | 3.8 |
Pid namespace
- 不同用户的进程就是通过 Pid namespace 隔离开的
- 这使得不同 namespace 中,可以拥有相同的 Pid
net namespace
- 网络隔离,每个 net namespace 有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。
- Docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge: docker0 连接 在一起。
ipc namespace
- container 中进程交互还是采用 linux 常见的进程间交互方法(IPC), 包括常见的信号量、消息队列和共享内存。
- container 的进程间交互实际上还是,同 Pid namespace 中的进程间交互,因此需要在 IPC 资源申请时加入 namespace 信息,每个 IPC 资源有一个唯一的 32 位 ID。
mnt namespace
- mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看 到的文件目录就被隔离开了。
uts namespace
- UTS(“UNIX Time-sharing System”) namespace 允许每个 container 拥有独立的 hostname 和 domain name,使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。
user namespace
- 每个 container 可以有不同的 user 和 group id, 也就是说可以在 container 内部用 container 内部的用户 执行程序而非 Host 上的用户。
namespace 常用操作
-
查看当前系统的 namespace:
lsns –t <type>
-
查看某进程的 namespace:
ls -la /proc/<pid>/ns/
-
进入某 namespace 运行命令:
nsenter -t <pid> -n ip addr
Cgroups
介绍
- Cgroups (Control Groups)是 Linux 下用于对一个或一组进程进行资源控制和监控的机制;
- 可以对诸如 CPU 使用时间、内存、磁盘 I/O 等进程所需的资源进行限制;
- 不同资源的具体管理工作由相应的 Cgroup 子系统(Subsystem)来实现;
- 针对不同类型的资源限制,只要将限制策略在不同的的子系统上进行关联即可;
- Cgroups 在不同的系统资源管理子系统中以层级树(Hierarchy)的方式来组织管理:每个 Cgroup 都可以 包含其他的子 Cgroup,因此子 Cgroup 能使用的资源除了受本 Cgroup 配置的资源参数限制,还受到父 Cgroup 设置的资源限制 。
Linux 内核代码中 Cgroups 的实现
Cgroup 可限制和度量的资源
资源 | 说明 |
---|---|
blkio | 这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及 USB 等等。 |
CPU | 这个子系统使用调度程序为 cgroup 任务提供 CPU 的访问。 |
cpuacct | 产生 cgroup 任务的 CPU 资源报告 |
cpuset | 如果是多核心的 CPU,这个子系统会为 cgroup 任务分配单独的 CPU 和内存。 |
devices | 允许或拒绝 cgroup 任务对设备的访问。 |
freezer | 设置每个 cgroup 的内存限制以及产生内存资源报告。 |
memory | 设置每个 cgroup 的内存限制以及产生内存资源报告。 |
net_cls | 标记每个网络包以供 cgroup 方便使用。 |
ns | 名称空间子系统。 |
pid | 进程标识子系统。 |
CPU 子系统
cpuacct 子系统
Memory 子系统
文件系统
介绍
- 将不同目录挂载到同一个虚拟文件系统下的文件系统
- 支持为每一个成员目录(类似Git Branch)设定 readonly、readwrite 和 whiteout-able 权限
- 文件系统分层, 对 readonly 权限的 branch 可以逻辑上进行修改(增量地, 不影响 readonly 部分的)。
- 通常 Union FS 有两个用途, 一方面可以将多个 disk 挂到同一个目录下, 另一个更常用的就是将一个 readonly 的 branch 和一个 writeable 的 branch 联合在一起。
docker 初始化时,是将 rootfs 以 readonly 方式加载并检查,再通过 union mount 的方式,将 readwrite 文件系统挂在到 rootfs 之上。且允许不断往上叠加,并将下层的 FS 设定为 readonly。
这样一组 readonly 和 writeable 的结构,构成了 docker container 的运行时。
写操作
docker 的镜像具有共享的特性(镜像是一层一层的,底层的 readonly 镜像对于多个容器而言是共享的)。
- 写时复制
- 一个镜像可以被多个容器使用,但是不需要在内存和磁盘上做多个拷贝。
- 在需要对镜像提供的文件进行修改时,该文件会从镜像的文件系统被复制到容器的可写层的文件系统 进行修改,而镜像里面的文件不会改变。
- 不同容器对文件的修改都相互独立、互不影响。
- 用时分配
- 按需分配空间,而非提前分配,即当一个文件被创建出来后,才会分配空间。
OverlayFS
Docker 架构
docker 守护进程 是由 init 创建的,containerd 是由守护进程创建的;
但是 docker 容器进程由 docker shim(垫片,由 init 创建) 创建的,以避免 containerd 带挂一堆下面的进程;
docker 网络
默认模式