219

我看过一堆教程,它们似乎和我想做的事情一样,但由于某种原因,我的 Docker 容器退出了。基本上,我在 Docker 容器中设置了一个 Web 服务器和一些守护进程。我通过一个 bash 脚本来完成最后的部分,该脚本run-all.sh在我的 Dockerfile 中通过 CMD 运行。run-all.sh看起来像这样:

service supervisor start
service nginx start

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

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

我可以看到,当我手动运行时(即使用 -i -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 循环来保持它,但是阻止它退出的正确方法是什么?

4

13 回答 13

288

如果您使用的是 Dockerfile,请尝试:

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

(显然这仅用于开发目的,除非容器正在运行一个进程,例如 nginx ...,否则您不需要保持容器处于活动状态。)

于 2017-03-18T11:33:39.097 回答
117

我刚刚遇到了同样的问题,我发现如果您使用-tand-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只是让您在后台运行容器。

于 2016-04-26T17:50:31.820 回答
58

这不是你应该如何设计 Docker 容器的方式。

在设计 Docker 容器时,您应该构建它以便只运行一个进程(即您应该有一个用于 Nginx 的容器,一个用于 supervisord 或它正在运行的应用程序);此外,该进程应该在前台运行。

当进程本身退出时,容器将“退出”(在您的情况下,该进程是您的 bash 脚本)。


但是,如果您确实需要(或想要)在 Docker 容器中运行多个服务,请考虑从“Docker Base Image”开始,它runit用作伪初始化进程(runit将在 Nginx 和 Supervisor 运行时保持在线),它将保持在前台,而你的其他进程做他们的事情。

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

于 2014-09-10T21:31:53.473 回答
45

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

你可以使用supervisor来做任何事情,如果使用“-n”标志运行它被告知不要守护进程,所以它将保持作为第一个进程:

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

还有你的supervisord.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 的情况下使用 supervisord 并且将它们分开没有多大意义。

于 2015-06-03T23:39:16.913 回答
45

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

于 2016-07-10T14:05:46.467 回答
25

动机:

docker 容器内运行多个进程没有任何问题。如果有人喜欢将 docker 用作轻量级 VM - 就这样吧。其他人喜欢将他们的应用程序拆分为微服务。我想:一个容器中的 LAMP 堆栈?太好了。

答案:

坚持使用好的基础镜像,比如phusion 基础镜像。可能还有其他人。请评论。

这只是对主管的又一次恳求。因为除了 cron 和 locale 设置等其他一些东西之外,phusion 基础映像还提供了主管。在运行如此轻量级的 VM 时,您喜欢设置的东西。值得一提的是,它还为容器提供了 ssh 连接。

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

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 stop.

很简单sleep,或者在容器被docker 强行杀死cat之前需要几秒钟。

更新

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

这是一个意见。文档指向这个方向。一句话:“拥有多个进程是可以的,但要从 Docker 中获得最大收益,请避免一个容器负责整个应用程序的多个方面。” 当然,将复杂的服务分成多个容器显然要强大得多。但在某些情况下,走一条集装箱路线可能会有所帮助。特别是对于电器。GitLab Docker镜像是我最喜欢的多进程容器示例。它使这个复杂系统的部署变得容易。没有办法配置错误。GitLab 保留对其设备的所有控制权。双赢。

于 2019-04-17T19:08:09.510 回答
13

确保您添加daemon off;到您的 nginx.conf 或CMD ["nginx", "-g", "daemon off;"]按照官方 nginx 映像运行它

然后使用以下命令将主管作为服务和 nginx 作为前台进程运行,这将阻止容器退出

service supervisor start && nginx

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

因此,您需要了解权衡并做出相应的决定。

于 2014-11-04T12:58:21.207 回答
5

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

wait $NGNIX_PID 

这样,您的容器应该一直运行到 ngnix 还活着,当 ngnix 停止时,容器也会停止

于 2017-12-18T15:27:39.953 回答
2

除了在您的 docker 文件中包含类似 :的内容外,您还应该使用选项ENTRYPOINT ["tail", "-f", "/dev/null"]运行 docker 容器。-td这在容器在远程 m/c 上运行时特别有用。把它想象成你已经 ssh'ed 到一个具有图像的远程 m/c 并启动了容器。在这种情况下,当您退出 ssh 会话时,容器将被杀死,除非它使用-td选项启动。运行图像的示例命令是:docker run -td <any other additional options> <image name>

这适用于 docker 版本20.10.2

于 2021-01-17T15:15:58.707 回答
2

由于 docker engine v1.25 有一个选项叫做init. Docker
-compose从.version 3.7

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

CMD ["sleep", "infinity"]

然后使用以下命令运行它:

docker build
docker run --rm --init app

crf.: rm 文档初始化文档

于 2022-01-18T12:50:58.677 回答
0

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

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

while true; do
  sleep 100
done

随着开发的进展,你会用更严肃的东西来代替它。

于 2021-02-19T15:52:51.053 回答
0

这 4 个命令都可以使您的 docker 容器保持运行:

docker run -td <image>
docker run -dt <image>
docker run -t -d <image>
docker run -d -t <image>
于 2022-01-17T12:52:48.997 回答
-1

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

服务 YOUR_SERVICE 监督

一旦 supervise 成功运行,它不会退出,除非它被杀死或特别要求退出。

节省必须创建一个supervisord.conf

于 2019-09-17T11:32:20.607 回答