容器里的进程组织或关系
0号进程:containerd-shim
角色:
- containerd-shim 是容器的父进程,负责管理容器的生命周期,接收容器内的执行的指令。
- 它通过调用 runc 创建容器,并处理容器内的指令。
特点:
- 容器依赖:
- containerd-shim 是容器的祖宗进程,如果它挂掉,整个容器也会退出。
- 进程管理:
- 如果容器的1号进程结束,containerd-shim 会回收容器命名空间中的所有进程。
- 如果1号进程未结束,但其子进程结束,子进程会成为僵尸进程,需要由1号进程回收。
- 信号处理:
- docker stop 会向容器的1号进程发送 sigterm(-15)信号。
- 如果1号进程没有信号转发能力,它会向容器内的所有进程发送 sigkill(-9)信号。
- 如果1号进程有信号转发能力,它会向容器内的所有进程转发 sigterm(-15) 信号。
- docker stop 会向容器的1号进程发送 sigterm(-15)信号。
1号进程:容器内的第一个进程
角色:
- 1号进程是容器内的第一个进程,代表容器的生命周期。
- 它通常是用户指定的应用程序进程。
特点:
- 生命周期:
- 1号进程结束,容器也会结束。
- 1号进程必须在前台运行,否则容器会退出。
- 功能缺陷(与操作系统进程的区别):
- 容器内的1号进程不一定是所有用户进程的祖先。
- 如果1号进程成为孤儿进程,它会被init进程(0号进程)收养。
- 用户开发的1号进程可能缺乏回收僵尸进程和转发信号的能力。
应具备的能力:
- 回收僵尸进程::定期调用 wait 或 waitpid 回收僵尸子进程。
- 信号转发:将接收到的信号(如 sigterm)转发给子进程。
~# docker container inspect text | grep -i pid pid:41404---------对应的就是容器内的1号进程 ~# ps -elf | grep 41404 pid:41404 ppid:41382---------对应的就是容器内的0号进程
进程收到信号后的三种反应
信号是操作系统向进程发送的一种通知,用于通知进程发生了某种事件。可以用于进程间通信或控制进程行为。
- 忽略(ignore):
- 进程对信号不做任何处理。
- 示例:忽略 sigterm 信号,进程不会被终止。
- 捕获(catch):
- 进程可以注册自定义的处理函数(handler)来处理捕获的信号。
- 当信号到达时,触发 handler 执行。
- 示例:trap 'echo "signal received"' sigterm
- 默认行为(default):
- 每个信号都有默认行为,由操作系统定义。
- 示例:
- sigterm 的默认行为是终止进程。
- sigkill 的默认行为是强制终止进程。
两个特权信号
sigkill (-9)
- 作用: 强制终止进程。
- 特点:
- 无法被忽略。
- 无法被捕获。
- 使用场景: 当进程无响应时,强制终止进程。
sigstop (-19):
- 作用: 暂停进程的运行
- 特点:
- 无法被忽略。
- 无法被捕获。
- 恢复运行: 发送 sigcont (-18) 信号。
sigterm(-15)信号是可以被进程忽略或者捕获的
在容器内执行 kill 命令的行为
kill -9 1
- 无法杀死容器内的1号进程。
- 原因: 容器内的1号进程被打上了 signal_unkillable 标签。
kill -19 1
- 无法暂停容器内的1号进程。
- 原因: 容器内的1号进程被打上了 signal_unkillable 标签。
kill -15 1
- 有可能杀死容器内的1号进程。
- 如果1号进程没有注册 sigterm 信号的处理函数,它会忽略该信号。
- 如果1号进程注册了 sigterm 信号的处理函数,它会执行该函数。
cgroup 介绍
cgroup(control group)是 linux 内核提供的一种机制,用于限制、控制和监控进程组的资源使用。它允许系统管理员对一组进程的资源使用进行精细化管理,包括 cpu、内存、磁盘 i/o 等。cgroup 是容器技术(如 docker、kubernetes)中实现资源隔离和管理的基础。
为何要用 cgroup?cgroup 的主要作用是限制容器或进程组对宿主机资源的使用,防止某个容器或进程过度占用资源,从而影响其他容器或进程的正常运行。通过 cgroup,可以确保宿主机上的多个容器或进程能够公平、稳定地共享系统资源。
在 linux 系统中,可以通过以下命令查看和管理 cgroup
# 查看当前的 cgroup 控制层级 cat /proc/cgroups # 创建一个新的 cgroup mkdir /sys/fs/cgroup/cpu/my_cgroup # 将一个进程加入到 cgroup 中 echo "pid" > /sys/fs/cgroup/cpu/my_cgroup/tasks # 设置 cpu 限制 echo "2" > /sys/fs/cgroup/cpu/my_cgroup/cpu.cfs_quota_us
cpu cgroup 中与 cfs 相关的参数
cfs(completely fair scheduler)是 linux 内核中的一种调度算法,用于公平地分配 cpu 时间给各个进程。cgroup 中与 cfs 相关的参数决定了进程组对 cpu 的使用率。
- cpu.cfs_period_us:表示 cpu 的时间周期,单位为微秒 (μs)。例如,设置为 100ms (100,000 μs),表示一个周期为 100 毫秒。
- cpu.cfs_quota_us:表示在该时间周期内,控制组内的进程最多可以使用的 cpu 时间。例如,设置为 50ms (50,000 μs),表示在 100ms 的周期内,进程最多可以使用 50ms 的 cpu 时间。此时,cpu 使用率为 50ms / 100ms = 0.5,即 50%。
- cpu.shares:用于控制同一层级下的多个控制组之间的 cpu 资源分配。当宿主机上的 cpu 资源不足时,cpu.shares 会生效,决定各个控制组之间的 cpu 资源分配比例。cpu.shares 的值越大,分配的 cpu 资源越多。
总结:
- cpu.cfs_quota_us与cpu.cfs_period_us这两个值决定了每个控制组所有进程可使用cpu资源的最大值
- cpu.shares这个值决定了cpu cgroup子系统下控制组可用cpu的相对比例,不过只有当系统上cpu被占满时,这个比例才会在各个控制组间起作用
kubernetes 中的资源管理
在 kubernetes 中,pod 的资源请求和限制可以通过 requests 和 limits 来设置。
- requests:表示 pod 对资源的最低需求。kubernetes 会根据 requests 来调度 pod,确保节点上有足够的资源。requests 对应 cgroup 中的 cpu.shares,表示初始的 cpu 资源申请量。实际使用量可以超过 requests,但不会低于它。
- limits:表示 pod 对资源使用的上限。kubernetes 会通过 cgroup 限制 pod 的资源使用,确保不会超过 limits 设置的值。limits 对应 cgroup 中的 cpu.cfs_quota_us 和 cpu.cfs_period_us,表示 cpu 使用的硬性上限。
但是要注意,limits 设置的上限是否能达到,还取决于宿主机的实际资源情况。如果宿主机资源不足,pod 可能无法达到 limits 设置的上限。
memory cgroup
每个容器都有对应的 memory cgroup 控制组,位于 /sys/fs/cgroup/memory/system.slice/docker - xxx
,用于管理容器内存。
主要参数:
- memory.limit_in_bytes:设置容器内所有进程可占用的物理内存上限,子 group 最多只能设置到父级 group 的该值。
- memory.oom_control:默认为 0,表示开启 oom 机制;可设为 1 关闭,通过 echo 1 > memory.oom_control 实现。
- memory.usage_in_bytes:只读参数,显示容器内所有进程占用的物理内存总量。
示例: 容器启动时,rss 为 100 m,page cache 为 899 m,内存总使用量为 999 m;随着进程运行,申请更多内存后,rss 增至 200 m,page cache 减至 699 m,内存总使用量仍为 899 m,但实际进程占用的物理内存增大。
容器的可用磁盘进行配额
默认情况,容器内的可用磁盘空间是没有限制的。
容器内的文件系统 = lowerdir + upperdir
写入操作
- 在容器内写容器文件系统里写东西(任何目录都没有挂载任何外部存储卷)
- 那此时写入的数据,都写到了upperdir层,也就是写到的宿主机上。
- 所以如果不加以限制,很有可能会导致宿主机磁盘空间写满。
如何解决问题?有两种方式:
- 对容器的可用磁盘进行配额
- 对容器写操作的目录,应该挂载一个专门的外部存储卷(推荐)
到此这篇关于docker的进程和cgroup概念的文章就介绍到这了,更多相关docker cgroup概念内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论