我正在设置一个简单的图像:一个保存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。
答案 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 start
和tail -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
,因为我总是使用启动文件。