为啥docker容器立即退出

Posted

技术标签:

【中文标题】为啥docker容器立即退出【英文标题】:Why docker container exits immediately为什么docker容器立即退出 【发布时间】:2015-03-28 12:59:06 【问题描述】:

我在后台运行一个容器

 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

【问题讨论】:

黄金法则是你应该防止你的 dockerized 服务器守护进程。大多数服务器包都有强制它们在前台运行的选项,因为守护进程是正常情况。 无论您希望完成什么,chmod 777 都是不安全并且错误的。您应该恢复正常的权限(在这种情况下可能是 755)。 【参考方案1】:

docker 容器在其主进程完成时退出。

在这种情况下,它会在您的start-all.sh 脚本结束时退出。我对 hadoop 了解不多,无法告诉您如何在这种情况下执行此操作,但是您需要让某些东西在前台运行,或者使用诸如 runit 或 supervisord 之类的进程管理器来运行进程。

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

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

while true; do sleep 1000; done

到脚本的末尾。不过我不喜欢这样,因为脚本应该真正监控它启动的进程。

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

【讨论】:

【参考方案2】:

这对我有用:

docker run -dit ubuntu

之后,我检查了正在运行的进程:

docker ps -a

为了再次附加容器

docker attach CONTAINER_NAME

提示:对于不停止容器类型的退出:^P^Q

【讨论】:

@Tommy, from docs.docker.com/engine/reference/commandline/run -d, --detach 分离模式:在后台运行命令,-i, --interactive 即使没有附加也保持STDIN打开,-t, --tty分配一个伪 TTY -dit 只是简写 @am17torres 对,对不起,让我澄清一下我令人困惑的问题; d 是分离的,而 i 是交互式的,所以 d 和 i 的组合让我感到困惑。我认为 d 是将其作为后台(非交互式)进程启动。 @Tommy 当这些选项组合在一起时,容器将在后台进入交互模式 @Tommy, @am17torres -di 是最低要求,如果我理解正确,-t 选项与-d 一起使用时是多余的 实际上,如果您在未启用-t 的情况下重新连接,您将无法看到提示...但由于我通常exec 每次我没有注意到时都会重新连接。我在与 Mac 分离时遇到了问题,但也许我做错了..【参考方案3】:

我想扩展或敢说,改进camposer提到的答案

当你运行时

docker run -dit ubuntu

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

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

利用已经在运行的容器,我只需 fork 另一个 bash 进程并通过运行获得伪 TTY:

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

这个想法是从 Sébastien Pujadas 的start script for his elk build 那里得到的。

从最初的问题来看,你的 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

【讨论】:

这在 docker-compose 中也有同样的问题,使用--wait wait 命令不同于可能的--wait 选项,这不是大多数命令的标准选项。 你能澄清哪个命令有 --wait 选项吗?我正在使用 docker-compose,但我的图像和 compose 文件都没有任何命令或入口点。我们更喜欢在没有任何入口点的情况下启动容器,然后单独启动我们的服务(不是作为容器启动的一部分自动启动)。但显然对于撰写,命令或入口点是强制性的。试图理解这个 --wait 是什么。【参考方案6】:

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

【讨论】:

【参考方案7】:

每当我希望容器在完成脚本执行后保持运行时,我都会添加

&& tail -f /dev/null

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

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

【讨论】:

这个可以解决,但是不知道这个命令会不会导致内存泄漏或者其他问题?与运行while true; do sleep 1; done;相比如何?【参考方案8】:

添加

exec "$@"

在我的 shell 脚本末尾是我的修复!

【讨论】:

这只是意味着它会运行你的 cmd,如果你的 cmd 只是 'bash' 那么它仍然无法工作【参考方案9】:

有许多可能的方法可以让 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。这使我想到了实际问题。

发现问题后,我不得不重新构建、恢复、发布我的容器。

【讨论】:

【参考方案10】:

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

如果您想强制图像挂起(为了调试某些东西或检查文件系统的状态),您可以覆盖入口点以将其更改为 shell:

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

【讨论】:

我使用--entrypoint的时候只能停留3秒,还能保持更多吗? 这应该保持它运行直到 bash 进程退出。您的图片是否由于某种原因没有/bin/bash 是的,一旦我的 bash 进程结束,它就退出了。我认为这就是它的设计方式。 docker exec -it MyAvalanche /bin/avalanche【参考方案11】:

将此添加到 Dockerfile 的末尾:

CMD tail -f /dev/null

示例 Docker 文件:

FROM ubuntu:16.04

# other commands

CMD tail -f /dev/null

Reference

【讨论】:

CMD tail -f /dev/null 通过sh -c "..." 运行它。我们可以改用exec 表格吗? IE。 CMD ["tail", "-f", "/dev/null"] 它对我有用【参考方案12】:

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

您会看到他在文件的末尾添加了以下命令: 虽然是真的;睡一觉;完成

现在,我建议你这样做

docker container ls --all | grep 127

然后,你会看到你的 docker 镜像是否有错误,如果它以 0 退出,那么它可能需要这些将永远休眠的命令之一。

【讨论】:

【参考方案13】:

我在最后添加了read shell 语句。这样可以保持容器的主进程——启动 shell 脚本——运行。

【讨论】:

【参考方案14】:

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

简单来说,如果你有

my-main-thing &

然后要么取出&amp; 在前台运行作业,要么添加

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 ] 这样的愚蠢的东西碰巧起作用,但并不意味着作者可能想象的他们应该是什么意思。)

【讨论】:

@BrianOlsen 2017 提到了添加 --wait。仍然是一个很好的答案。 如果你有一个支持同名选项的命令,它肯定会有用;但它不会扩展到您没有该选项的情况。我不清楚答案是否应该只建议 wait 没有破折号,但如果是这样,希望这至少可以作为一个澄清。 你是对的,无论如何你得到了我的支持。您的答案不是重复的,它显示了使用wait 的直接方式。您的回答更清楚地说明了等待解决现有问题的原因:对所有后台作业保持清醒。 感谢您回复我的澄清,非常感谢。【参考方案15】:

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

docker run -d -it ubuntu bash

【讨论】:

docker run -d -it ubuntu 对我有用。 伙计,你拯救了我的一天!我能够在 Windows 上运行 Microsoft 的 mcr.microsoft.com/windows/servercore:ltsc2019 图像。 如果使用-d 运行,-it 选项基本上会被忽略。【参考方案16】:

如果您只需要让容器运行而不退出,只需运行

docker run -dit --name MY_CONTAINER MY_IMAGE:latest

然后

docker exec -it MY_CONTAINER /bin/bash

你将在容器的bash shell 中,它不应该退出。

或者如果在docker-compose期间退出,使用

command: bash -c "MY_COMMAND --wait"

正如这里其他两个答案已经说明的那样(虽然没有那么清楚地指代 docker-compose,这就是为什么我仍然再次提到“等待”技巧)。

【讨论】:

以上是关于为啥docker容器立即退出的主要内容,如果未能解决你的问题,请参考以下文章

为啥docker容器内无法启动tomcat,容器外可以

为啥不需要在 Docker 容器中运行 sshd

前端应用容器化部署 Docker

如何在Docker容器中运行Nginx而不停止?

docker之docker-compose——容器管理

Docker Compose 保持容器运行