在docker容器中自动运行服务

时间:2013-06-22 15:31:14

标签: riak docker

我正在设置一个简单的图像:一个保存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根据他的评论

在CMD中更改为-F

我自己的答案

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

6 个答案:

答案 0 :(得分:42)

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

所以你可以用

替换你的Dockerfile中的最后一行
CMD /bin/riak console

甚至

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

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

答案 1 :(得分:31)

使用tail来保持容器存活是个黑客攻击。另请注意,使用-f选项容器将在日志轮换发生时终止(这可以通过使用-F来避免)。

更好的解决方案是使用supervisor。看看这个tutorial关于在Docker容器中运行Riak。

答案 2 :(得分:4)

解释:

  

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

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

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

答案 3 :(得分:4)

  

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

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

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

在您的情况下,只需添加行/bin/riak start && tail -F /var/log/riak/erlang.log.1,或将/bin/riak starttail -F /var/log/riak/erlang.log.1放在不同的行上,具体取决于所需的功能。

现在将更改提交到容器,然后使用:docker run -i -t quintenk/riak-dev /bin/bash再次运行它。您可以在附加时找到放在bashrc中的命令。

答案 4 :(得分:3)

因为我想要一个干净的方法让进程退出以后我将最后一个命令调用shell的 read,这会导致该进程被阻塞,直到我以后附加到它和点击进入。

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更复杂的脚本。

答案 5 :(得分: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,因为我总是使用启动文件。