Docker:如何将多个 LAMP 应用程序实例 Docker 化并部署

52

我需要部署许多相同的LAMP(或LEMP)应用程序实例:

  • 每个实例将可从子域访问,并带有前端负载均衡器/代理
  • 每个实例必须具有其自己的数据库数据和文件数据。
  • 每个实例可能会被监视
  • 每个应用程序实例可能会设置内存限制/ CPU
  • 易于自动化部署新的webapp实例
  • 环境可能很容易地复制以进行测试和开发。

应用程序要求:

  • 守护进程(Nginx, MariaDB, PHPFPM)
  • 二进制文件(composer, bower, ...)
  • 其他特定于系统的库和配置

阅读Docker文档和许多howtos后,我看到了不同的解决方案来构建这个Web应用程序的docker镜像:


解决方案1:使用一个全包容镜像

所有堆栈都在一个容器中:

  • webapp源文件、EMP守护进程、二进制文件等
  • 挂载的卷用于mysql和webapp数据文件

例如:

优点(在我看来):

  • 似乎容易自动化部署、监控、销毁……
  • 易于在生产、测试和开发环境中使用。

缺点(在我看来):

  • 单体架构
  • 难以扩展
  • 没有充分利用 Docker 的所有优势

解决方案2:每个 Web 应用实例使用一个容器堆栈

为了部署每个 Web 应用,都会部署一个容器堆栈:

  • 每个进程一个容器:Nginx, Mysql, PHP-FPM,
  • 二进制容器(composer,bower等)也可以被dockerize,或者合并到phpfpm容器中
  • 挂载卷用于mysql和webapp数据文件

示例:

优点(在我看来):

  • 解耦合的
  • 每个实例隔离的进程
  • 一个容器一个进程,不需要像RUnit或Supervisord这样的守护进程管理器

缺点(在我看来):

  • 似乎更加复杂
  • 难以维护,难以看到所有容器状态、链接、版本等的“大局”。

解决方案3:混合前两种解决方案

  • 一个包含应用程序源文件、nginx、php-fpm、composer和git的“应用程序”容器。
  • 一个包含MySQL数据库的容器,可以与应用程序容器共享或不共享。

在单个容器中运行多个进程也会带来安全隐患。请参阅Docker团队/CIS提供的这份(有些过时)安全建议清单 - jpaugh
2个回答

18

我最近对Docker进行了分析,来针对这种设置。我知道有些人将Docker视为一种类似于MicroVM的东西,但我的看法是Docker的理念更倾向于每个容器单独运行一个进程。这与编程中的单一职责原则相符合。一个Docker容器做的越多,就越难复用和管理。我在这里发布了我所有的想法:

http://software.danielwatrous.com/a-review-of-docker/

然后我继续使用Docker构建了一个LEMP堆栈。我发现将PHP和Nginx进程拆分成单独的Docker容器中并没有太大的价值,但Web和数据库函数是在不同的容器中。我还展示了如何管理链接和共享卷以避免在容器中运行SSH守护程序。您可以按照我的步骤作为参考。

http://software.danielwatrous.com/use-docker-to-build-a-lemp-stack-buildfile/

关于单一功能每个容器增加的复杂性,您是正确的。它看起来和感觉就像您有着独立的分布式层。非常大的应用程序已经这样做了多年,它会增加通信、安全和管理方面的复杂性。当然,它也带来了许多好处。


2
你为什么选择使用Ubuntu作为FROM容器来创建自己的容器,而不是使用Docker提供的nginx和mysql容器?Docker提供的容器不是更加流畅吗? - freethebees
3
@freethebees 这个教程有几个目的。其中之一是展示如何在多个虚拟机上搭建LEMP堆栈,另一个目的是演示Dockerfile。由于我对基础设施作为代码非常感兴趣,所以选择了这种方式。如果你想将我开始的内容推向生产环境,你可能会发现可用的镜像更加方便。 - Daniel Watrous

9
两种方案都可行。然而,我会选择解决方案2 - 每个进程一个容器 - 因为它更符合Docker的“哲学”。
Docker的好处在于,您可以使用独立的构建块(单个应用程序的映像)创建应用程序堆栈(如您的堆栈)。您可以组合这些构建块并重复使用它们。如果您查看官方Docker注册表,您将发现大多数组件都是预先构建的映像。例如,您将在https://registry.hub.docker.com/u/dockerfile/nginx找到Nginx,在https://registry.hub.docker.com/_/mysql找到MySQL数据库。因此,如果您选择每个进程/应用程序一个容器,则设置堆栈变得非常容易:
(请注意,这只是一个示例,我不熟悉PHP和其他东西...)
获取您的映像:
docker pull mysql
docker pull dockerfile/nginx
docker pull tutum/apache-php

docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql
docker run -d -p 80:80 -v <sites-enabled-dir>:/etc/nginx/sites-enabled -v <log-dir>:/var/log/nginx dockerfile/nginx
docker run -d -p 80:80 tutum/apache-php

你可以很容易地像这样设置你的堆栈。如果需要,你可以更改某些单个组件。例如,你可以在不触及其他组件的情况下将MySQL数据库更改为MariaDB。
关于该解决方案最复杂的问题是如何配置你的堆栈。要链接你的容器,请查看https://docs.docker.com/userguide/dockerlinks。你可以使用此方法将例如应用程序容器与MySQL容器链接起来。

感谢您的回复。我完全同意解决方案2更符合Docker的理念。但是,主要的缺点(在我看来)是要保持所有容器状态和链接的“大局观”。我尝试过Shipyard和Gaudi,但不知道是否存在更好的方法。 - Koryonik
2
我认为Shipyard很酷,可以保持概览。然而,我不认为它有任何部署支持。你可以看看fig。 - Thomas Uhrig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接