假设我有以下Dockerfile:
FROM ubuntu
RUN apt-get update
RUN apt-get install -y apache2
RUN apt-get install -y mongod #pretend this exists
EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2"]
Run Code Online (Sandbox Code Playgroud)
该ENTRYPOINT命令使其apache2在容器启动时启动.我希望能够mongod在容器以命令启动时启动service mongod start.但是根据文档,ENTRYPOINTDockerfile中必须只有一个.那么这样做的正确方法是什么?
Pie*_*ean 64
正如Jared Markell所说,如果你想在docker容器中启动多个进程,你必须使用supervisor.您必须配置主管告诉他启动您的不同流程.
我在这篇博文中写过这篇文章,但你在这里有一篇非常好的文章,详细介绍了如何以及为什么在Docker中使用supervisor.
基本上,你会想做类似的事情:
FROM ubuntu
RUN apt-get update
RUN apt-get install -y apache2
RUN apt-get install -y mongod #pretend this exists
RUN apt-get install -y supervisor # Installing supervisord
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
EXPOSE 80
ENTRYPOINT ["/usr/bin/supervisord"]
Run Code Online (Sandbox Code Playgroud)
并添加配置文件supervisord.conf
[supervisord]
nodaemon=true
[program:mongodb]
command=/etc/mongod/mongo #To adapt, I don't know how to launch your mongodb process
[program:apache2]
command=/usr/sbin/apache2 -DFOREGROUND
Run Code Online (Sandbox Code Playgroud)
编辑:由于这个答案得到了很多赞成,我想要精确地警告说,使用Supervisor 不被视为运行多个工作的最佳实践.相反,您可能有兴趣为不同的进程创建多个容器,并通过docker compose管理它们.简而言之,Docker Compose允许您在一个文件中定义应用程序所需的所有容器,并在一个命令中启动它们.
gak*_*gak 18
我的解决方案是将单个脚本放入/opt/run/并执行它们:
#!/bin/bash
LOG=/var/log/all
touch $LOG
for a in /opt/run/*
do
$a >> $LOG &
done
tail -f $LOG
Run Code Online (Sandbox Code Playgroud)
我的入口点就是这个脚本的位置,比如它的名字/opt/bin/run_all:
ADD 00_sshd /opt/run/
ADD 01_nginx /opt/run/
ADD run_all /opt/bin/
ENTRYPOINT ["/opt/bin/run_all"]
Run Code Online (Sandbox Code Playgroud)
简单的答案是你不应该因为它违反单一责任原则:一个容器,一个服务.想象一下,由于突然的工作量,你想要产生MongoDB的其他云图像 - 为什么还要以1:1的比例增加Apache2实例?相反,您应该链接框并让它们通过TCP说话.有关详细信息,请参阅https://docs.docker.com/userguide/dockerlinks/.
我无法使用&&来工作。我能够按照这里的描述解决这个问题:https : //stackoverflow.com/a/19872810/2971199
所以在你的情况下,你可以这样做:
RUN echo "/usr/sbin/apache2" >> /etc/bash.bashrc
RUN echo "/path/to/mongodb" >> /etc/bash.bashrc
ENTRYPOINT ["/bin/bash"]
Run Code Online (Sandbox Code Playgroud)
您可能需要/想要编辑启动命令。
如果您多次运行 Dockerfile,请小心,您可能不希望将多个命令副本附加到您的bash.bashrc文件中。您可以使用grepand 一个if语句来使您的RUN命令具有幂等性。
通常,您不会这样做。这是一种反模式,因为:
因此,最好的选择是创建两个单独的映像,并使用处理共享专用网络的撰写文件启动两个容器。
如果您不能遵循该最佳实践,那么您最终会遇到如下情况。父图像包含一行:
ENTRYPOINT ["/entrypoint-parent.sh"]
Run Code Online (Sandbox Code Playgroud)
并且您想将以下内容添加到您的子图像中:
ENTRYPOINT ["/entrypoint-child.sh"]
Run Code Online (Sandbox Code Playgroud)
然后将ENTRYPOINT结果图像中的 值替换为/entrypoint-child.sh,换句话说, 的值只有一个ENTRYPOINT。Docker 只会调用一个进程来启动您的容器,尽管该进程可以产生子进程。有几种技术可以扩展入口点。
选项 A:调用您的入口点,然后在最后运行父入口点,例如/entrypoint-child.sh可能如下所示:
#!/bin/sh
echo Running child entrypoint initialization steps here
/usr/bin/mongodb ... &
exec /entrypoint-parent.sh "$@"
Run Code Online (Sandbox Code Playgroud)
该exec部分很重要,它用/entrypoint-parent.sh外壳或进程替换当前外壳,从而消除信号处理问题。结果是您在子入口点中运行第一个初始化,然后委托给原始的父入口点。这确实需要您跟踪父入口点的名称,可能会在基础映像的版本之间发生变化。这也意味着您将无法在 mongodb 上进行错误处理和正常终止,因为它是在后台运行的。这可能会导致错误的健康容器和数据丢失,这两种情况我都不推荐用于生产环境。
选项 B:在后台运行父入口点。这不太理想,因为除非您采取一些额外的步骤,否则您将不再对父进程进行错误处理。最简单的,这在您的/entrypoint-child.sh.
#!/bin/sh
# other initialization steps
/entrypoint-parent.sh "$@" &
# potentially wait for parent to be running by polling
# run something new in the foreground, that may depend on parent processes
exec /usr/bin/mongodb ...
Run Code Online (Sandbox Code Playgroud)
请注意,"$@"我一直使用的符号是将 的值CMD作为参数传递给父入口点。
选项 C:切换到诸如supervisord 之类的工具。我不是这个的忠实粉丝,因为它仍然意味着在你的容器中运行多个守护进程,你通常最好将它拆分成多个容器。当单个子进程不断失败时,您需要决定正确的响应是什么。
选项 D:与选项 A 和 B 类似,我经常创建一个入口点脚本目录,可以在映像构建的不同级别进行扩展。入口点本身没有变化,我只是将新文件添加到一个目录中,该目录根据文件名顺序调用。在我的场景中,这些脚本都在前台运行,我CMD在最后执行。您可以在我的基本映像 repo 中看到一个示例,特别是包含以下部分的entrypoint.d目录和bin/entrypointd.sh脚本:
# ...
for ep in /etc/entrypoint.d/*; do
ext="${ep##*.}"
if [ "${ext}" = "env" -a -f "${ep}" ]; then
# source files ending in ".env"
echo "Sourcing: ${ep}"
set -a && . "${ep}" && set +a
elif [ "${ext}" = "sh" -a -x "${ep}" ]; then
# run scripts ending in ".sh"
echo "Running: ${ep}"
"${ep}"
fi
done
# ...
# run command with exec to pass control
echo "Running CMD: $@"
exec "$@"
Run Code Online (Sandbox Code Playgroud)
然而,以上更多是为了扩展初始化步骤,而不是为了在容器内运行多个守护进程。鉴于他们每个人都有的糟糕选择和问题,我希望很清楚为什么在您的场景中运行两个容器是首选。
我可以想到几种方法:
ADD执行所有启动命令的容器 ( ) 上,然后将其放入ENTRYPOINTENTRYPOINT,这样你就可以service mongod start && /usr/sbin/apache2| 归档时间: |
|
| 查看次数: |
71788 次 |
| 最近记录: |