docker容器必须要有前台进程

前言

环境:centos7.9 docker-ce-20.10.9 kubernetes-version v1.22.6

容器应用必须以前台方式运行

每个docker容器必须要有一个前台进程一直运行,因为docker容器并不是虚拟机,是利用linux的cgroup和namespace隔离的,在宿主机上本质是个隔离的进程,例如一个容器的主进程是启动nginx,使用命令systemctl start nginx启动nginx,这句shell充当了主进程,fork了一个子进程启动了nginx后这个shell就退出了,nginx是shell的子进程,主进程消亡子进程也就停止了,容器也就会一运行就exited了。执行完成systemctl start nginx这个命令也就几秒钟,容器就退出了。
Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。

使用nohup ./start & 这种命令运行程序也是后台进行,容器中的进程就会退出。

所以,我们在写dockerfile时,启动程序一定不能以后台方式运行程序,所以你会看到官方的apache、nginx的Dockerfile都是这样写的:

apache的官方docker是这样写的:
ENTRYPOINT [ "/usr/sbin/apache2" ]  
CMD ["-D""FOREGROUND"]  										#让apache以前台方式运行

nginx的官方Dockerfile是这样写的:
ENTRYPOINT [ "/usr/sbin/nginx""-g""daemon off;" ]  		#"daemon off;就是要关闭nginx后台运行

演示案例

下面将进行一个活生生的案例演示,是本人在k8s上部署redis集群时遇到的活生生的案例:

准备好两个redis.conf文件,简记为redis.conf1 ,redis.conf2, redis.conf1内容较少,redis.conf2 内容较多。

redis.conf1 的内容如下:
在这里插入图片描述

redis.conf2 的内容如下:
在这里插入图片描述

两者除了内容参数多点少点没什么区别,redis.conf配置文件是通过configmap卷的形式挂载到容器中,供redis启动使用,yaml中容器的启动命令是这样写的:redis-server /etc/redis/redis.conf,如下图:

在这里插入图片描述
问题就在于,使用redis.conf1配置文件创建的sts能正常启动pod,而使用redis.conf2配置文件创建的sts发现pod一直处于 CrashLoopBackOff 状态,pod一直重启,由于容器根本没有启动,所以根本不存在查看容器日志这一说,kubectl describe pods redis-sts-0 查看pod的信息,发现pod其实已经被调度到node2上,redis镜像也已经下载完成,但是kubelet启动容器失败,查看node2上的kubelet服务,发现了以下报错:

在这里插入图片描述

但是视乎看不出什么问题,继续排查,现在问题已经定位为我们的redis.conf2配置文件存在问题,但是具体是什么问题呢,是redis.conf2配置文件不能用导致redis启动不了还是什么?问题暂时排查不出来,redis的启动命令都一样的,说明不是容器启动命令的问题。
找不到具体原因,这样,暂且不在容器启动命令里写redis-server /etc/redis/redis.conf,我们暂时使用 sleep 999999 命令启动容器,然后进入到容器里面启动redis 看看能不能启动redis服务,如下所示,发现能正常创建pod,容器里面启动执行redis-server /etc/redis/redis.conf 也能正常启动redis。说明什么呢?同样的redis.conf2文件同样的redis /etc/redis/redis.conf启动命令,放在yaml里面不能正常启动pod,在容器里面就能正常启动。

后来仔细研究发现,原来,这是因为我们的redis.conf2里面有一个很重要的参数,即:daemonize 参数,因为这个redis.conf2配置文件是从实际生产环境拷贝过来的,我们也知道,在实际生产环境中redis一般是以后台方式运行的,所以这个参数设置为 “daemonize yes ” 了,但是,在容器中,“daemonize no ”,这个参数必须设置为是no,即关闭redis后台方式运行,设置为no,就是让redis以前台方式运行,我们在redis.conf1中并没有配置这个参数,redis.conf1就能正常启动pod,那是因为不写这个参数官方默认daemonize就为no。
这就解释通了为什么开头提的pod一直处于 CrashLoopBackOff 状态,pod一直重启,这是因为redis 进程被设置为后台运行了,容器里没有前台运行的程序,这样启动完redis就退出了,而容器重启策略设置为了always,导致kubelet一直重启容器。

总结

1、容器进程要以前台方式运行,因为如果你以后台运行;
2、如果程序的启动要指定配置文件,如redis服务启动时使用redis.conf,那么redis.conf配置文件里面一定要配置redis服务以前台方式运行。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值