docker容器技术基础之linux cgroup、namespace
一、开头
接触过docker的同学多多少少听过这样一句话“docker容器通过linux namespace、cgroup特性实现资源的隔离与限制”。今天我们来尝试学习一下这两个东西。
二、关于namesapce
命名空间将全局系统资源包装在一个抽象中,使命名空间内的进程看起来它们拥有自己独立的全局资源实例。命名空间内对全局资源的改变对其他进程可见,命名空间的成员对其他进程不可见。
目前linux 内核已实现的7种命名空间如下:
Namespace Flag(API操作类型别名) Isolates(隔离内容)
Cgroup CLONE_NEWCGROUP Cgroup root directory (since Linux 4.6)
IPC CLONE_NEWIPC System V IPC, POSIX message queues (since Linux 2.6.19)
Network CLONE_NEWNET Network devices, stacks, ports, etc. (since Linux 2.6.24)
Mount CLONE_NEWNS Mount points (since Linux 2.4.19)
PID CLONE_NEWPID Process IDs (since Linux 2.6.24)
User CLONE_NEWUSER User and group IDs (started in Linux 2.6.23 and completed in Linux 3.8)
UTS CLONE_NEWUTS Hostname and NIS domain name (since Linux 2.6.19)
查看进程的namespace
[root@i-k9pwet2d ~]# pidof bash
14208 11123 2053
[root@i-k9pwet2d ~]# ls -l /proc/14208/ns
total 0
lrwxrwxrwx 1 root root 0 Jul 20 09:36 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jul 20 09:36 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Jul 20 09:36 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Jul 20 09:36 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jul 20 09:36 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul 20 09:36 uts -> uts:[4026531838]
每一个进程在/proc/[pid]/ns 都可以看到其所属的namespace信息,这些链接文件指向所属的namespace及inode ID,我们可以通过readlink 来查看两个进程的是否属于同一个命名空间,inode相同则他们所属相同命名空间
[root@i-k9pwet2d ~]# readlink /proc/11123/ns/uts
uts:[4026531838]
[root@i-k9pwet2d ~]# readlink /proc/14208/ns/uts
uts:[4026531838]
如何将你的进程注册到命名空间(API操作)?
clone():创建一个新的命名空间,子进程同属新的命名空间,flags即我们创建的namespace类型,形如CLONE_NEW*
int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
/* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
setns(): 加入一个命名空间,fd为/proc/[pid]/ns 下的链接文件,nstype即我们的Flag
int setns(int fd, int nstype);
unshare() :退出某个namespace并加入创建的新空间。
int unshare(int flags);
ioctl() : ioctl系统调用可用于查询命名空间的信息
int ioctl(int fd , unsigned long request , ...);
下面我们通过shell 命令 unshare 来看看命名空间7大隔离实现
1.PID Namespace
PID Namespace 的作用是用来隔离进程,利用 PID Namespace 可以实现每个容器的主进程为 1 号进程,而容器内的进程在主机上却拥有不同的PID。
[root@i-k9pwet2d ~]# unshare --fork --pid --mount-proc /bin/bash
[root@i-k9pwet2d ~]# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 115680 2036 pts/0 S 10:46 0:00 /bin/bash
root 12 0.0 0.1 115684 2048 pts/0 S 10:47 0:00 -bash
root 30 0.0 0.0 155468 1804 pts/0 R+ 10:57 0:00 ps -aux
ls -l /proc/1/ns
total 0
lrwxrwxrwx 1 root root 0 Jul 20 11:05 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jul 20 11:05 mnt -> mnt:[4026532545]
lrwxrwxrwx 1 root root 0 Jul 20 11:05 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Jul 20 11:05 pid -> pid:[4026532546]
lrwxrwxrwx 1 root root 0 Jul 20 11:05 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul 20 11:05 uts -> uts:[4026531838]
在新的PID Namespace中我们只能看到自身命名空间的进程。并且当前的bash处于起来的mnt、pid命名空间。
2.Mount Namespace
它可以用来隔离不同的进程或进程组看到的挂载点。在容器内的挂载操作不会影响主机的挂载目录。
我们创建一个命名空间
unshare --mount --fork /bin/bash
挂在一个目录
[root@i-k9pwet2d ~]# mkdir /tmp/mnt
[root@i-k9pwet2d ~]# mount -t tmpfs -o size=1m tmpfs /tmp/mnt
[root@i-k9pwet2d ~]# df -h |grep mnt
tmpfs 1M 0 1M 0% /tmp/mnt
在命名空间内的挂载并不影响我们的主机目录,我们在主机上查看不到挂载信息
df -h |grep mnt
3.User Namespace
User Namespace用来隔离用户和用户组。我们来创建一个用户命名空间并修改提示符
[root@i-k9pwet2d ~]# PS1='\u@container#' unshare --user -r /bin/bash
root@container#
再查看ns,用户链接是不同的,已处于不同空间。
[root@i-k9pwet2d ~]# readlink /proc/1835/ns/user
user:[4026532192]
[root@i-k9pwet2d ~]# readlink /proc/$$/ns/user
user:[4026531837]
用户命名空间的最大优势是无需 root 权限即可运行容器,避免应用使用root对主机的影响。
4.UTS Namespace
UTS Namespace 用于隔离主机名的,它允许每个 UTS Namespace 拥有一个独立的主机名。
[root@i-k9pwet2d ~]# unshare --fork --uts /bin/bash
在命名空间中修改主机名,在主机中不受影响
[root@i-k9pwet2d ~]# hostname -b container
[root@i-k9pwet2d ~]# hostname
container
主机中
[root@i-k9pwet2d ~]# hostname
i-k9pwet2d
5.IPC Namespace
IPC 命名空间隔离某些 IPC 资源,即 System V IPC 对象(参见sysvipc(7))和(自 Linux 2.6.30 起)POSIX 消息队列(请参阅mq_overview(7))。容器通过IPC Namespace、PID Namespace实现同一 IPC Namespace 内的进程彼此可以通信,不同 IPC Namespace 的进程却不能通信。
我们使用linux中ipc相关命令来测试
ipcs -q 命令:用来查看系统间通信队列列表。
ipcmk -Q 命令:用来创建系统间通信队列。
我们先创建一个IPC Namespace
[root@i-k9pwet2d ~]# unshare --fork --ipc /bin/bash
创建一个通信队列后查询一下
[root@i-k9pwet2d ~]# ipcmk -Q
Message queue id: 0
[root@i-k9pwet2d ~]# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x1de4aef6 0 root 644 0 0
在主机上查询,可以看到通信已经被隔离了
[root@i-k9pwet2d ~]# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
6.Net Namespace
Net Namespace 可用于隔离网络设备、IP 地址和端口等信息。Net Namespace 可以让每个进程拥有自己独立的 IP 地址,端口和网卡信息。
我们继续创建一个Net Namespace
[root@i-k9pwet2d ~]# unshare --net --fork /bin/bash
查看网络和端口信息
[root@i-k9pwet2d ~]# ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
[root@i-k9pwet2d ~]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
上面看到了一个回环接口lo,状态处于DOWN,我们将它启动,这样我们的Namespace有了自己的网络地址。
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
主机中
[root@i-k9pwet2d ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:96:e1:36:04 brd ff:ff:ff:ff:ff:ff
inet 10.150.25.9/24 brd 10.150.25.255 scope global noprefixroute dynamic eth0
valid_lft 80720sec preferred_lft 80720sec
inet6 fe80::5054:96ff:fee1:3604/64 scope link
valid_lft forever preferred_lft forever
[root@i-k9pwet2d ~]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 757/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1112/master
...
7.Cgroup Namespace
Cgroup是对进程的cgroup视图虚拟化。 每个 cgroup 命名空间都有自己的一组 cgroup 根目录。Linux 4.6开始支持。
cgroup 命名空间提供的虚拟化有多种用途:
- 防止信息泄漏。否则容器外的cgroup 目录路径对容器中的进程可见。
- 简化了容器迁移等任务。
- 允许更好地限制容器化进程。可以挂载容器的 cgroup 文件系统,这样容器无需访问主机 cgroup 目录。
8.Time Namespace
虚拟化两个系统时钟,用于隔离时间。 linux 5.7内核开始支持 参考地址:TIME_NAMESPACES(7)
三、关于Cgroup
从上面我们了解到当我们要运行一个容器时,docker等应用会为该容器创建一组 namespace,对操作系统而言可以理解为一组进程。这下我们完成了“权利”的集中,但是“权利越大,责任也大”,我们不能放任这组“大权“不管,所以又有了Cgroup(Linux Control Group)这个东西。
Cgroup最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
cgroups 框架提供了以下内容:
- 资源限制: 可以为我们的进程组配置内存限制或cpu个数限制又或者仅限于某个特定外围设备。
- 优先级: 一个或多个组可以配置为优先占用 CPU 或磁盘 I/O 吞吐量。
- 资源记录: 监视和测量组的资源使用情况。
- 控制: 可以冻结或停止和重新启动进程组。
一个 cgroup 可以由一个或多个进程组成,这些进程都绑定到同一组限制。这些组也可以是分层的,即子组可以继承父组管理的限制。
Linux 内核为 cgroup 技术提供了对一系列控制器或子系统的访问。控制器负责将特定类型的系统资源分配给一组一个或多个进程。例如,memory控制器限制内存使用,而cpuacct控制器监控 CPU 使用。
我们通过Mount查看系统中cgroup的子系统
[root@i-k9pwet2d ~]# 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/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
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/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
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/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
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/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
可以看到cgroup已通过文件系统方式挂载到/sys/fs/cgroup/
[root@i-k9pwet2d ~]# ls -l /sys/fs/cgroup/
total 0
drwxr-xr-x 2 root root 0 Jul 20 12:23 blkio
lrwxrwxrwx 1 root root 11 Jul 20 12:23 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jul 20 12:23 cpuacct -> cpu,cpuacct
drwxr-xr-x 2 root root 0 Jul 20 12:23 cpu,cpuacct
drwxr-xr-x 2 root root 0 Jul 20 12:23 cpuset
drwxr-xr-x 4 root root 0 Jul 20 12:23 devices
drwxr-xr-x 2 root root 0 Jul 20 12:23 freezer
drwxr-xr-x 2 root root 0 Jul 20 12:23 hugetlb
drwxr-xr-x 2 root root 0 Jul 20 12:23 memory
lrwxrwxrwx 1 root root 16 Jul 20 12:23 net_cls -> net_cls,net_prio
drwxr-xr-x 2 root root 0 Jul 20 12:23 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jul 20 12:23 net_prio -> net_cls,net_prio
drwxr-xr-x 2 root root 0 Jul 20 12:23 perf_event
drwxr-xr-x 2 root root 0 Jul 20 12:23 pids
drwxr-xr-x 4 root root 0 Jul 20 12:23 systemd
接下来我们通过一个实例看看cgroup是如何限制内存的
我们启动一个循环脚本,这个循环脚本将占用近100%的CPU,我们通过cgroup限制到50%
$ cat loop.sh
#!/bash/sh
while [ 1 ]; do
:
done
将我们的脚本放到后台,获取它的PID为21497
nohup bash loop.sh &
我们需要创建一个cgroup控制组loop
[root@i-k9pwet2d ~]# mkdir /sys/fs/cgroup/cpu/loop
loop组是CPU的子组,上面提到子组可以继承父组管理的限制所以loop将继承对系统整个cpu的访问权限
[root@i-k9pwet2d shell]# ls -l /sys/fs/cgroup/cpu/loop
total 0
-rw-r--r-- 1 root root 0 Jul 20 17:15 cgroup.clone_children
--w--w--w- 1 root root 0 Jul 20 17:15 cgroup.event_control
-rw-r--r-- 1 root root 0 Jul 20 17:15 cgroup.procs
-r--r--r-- 1 root root 0 Jul 20 17:15 cpuacct.stat
-rw-r--r-- 1 root root 0 Jul 20 17:15 cpuacct.usage
-r--r--r-- 1 root root 0 Jul 20 17:15 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 Jul 20 17:15 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jul 20 17:15 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jul 20 17:15 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Jul 20 17:15 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Jul 20 17:15 cpu.shares
-r--r--r-- 1 root root 0 Jul 20 17:15 cpu.stat
-rw-r--r-- 1 root root 0 Jul 20 17:15 notify_on_release
-rw-r--r-- 1 root root 0 Jul 20 17:15 tasks
查看继承后的loop组cpu限制,计算周期为100000us,采样时间无限制(-1)
[root@i-k9pwet2d shell]# cat /sys/fs/cgroup/cpu/loop/cpu.cfs_period_us
100000
[root@i-k9pwet2d shell]# cat /sys/fs/cgroup/cpu/loop/cpu.cfs_quota_us
-1
为了限制进程的的cpu使用率为50%,我们需要更新cpu.cfs_quota_us的值为50000
echo 50000 >/sys/fs/cgroup/cpu/loop/cpu.cfs_quota_us
将脚本PID更新到loop控制组下的tasks
[root@i-k9pwet2d shell]# echo 21497 >/sys/fs/cgroup/cpu/loop/tasks
此时我们的脚本CPU使用率已被限制到50%
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21497 root 20 0 113284 1176 996 R 50.0 0.1 12:17.48 bash
在docker启动容器时做的cpu限制参数--cpu-period、--cpu-quota实际上就是调整对应容器控制组的cpu配额。
参考:
小作文有不足的地方欢迎指出。
欢迎收藏、点赞、提问。关注顶级饮水机管理员,除了管烧热水,有时还做点别的。
docker容器技术基础之linux cgroup、namespace的更多相关文章
- docker容器技术基础之联合文件系统OverlayFS
我们在上篇介绍了容器技术中资源隔离与限制docker容器技术基础之linux cgroup.namespace 这篇小作文我们要尝试学习容器的另外一个重要技术之联合文件系统之OverlayFS,在介绍 ...
- docker容器技术基础入门
目录 docker容器技术基础入门 容器(Container) 传统虚拟化与容器的区别 Linux容器技术 Linux Namespaces CGroups LXC docker基本概念 docker ...
- 1.docker容器技术基础入门
内容来自:https://www.cnblogs.com/marility/p/10215062.html https://blog.51cto.com/gouyc/2310785?source=dr ...
- Docker容器技术基础
Docker基础 目录 Docker基础 容器(Container) 传统虚拟化与容器的区别 Linux容器技术 Linux Namespaces CGroups LXC docker基本概念 doc ...
- Docker容器技术-基础命令
一.基础命令 1.运行一个镜像 [root@bogon ~]# docker run debian echo "Hello World" Unable to find image ...
- Docker容器技术-基础与架构
一.什么是容器 容器是对应用程序及其依赖关系的封装. 1.容器的优点 容器与主机的操作系统共享资源,提高了效率,性能损耗低 容器具有可移植性 容器是轻量的,可同时运行数十个容器,模拟分布式系统 不必花 ...
- 1、docker容器技术基础入门
Docker和传统虚拟机的区别 参考文章: https://lwn.net/Articles/531114/ 操作中的命名空间详解 https://blog.yadu ...
- 1.云原生之Docker容器技术基础知识介绍
转载自:https://www.bilibili.com/read/cv15180540/?from=readlist
- Docker容器技术的核心原理
目录 1 前言 2 docker容器技术 2.1 隔离:Namespace 2.2 限制:Cgroup 2.3 rootfs 2.4 镜像分层 3 docker容器与虚拟机的对比 1 前言 上图是百度 ...
随机推荐
- Go语言流程控制06--猜数字游戏
package main import ( "fmt" "math/rand" "time" ) /* ·随机生成一个三位数 ·让用户输入其 ...
- 重新整理 .net core 实践篇—————日志系统之战地记者[十五]
前言 本节开始整理日志相关的东西.先整理一下日志的基本原理. 正文 首先介绍一下包: Microsoft.Extengsion.Logging.Abstrations 这个是接口包. Microsof ...
- GPU上的快速光谱图分区
GPU上的快速光谱图分区 图形是用于对物理,生物,社会和信息系统中许多类型的关系和过程进行建模的数学结构.用于解决各种高性能计算和数据分析问题.对于网络分析,基因组学,社交网络分析和其他领域,大规模图 ...
- HLS后端示例
HLS后端示例 TVM支持带有SDAccel的Xilinx FPGA板.这是有关如何将TVM部署到AWS F1 FPGA实例的文档. 此功能仍处于试验阶段.暂时无法使用SDAccel部署端到端神经网络 ...
- [NOIP1998 提高组] 拼数
题目描述 设有 n 个正整数 a1-an,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数. 输入格式 第一行有一个整数,表示数字个数 n. 第二行有 n 个整数,表示给出的 n 个整数 a_ ...
- SQL进阶总结(二)
2.第二个特性----以集合为单位进行操作 在我们以往面向过程语言不同,SQL是一门面向集合的一门语言.由于习惯了面向过程的思考方式,导致我们在使用SQL时往往也陷入之前的思维定式. 我们现在分别创建 ...
- jvm相关自我总结和 VisualVM工具的使用
idea 二个工具: jclasslib Hexview jdk监控工具 VisualVM工具的使用: https://www.ibm.com/developerworks/cn/java/j-lo- ...
- 七、Nginx反向代理
调度器调度后端服务器 : web高可用 负载均衡 解决web单点故障 部署后端服务器---配置Nginx服务器(定义集群.请求转发)---起服务.测试----配置集群池属性(权重.失败次数.失败 ...
- SpringBoot数据访问(二) SpringBoot整合JPA
JPA简介 Spring Data JPA是Spring Data大家族的一部分,它可以轻松实现基于JPA的存储库.该模块用于增强支持基于JPA的数据访问层,它使我们可以更加容易地构建使用数据访问技术 ...
- 这应该是把Java内存区域讲的最清楚的一篇文章
基本问题: 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和直接指针两种方式) 拓展问题: ...