为什么Docker容器会立即退出


239

我在后台运行一个容器

 docker run -d --name hadoop h_Service

它迅速退出。但是,如果我在前台运行,则可以正常运行。我使用检查了日志

docker logs hadoop

没有错误。有任何想法吗?

DOCKERFILE

 FROM java_ubuntu_new
 RUN wget http://archive.cloudera.com/cdh4/one-click-install/precise/amd64/cdh4-repository_1.0_all.deb
 RUN dpkg -i cdh4-repository_1.0_all.deb
 RUN curl -s http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh/archive.key | apt-key add -
 RUN  apt-get update
 RUN apt-get install -y hadoop-0.20-conf-pseudo
 RUN dpkg -L hadoop-0.20-conf-pseudo
 USER hdfs
 RUN hdfs namenode -format
 USER root
 RUN apt-get install -y sudo
 ADD . /usr/local/
 RUN chmod 777 /usr/local/start-all.sh
 CMD ["/usr/local/start-all.sh"]

start-all.sh

 #!/usr/bin/env bash
 /etc/init.d/hadoop-hdfs-namenode start
 /etc/init.d/hadoop-hdfs-datanode start
 /etc/init.d/hadoop-hdfs-secondarynamenode start
 /etc/init.d/hadoop-0.20-mapreduce-tasktracker start
 sudo -u hdfs hadoop fs -chmod 777 /
 /etc/init.d/hadoop-0.20-mapreduce-jobtracker start
 /bin/bash

1
黄金法则是您应该防止您的dockerized服务器守护进程。大多数服务器程序包都具有强制将它们置于前台的选项,因为守护进程是正常情况。
Arnaud Meuret 2015年

无论您希望实现什么,chmod 777都是不安全错误的。您应该还原为健全的权限(在这种情况下,大约为755)。
人间

Answers:


125

一个docker容器在其主要过程完成后退出。

在这种情况下,它将在start-all.sh脚本结束时退出。我对hadoop不太了解,无法在这种情况下告诉您如何做,但是您需要要么在前台运行某些东西,要么使用诸如runit或supervisor之类的流程管理器来运行流程。

我认为,如果您未指定-d,您一定会误以为它会起作用;它应该具有完全相同的效果。我怀疑您使用稍微不同的命令启动了它,或者使用-it它会改变某些情况。

一个简单的解决方案可能是添加类似以下内容:

while true; do sleep 1000; done

到脚本末尾。但是,我不喜欢这样,因为脚本实际上应该监视启动的进程。

(我应该说我从https://github.com/sequenceiq/hadoop-docker/blob/master/bootstrap.sh窃取了该代码)


217

这帮了我大忙:

docker run -dit ubuntu

之后,我检查了使用以下命令运行的进程:

docker ps -a

用于再次连接容器

docker attach CONTAINER_NAME

提示:要退出而不停止容器类型: ^P^Q


15
@Tommy,来自docs.docker.com/engine/reference/commandline/run -d,-- detach分离模式:在后台运行命令-i,-interactive即使未连接STDIN仍保持打开状态,-t,- -tty分配伪TTY -dit只是速记

3
@ am17torres对,对不起,让我澄清一下我令人困惑的问题;d是独立的,而i是交互式的,因此d和i的组合使我感到困惑。我以为d是作为后台(非交互式)过程启动的。
汤米

2
@Tommy当这些选项组合在一起时,容器将在后台进入交互模式

2
@ Tommy,@ am17torres -di是最低要求,如果我正确理解的话,该-t选项是多余的-d
Renaud

2
实际上,如果您在未-t启用的情况下重新连接,您将看不到提示。但是由于exec每次我不注意时,我通常都会进行一次新操作。我在从Mac上拆离时遇到了问题,但也许我做错了..
Renaud

65

我想扩大或敢于说,改善 Camposer答案

当你跑步

docker run -dit ubuntu

您基本上是在交互式模式下在后台运行容器。

当您通过CTRL + D附加和退出容器(最常用的方法)时,您停止了容器,因为您刚刚杀死了使用上述命令启动容器的主要过程。

利用已经运行的容器,我将分叉另一个bash进程并通过运行获得伪TTY:

docker exec -it <container ID> /bin/bash

29

每当我希望容器在完成脚本执行后停下来时,我都会添加

&& tail -f /dev/null

在命令末尾。所以应该是:

/usr/local/start-all.sh && tail -f /dev/null

19

为什么Docker容器会立即退出?

如果要强制映像徘徊(以便调试某些内容或检查文件系统的状态),则可以覆盖入口点以将其更改为shell:

docker run -it --entrypoint=/bin/bash myimagename

18

一种不错的方法是启动在后台运行它们的进程和服务,并在wait [n ...]脚本末尾使用命令。在bash中,wait命令强制当前进程执行以下操作:

等待每个指定的进程并返回其终止状态。如果未给出n,则等待所有当前活动的子进程,并且返回状态为零。

我从塞巴斯蒂安·普亚达斯(SébastienPujadas)的麋鹿制作开始脚本中得到了这个想法

从原始问题出发,您的start-all.sh看起来像这样...

 #!/usr/bin/env bash
 /etc/init.d/hadoop-hdfs-namenode start &
 /etc/init.d/hadoop-hdfs-datanode start &
 /etc/init.d/hadoop-hdfs-secondarynamenode start &
 /etc/init.d/hadoop-0.20-mapreduce-tasktracker start &
 sudo -u hdfs hadoop fs -chmod 777 /
 /etc/init.d/hadoop-0.20-mapreduce-jobtracker start &
 wait

5

将此添加到Dockerfile的末尾:

CMD tail -f /dev/null

样本Docker文件:

FROM ubuntu:16.04

# other commands

CMD tail -f /dev/null

参考


CMD tail -f /dev/null通过它运行sh -c "..."。我们可以改用exec表格吗?即CMD ["tail", "-f", "/dev/null"]
Meglio

4

我的主意是在Dockerfile中启动一个不会立即退出的shell CMD [ "sh", "-c", "service ssh start; bash"],然后运行docker run -dit image_name。这样,(ssh)服务和容器就可以运行了。


1

read在最后添加了shell语句。这使容器的主要过程-启动外壳脚本-保持运行。


1

新增中

exec "$@"

我的shell脚本结尾是我的解决方案!


那只是意味着它将运行您的cmd,如果您的cmd只是“ bash”,那么它仍然将不起作用
Shardj

1

如果您从容器中检查Dockerfile,例如fballiano / magento2-apache-php

您会看到他在文件末尾添加了以下命令:睡1 完成

现在,我建议您这样做

docker container ls --all | grep 127

然后,您将看到docker映像是否有错误,如果以0退出,则可能需要这些将永远休眠的命令之一。


0

有多种可能的方法可以使Docker立即退出。对我来说,这是我的问题Dockerfile。该文件中有一个错误。我有ENTRYPOINT ["dotnet", "M4Movie_Api.dll]代替ENTRYPOINT ["dotnet", "M4Movie_Api.dll"]。如您所见,我在末尾错过了一个引号(“)。

为了分析问题,我启动了我的容器并迅速连接了我的容器,以便我可以看到确切的问题。

C:\SVenu\M4Movie\Api\Api>docker start 4ea373efa21b


C:\SVenu\M4Movie\Api\Api>docker attach 4ea373efa21b

其中4ea373efa21b是我的容器ID。这将我带到了实际问题上。

在此处输入图片说明

发现问题后,我不得不再次构建,还原和发布我的容器。


0

由于重复,我在这里看不到任何答案,该答案解决了将主要工作负载作为后台作业运行,然后想知道为什么Docker退出的非常常见的反模式。

简单来说,如果您有

my-main-thing &

然后取出来&在前台运行作业,或添加

wait

在脚本的末尾使其等待所有后台作业。

然后,如果主要工作负载退出,它仍然会退出,因此可能需要while true循环运行以强制其永远重启:

while true; do
    my-main-thing &
    other things which need to happen while the main workload runs in the background
    maybe if you have such things
    wait
done

(也请注意如何编写while true。看到类似while [ true ]while [ 1 ]偶然发生的愚蠢现象很常见,但并不意味着作者可能想像的那样。)


0

您需要使用-d标志运行它,以使其在后台作为守护程序运行。

docker运行-d -it ubuntu bash



-8

由于映像是Linux,因此要检查的一件事是确保容器中使用的所有shell脚本都具有unix行结尾。如果它们的末尾有^ M,则它们是Windows行的结尾。修复它们的一种方法是在/usr/local/start-all.sh上使用dos2unix将它们从Windows转换为UNIX。以交互模式运行docker可以帮助解决其他问题。您可能有文件名错字或其他东西。参见https://en.wikipedia.org/wiki/Newline

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.