helios741 / myblog

觉得好请点小星星,欢迎有问题交流(issue/email)
109 stars 21 forks source link

浅谈Docker的核心概念和原理(上) #48

Closed helios741 closed 5 years ago

helios741 commented 5 years ago

容器的本质是进程

比如我们用c语言写了一个不断接受标准输入然后打印到标准输出的程序。 当这个程序不执行的时候,躺在硬盘就是一个文件,当我们把它运行起来的时候,他就是操作系统里面中的一个进程。

所以对于进程来说,它的静态的表现形式就是硬盘中的一个文件,当它运行起来的时候,就是计算机里面状态和数据的集合,也就说进程的动态表现。

容器也是如此,容器本身也是一个tar包,当我们不运行它的时候,它也是一个文件,当我们把它运行起来的时候,他才是宿主机里面的一个进程。只不错Linux通过一些技术,让这个“进程“有了边界。

也就是我们经常会听到的:Namespace技术改变进程视图,CGroups对进程的资源进行限制

Namespace

一个Docker容器就是宿主机中的一个进程

Docker使用linux内核的namespace技术来实现容器的隔离。

Linux中的Namespace有七个(namespace list)对应的功能如下表:

Namespave 描述 系统调用
UTS 隔离hostname/NIS domain name CLONE_NEWUSER
IPC 隔离进程间通信 CLONE_NEWIPC
PID 隔离PID CLONE_NEWPID
Mount 隔离文件系统 CLONE_NEWNS
Cgroups 隔离cgroups CLONE_NEWCGROUP
User 隔离用户 CLONE_NEWUSER
Network 隔离网络 CLONE_NEWNET

Docker默认开启的Namespace有:

还有一个User Namespace默认不是开启的。

以PID Namespace举例。

当我们理解了,Docker是怎么做到隔离,然后我们来看看官网上展示的图是不是有些问题呢。

image

CGroups

我们知道了Docker是怎么做隔离的,既然一个Docker容器在宿主机就是一个进程(可以通过docker inspect --format '{{ .State.Pid }}' containerId查看容器在宿主机的进程),那么我们就不能让这个进程吃光了我们宿主机的资源,所以就要对使用资源进行限制。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。

Cgroups暴露给用户的操作是文件系统,是通过文件或者目录的方式存在于宿主机操作系统的/sys/fs/cgroup目录下,我们可以通过ll /sys/fs/cgroup将他们展示出来,也可以通过mount命令:

$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
......

我们可以看到很多能被限制的资源,比如说cup和memery,他们都是以目录的方式存在的,目录下面的文件是对该资源限制的描述,我们可以看一下cpu下面的文件:

ls /sys/fs/cgroup/cpu
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us  cpu.shares notify_on_release
cgroup.procs      cpu.cfs_quota_us  cpu.rt_runtime_us cpu.stat  tasks

这里比较重要的是cpu.cfs_period_uscpu.cfs_quota_us,表示在cfs_period这段时间内,该进程最多占用cfs_quota/cfs_period的CPU(-1表示没有限制)。比如我们设置cfs_period=100cfs_quota=50,那么这个进程最多占用宿主机50%的CPU资源。

当我们在/sys/fs/cgroup/cpu这个目录下面新建一个目录containercontainer这个目录就被称为一个控制组,操作系统会给这个子系统生成默认的资源控制文件。

$ sys/fs/cgroup/cpu$ mkdir container
$ /sys/fs/cgroup/cpu$ ls container/
cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us  cpu.shares notify_on_release
cgroup.procs      cpu.cfs_quota_us  cpu.rt_runtime_us cpu.stat  tasks

我们可以先看一下现在操作系统对container的cpu限制:

cat /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 
-1
$ cat /sys/fs/cgroup/cpu/container/cpu.cfs_period_us 
100000

结论是:没有限制

⚠️: cfs_periodcfs_quota的单位是us,所以上述cfs_period表示的是100000us/100ms。

然后我们执行一个死循环:

while : ; do : ; done &
[1] 7512

image

可以看到机器上的一个cpu已经被打满了。

但是我们的预期是这个死循环进程最多占用一个CPU的百分之二十,那我们应该怎么操作呢?

  1. 已知cfs_period是100000us和进程的占用一个cpu的百分比等于cfs_quota/cfs_period,所以我们需要修改cfs_quota
  2. 修改cfs_quota: echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
  3. 把PID加入到containr/tasks里面:echo 7512 > /sys/fs/cgroup/cpu/container/tasks

我们就能看到现在这个进程的CPU资源利用率的上线就是百分之二十了。 image

除了CPU子系统之外,Cgroup对每一个子系统都有其独有的资源限制能力:

我们可以举个在限制docker容器的cpu只能占用20%的例子:

docker run -it --cpu-period=100000 --cpu-quota=20000 centos /bin/bash

查看容器中的:

# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
20000
# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
100000

容器的隔离并完美

众所周知的是容器之间还是共享的宿主机的内核。/proc中存储的是当前内核运行状态的一系列的特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程信息。比如CPU的使用情况,内存的占用率等,这些文件是查看系统的信息指令(比如top)的主要信息来源。

造成这个问题的原因就是:/proc文件系统并不知道用户通过Cgroup对这个容器做了什么样子的限制

怎么修复呢? lxfs