我试图从部署一个旨在在桌面用户上运行的应用程序的角度开始围绕 Docker 进行思考。我的应用程序只是一个烧瓶 Web 应用程序和 mongo 数据库。通常我会在虚拟机中安装两者,并将主机端口转发到来宾 Web 应用程序。我想尝试一下 Docker,但我不确定我打算如何使用多个程序。文档说只能有 ENTRYPOINT 所以我怎么能有 Mongo 和我的烧瓶应用程序。或者它们是否需要在单独的容器中,在这种情况下它们如何相互通信以及这如何使分发应用程序变得容易?
8 回答
ENTRYPOINT 只能有一个,但该目标通常是一个脚本,它可以启动尽可能多的程序。您还可以使用例如Supervisord或类似工具来负责在单个容器内启动多个服务。这是一个在单个容器中运行 mysql、apache 和 wordpress 的 docker 容器示例。
假设您有一个数据库供单个 Web 应用程序使用。那么在单个容器中运行两者可能更容易。
如果您有一个由多个应用程序使用的共享数据库,那么最好在其自己的容器中运行数据库,并在各自的容器中运行应用程序。
当应用程序在不同的容器中运行时,至少有两种可能性可以相互通信:
- 使用暴露的 IP 端口并通过它们连接。
- 最近的 docker 版本支持链接。
我强烈不同意以前的一些解决方案,这些解决方案建议在同一个容器中运行这两种服务。文档中明确指出不建议这样做:
通常建议您通过每个容器使用一项服务来分隔关注区域。该服务可能会分叉成多个进程(例如,Apache Web 服务器启动多个工作进程)。拥有多个进程是可以的,但要从 Docker 中获得最大收益,请避免一个容器负责整个应用程序的多个方面。您可以使用用户定义的网络和共享卷连接多个容器。
supervisord 或类似程序有很好的用例,但运行 Web 应用程序 + 数据库不是其中的一部分。
您绝对应该使用docker-compose来执行此操作并编排具有不同职责的多个容器。
我对运行 LAMP 堆栈、Mongo DB 和我自己的服务有类似的要求
Docker 是基于操作系统的虚拟化,这就是为什么它将容器隔离在一个正在运行的进程周围,因此它需要至少一个进程在 FOREGROUND 中运行。
因此,您提供自己的启动脚本作为入口点,因此您的启动脚本成为扩展的 Docker 映像脚本,您可以在其中堆叠任意数量的服务,直到启动至少一个前台服务,这太接近结束了
所以我的 Docker 镜像文件最后有两行:
COPY myStartupScript.sh /usr/local/myscripts/myStartupScript.sh
CMD ["/bin/bash", "/usr/local/myscripts/myStartupScript.sh"]
在我的脚本中,我运行所有 MySQL、MongoDB、Tomcat 等。最后,我将 Apache 作为前台线程运行。
source /etc/apache2/envvars
/usr/sbin/apache2 -DFOREGROUND
这使我能够启动所有服务并使容器保持活动状态,最后一个服务开始在前台
希望能帮助到你
更新:自从我上次回答这个问题以来,像Docker compose这样的新东西出现了,它可以帮助您在自己的容器上运行每个服务,但将所有服务绑定在一起作为这些服务之间的依赖关系,尝试了解更多关于docker-compose和使用它,除非您的需要与它不匹配,否则它是更优雅的方式。
虽然不建议您使用wait
. 只需制作一个包含以下内容的 bash 脚本。例如start.sh
:
# runs 2 commands simultaneously:
mongod & # your first application
P1=$!
python script.py & # your second application
P2=$!
wait $P1 $P2
在您的 Dockerfile 中,以
CMD bash start.sh
如果您想同时运行多个进程,我建议您设置一个本地 Kubernetes 集群。您可以通过为他们提供一个简单的 Kubernetes 清单来“分发”应用程序。
它们可以在单独的容器中,实际上,如果应用程序还打算在更大的环境中运行,它们可能会。
多容器系统需要更多的编排才能调出所有必需的依赖项,尽管在 Docker v0.6.5+ 中,有一个新的工具可以帮助 Docker 本身内置 - Linking。然而,对于多机解决方案,它仍然必须从 Docker 环境之外进行安排。
使用两个不同的容器,这两个部分仍然通过 TCP/IP 进行通信,但除非端口已被明确锁定(不推荐,因为您无法运行多个副本),否则您必须传递新端口数据库已向应用程序公开,以便它可以与 Mongo 通信。这又是 Linking 可以帮助解决的问题。
对于更简单的小型安装,所有依赖项都在同一个容器中,数据库和 Python 运行时由最初称为 ENTRYPOINT 的程序启动也是可能的。这可以像 shell 脚本或其他一些进程控制器一样简单——Supervisord非常流行,公共 Dockerfile 中存在许多示例。
Docker 提供了几个例子来说明如何做到这一点。轻量级选项是:
将所有命令放在一个包装脚本中,并附上测试和调试信息。将包装脚本作为您的
CMD
. 这是一个非常幼稚的例子。首先,包装脚本:
#!/bin/bash
# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_first_process: $status"
exit $status
fi
# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_second_process: $status"
exit $status
fi
# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container will exit with an error
# if it detects that either of the processes has exited.
# Otherwise it will loop forever, waking up every 60 seconds
while /bin/true; do
ps aux |grep my_first_process |grep -q -v grep
PROCESS_1_STATUS=$?
ps aux |grep my_second_process |grep -q -v grep
PROCESS_2_STATUS=$?
# If the greps above find anything, they will exit with 0 status
# If they are not both 0, then something is wrong
if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
echo "One of the processes has already exited."
exit -1
fi
sleep 60
done
接下来,Dockerfile:
FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh
我同意使用两个容器更可取的其他答案,但是如果您决心将多个服务捆绑在一个容器中,则可以使用类似 supervisord 的东西。
例如,在Hipache中,包含的 Dockerfile 运行 supervisord,文件 supervisord.conf 指定运行 hipache 和 redis-server。
如果专用脚本的开销太大,您可以使用sh -c
. 例如:
CMD sh -c 'mini_httpd -C /my/config -D &' \
&& ./content_computing_loop