一直学习,终生学习
初学者容易犯的错误:
在docker容器中主进程ID为1,而这个主进程ID就是在构建dockerfile或者run运行容器时,指定的CMD或者ENTRYPOINT中执行的命令程序,这就是docker主进程id唯一的程序。
冲突的根源在于Docker守护进程被设计用来接管很多systemd也为Linux完成的功能。包括初始化、服务激活、安全及日志。“从很多方面讲,Docker想成为systemd,”他声称,“它梦想成为systemd。
docker启动的是进程,因为所谓的后台服务应该放到前台,一个docker容器同时只能管理一个进程,docker容器仅在它的进程PID为1运行。如果进程PID1退出了,docker容器也就退出了。
docker不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机,物理机里面那样,用systemd去启动后台服务,容器内没有后台服务的概念。
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去存在的意义,然后退出,其他辅助进程不是它需要关系的东西。
不推荐一个容器中有太多服务。
容器内部的systemd
Walsh还想在Fedora、红帽企业Linux(RHEL)及CentOS容器基础镜像中启用systemd,部分是因为很多软件包需要systemctl功能以便正确安装。他一开始尝试的是使用“fakesystemd”来代替systemctl,该服务用于满足软件包的systemctl需要,没有其余的功能。结果这会造成问题,他很快就放弃了,不过还是迟了一步,未能阻止它在RHEL 7.0中发布。
在RHEL 7.1中,该团队添加了“systemd-container”,这是systemd的一个大幅度删减版本。这依然会对那些软件中需要完整systemd的用户造成问题,Poettering要求容器团队进行修改。在RHEL 7.2中,容器具有了真正的systemd,减少了需要安装的依赖,因此尺寸更小。Walsh的团队正着手进一步缩减这些依赖。
根据Walsh所说,容器中没有systemd最大的问题是它“退回到了使用初始化脚本之前。”每个镜像作者都在容器内创建自己的疯狂的启动脚本,而不是使用软件包作者精心制作的启动脚本。他演示了在具有systemd的容器内,服务初始化是何尝的简单,创建一个运行Apache httpd服务器的容器,其Dockerfile只有三行:
FROM fedora
RUN yum -y install httpd; yum clean all; systemctl enable httpd;
CMD [ "/sbin/init" ]
不过,要在Docker中使用systemd,有一个主要障碍:运行具有systemd的容器要求运行时要带有–privileged标记,这让它变得不安全。这是因为Docker守护进程要求容器运行的“服务”应用程序其PID永远是1。在具有systemd的容器中,其PID是1,应用程序则具有其他的PID,这会造成Docker认为容器失败并将其停止。
Poettering说PID 1具有特殊要求。其中之一是杀死那些被它们的调用会话所遗弃的“僵尸”进程。对Docker来说,这是一个真正的问题,因为应用程序以PID 1运行,却不处理僵尸进程。比如,运行Oracle数据库的容器可能在退出时会遗留几千个僵尸进程。另一个要求是写入syslog,除非配置容器写入日志到journald,否则将进入/dev/null。
那么为什么容器一运行就退出了啊?
这是初学 Docker 常常碰到的问题,此时还以虚拟机来理解 Docker,认为启动 Docker 就是启动虚拟机,也没有搞明白前台和后台的区别。
首先,碰到这类问题应该查日志和容器主进程退出码。
检查容器日志:
docker logs <容器ID>
查看容器退出码:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc2aa3f4745f ubuntu "/bin/bash" 23 hours ago Exited (0) 22 hours ago clever_lewin
25510a2cb171 twang2218/gitlab-ce-zh:8.15.3 "/assets/wrapper" 2 days ago Exited (127) 2 days ago determined_mirzakhani
在 STATUS 一栏中,可以看到退出码是多少。
如果看到了 Exited (127) 那很可能是由于内存超标导致触发 Out Of Memory 然后被强制终止了。
如果看到了 Exited (0),这说明容器主进程正常退出了。
如果是其他情况,应该检查容器日志。
初学 Docker 的人常常会不理解既然正常怎么会退出的意思。不得不在强调一遍,Docker 不是虚拟机,容器只是进程。因此当执行 docker run 的时候,实际所做的只是启动一个进程,如果进程退出了,那么容器自然就终止了。
那么进程为什么会退出?
如果是执行 service nginx start 这类启动后台服务程序的命令,那说明还是把 Docker 当做虚拟机了。Docker 启动的是进程,因此所谓的后台服务应该放到前台,比如应该 nginx -g ‘daemon off;’ 这样直接前台启动应用才对。
如果发现 COMMAND 一栏是 /bin/bash,那还是说明把 Docker 当虚拟机了。COMMAND 应该是应用程序,而不交互式操作界面,容器不需要交互式操作界面。此外,如果使用 /bin/bash 希望起一个交互式的界面,那么也必须提供给其输入和终端,因此必须加 -it 选项,比如 docker run -it ubuntu /bin/bash
请遵守容器的设计原则,一个容器里运行一个前台服务!
如果有不对地方,请麻烦指出,让我们一起学习吧!!!