页面加载中,请稍候
来源:开源Linux发布时间:2022-11-221327浏览
询问 AI

其实你没有错,错的是 docker,它执行的太快了
这话怎么说呢,我拿 nginx 官方的 dockerfile 给你解释下。

上面是 nginx 官方的 dockerfile 文件,我把set部分删掉了,其他没啥,主要看下CMD
为什么这里不是systemctl nginx start,或者/etc/init.d/nginx start,再或者 nginx 直接启动,而是用 daemon off 的方式启动?这是因为如果 nginx 用后台模式运行,启动的命令执行完之后,这个启动的命令就退出了,这个时候,容器也就跟着退出了。
又为什么命令执行完,容器就退出了?这个要从 Linux 内核说起。
在 Linux 操作系统中,当内核初始化完毕之后,会启动一个 init 进程,这个进程是整个操作系统的第一个用户进程,所以它的进程 ID 为 1,也就是我们常说的 PID1 进程,然后所有的用户态进程,都是这个进程的子进程,所以,整个系统的用户进程,都是由init进程作为根进程的。要了解这个PID1进程,要从以下几个概念了解:我用docker run -d nginx直接启动的

可以看到,就是Dockerfile中指定的CMD那个进程,注意:如果你启动容器的时候,指定了命令,会覆盖CMD,也就是CMD是条默认启动的命令参数,如果启动容器时指定了命令,会覆盖,当Dockerfile中有多条CMD时,执行最后一条
这个进程其实在宿主机上有一个普通的用户进程ID

之所以在容器中PID变成1,是因为linux内核提供的PID namespaces功能,如果宿主机上所有用户进程构成了一个完整的树形结构,那么PID namespaces实际上就是将这个CMD或ENTRYPOINT进程及其子进程作为另外一个分支,很显然这部分也是一个树形结构
当我们在宿主机上kill掉这个进程ID,那么整个容器便会处于退出状态
这也就解释了上面为什么命令执行完之后,容器就退出了
认真的小伙伴从上面图中看到了,我上面说linux中PID1进程为所有用户进程的父进程,但是在容器里面,通过ps命令看到的进程的父进程都是“0”,这又是为什么呢?
前面提到,容器中的进程树实际上是宿主机进程树的一棵子树,或者说分支,那么我们在宿主机上就可以找到这颗子树的父进程。

我们可以看到,这个docker容器中PID 0的进程应该就是这个containerd-shim
我们结合docker的结构图看一下

从架构图中,我们可以看到 containerd-shim 进程下还有一个 runC 进程,但是我们在上面过程中,并没有发现 runC 这个进程。runC 是 OCI 标准的一个参考实现,而 OCI Open Container Initiative,是由多家公司共同成立的项目,并由 Linux 基金会进行管理,致力于 container runtime 的标准的制定和 runc 的开发等工作。runc,是对于 OCI 标准的一个参考实现,是一个可以用于创建和运行容器的 CLI(command-line interface)工具。runc直接与容器所依赖的 cgroup/linux kernel 等进行交互,负责为容器配置cgroup/namespace 等启动容器所需的环境,创建启动容器的相关进程。事实上,Docker 容器的创建过程是这样子的 docker-containerd-shim –> runC –> entrypoint,而我们看到的最终状态是 docker-containerd-shim –> entrypoint,而runc进程创建完容器之后,自己就先退出去了,所以我们上面的过程中一直没有出现。
看到这里你应该了解,为什么你启动容器或写好的dockerfile,总是刚启动就退出,而且没有任何错误了吧!
新闻来源:开源Linux,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!
2026-06-08

2026-06-08
2026-07-08