容器的底层技术:CGroup和NameSpace

无论是容器,还是虚拟机,都依赖于内核中的技术,虚拟机依赖的是 KVM,容器依赖的是 namespace 和 cgroup 对进程进行隔离和资源限制。

容器实现封闭的环境主要要靠两种技术,一种是看起来是隔离的技术,称为namespace(命名空间)。在每个 namespace 中的应用看到的,都是不同的 IP 地址、用户空间、进程 ID 等。另一种是用起来是隔离的技术,称为cgroup(资源限制),即明明整台机器有很多的 CPU、内存,但是一个应用只能用其中的一部分。

CGroup

Docker 提供了这样的功能。Docker 可以限制对于 CPU 的使用,我们可以分几种的方式。

  • Docker 允许用户为每个容器设置一个数字,代表容器的 CPU share,默认情况下每个容器的 share 是 1024。这个数值是相对的,本身并不能代表任何确定的意义。当主机上有多个容器运行时,每个容器占用的 CPU 时间比例为它的 share 在总额中的比例。Docker 为容器设置 CPU share 的参数是 -c --cpu-shares。
  • Docker 提供了 --cpus 参数可以限定容器能使用的 CPU 核数。
  • Docker 可以通过 --cpuset 参数让容器只运行在某些核上

Docker 也能够限制容器内存使用量,下面是一些具体的参数。

  • -m --memory:容器能使用的最大内存大小。
  • –memory-swap:容器能够使用的 swap 大小。
  • –memory-swappiness:默认情况下,主机可以把容器使用的匿名页 swap 出来,你可以设置一个 0-100 之间的值,代表允许 swap 出来的比例。
  • –memory-reservation:设置一个内存使用的 soft limit,如果 docker 发现主机内存不足,会执行 OOM (Out of Memory) 操作。这个值必须小于 --memory 设置的值。
  • –kernel-memory:容器能够使用的 kernel memory 大小。
  • –oom-kill-disable:是否运行 OOM (Out of Memory) 的时候杀死容器。只有设置了 -m,才可以把这个选项设置为 false,否则容器会耗尽主机内存,而且导致主机应用被杀死。

这就是用起来隔离的效果。

容器里面不包含内核,是共享宿主机的内核的。对比虚拟机,虚拟机在 qemu 进程里面是有客户机内核的,应用运行在客户机的用户态。

2a155c6e3436fd772c23465ad6d885ba.jpeg

namespace

隔离

为了隔离不同类型的资源,Linux 内核里面实现了以下几种不同类型的 namespace。

  • UTS,对应的宏为 CLONE_NEWUTS,表示不同的 namespace 可以配置不同的 hostname。
  • User,对应的宏为 CLONE_NEWUSER,表示不同的 namespace 可以配置不同的用户和组。
  • Mount,对应的宏为 CLONE_NEWNS,表示不同的 namespace 的文件系统挂载点是隔离的
  • PID,对应的宏为 CLONE_NEWPID,表示不同的 namespace 有完全独立的 pid,也即一个 namespace 的进程和另一个 namespace 的进程,pid 可以是一样的,但是代表不同的进程。
  • Network,对应的宏为 CLONE_NEWNET,表示不同的 namespace 有独立的网络协议栈。

这些宏可以在代码里进行使用。

还有个最新的   Cgroup namespace。对cgroup视图进行隔离的手段。

Linux 在很早的版本中就实现了部分的 namespace,比如内核 2.4 就实现了 mount namespace。大多数的 namespace 支持是在内核 2.6 中完成的,比如 IPC、Network、PID、和 UTS。还有个别的 namespace 比较特殊,比如 User,从内核 2.6 就开始实现了,但在内核 3.8 中才宣布完成。在内核 4.6 中才添加了 Cgroup namespace

查看namespace

先使用docker启动一个ng

docker run -p 8080:80 -d nginx:1.14-alpine
[root@paas-m-k8s-node-5 ~]# docker ps | grep nginx
afcc1b255416 nginx:1.14-alpine "nginx -g 'daemon of…" 18 seconds ago Up 17 seconds 0.0.0.0:8080->80/tcp angry_gates

使用 docker inspect 命令。可以看到容器在主机上的进程号Pid

docker inspect afcc1b255416
···
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 31704,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-10-12T05:26:02.315208578Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
···


因为,根本上来讲,容器也不过是主机上的一个进程。所以通过ps也可以查看ng的进程

# ps -ef | grep nginx
root 31704 31687 0 13:26 ? 00:00:00 nginx: master process nginx -g daemon off;
100 31752 31704 0 13:26 ? 00:00:00 nginx: worker process


可以看到,进程号都是31704。然后ng的worker进行的pid是31752。

在主机上到/proc/pid/ns 目录里面,可以看到这两个进程的6种namaspace

# ls -l /proc/31704/ns
总用量 0
lrwxrwxrwx 1 root root 0 10月 12 13:31 ipc -> ipc:[4026533228]
lrwxrwxrwx 1 root root 0 10月 12 13:31 mnt -> mnt:[4026533226]
lrwxrwxrwx 1 root root 0 10月 12 13:26 net -> net:[4026533231]
lrwxrwxrwx 1 root root 0 10月 12 13:31 pid -> pid:[4026533229]
lrwxrwxrwx 1 root root 0 10月 12 13:31 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 10月 12 13:31 uts -> uts:[4026533227]


再看看31752的

# ls -l /proc/31752/ns
总用量 0
lrwxrwxrwx 1 100 101 0 10月 12 13:32 ipc -> ipc:[4026533228]
lrwxrwxrwx 1 100 101 0 10月 12 13:32 mnt -> mnt:[4026533226]
lrwxrwxrwx 1 100 101 0 10月 12 13:32 net -> net:[4026533231]
lrwxrwxrwx 1 100 101 0 10月 12 13:32 pid -> pid:[4026533229]
lrwxrwxrwx 1 100 101 0 10月 12 13:32 user -> user:[4026531837]
lrwxrwxrwx 1 100 101 0 10月 12 13:32 uts -> uts:[4026533227]


可以看到他们属于同一个namespace

进入namespace

nsenter指令,可以用来运行一个进程,进入指定的 namespace。

# nsenter --target 31704 --mount --uts --ipc --net --pid -- env --ignore-environment -- /bin/sh


进入 nginx 所在容器的 namespace。现在执行ipaddr 和ps看到的就是nginx容器的相关信息

/ # ipaddr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
370: eth0@if371: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 nginx: master process nginx -g daemon off;
6 nginx 0:00 nginx: worker process
8 root 0:00 /bin/sh
11 root 0:00 ps aux


创建namespace

unshare指令,它会离开当前的 namespace,创建且加入新的 namespace

在进入的命令空间中执行

/ # unshare --mount --ipc --pid --net --mount-proc=/proc --fork /bin/sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
2 root 0:00 ps aux
/ # ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0


进去了一个新的namespace。所以之前的ng进程和主机的eth0都看不到了。

# ls -l /proc/31704/ns
总用量 0
lrwxrwxrwx 1 root root 0 10月 12 13:31 ipc -> ipc:[4026533228]
lrwxrwxrwx 1 root root 0 10月 12 13:31 mnt -> mnt:[4026533226]
lrwxrwxrwx 1 root root 0 10月 12 13:26 net -> net:[4026533231]
lrwxrwxrwx 1 root root 0 10月 12 13:31 pid -> pid:[4026533229]
lrwxrwxrwx 1 root root 0 10月 12 13:31 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 10月 12 13:31 uts -> uts:[4026533227]


操作 namespace的函数

还可以通过函数操作 namespace

clone

clone函数可以创建一个新的进程,并把它放到新的 namespace 中。里面有一个参数 flags,可以设置为 CLONE_NEWUTS、CLONE_NEWUSER、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWNET。 会将 clone 出来的新进程放到新的 namespace 中。

setns

用于将当前进程加入到已有的 namespace 中

unshare

使当前进程退出当前的 namespace,并加入到新创建的 namespace。

clone 和 unshare 的区别是,unshare 是使当前进程加入新的 namespace;clone 是创建一个新的子进程,然后让子进程加入新的 namespace,而当前进程保持不变。

查看CGroup

c就是控制。全称是 Control Group。

cgroups 定义了下面的一系列子系统,每个子系统用于控制某一类资源。

  • cpu 子系统,主要限制进程的 cpu 使用率。
  • cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
  • cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
  • memory 子系统,可以限制进程的 memory 使用量。
  • blkio 子系统,可以限制进程的块设备 io。
  • devices 子系统,可以控制进程能够访问某些设备。
  • net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
  • freezer 子系统,可以挂起或者恢复 cgroups 中的进程。

在 Linux 上,为了操作 Cgroup,有一个专门的 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/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
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/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_prio,net_cls)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)


在/sys/fs/cgroup/下

# ll /sys/fs/cgroup/cpu,cpuacct
总用量 0
-rw-r--r-- 1 root root 0 7月 7 10:09 cgroup.clone_children
--w--w--w- 1 root root 0 7月 7 10:09 cgroup.event_control
-rw-r--r-- 1 root root 0 7月 7 10:09 cgroup.procs
-r--r--r-- 1 root root 0 7月 7 10:09 cgroup.sane_behavior
-r--r--r-- 1 root root 0 7月 7 10:09 cpuacct.stat
-rw-r--r-- 1 root root 0 7月 7 10:09 cpuacct.usage
-r--r--r-- 1 root root 0 7月 7 10:09 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 7月 7 10:09 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 7月 7 10:09 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 7月 7 10:09 cpu.rt_period_us
-rw-r--r-- 1 root root 0 7月 7 10:09 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 7月 7 10:09 cpu.shares
-r--r--r-- 1 root root 0 7月 7 10:09 cpu.stat
drwxr-xr-x 3 root root 0 7月 19 16:23 docker
drwxr-xr-x 5 root root 0 7月 15 16:37 kubepods
-rw-r--r-- 1 root root 0 7月 7 10:09 notify_on_release
-rw-r--r-- 1 root root 0 7月 7 10:09 release_agent
drwxr-xr-x 204 root root 0 10月 12 13:20 system.slice
-rw-r--r-- 1 root root 0 7月 7 10:09 tasks


里面有个docker。容器的资源控制在这里面。

[root@paas-m-k8s-node-5 cpu,cpuacct]# cd docker/
[root@paas-m-k8s-node-5 docker]# ll
总用量 0
drwxr-xr-x 2 root root 0 10月 12 13:26 afcc1b255416ebf7b3303904e5aee41afd281073fe00d5eb065dd9f73e31269b
-rw-r--r-- 1 root root 0 7月 19 16:19 cgroup.clone_children
--w--w--w- 1 root root 0 7月 19 16:19 cgroup.event_control
-rw-r--r-- 1 root root 0 7月 19 16:19 cgroup.procs
-r--r--r-- 1 root root 0 7月 19 16:19 cpuacct.stat
-rw-r--r-- 1 root root 0 7月 19 16:19 cpuacct.usage
-r--r--r-- 1 root root 0 7月 19 16:19 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 7月 19 16:19 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 7月 19 16:19 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 7月 19 16:19 cpu.rt_period_us
-rw-r--r-- 1 root root 0 7月 19 16:19 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 7月 19 16:19 cpu.shares
-r--r--r-- 1 root root 0 7月 19 16:19 cpu.stat
-rw-r--r-- 1 root root 0 7月 19 16:19 notify_on_release
-rw-r--r-- 1 root root 0 7月 19 16:19 tasks
[root@paas-m-k8s-node-5 docker]# docker ps | grep nginx
afcc1b255416 nginx:1.14-alpine "nginx -g 'daemon of…" About an hour ago Up About an hour 0.0.0.0:8080->80/tcp angry_gates


里面有个afcc1b255416开头的文件夹,其实就是我们前面启动的nginx的docker id。里面存这这个容器的资源控制。

[root@paas-m-k8s-node-5 afcc1b255416ebf7b3303904e5aee41afd281073fe00d5eb065dd9f73e31269b]# ll
总用量 0
-rw-r--r-- 1 root root 0 10月 12 13:26 cgroup.clone_children
--w--w--w- 1 root root 0 10月 12 13:26 cgroup.event_control
-rw-r--r-- 1 root root 0 10月 12 13:26 cgroup.procs
-r--r--r-- 1 root root 0 10月 12 13:26 cpuacct.stat
-rw-r--r-- 1 root root 0 10月 12 13:26 cpuacct.usage
-r--r--r-- 1 root root 0 10月 12 13:26 cpuacct.usage_percpu
-rw-r--r-- 1 root root 0 10月 12 13:26 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 10月 12 13:26 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 10月 12 13:26 cpu.rt_period_us
-rw-r--r-- 1 root root 0 10月 12 13:26 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 10月 12 13:26 cpu.shares
-r--r--r-- 1 root root 0 10月 12 13:26 cpu.stat
-rw-r--r-- 1 root root 0 10月 12 13:26 notify_on_release
-rw-r--r-- 1 root root 0 10月 12 13:26 tasks


可以cat查看

cpu.cfs_period_us 是运行周期,cpu.cfs_quota_us 是在周期内这些进程占用多少时间。

还有个关键点是在task文件里

里面放了这个cgroup控制组能控制哪个进程的pid

[root@paas-m-k8s-master-1 172e8d6f1bc755e1bc6ca3a25d10d847a1efa81df4c651f0bb7d36653a32976c]# cat tasks
21706


这个也就是容器进程pid

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/589681.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理NLP概述

大家好&#xff0c;自然语言处理(NLP)是计算机科学领域与人工智能领域中的一个重要方向&#xff0c;其研究能实现人与 计算机之间用自然语言进行有效通信的各种理论和方法。本文将从自然语言处理的本质、原理和应用三个方面&#xff0c;对其进行概述。 一、NLP的本质 NLP是一…

定时器-间歇函数

1.开启定时器 setInterval(function (){console.log(一秒执行一次)},1000) function fn(){console.log(一秒执行一次) } setInterval(fn,1000) //调用有名的函数&#xff0c;只写函数名 1.函数名字不需要加小括号 2.定时器返回是一个id数字 每个定时器的序号是不一样的 2.关…

Codigger Desktop:开发者的利器,每个人的好帮手(二)

昨日&#xff0c;我们为大家揭开了Codigger Desktop开发者利器的三种特性&#xff0c;展现了其独特的亮点。今日&#xff0c;我们将继续为大家呈现另外三项引人注目的特性&#xff0c;以展现这款工具的全面实力。 一、AI辅助&#xff1a;智能识别Module&#xff0c;环境配置一步…

【JAVASE】学习类与对象的创建和实例化

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 掌握类的定义方式以及对象的实例化 2. …

鸿蒙OS开发实例:【应用事件打点】

简介 传统的日志系统里汇聚了整个设备上所有程序运行的过程流水日志&#xff0c;难以识别其中的关键信息。因此&#xff0c;应用开发者需要一种数据打点机制&#xff0c;用来评估如访问数、日活、用户操作习惯以及影响用户使用的关键因素等关键信息。 HiAppEvent是在系统层面…

Day18-【Java SE进阶】多线程

一、线程 1. 什么是线程? 线程(Thread)是一个程序内部的一条执行流程。程序中如果只有一条执行流程&#xff0c;那这个程序就是单线程的程序。 2. 多线程 多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行) 3. 如何在程序中创建出多条线程? Ja…

MyBatis动态SQL--if 标签

mybatis动态sql对我们来说是非常常见的&#xff0c;比如在下面这样一个场景中&#xff0c; 我们需要多条件查询&#xff0c;但是查询的条件又不是固定的&#xff0c;是可以动态改变的&#xff0c;那我们就需要用到动态sql去完成。 动态SQL之 if 标签 接下来我们介绍第一个动态…

【fastadmin】脚本模式下,日志钩子函数执行出现死循环,导致内存溢出奔溃

问题出现原因是想对项目中error级别的日志&#xff0c;接入钉钉告警&#xff0c;方便查看 于是使用钩子方法&#xff0c;日志写入完成后&#xff0c;自动调用自定义的告警方法中 1、在application/tags.php 中添加log_write_done > [app\\common\\behavior\\Common, ],2、在…

2024 蓝桥打卡Day31

递归与辗转相除法 递归&#xff08;Recursion&#xff09;辗转相除法&#xff08;Euclidean Algorithm&#xff09;总结 递归&#xff08;Recursion&#xff09; 递归是指一个函数在执行过程中调用自身的过程。在编程中&#xff0c;递归函数在遇到满足某个条件时会停止调用自身…

苍穹外卖Day04套餐管理部分总结

写给像我一样完完全全的小白的。本人代码水平一塌糊涂&#xff0c;前几天就是机械地跟着视频敲代码。对于Day04的作业本来感觉代码抓瞎一点不会写&#xff0c;尽力去理解业务逻辑后发现好像也没那么难&#xff0c;整体代码可以仿照Day03新增菜品来进行实现&#xff01; 一、功…

关于简单又挣钱的冷门美团项目,美团圈圈

大家好&#xff0c;最近美团又开始搞事情了。接连推出了好几个网推项目&#xff0c;让一大波人都吃上了肉了。 美团的项目很简单&#xff0c;就是给它们的活动做推广。用户只需要拿到它推广的链接&#xff0c;然后去扫码进群就可以了。只要用户保持8天不退就行了。 下面是体验…

2024 ccfcsp认证打卡 2022 09 01 如此编码

2022 09 01 如此编码 题解1题解2 题解1 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt(); // 天数int m sc.nextInt(); // 科目数int[] b new int[n 1]; // 存放结果的数…