1、资源隔离
1.1、需求
在一个操作系统中,启动了多个应用容器,那么这些应用容器如何来保障互相的操作不受影响?
-- 资源隔离
1.2、简介
Linux内核实现namespace的主要目的,就是为了实现轻量级虚拟化技术服务。在同一个namespace下的进程合一感知彼此的变化,而对外界的进程一无所知。
Docker通过linux的 pid、net、ipc、mnt、uts、user这六类的namespace将容器的进程、网络、消息、文件系统、UTS和操作系统资源隔离开。
从而让容器中的进程产生错觉,仿佛自己置身一个独立的系统环境中,以达到隔离的目的。
1.3、namespace
1.3.1、分类
namespace 系统调用参数 隔离内容
UTS CLONE_NEWUTS 主机名或域名
IPC CLONE_NEWIPC 信号量、消息队列和共享内存
PID CLONE_NEWPID 进程编号
Network CLONE_NEWNET 网络设备、网络战、端口等
Mount CLONE_NEWNS 挂载点(文件系统)
User CLONE_NEWUSER 用户组和用户组
Time CLONE_NEWTIME 启动和单调时钟
1.3.2、通过命令查询ns
]# ps -aux | grep docker | grep -v grep
root 32141 0.0 1.9 1096140 72988 ? Ssl 15:16 0:03 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
]# ll /proc/32141/ns/
lrwxrwxrwx. 1 root root 0 5月 18 18:51 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0 5月 18 18:51 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 5月 18 18:51 net -> net:[4026531956]
lrwxrwxrwx. 1 root root 0 5月 18 18:51 pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 5月 18 18:51 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 5月 18 18:51 uts -> uts:[4026531838]
1.4、环境准备
1.4.1、启动2个nginx容器【nginx80,nginx81】
docker run -d --rm --name nginx80 nginx
docker run -d --rm --name nginx81 nginx
1.4.2、查询基本信息
docker inspect nginx80
docker inspect nginx81
1.5、隔离级别-实战
1.5.1、文件系统隔离
# nginx80
]# docker exec -it nginx80 cat /proc/self/mountinfo | head -5
185 122 0:51 / / rw,relatime master:68 - overlay overlay rw,seclabel,lowerdir=/var/lib/docker/overlay2/l/2IYIZJRREC556PKKX43OBOFM5W:/var/lib/docker/overlay2/l/2UFXEGQEPFQFJD7FSGBOJZOEFF:/var/lib/docker/overlay2/l/54URWT4BBGRSLW4CMO6EDCWNP5:
/var/lib/docker/overlay2/l/HJCFS3MVHVODBCH3ITLJJAMKX4:/var/lib/docker/overlay2/l/BOZLGSVQXEAZ7YORN76HBA7GJH:/var/lib/docker/overlay2/l/3BVRX2BKGYF5V56C4PCECSOSFS:/var/lib/docker/overlay2/l/6LEGS22UCMTWB5QBNC5TO3GIV3,upperdir=/var/lib/docker/
overlay2/be42eef2b650ab981e4bd9141ddaeaff0aae3fe7317d6b4cb0f8edaae06caf9d/diff,workdir=/var/lib/docker/overlay2/be42eef2b650ab981e4bd9141ddaeaff0aae3fe7317d6b4cb0f8edaae06caf9d/work
186 185 0:53 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
187 185 0:54 / /dev rw,nosuid - tmpfs tmpfs rw,seclabel,size=65536k,mode=755
188 187 0:55 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=666
189 185 0:56 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro,seclabel
# nginx81
]# docker exec -it nginx81 cat /proc/self/mountinfo | head -5
238 174 0:63 / / rw,relatime master:71 - overlay overlay rw,seclabel,lowerdir=/var/lib/docker/overlay2/l/PI3ZEHEP46H5BW6II33FK3SFLS:/var/lib/docker/overlay2/l/2UFXEGQEPFQFJD7FSGBOJZOEFF:/var/lib/docker/overlay2/l/54URWT4BBGRSLW4CMO6EDCWNP5:
/var/lib/docker/overlay2/l/HJCFS3MVHVODBCH3ITLJJAMKX4:/var/lib/docker/overlay2/l/BOZLGSVQXEAZ7YORN76HBA7GJH:/var/lib/docker/overlay2/l/3BVRX2BKGYF5V56C4PCECSOSFS:/var/lib/docker/overlay2/l/6LEGS22UCMTWB5QBNC5TO3GIV3,upperdir=/var/lib/docker/
overlay2/abf9cd19e452f4922e0258b4bef1b35b8601aedae3dde5dde161e4287b4eaa7f/diff,workdir=/var/lib/docker/overlay2/abf9cd19e452f4922e0258b4bef1b35b8601aedae3dde5dde161e4287b4eaa7f/work
239 238 0:65 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
240 238 0:66 / /dev rw,nosuid - tmpfs tmpfs rw,seclabel,size=65536k,mode=755
241 240 0:67 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=666
242 238 0:68 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro,seclabel
# 发现到workdir是不一样的
1.5.2、UTC资源隔离
]# cat /var/lib/docker/containers/ea887c4677393fde4dcd98709f21769e551e312d51014faf1d91029a1db221b9/hostname
ea887c467739
]# cat /var/lib/docker/containers/ea887c4677393fde4dcd98709f21769e551e312d51014faf1d91029a1db221b9/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.4 ea887c467739
1.5.3、IPC资源隔离
# 宿主机的IPCS
]# ipcmk -Q
消息队列 id:0
]# ipcs
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
0x48951c54 0 root 644 0 0
------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 nattch 状态
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
# 容器的IPCS
]# docker exec -it nginx80 /bin/bash
root@2bcea13a72c7:/# ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
------ Semaphore Arrays --------
key semid owner perms nsems
ipcmk -Q # 建立一个消息队列
ipcs # 查看消息情况
1.5.4、PID资源隔离
# 宿主机的PID
]# docker inspect --format '{{.State.Pid}}' nginx80
51094
]# pstree -g 51094
nginx(51094)───nginx(51094)
# 容器内的PID
]# docker exec -it nginx80 /bin/bash
root@2bcea13a72c7:/# pstree -g
nginx(1)---nginx(1)
1.5.5、net资源隔离
]# ls /var/lib/docker/network/files/local-kv.db
/var/lib/docker/network/files/local-kv.db
]# docker exec -it nginx80 ifconfig | grep inet
inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255
inet 127.0.0.1 netmask 255.0.0.0
]# docker exec -it nginx81 ifconfig | grep inet
inet 172.17.0.4 netmask 255.255.0.0 broadcast 172.17.255.255
inet 127.0.0.1 netmask 255.0.0.0
1.5.6、User资源隔离
]# docker exec -it nginx80 id
uid=0(root) gid=0(root) groups=0(root)
]# docker exec -it nginx81 id
uid=0(root) gid=0(root) groups=0(root)
2、资源控制
2.1、基础知识
2.1.1、简介
对于容器的资源限制,LXC给出的方法是Cgroup,Cgroup 全称Control group,Docker把它继承过来了。
CGroup其实就是通过创建一个虚拟的文件系统交给容器使用,同时还能对容器的容量做出限制。
通过CGroup可以实现的功能:资源限制、优先级分配、资源统计、任务控制
2.1.2、默认情况下,资源限制的功能已经开启
]# grep -i cgroup /boot/config-3.10.0-1160.el7.x86_64
CONFIG_CGROUPS=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NETPRIO_CGROUP=y
2.1.3、系统cgroup的体现
]# ll /sys/fs/cgroup/
drwxr-xr-x. 5 root root 0 5月 15 03:41 blkio
lrwxrwxrwx. 1 root root 11 5月 15 03:41 cpu -> cpu,cpuacct
lrwxrwxrwx. 1 root root 11 5月 15 03:41 cpuacct -> cpu,cpuacct
drwxr-xr-x. 5 root root 0 5月 15 03:41 cpu,cpuacct
drwxr-xr-x. 3 root root 0 5月 15 03:41 cpuset
drwxr-xr-x. 5 root root 0 5月 15 03:41 devices
drwxr-xr-x. 3 root root 0 5月 15 03:41 freezer
drwxr-xr-x. 3 root root 0 5月 15 03:41 hugetlb
drwxr-xr-x. 5 root root 0 5月 15 03:41 memory
lrwxrwxrwx. 1 root root 16 5月 15 03:41 net_cls -> net_cls,net_prio
drwxr-xr-x. 3 root root 0 5月 15 03:41 net_cls,net_prio
lrwxrwxrwx. 1 root root 16 5月 15 03:41 net_prio -> net_cls,net_prio
drwxr-xr-x. 3 root root 0 5月 15 03:41 perf_event
drwxr-xr-x. 5 root root 0 5月 15 03:41 pids
drwxr-xr-x. 5 root root 0 5月 15 03:41 systemd
2.1.4、以CPU限制为例
]# tree /sys/fs/cgroup/cpu/docker
/sys/fs/cgroup/cpu/docker
├── 2bcea13a72c7ab25d8ce8067c1f4a97e9532b09380318d57ea7f1b9f6a79ed23
│ ├── cgroup.clone_children
│ ├── cgroup.event_control
│ ├── cgroup.procs
│ ├── cpuacct.stat
│ ├── cpuacct.usage
│ ├── cpuacct.usage_percpu
│ ├── cpu.cfs_period_us
│ ├── cpu.cfs_quota_us
│ ├── cpu.rt_period_us
│ ├── cpu.rt_runtime_us
│ ├── cpu.shares
│ ├── cpu.stat
│ ├── notify_on_release
│ └── tasks
├── 61a640daad394d4c1d6e44bd184fd44fdbdd955175cb7da4931a4868cd3cd155
│ ├── cgroup.clone_children
│ ├── cgroup.event_control
│ ├── cgroup.procs
│ ├── cpuacct.stat
│ ├── cpuacct.usage
│ ├── cpuacct.usage_percpu
│ ├── cpu.cfs_period_us
│ ├── cpu.cfs_quota_us
│ ├── cpu.rt_period_us
│ ├── cpu.rt_runtime_us
│ ├── cpu.shares
│ ├── cpu.stat
│ ├── notify_on_release
│ └── tasks
2.2、资源限制的命令和工具介绍
2.2.1、简介
默认情况下,容器没有资源的 "使用限制" -- 可以使用尽可能多的主机资源。
Docker提供了控制容器使用资源的方法,可以限制当前容器可以使用的内存数量和cpu资源。我们可以通过docker run的参数来进行简单的控制
2.2.2、资源限制的命令
]# docker run --help | grep -iE 'cpu|oom|memory'
--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
--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)
--kernel-memory bytes Kernel memory limit
-m, --memory bytes Memory limit
--memory-reservation bytes Memory soft limit
--memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
--oom-kill-disable Disable OOM Killer
--oom-score-adj int Tune host's OOM preferences (-1000 to 1000)
2.2.3、docker-stress-ng压测工具的介绍
网上有一个非常好的容器压力测试工具,docker-stress-ng 我们可以基于该镜像来进行各种容量的限制测试
# 查看帮忙信息
]# docker run -it --rm lorel/docker-stress-ng:latest | grep -iE 'cpu|mem'
--affinity N start N workers that rapidly change CPU affinity
-C N, --cache N start N CPU cache thrashing workers
--cache-flush flush cache after every memory write (x86 only)
-c N, --cpu N start N workers spinning on sqrt(rand())
--cpu-ops N stop when N cpu bogo operations completed
-l P, --cpu-load P load CPU by P %%, 0=sleep, 100=full load (see -c)
--cpu-method m specify stress cpu method m, default is all
--memcpy N start N workers performing memory copies
--memcpy-ops N stop when N memcpy bogo operations completed
--vm-hang N sleep N seconds before freeing memory
--vm-keep redirty memory instead of reallocating
--vm-locked lock the pages of the mapped region into memory
2.3、内存资源限制-实战
2.3.1、开启两个work的容器,每个work默认占256m,当前容器占 512m【--vm】
]# docker run --name mem_stress -it --rm lorel/docker-stress-ng:latest --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm
]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
280cbd4988f8 mem_stress 99.41% 514.2MiB / 3.612GiB 13.90% 656B / 0B 0B / 0B 5
2.3.2、调整最大的容器内存量为 100m【-m】
# 关闭容器后,调整最大的容器内存量为 100m
]# docker run --name mem_stress -it --rm -m 100m lorel/docker-stress-ng:latest --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm
]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
db65e6d9b724 mem_stress 95.49% 99.94MiB / 100MiB 99.94% 656B / 0B 3.6MB / 12.6GB 5
2.4、CPU资源限制-实战
2.4.1、查看当前的cpu信息
]# lscpu | grep CPU
CPU op-mode(s): 32-bit, 64-bit
CPU(s): 1
On-line CPU(s) list: 0
CPU 系列: 23
CPU MHz: 2894.563
NUMA 节点0 CPU: 0
2.4.2、开启使用两个cpu的容器【--cpu】
]# docker run --name cpu_stress -it --rm lorel/docker-stress-ng:latest --cpu 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 cpu
# 查看状态
]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7f58ff01d9ef cpu_stress 100.06% 6.016MiB / 3.612GiB 0.16% 656B / 0B 0B / 0B 3
2.4.3、调整cpu的使用数量为1,压测的CPU为2【--cpus】
# 限制只能使用一半的CPU
]# docker run --name cpu_stress -it --rm --cpus 0.5 lorel/docker-stress-ng:latest --cpu 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 cpu
# 查看状态
]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
514173c9426a cpu_stress 50.29% 6.016MiB / 3.612GiB 0.16% 586B / 0B 0B / 0B 3
2.4.5、定制cpu绑定操作【--cpuset-cpus】
]# docker run -it --rm --name cpu_stress --cpus 0.5 --cpuset-cpus 0 lorel/docker-stress-ng:latest --cpu 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 cpu
]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
9cef3ce365c9 cpu_stress 49.97% 6.023MiB / 3.612GiB 0.16% 656B / 0B 0B / 0B 3