前两篇文章简单的介绍了有关容器和有关Docker的一些基本的操作和用法,也简单的说了本人对于容器的基本理解和工作中使用docker的情况,这个系列定调在容器的原理和编排方面,前面文章中一笔带过的东西我将深入的做阐述和研究。
本文的目的是告诉大家容器其实也没有什么特别的神奇的地方,对于操作系统来说它也是一个进程,也是一个从磁盘上被操作系统装载的二进制文件。那么容器技术带来的这个进程和其他进程有什么区别呢或者说容器到底做了什么呢?
容器技术的核心功能,就是通过约束和修改进程的动态表现,从而创造出一个边界,那么如何实现所谓的创造一个边界呢?
Docker等容器技术是依靠Linux内核提供的cgroup技术来制造约束,而通过namespaces技术来时动态修改进程的表现。
我们先围绕什么是cgroups展开本文。
那什么是cgroups呢?
CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物力资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24 内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来。可以看出cgroups主要限制了容器进程对于计算机硬件或者物理资源的使用,不至于当系统中存在大量容器的时候某些进程无限制的使用计算机资源造成系统假死等现象。来看下cgroups在Linux下究竟使用和体现。作为一个万物都是文件的系统,Linux下的cgroup自然也是文件。
CGroup 功能及组成
CGroup 是将任意进程进行分组化管理的 Linux 内核功能。CGroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为 CGroup 子系统或控制器。CGroup 子系统有控制内存的 Memory 控制器、控制进程调度的 CPU 控制器等。运行中的内核可以使用的 Cgroup 子系统由/proc/cgroup 来确认。
[root@lokie-web ~]# ls /proc/cgroups
/proc/cgroups
CGroup 提供了一个 CGroup 虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。要使用 CGroup,必须挂载 CGroup 文件系统。这时通过挂载选项指定使用哪个子系统。
来看下在Linux下如何应用cgroups限制一个进程的cpu使用。
cgroup已文件和目录的方式组织在操作系统的/sys/fs/cgroup下
[root@lokie-web ~]# ls /sys/fs/cgroup/
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids systemd
也可以通过
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/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
那对于cpu我们可以看到有
ls /sys/fs/cgroup/cpu
cgroup.clone_children cgroup.procs cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat notify_on_release system.slice user.slice
cgroup.event_control cgroup.sane_behavior cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares docker release_agent tasks
好如何使用呢这些配置文件呢?
[root@lokie-web cpu]# mkdir container #创建一个新的组
[root@lokie-web cpu]# ls container/
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
通过执行
[root@localhost cpu]# echo 'while True: pass'|python &
[1] 8994
[root@localhost cpu]# echo 50000 >/sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
[root@localhost cpu]# top
top - 22:48:47 up 127 days, 11:15, 5 users, load average: 2.34, 1.56, 1.33
Tasks: 290 total, 2 running, 288 sleeping, 0 stopped, 0 zombie
%Cpu(s): 10.4 us, 0.6 sy, 0.0 ni, 88.4 id, 0.1 wa, 0.0 hi, 0.5 si, 0.0 st
KiB Mem : 3876192 total, 314580 free, 3075640 used, 485972 buff/cache
KiB Swap: 8388604 total, 5817712 free, 2570892 used. 532504 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8994 root 20 0 123208 4432 1940 R 89.5 0.1 0:09.07 python
此时cpu 100%
echo 8994 > /sys/fs/cgroup/cpu/foo/tasks
[root@localhost cpu]# top
top - 22:49:28 up 127 days, 11:15, 5 users, load average: 1.79, 1.51, 1.32
Tasks: 290 total, 2 running, 288 sleeping, 0 stopped, 0 zombie
%Cpu(s): 11.5 us, 0.3 sy, 0.0 ni, 88.0 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
KiB Mem : 3876192 total, 313496 free, 3076672 used, 486024 buff/cache
KiB Swap: 8388604 total, 5817804 free, 2570800 used. 531412 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8994 root 20 0 123208 4432 1940 R 49.5 0.1 0:46.05 python
以上结果表明生效,CPU被限制为50%.
那对于docker是怎么体现这个限制的呢?如何设置呢?毫无疑问是通过docker run命令加参数来实现的。
docker run --help | grep cpu
--cpu-count int CPU count (Windows only)
--cpu-percent int CPU percent (Windows only)
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
--cpu-rt-period int Limit CPU real-time period in microseconds
--cpu-rt-runtime int Limit CPU real-time runtime in microseconds
-c, --cpu-shares int CPU shares (relative weight)
--cpus decimal Number of CPUs (default 0.000)
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
来看下是不是创建了cgoups
docker的cgroups路径,很明显在
/sys/fs/cgroup/cpu/docker
根据每个容器都有个uuid组,如下:
[root@localhost docker]# ls
2da17847579a2e33ce13fd5740c0412ceca2910886303408248685e28b76915d cgroup.procs cpu.rt_runtime_us
6f3e7c28e465ef224a63d4f30884ef0e0e6251bcff97b56db47a8d693c1d4855 cpuacct.stat cpu.shares
716146baed45fd69ec8e9ff8e8f6d44538076a6225f7db667351176d875c4117 cpuacct.usage cpu.stat
866ebb91d7ed3778936caa8a31b88d0c6c3febab3ee2fa68992f07dcb618f313 cpuacct.usage_percpu d82f0adca7ae2f0bc6cf0fda9832b453b735648f0480a94a6015be41c6511e51
ad93c9022f308f55cde59858407cd15872f43ae2a82b2451e7c52bc29ebc0f53 cpu.cfs_period_us feadb6f11aec9b6b32934f2b75ff220c133df5adbb7c4448afecea2e16bdb559
cgroup.clone_children cpu.cfs_quota_us notify_on_release
cgroup.event_control cpu.rt_period_us tasks
如下过程即可证明docker是创建了cgroup来限制cpu使用的
docker run --cpu-rt-period 20000 -d redis
dd3c56a92a824d68c4a92f038737de09bd9534f55d37040d8680e750e49dda0d
[root@localhost docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd3c56a92a82 redis "docker-entrypoint..." 8 seconds ago Up 5 seconds 6379/tcp heuristic_roentgen
716146baed45 redis "docker-entrypoint..." 7 months ago Up 4 months 0.0.0.0:6379->6379/tcp clever_wescoff
6f3e7c28e465 dotnet "bash" 22 months ago Up 4 months 0.0.0.0:8086->80/tcp supplierApi
2da17847579a dotnet "bash" 22 months ago Up 4 months 0.0.0.0:8085->80/tcp openevalApi
feadb6f11aec microsoft/dotnet:latest "bash" 22 months ago Up 4 months 0.0.0.0:8084->80/tcp fileApi
ad93c9022f30 dotnet:latest "bash" 23 months ago Up 4 months 0.0.0.0:8083->80/tcp tradeApi
866ebb91d7ed microsoft/dotnet:1.1.0-sdk-projectjson "bash" 23 months ago Up 4 months 0.0.0.0:8081->80/tcp toolapi
d82f0adca7ae mysql:5.6 "docker-entrypoint..." 23 months ago Up 4 months 0.0.0.0:3306->3306/tcp mysql
[root@localhost docker]# cat dd3c56a92a824d68c4a92f038737de09bd9534f55d37040d8680e750e49dda0d/cpu
cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat
cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares
[root@localhost docker]# cat dd3c56a92a824d68c4a92f038737de09bd9534f55d37040d8680e750e49dda0d/cpu.rt_period_us
20000
下篇文章会详细研究namespace对于docker的作用
本文为Lokie.Wang原创文章,转载无需和我联系,但请注明来自lokie博客http://lokie.wang