资源隔离
Docker的资源隔离是基于Namespace的。在Linux中有8种Namespace,Docker仅使用了其中6种:Mount Namespace、PID Namespace、Net Namespace、IPC Namespace、UTS Namespace、User Namespace。
各个Namespace的作用
名称 | 作用 |
---|---|
Mount Namespace | 隔离不同的进程或进程组看到的挂载点,即不同的进程看到不同的挂载目录, 在独立的 Mount Namespace 内创建挂载目录是不影响主机的挂载目录的。 |
PID Namespace | 隔离进程,在不同的PID Namespace中,进程可以拥有相同的PID号。 |
UTS Namespace | 隔离主机名,允许每个UTS Namespace拥有一个独立的主机名 |
IPC Namespace | 隔离进程间通信。PID Namespace 和 IPC Namespace 一起使用可以实现同一 IPC Namespace 内的进程彼此可以通信,不同 IPC Namespace 的进程却不能通信 |
User Namespace | 隔离用户和用户组。一个比较典型的应用场景就是在主机上以非 root 用户运行的进程可以在一个单独的 User Namespace 中映射成 root 用户 |
Net Namespace | 隔离网络设备、IP地址和端口等信息。Net Namespace 可以让每个进程拥有自己独立的 IP 地址,端口和网卡信息 |
Namespace对于Docker
当 Docker 新建一个容器时, 它会创建这六种 Namespace,然后将容器中的进程加入这些 Namespace 之中,使得 Docker 容器中的进程只能看到当前 Namespace 中的系统资源。
正是由于 Docker 使用了 Linux 的这些 Namespace 技术,才实现了 Docker 容器的隔离,可以说没有 Namespace,就没有 Docker 容器。
资源限制
Docker容器有了Namespace之后,可以进行资源隔离了,但是使用的还是宿主机的CPU、内存等资源。如果容器占据了太多的资源,那么会影响主机的正常运行。在这里,Docker使用Linux内核的另一个核心技术cgroups。
cgroups
cgroups(全称:control groups)是 Linux 内核的一个功能,它可以实现限制进程或者进程组的资源(如 CPU、内存、磁盘 IO 等)
cgroups的功能
功能 | 描述 |
---|---|
资源限制 | 限制资源的使用量,例如我们可以通过限制某个业务的内存上限,从而保护主机其他业务的安全运行。 |
优先级控制 | 不同的组可以有不同的资源( CPU 、磁盘 IO 等)使用优先级。 |
审计 | 计算控制组的资源使用情况。 |
控制 | 控制进程的挂起或恢复。 |
cgroups的核心概念
概念 | 描述 |
---|---|
子系统(subsystem) | 是一个内核的组件,一个子系统代表一类资源调度控制器。例如内存子系统可以限制内存的使用量,CPU 子系统可以限制 CPU 的使用时间。 |
控制组(cgroup) | 表示一组进程和一组带有参数的子系统的关联关系。例如,一个进程使用了 CPU 子系统来限制 CPU 的使用时间,则这个进程和 CPU 子系统的关联关系称为控制组。 |
层级树(hierarchy) | 是由一系列的控制组按照树状结构排列组成的。这种排列方式可以使得控制组拥有父子关系,子控制组默认拥有父控制组的属性,也就是子控制组会继承于父控制组。比如,系统中定义了一个控制组 c1,限制了 CPU 可以使用 1 核,然后另外一个控制组 c2 想实现既限制 CPU 使用 1 核,同时限制内存使用 2G,那么 c2 就可以直接继承 c1,无须重复定义 CPU 限制。 |
cgroups的子系统
可以通过命令sudo mount -t cgroup
查看cgroup挂载信息
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_prio,net_cls)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuacct,cpu)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb)
可以看到cgroup挂载了很多子系统,包括cpu、内存等
1. CPU子系统
cpu子系统的创建只需在/sys/fs/cgroup/cpu/
下创建新文件夹即可
如以下命令
mkdir /sys/fs/cgroup/cpu/mydocker
使用命令ls -l /sys/fs/cgroup/cpu/mydocker
查看创建文件夹后的文件夹内容
-rw-r--r--. 1 root root 0 Dec 11 10:53 cgroup.clone_children
--w--w--w-. 1 root root 0 Dec 11 10:53 cgroup.event_control
-rw-r--r--. 1 root root 0 Dec 11 10:53 cgroup.procs
-r--r--r--. 1 root root 0 Dec 11 10:53 cpuacct.stat
-rw-r--r--. 1 root root 0 Dec 11 10:53 cpuacct.usage
-r--r--r--. 1 root root 0 Dec 11 10:53 cpuacct.usage_percpu
-rw-r--r--. 1 root root 0 Dec 11 10:53 cpu.cfs_period_us
-rw-r--r--. 1 root root 0 Dec 11 11:03 cpu.cfs_quota_us
-rw-r--r--. 1 root root 0 Dec 11 10:53 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Dec 11 10:53 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Dec 11 10:53 cpu.shares
-r--r--r--. 1 root root 0 Dec 11 10:53 cpu.stat
-rw-r--r--. 1 root root 0 Dec 11 10:53 notify_on_release
-rw-r--r--. 1 root root 0 Dec 11 10:58 tasks
cgroup自动创建了很多关联文件,其中cpu.cfs_quota_us
标识某一个阶段限制的CPU时间总量,单位为微秒。我们想限制某个进程最多使用 1 核 CPU,就在这个文件里写入 100000(100000 代表限制 1 个核) ,tasks 文件中写入进程的 ID 即可(如果要限制多个进程 ID,在 tasks 文件中用换行符分隔即可)。
2. Memroy子系统
与上面一样,使用命令mkdir /sys/fs/cgroup/memory/mydocker
即可创建Memroy的子系统
其中 memory.limit_in_bytes 文件代表内存使用总量,单位为 byte。
例如,这里对内存使用限制为 1G,则向 memory.limit_in_bytes 文件写入 1073741824
cd /sys/fs/cgroup/memory/mydocker
echo $$ > tasks
删除cgroups
上面创建的子系统不需要后,可以直接删除创建的文件夹即可
如:
rmdir /sys/fs/cgroup/cpu/mydocker
Docker使用cgroups
先创建一个限制为1Gb的Nginx容器
docker run -d -m=1g nginx
然后使用命令ls -l /sys/fs/cgroup/memory
查看cgroups的内存子系统的目录
[root@centeros home]# ls -l /sys/fs/cgroup/memory
total 0
-rw-r--r--. 1 root root 0 Nov 30 11:07 cgroup.clone_children
--w--w--w-. 1 root root 0 Nov 30 11:07 cgroup.event_control
-rw-r--r--. 1 root root 0 Nov 30 11:07 cgroup.procs
-r--r--r--. 1 root root 0 Nov 30 11:07 cgroup.sane_behavior
drwxr-xr-x. 4 root root 0 Dec 11 11:19 docker
可以看到有docker目录,进入目录
[root@centeros memory]# cd docker/
[root@centeros docker]# ls
3c65b074d1626159abba5c2096b992bbda2dd235f5357a51ebecea855e366273 memory.force_empty memory.kmem.tcp.limit_in_bytes memory.memsw.failcnt memory.oom_control memory.use_hierarchy
7d8786780f1cba1ec40a452e103c5ca11c3826203452aefbc9f8d08306ada012
有刚刚创建的容器ID,进入,查看一下该容器的memroy.limit_in_bytes文件内容
[root@centeros 3c65b074d1626159abba5c2096b992bbda2dd235f5357a51ebecea855e366273]# cat memory.limit_in_bytes
1073741824
正好是1Gb