39

我正在设置一个简单的图像:一个包含 Riak(一个 NoSQL 数据库)的图像。riak start该映像以 CMD形式启动 Riak 服务。现在,如果我将它作为守护进程运行docker run -d quintenk/riak-dev,它会启动 Riak 进程(我可以在日志中看到)。但是,它会在几秒钟后自动关闭。如果我使用docker run -i -t quintenk/riak-dev /bin/bash未启动的 riak 进程运行它(更新:请参阅答案以获得对此的解释)。事实上,根本没有任何服务在运行。我可以使用终端手动启动它,但我希望 Riak 自动启动。我认为其他服务也会发生这种行为,Riak 只是一个例子。

因此,运行/重启容器应该会自动启动 Riak。设置它的正确方法是什么?


作为参考,这里是可以用来创建图像的 Dockerfile(更新:使用选择的答案进行更改):

FROM ubuntu:12.04
RUN apt-get update
RUN apt-get install -y openssh-server curl 
RUN curl http://apt.basho.com/gpg/basho.apt.key | apt-key add -
RUN bash -c "echo deb http://apt.basho.com precise main > /etc/apt/sources.list.d/basho.list"
RUN apt-get update
RUN apt-get -y install riak
RUN perl -p -i -e 's/(?<=\{http,\s\[\s\{")127\.0\.0\.1/0.0.0.0/g' /etc/riak/app.config
EXPOSE 8098 
CMD /bin/riak start && tail -F /var/log/riak/erlang.log.1

编辑: -f 根据 sesm 他的评论在 CMD 中更改为 -F


我自己的答案

在使用 Docker 一段时间后,我养成了使用 supervisord 来调整我的进程的习惯。如果您想要示例代码,请查看https://github.com/Krijger/docker-cookbooks。我使用我的主管图像作为我所有其他图像的基础。我在这里写了关于使用主管的博客。

4

6 回答 6

45

要保持 docker 容器运行,您需要在前台保持一个进程处于活动状态。

因此,您可能可以将 Dockerfile 中的最后一行替换为

CMD /bin/riak console

甚至

CMD /bin/riak start && tail -F /var/log/riak/erlang.log.1

请注意,您不能有多行 CMD 语句,只能运行最后一个。

于 2013-07-16T09:43:00.343 回答
32

使用 tail 保持容器存活是一种 hack。另外,请注意,带有-f选项的容器将在日志轮换发生时终止(这可以通过使用-F来避免)。

更好的解决方案是使用supervisor。查看有关在 Docker 容器中运行 Riak 的教程。

于 2013-10-09T13:39:05.293 回答
5

“如果我使用 docker run -i -t quintenk/riak-dev /bin/bash 运行它,则不会启动 riak 进程”

听起来您只想在附加到容器时能够监视日志。我的用例有点不同,我希望命令自动启动,但我希望能够附加到容器并位于 bash shell 中。我能够解决我们的两个问题,如下所示:

在图像/容器中,将要自动启动的命令添加到/etc/bash.bashrc文件末尾。

在您的情况下,只需添加 line /bin/riak start && tail -F /var/log/riak/erlang.log.1,或根据所需的功能将/bin/riak startand放在单独的行上。tail -F /var/log/riak/erlang.log.1

现在将您的更改提交到您的容器,并使用以下命令再次运行它:docker run -i -t quintenk/riak-dev /bin/bash。您会发现您在 bashrc 中输入的命令在您附加时已经在运行。

于 2013-11-09T05:44:33.133 回答
4

解释:

如果我使用docker run -i -t quintenk/riak-dev /bin/bashriak 运行它,进程未启动

如下。在 Dockerfile 中使用 CMD 实际上与使用docker run {image} {command}. 正如 Gigablah 所说,只使用了最后一个 CMD,所以在这种情况下,写在 Dockerfile 中的那个会被覆盖。

通过CMD /bin/riak start && tail -f /var/log/riak/erlang.log.1在 Buildfile 中使用,您可以使用 将容器作为后台进程启动docker run -d {image},这就像一个魅力。

于 2013-07-29T16:00:22.030 回答
3

因为我想要一种干净的方式让进程稍后退出,所以我将最后一个命令调用到 shell read,这会导致该进程阻塞,直到我稍后附加到它并按 Enter 键。

arthur@macro:~/docker$ sudo docker run -d -t -i -v /raid:/raid -p 4040:4040 subsonic /bin/bash -c 'service subsonic start && read -p "waiting"'
WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: [8.8.8.8 8.8.4.4]
f27229a260c9

arthur@macro:~/docker$ sudo docker ps                                                                                                                                     
[sudo] password for arthur: 
ID                  IMAGE               COMMAND                CREATED              STATUS              PORTS
35f253bdf45a        subsonic:latest     /bin/bash -c service   2 days ago          Up 2 days           4040->4040

arthur@macro:~/docker$ sudo docker attach 35f253bdf45a

arthur@macro:~/docker$ sudo docker ps                                                                                                                                     
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS

如您所见,容器在附加到它并取消阻止读取后退出。您当然可以使用比read -p您需要进行其他清理(例如停止服务和保存日志等)更复杂的脚本。

于 2013-10-14T17:15:53.917 回答
0

每当我开始构建一个新的 docker 容器时,我都会使用一个简单的技巧。为了让它保持活力,我在入口点脚本中使用了 ping。

因此,在 Dockerfile 中,例如,当使用 debian 时,我确保可以 ping。顺便说一句,检查容器内可以访问的内容总是很好。

...
RUN DEBIAN_FRONTEND=noninteractive apt-get update \
 && apt-get install -y iputils-ping 
...
ENTRYPOINT ["entrypoint.sh"]

在 entrypoint.sh 文件中

#!/bin/bash
...
ping 10.10.0.1 >/dev/null 2>/dev/null

我使用它而不是CMD bash,因为我总是使用启动文件结束。

于 2018-03-22T08:28:10.507 回答