我已经看到了一堆教程,似乎做同样的事情,我试图做,但出于某种原因,我的Docker容器退出。基本上,我在Docker容器中设置了一个web服务器和几个守护进程。我通过一个名为run-all.sh的bash脚本来完成最后的部分,我在Dockerfile中通过CMD运行该脚本。Run-all.sh看起来像这样:

service supervisor start
service nginx start

我在Dockerfile中启动它,如下所示:

CMD ["sh", "/root/credentialize_and_run.sh"]

我可以看到,当我手动运行(即使用-t /bin/bash进入映像)时,所有服务都正确启动,并且当我运行映像时,一切看起来都正确运行,但一旦它完成启动我的进程,它就退出了。我希望进程无限期地运行,据我所知,容器必须一直运行才能实现这一点。然而,当我运行docker ps -a时,我看到:

➜  docker_test  docker ps -a
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS                      PORTS               NAMES
c7706edc4189        some_name/some_repo:blah   "sh /root/run-all.sh   8 minutes ago       Exited (0) 8 minutes ago                        grave_jones

到底发生了什么事?为什么它令人兴奋?我知道我可以在bash脚本的末尾放一个while循环来保持它,但是怎样才能使它不退出呢?


这并不是你真正应该如何设计Docker容器。

在设计Docker容器时,你应该让它只有一个进程在运行(也就是说,你应该为Nginx准备一个容器,为它正在运行的应用程序准备一个容器);此外,该进程应该在前台运行。

当进程本身退出时,容器将“退出”(在您的示例中,该进程就是您的bash脚本)。


然而,如果你真的需要(或想要)在Docker容器中运行多个服务,可以考虑从“Docker Base Image”开始,它使用runit作为伪init进程(当Nginx和Supervisor运行时,runit将保持在线),当其他进程运行时,runit将保持在前台。

他们有大量的文档,所以你应该能够很容易地实现你想要做的事情。


确保你添加了daemon;或者使用CMD ["nginx", "-g", "daemon off;"根据nginx的官方图片

然后使用以下命令运行监控器作为服务,nginx作为前台进程,以防止容器退出

服务管理启动&& nginx

在某些情况下,容器中需要有多个进程,因此强制容器只有一个进程是行不通的,而且会在部署中产生更多问题。

所以你需要了解其中的利弊,并做出相应的决定。


它退出的原因是因为shell脚本首先作为PID 1运行,当它完成时,PID 1消失了,而docker只在PID 1运行时运行。

你可以使用监控器来做所有的事情,如果运行时带有“-n”标志,它会被告知不要守护进程,所以它将保持作为第一个进程:

CMD ["/usr/bin/supervisord", "-n"]

你的supervisor .conf:

[supervisord]
nodaemon=true

[program:startup]
priority=1
command=/root/credentialize_and_run.sh
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false
startsecs=0

[program:nginx]
priority=10
command=nginx -g "daemon off;"
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.log
autorestart=true

然后你可以有很多其他的进程,你想要和管理将处理重新启动他们,如果需要。

这样你就可以在需要nginx和php5-fpm的情况下使用supervisor ord,而把它们分开没有太大意义。


我刚刚遇到了同样的问题,我发现如果你运行带有-t和-d标志的容器,它会继续运行。

docker run -td <image>

下面是标志的作用(根据docker run——help):

-d, --detach=false         Run container in background and print container ID
-t, --tty=false            Allocate a pseudo-TTY

最重要的是-t标志。-d只是让你在后台运行容器。


你可以像兄弟@Sa'ad提到的那样,不带任何参数地运行plain cat,简单地让容器工作(实际上什么都不做,只是等待用户输入)(Jenkins的Docker插件也做同样的事情)


如果您正在使用Dockerfile,请尝试:

ENTRYPOINT ["tail", "-f", "/dev/null"]

(显然这只是为了开发目的,你不需要让容器保持活动状态,除非它正在运行一个进程。nginx…)


在一个变量(例如$NGNIX_PID)中捕获ngnix进程的PID,并在入口点文件do的末尾

wait $NGNIX_PID 

通过这种方式,容器应该一直运行到ngnix激活,当ngnix停止时,容器也会停止


动机:

在docker容器中运行多个进程并没有什么错。如果你喜欢使用docker作为一个轻量级的VM,那就这样吧。其他人则喜欢将他们的应用程序拆分为微服务。我想:一个容器里的LAMP堆栈?就好了。

答案是:

坚持使用一个好的基础图像,如phusion基础图像。可能还有其他的。请发表评论。

这只是另一个请求监督的请求。因为phusion base image除了提供cron和locale setup之类的东西外,还提供了监督器。当运行这样一个轻量级VM时,你想要设置的东西。它还提供了到容器的ssh连接。

phusion镜像本身将启动并继续运行,如果你发出以下基本的docker运行语句:

moin@stretchDEV:~$ docker run -d phusion/baseimage
521e8a12f6ff844fb142d0e2587ed33cdc82b70aa64cce07ed6c0226d857b367
moin@stretchDEV:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS
521e8a12f6ff        phusion/baseimage   "/sbin/my_init"     12 seconds ago      Up 11 seconds

或者非常简单:

如果基本图像不适合你……对于快速CMD,让它保持运行,我认为bash是这样的:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

或者busybox是这样的:

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"

这很好,因为它将在docker停止时立即退出。

在集装箱被码头工人强行杀死之前,只是单纯的睡眠或猫将需要几秒钟。

更新

作为对Charles Desbiens关于在一个容器中运行多个进程的回应:

This is an opinion. And the docs are pointing in this direction. A quote: "It’s ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application." For sure it obviously much more powerful to devide your complex service into multiple containers. But there are situations where it can be beneficial to go the one container route. Especially for appliances. The GitLab Docker image is my favourite example of a multi process container. It makes deployment of this complex system easy. There is no way for mis-configuration. GitLab retains all control over their appliance. Win-Win.


如果可以的话,使用监督形式的服务怎么样?

service YOUR_SERVICE监督

一旦supervise成功运行,它就不会退出 被杀或被特别要求离开。

省去了创建supervisor .conf文件的麻烦


Along with having something along the lines of : ENTRYPOINT ["tail", "-f", "/dev/null"] in your docker file, you should also run the docker container with -td option. This is particularly useful when the container runs on a remote m/c. Think of it more like you have ssh'ed into a remote m/c having the image and started the container. In this case, when you exit the ssh session, the container will get killed unless it's started with -td option. Sample command for running your image would be: docker run -td <any other additional options> <image name>

这适用于docker 20.10.2版本


在开发过程中,有些情况下还没有服务,但您希望模拟它并保持容器处于活动状态。

编写一个bash占位符来模拟一个正在运行的服务是非常容易的:

while true; do
  sleep 100
done

随着开发的进展,你可以用一些更严重的东西来代替它。


从docker引擎v1.25开始,就有一个名为init的选项。 Docker-compose从3.7版开始包含此命令。

所以当我运行一个容器时,我当前的CMD应该运行到无穷大:

CMD ["sleep", "infinity"]

然后运行它,使用:

docker build
docker run --rm --init app

crf。 Rm文档和init文档