我应该为我的 Web 应用程序使用单独的 Docker 容器吗?

Should I use separate Docker containers for my web app?

我是否需要为我的复杂 Web 应用程序使用单独的 Docker 容器,或者我可以将所有必需的服务放在一个容器中? 当我能够在一个容器中安装和启动所有内容时,谁能解释一下为什么我应该将我的应用程序划分为多个容器(例如 php-fpm 容器、mysql 容器、mongo 容器) ?

有些人会告诉您,您应该 运行 每个容器只有 1 个进程。其他人会说每个容器 1 个应用程序。这些建议基于 microservices.

的原则

我不认为微服务是适用于所有情况的正确解决方案,因此我不会出于这个原因盲目地遵循这些建议。如果在您的情况下在一个容器中有多个进程是有意义的,那么就这样做。 (参见 Supervisor and Phusion baseimage

但分离容器还有另一个原因:在大多数情况下,您要做的工作更少。

Docker Hub 上,有大量可供使用的 Docker 图片。拉你需要的就行了。

接下来您要做的是:

  • 阅读那些 docker 图片的文档(设置什么环境变量等)
  • 创建一个 docker-compose.yml 文件以简化这些容器的操作

当您将 Web 应用程序划分为多个容器时,您无需在部署应用程序时重新启动所有服务。与传统一样,您在更新 Web 层时不会重新启动 mysql 服务器。

此外,如果您想扩展您的应用程序,将您的应用程序划分为单独的容器会更容易。然后,您只需扩展解决瓶颈所需的应用程序部分。

最好将您的 webapp 放在一个容器中,将您的支持服务(如数据库等)放在单独的容器中。通过这样做,如果您需要进行滚动更新或重新启动,您可以在应用程序节点单独重新启动时保持数据库在线,这样您就不会遇到停机时间。如果您使用 Redis 等缓存,出于同样的原因,这也很有用。它还将允许您更轻松地添加节点以以松散耦合的方式进行扩展。它还将允许您以更适合特定目的的方式管理容器。对于您所描述的应用程序类型,我看到很少有人支持 运行 单个容器上的所有服务。

使用 Docker 时需要考虑的是它在内部的工作方式。 Docker 将您的 PID 1 替换为您在 Docker 文件中的 CMD(和 ENTRYPOINT 指令中指定的命令,后者稍微复杂一些)。 PID 1 通常是您的初始化系统所在的位置(sysvinit、运行it、systemd,等等)。无论在那里启动什么进程,您的容器都会生死存亡。当进程终止时,您的容器也会终止。容器中该进程 的标准输出和标准错误 是您键入 docker logs myContainer 时在主机上提供的内容。顺便说一句,这就是为什么您需要跳过箍来启动服务和 运行 cronjobs(通常由您的 init 系统完成的事情)。这对于理解以某种方式做事的动机非常重要。

现在,您可以随心所欲。关于 "right" 的方法有很多意见,但您可以抛开所有这些,做您想做的事。所以你可以想出如何 运行 在一个容器中的所有这些服务。但是既然您知道 docker 如何用您在 Docker 文件中的 CMD(和 ENTRYPOINT)中指定的任何命令替换 PID 1,您可能会认为谨慎尝试将您的应用程序 运行 保持在各自的容器中,并让它们通过 container linking. (Update -- 27 April 2017: Container linking has been deprecated in favor of regular ole container networking 相互协作,这更加稳健,您只需将单独的应用程序容器加入同一个网络即可这样他们就可以互相交谈了)。

如果您需要一点帮助来决定,我可以根据我自己的经验告诉您,当您将应用程序分离到单独的容器中然后 link 将它们放在一起时,它最终会变得更加干净和易于维护。刚才我正在从 HHVM 构建一个 Wordpress 安装,我正在安装 Nginx 和 HHVM/php-fpm,在一个容器中安装 Wordpress,在另一个容器中安装 MariaDB。将来,这将让我几乎没有麻烦地直接在我的 MariaDB 数据前面安装替换 Wordpress。为每个应用程序容器化是值得的。祝你好运!

这取决于您对应用程序的愿景和路线图。在这种情况下,将应用程序的所有组件放在一层 docker 容器中就像将所有鸡蛋放在一个篮子里。

每当您的应用程序需要安全性、性能相关问题时,将这三个组件分离在它们自己的容器中将是一个理想的解决方案。不用说,跨容器的这种分工会带来一些成本,这与将这些容器连接在一起以实现通信和安全等有关。