将docker容器作为进程来使用

1. 容器只是一个进程

使用docker部署一个mysql服务,或者一个nginx服务,这些服务是持久存在的,加上环境的隔离特性,我一直都将docker容器的使用限定在容器这个范围内。在容器内,启动某个程序对外提供服务。

但本质上,容器相对于宿主机,不过是一个进程而已。用进程的视角去看待它,我突然有了一个想法,或许早已经有人在这样做,或许我的这个思路存在一些问题,如果你对此有自己的经验和看法,欢迎你能够与我交换意见。

我的想法很简单,对于一些任务,或者一些命令,如果执行他们需要特定的环境,那么就可以将这个环境制作成docker 镜像,需要执行命令或启动任务时,启动容器,待任务或者命令执行结束后,容器自然也会退出。

前面所说的命令,你可以理解为类似spark-submit这样的命令,它需要spark环境的支持,任务,可以是一个可执行程序,一个pyhton脚本,或者一个jar包,任务不是持久存在的,任务完成进程也就随之结束。这样的思路正是想利用docker容器技术所带来的环境隔离,尤其在生产环境,一旦两个程序所依赖的环境有冲突,使用docker很容易就能够解决。

想要将想法变为现实,有两个问题需要解决:

  1. 在宿主机上获得容器内前台进程的标准输出
  2. 容器退出状态码必须和前台进程的退出状态码保持一致

2. 前台进程

容器内部必须有一个前台进程,否则容器就会退出,在使用容器部署nginx等其他服务时,都必须指定前台运行参数。

在宿主机运行前台进程时,进程的输出内容,都会输出到你的屏幕上。容器里所运行的前端进程的标准输出,你在进入容器后是看不到的,但在宿主机里,可以通过docker logs container_id 来查看。如果在使用docker run 命令启动容器时,不使用-d选项,那么docker run 启动的容器于你而言就是前台进程,容器内前台进程的标准输出会成为容器的标准输出,这样,在宿主机上,就获得了容器内前台进程的标准输出。

这份标准输出是十分有必要获得的,你可能需要根据这份标准输出来对程序的运行状态进行判断。

标准输出的问题解决了,接下来要看容器的退出状态码和容器内前台进程的退出状态码是否保持一致。先说结论,两者一致,如果不一致,那么利用docker容器执行命令或者任务的想法就是不可实施的,原因在于,需要通过这个状态码来判断命令是否被正确执行。

(base) [root]# docker run -it --rm --name test_exit centos:7 ls /root
anaconda-ks.cfg
(base) [root]# echo $?
0

ls /root 是可以被正确执行的,这个命令的退出状态码是0, 使用echo $?命令查看的是最近一条命令(docekr run)的退出状态码,也是0。接下来验证命令无法正常执行的情况

(base) [root]# docker run -it --rm --name test_exit centos:7 ls /rootsdf
anaconda-ks.cfg
(base) [root]# echo $?
2

/rootsdf 是不存在的目录,ls 不能正常执行,退出码是2,docker run命令的退出码也是2,由此可以证明,docker run 退出的状态码就是容器内前台进程的退出状态码。除此外,还有一些状态码需要关注

状态码 描述
0 正常退出
非0 表示异常退出(退出状态码采用 chroot 标准)
125 Docker 守护进程本身的错误
126 容器启动后,要执行的默认命令无法调用
127 容器启动后,要执行的默认命令不存在
137 表明容器收到了 SIGKILL 信号,进程被杀掉,对应kill -9
139 表明容器收到了 SIGSEGV 信号,无效的内存引用,对应kill -11
143 表明容器收到了 SIGTERM 信号,终端关闭,对应kill -15

两个问题都得到了解决,那么在此思路下,启动某个命令或者某个任务,就变成了使用docker run 启动一个docker容器,命令或任务结束后,docker容器也就退出,通过查看docker run 命令的退出码就可以知道命令或任务是否正确执行。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案