Docker 简述

什么是容器

当一个应用程序仅由较少数量的大组件构成时,完全可以接受给每个组件分配专用的虚拟机,以及通过给每个组件提供自己的操作系统实例来隔离它们的环境。但是当这些组件开始变小且数量开始增长时,如果你不想浪费硬件资源,又想持续压低硬件成本,那就不能给每个组件配置一个虚拟机了。

容器类似与虚拟机,但开销小很多。一个容器里运行的进程实际上运行在宿主机的操作系统上,就像所有其他进程一样,不像虚拟机,进程是运行在不同的操作系统上的。但在容器里的进程仍然是和其他进程隔离的。对于容器内进程本身而言,就好像是在机器和操作系统上运行的唯一一个进程。

容器隔离机制

容器实现隔离有两个机制:第一个是 Linux 命名空间,它使每个进程只看到它自己的系统视图;第二个是 cgroups,它限制了进程能使用的资源量。

用 Linux 命名空间隔离进程

每个 Linux 系统最初只有一个命名空间,所有的系统资源都属于这一个命名空间。一个进程在一个命名空间下运行,进程将只能看到同一个命名空间下的资源。通过 clone 函数可以在创建新进程的同时创建 namespace:

1
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

在这里指定 CLONE_NEWPID 参数,这样新创建的进程,就会看到一个全新的进程空间。而此时这个新的进程,也就变成了 PID=1 的进程。

与 namespace 相关的 flag 参数有 CLONE_NEWNS、CLONE_NEWUTS、CLONE_NEWIPC、CLONE_NEWPID、CLONE_NEWNET 和 CLONE_NEWUSER,对应 Mount(mnt)、UTS、Inter-process communication(ipc)、Process ID(pid)、Network(net)、User ID(user) 这六种类型的命名空间。

用 cgroups 限制系统的可用资源

cgroups 是一个 Linux 内核功能,它用来限制一个进程或者一组进程的资源使用。一个进程的资源(CPU、内存、网络带宽等)使用量不能超过被分配的量。

cgroups 通过 cgroupfs 提供接口,cgroupfs 默认情况下挂载在 /sys/fs/cgroup 目录。

cgroups 限制 CPU、内存的简单操作方法:

1
2
3
4
5
6
7
8
9
# 创建一个新的目录,也就是创建了一个新的 cgroup 
mkdir /sys/fs/cgroup/cpuset/demo

# 配置这个 cgroup 的资源配额,限制这个 cgroup 的进程只能在 0 号 CPU 上运行,并且只能在 0 号内存节点分配内存
echo 0 > /sys/fs/cgroup/cpuset/demo/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpuset/demo/cpuset.mems

# 将进程 id 写进 tasks 文件,即整个进程移动到 cgroup 中,cgroup 开始起作用
echo > /sys/fs/cgroup/cpuset/demo/tasks

Docker 容器介绍

Docker 是第一个使容器在不同机器之间移植的系统。Docker 有三个概念:

  • 镜像 —— Docker 镜像里包含了打包的应用程序及其所依赖的环境。
  • 镜像仓库 —— Docker 镜像仓库用于存放 Docker 镜像。
  • 容器 —— 一个运行中的容器是一个运行在 Docker 主机上的进程,但它和主机以及所有运行在主机上的其他进程都是隔离的。

Docker 推荐将容器运行时的 cgroup driver 更改为 systemd,systemd 限制 CPU、内存的简单操作方法:

1
2
# 限制 CPU 占用为 0.1 个 CPU,内存为 200 MB
systemctl set-property xxxx.service CPUShares=100 MemoryLimit=200M

systemd 相对 cgroupfs 更加简单,目前主流 Linux 发行版中 systemd 是系统自带的 cgroup 管理器,系统初始化就存在的,和 cgroups 联系紧密。

如果 Docker 的 cgroup driver 是 cgroupfs,就会存在两个控制管理器,对于该服务器上启动的容器使用的是 cgroupfs,而对于其他 systemd 管理的进程使用的是 systemd,这样在服务器资源负载高的情况下可能会变的不稳定。

Author

王亮

Posted on

2022-01-20

Licensed under