从 Linux 进程控制机制看 Docker 容器管理



文章目录

  • 前言
  • 一、Linux 进程管理基本知识
    • 1、Systemd 的进程管理
    • 2、父子进程与僵尸进程
      • 2.1 父子进程
      • 2.2 僵尸进程
    • 3、Linux 系统间的通信信号
  • 二、验证 Linux 进程管理机制
    • 1、子进程后台运行
    • 2、子进程前台运行
  • 三、Docker 容器管理与 Linux 进程机制的联系
    • 1、容器错误启动方式:后台启动应用
    • 2、容器正确的启动方式:前台运行进程
    • 3、官方推荐的容器启动方式
  • 总结


前言

  容器化技术以其轻量级、便携性和高度可扩展性,正在引领软件开发和运维的新潮流。 Docker 作为容器化技术的先驱,其设计和实现深度依赖于 Linux 内核的 进程控制机制 。这些机制不仅为 Docker 提供了 隔离性安全性 的基础,还直接影响了容器的生命周期管理、资源分配和 进程调度 。本文将简要探讨 Linux 进程控制机制对 Docker 容器进程管理的影响。


  大家好,我是技术界的小萌新,今天要和大家分享一些干货。在阅读之前请先点赞👍,给我一点鼓励吧!这对我来说很重要 (*^▽^*)

一、Linux 进程管理基本知识

  

1、Systemd 的进程管理

   Systemd 是 Centos 7 发行版开始启用的系统服务 初始化 管理器,用于替代传统的 System V init ,优势是以服务的异步并行启动代替了 init 的脚本串行启动服务,显著减少了系统启动时间。
  Systemd 使用 Unit 单元 来管理服务,每一个单元代表一个服务或系统资源,单元的类型包括服务单元(.service)、挂载单元(.mount)、设备单元(.device)等。
  每个服务单元都有自己的配置文件,通常位于 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目录下,配置文件后缀名为 .service。配置文件中定义了服务的启动、停止、重启等行为。我们可以通过 Systemd start | stop | restart | 命令的的方式来管理服务。

2、父子进程与僵尸进程

2.1 父子进程

  Systemd 为 上帝进程 ,它在系统启动时作为用户空间的第一个进程(PID 为 1)运行,作为其他所有用户空间的父进程负责启动他它们所辖的子进程,父子进程机制是操作系统中进程管理的一个重要概念。
  它描述了进程之间的层级关系以及它们之间的 相互作用 ,它规定所有子进程在创建时需要 继承 父进程的许多属性,如 用户权限 、文件描述符、环境变量等。
  父子进程间还存在如下机制:

  • 当子进程终止,父进程存活时,它会向父进程发送 SIGCHLD 信号。父进程可以通过 wait() 或 waitpid() 系统调用来等待子进程的终止,进行 “收割” ,回收资源,并获取其退出状态。
  • 当子进程存活,父进程消亡时,子进程成为 “孤儿进程” ,但会认 Systemd 为父进程,交给上帝进程托管进而 后台运行 ,例如 httpd 服务后台启动时,会生成一个 httpd 父进程,它生成众多子进程后会把自己杀死,从而让上帝进程 托管 这些子进程,达到后台运行的目的。所有孤儿进程的 默认 父进程为 Systemd。
  • 由 Systemd 命令管理启动的子进程,都必须 前台运行,因为后台运行的进程只能通过杀掉父进程的方式被 Systemd 托管,然而由上帝进程直接管理的程序只会被分配到 一个 父进程,没有第二个,所以后台运行的结果只能是都被 Systemd 杀死,可以通过查看 Service 服务文件获知。这一点与容器的 进程管理 联系十分 紧密

2.2 僵尸进程

   僵尸进程 (Zombie Process)是类Unix操作系统中的一个特殊进程 状态 。当一个子进程完成其执行并退出时,它的进程描述符(包括进程ID、退出状态等信息)并不会立即被操作系统完全释放,而是保留在系统中,虽然 释放 了内存,CPU 等 资源 ,但会占用 进程表项 ,若被占满则不能启动新进程。
  承接上述情况,当子进程终止,父进程存活时,它会成为 “失效进程” ,即僵尸进程,倘若父进程 回收机制 不完善 (如 Redis daemon 进程) ,它就不会被 “收割”,直到父进程也死亡时,统一被 Systemd 上帝进程回收。(Systemd 先回收父进程,子进程成为孤儿进程,Systemd 同时负责对所有孤儿进程的回收)

3、Linux 系统间的通信信号

  Linux定义了多种信号,如 SIGINT(中断信号,通常由用户通过Ctrl+C产生)、SIGTERM(终止信号,用于请求进程正常退出)、SIGKILL(杀死信号,用于立即终止进程,不能被忽略或捕获)、SIGALRM(闹钟信号,用于定时提醒)、SIGCHLD(子进程状态改变信号,通知父进程子进程已经改变状态)等。
  进程可以通过kill 系统调用向另一个进程发送信号。例如, kill -9(SIGKILL) pid 会向进程ID为pid 的进程发送终止信号。


二、验证 Linux 进程管理机制

  我们通过使得子进程在前台和后台运行,可以观察到父子进程的启动机制,示例如下:

1、子进程后台运行

  我们需要把子进程放入后台运行,有两种方式,都是以父进程自杀的方式,来使得子进程被 systemd 托管的方式。如下, 直接执行 httpd 程序,可以看到 httpd 被放在了后台执行,这时候你也许没有看到 httpd 父进程被杀死的过程,因为 速度 太快了。同时使用 & 放入后台同样也是会杀死父进程,详细可见如下验证。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z7tTeNTz-1720453881932)(https://i-blog.csdnimg.cn/direct/08bf3b8287df4b44806328c5d3fd5309.gif#pic_center)]
  这里我们通过 循环启动 进程的方式,可以看到当前 bash 下,确实通过我们的命令产生了 httpd 的主进程,且被杀死,所以“孤儿进程”产生了,此时 systemd 上帝进程就成为了其他 httpd 进程的父进程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wbk6X2Kp-1720453881937)(https://i-blog.csdnimg.cn/direct/c754a64d9bc7452281278c2b330743e9.gif#pic_center)]
  & 同理,通过执行 命令 & 启动进程的时候,可以看到,另开了一个 bash 终端运行进程,随后子进程杀死父进程成为后台进程,如上述 逻辑一致 ,当然 & 也可以使进程挂在当前 bash 后台而不杀死 bash,但它也不会被 systemd 托管,这取决于子进程的 行为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l1jMsgbR-1720453881938)(https://i-blog.csdnimg.cn/direct/d68ad795097b44d9b75ebfa3e13b0137.gif#pic_cente =110%x)]

  如果使用上帝进程启动后台运行 httpd 会是什么情况呢?为了验证这个问题,我们可以修改 httpd 的 服务文件 ,它通过 $OPTIONS DFOREGROUND 的参数前台运行程序,去掉后再用 systemctl 的方式启动进程检查结果。

[root@ECS-PROXY ~] vim /usr/lib/systemd/system/httpd.service

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1P4JTBot-1720453881939)(https://i-blog.csdnimg.cn/direct/0eff9cbb73864574ae0c532c29c1d207.png#pic_center =70%x)]
  可以看到,只有当用 systemd 快速启动 进程时,你才能观察到 httpd 进程被杀死,说明在 systemd 进程启动模式下,只会给进程 分配 一个父进程,当父进程被杀死,它不会 接管 孤儿进程,这与用户启动进程的行为不同。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opbEPeq5-1720453881940)(https://i-blog.csdnimg.cn/direct/61fbde392cf54b358c29d41a7dca6ceb.gif#pic_center)]

2、子进程前台运行

  当子进程前台运行时,就会阻塞父进程 bash 界面,用户 不能输入 命令,子进程就会一直运行,直至终止。而当子进程后台运行时,结果就截然不同了。
  通过 -DFOREGROUND 参数可以实现进程前台运行的目的,如下可以看到当进程前台运行时, 阻塞 界面,父进程不会被杀死,当父进程退出,子进程会收到父进程的信号,跟着退出,不会成为后台进程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FYhufdn-1720453881940)(https://i-blog.csdnimg.cn/direct/390456730a6b43d490d1c0f511f59f5a.gif#pic_center)]

结论:

  • 子进程需要杀死父进程,首先成为“孤儿进程”,从而被 systemd 托管才能后台运行。
  • 由 systemd 上帝进程运行的进程必须 前台执行 ,因为 systemd 只会分配一个父进程给它,如果子进程为了后台运行把父进程杀死,那么 systemd 不会继续分配,而是直接杀死子进程进行回收。
  • 子进程前台运行会阻塞界面,但是父进程不会被杀死,父进程消亡,子进程跟着消亡, 不会进入 后台。

三、Docker 容器管理与 Linux 进程机制的联系

  在Docker 容器中进程管理引用了 Linux 的 PID 命名空间 管理方式,每一个容器都是一个 独立 的 PID 命名空间,每个空间内的 PID 号可以 重复 ,以这种方式 隔离容器应用
  在容器内启动的 第一个 进程就会成为上帝进程 (PID=1) ,他的行为与 Linux 系统的 systemd 行为一致,如上述结论。Docker 的守护进程会时刻 监视 PID=1 的容器进程,只要它停止了,容器就会停止运行,所以需要保持根进程 活跃 ,不能停止。
  如果使用 Docker 的新手不了解上述的 Linux 进程管理机制,在使用容器时,就会出现容器无论如何启动不了的问题。这都是因为在 Docker 中,容器应用的根进程 必须 在前台运行,否则根进程后台启动完子进程后会自杀,导致容器无法正常启动,进入容器使用 bash 后台启动应用同理,一旦退出容器,bash 就会自动消亡,与上述逻辑一致。
  下面进行演示:

1、容器错误启动方式:后台启动应用

  当你使用 bash 进入容器后,后台启动应用,用户在容器内应用正常运行,一旦退出容器或者 bash 因为其他原因而消亡,应用也不会由于父进程的消亡去找 systemd 托管,因为每个 PID 命名空间都是独立管理程序的,在这里 bash 就是上帝进程,之后 Docker 守护进程检测不到 PID = 1 的进程存在,也会终止容器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-51Nm8Zza-1720453881941)(https://i-blog.csdnimg.cn/direct/0c56651c07ed4ae98a211076cc47f446.gif#pic_center)]

   这里使用了 watch -n 1 docker exec test ps -ef 监视了容器内的应用,可以注意到其 PPID 父进程 ID 为 0 ,说明其父进程不在容器内。以 bash 后台启动应用后退出容器就会停止。

2、容器正确的启动方式:前台运行进程

  正常创建容器进入,以 bash 运行前台进程 nginx,可以看到 bash 被阻塞,此时按 crtl + p,crtl + q 可以退出容器,退出后可以看到容器内进程前台运行中,容器没有被 Docker 守护进程 停止,这才是容器正确的打开方式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r6vcnzpZ-1720453881941)(https://i-blog.csdnimg.cn/direct/3e934dcb27b84367ab14891a06dc8772.gif#pic_center)]

3、官方推荐的容器启动方式

apache 官方 Dockerfile 推荐写法:
ENTRYPOINT [ "/usr/sbin/apache2" ]  
CMD ["-D""FOREGROUND"]  										
# 让 apache 以前台方式运行

nginx 官方 Dockerfile 推荐写法:
ENTRYPOINT [ "/usr/sbin/nginx""-g""daemon off;" ]  		
# daemon off; 即关闭 nginx 后台运行

  在官方的推荐 Dockerfile 文件中,都表明了自动化 构建 Docker 镜像的过程中,需要让根进程以前台的方式运行,这就不会导致 Docker 容器的 错误停止


总结

  本文科普了 Linux 的 进程管理机制 ,特别是 Systemd 的进程管理、 父子进程关系 、僵尸进程问题以及信号通信,进而研究了一些机制在 Docker 容器化技术中的 应用 ,指出了容器进程管理的 最佳实践 ,包括前台运行进程的重要性和避免 错误停止 容器的方法。


  文章到这里就结束了,希望我的分享能为你的技术之旅增添一抹亮色。如果你喜欢这篇文章,请点赞收藏支持我,给予我前行的动力!🚀



  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值