使用docker-compose部署站点

比较早接触docker,也翻译过一些相关的文章,但坦白说平日里用的真心不多。

自2014年博客启用至今,出于对成本和性能的平衡,我已经对网站做了近20次的迁移。期间主要面临的问题是服务商提供的Linux发行版比较有限,且并未在所有平台(例如Xen)成功实施在线的发行版替换工作,由于平台的制约,运行环境无可避免地会出现不一致的情况,细节部分自然也难以统一,为此出过不少差错。

一般情况下,我是比较懒的,除非真正想要折腾,否则能拖就拖。而这次做出了docker化的决定,出于以下2点原因:

  1. 想折腾了,期望能够在部署、备份等环节尽可能实现自动化,最好能够实现闭环,这一切自然需要实践
  2. 近期有在规划重写整个站点将其转成一个SPA,采用MicroService彻底分离前后端,并使其跑在自己的server和framework之上

需求

站点的架构十分简单,nginx+php+mariadb,nginx通过fastcgi代理将请求发送到php-fpm,可以选择将它们打包成一个镜像,这么做很简单,但却没有什么折腾的余地了,显得有点low!

事实上,我需要的只是3+个进程,而非一个虚拟机,因此这里的策略是使用3个独立的镜像,nginx,hhvm和mariadb,以3个service运行,既然是多个service的协同,自然会涉及到服务的编排,这里选用的工具是docker-compose。

镜像选择

镜像,尽可能选择official的,nginx和mariadb均有official提供。

起初计划采用官方的php镜像,但在使用过程中发现如果需要使用pdo扩展似乎需要另行build。懒得折腾,于是就选择了hhvm,话说已经好久没用它了,它的配置项也挺方便,还默认开启了相关扩展。唯一遗憾的是这货没有official的镜像,因此使用的是dirgomarangoni/hhvm:fastcgi,它会让hhvm默认使用server模式,该模式使用的配置文件位于/etc/hhvm/server.ini

我的理念是想方设法不build,配置文件的问题,通过挂载volume的方式解决,因此在继续操作之前需要将镜像内的配置文件拷贝出来,大致的命令如下:

docker run -it -v /tmp:/tmp XXX:TAG bash

之后只需要将相关配置复制到/tmp目录下即可。

docker-compose配置

由于docker官方的PPA中并未提供compose,而ubuntu仓库中的compose只支持到v2,因此这里选择v2版进行讲解。

具体的格式请参考docker-compose document

按照上文所述,将整个站点划分成3个service:

  • blog_db
  • blog_php
  • blog_web

它们的依赖关系为:

blog_web -> blog_php -> blog_db

其中blog_web需要映射外部端口号80。

以上3个服务均需要挂载volume,其中blog_web挂载的是配置文件,blog_php挂载的是应用的目录(请注意权限问题),blog_db挂载的是数据目录datadir和数据库初始化文件目录。

假设我们的配置和数据的目录如下:

/var/www
  |-------conf
  |            |------ nginx.conf
  |--------db
  |            |------ sql
  |            |           |-------blog.sql
  |            |-------datadir
  |--------app

以下便是3个服务的配置:

blog_db:
  image: mariadb:latest
  volumes:
    - /var/www/db/datadir:/var/lib/mysql
    - /var/www/db/sql:/docker-entrypoint-initdb.d
  environment:
    - MYSQL_ROOT_PASSWORD=***************************
    - MYSQL_DATABASE=XXX_blog

按照镜像的描述,/docker-entrypoint-initdb.d目录下的sql文件会被自动用于恢复数据,而数据库的名字则是通过MYSQL_DATABASE指定,/var/www/db/datadir则是数据目录了,其余的配置均为其字面意思。这里我偷懒没有采用使用新用户的方式,具体方法见文档

blog_php:
  depends_on:
    - blog_db
  links:
    - blog_db
  image: diegomarangoni/hhvm:fastcgi
  volumes:
    - /var/www/app:/var/www/blog

hhvm使用的是默认配置,其默认端口是9000,暂时也没有太大的必要修改配置抑或是转而使用proxygen。依赖关系需要通过depend_on指定,注意这里的依赖仅表示启动的先后顺序,并非依赖项全部启动完毕后才启动服务。

由于app需要访问数据库,因此必须在links中也指定blog_db,否则是无法ping通的。

/var/www/blog是容器内应用的目录,这个需要和nginx配置文件中的root相对应,这样nginx的$document_root指向的才是有效路径。

blog_web:
  depends_on:
    - blog_php
  links:
    - blog_php
  image: nginx:latest
  volumes:
    - /var/www/conf/nginx.conf:/etc/nginx/nginx.conf
  ports:
    - "80:80"

nginx依赖blog_php,并且需要挂载实际的配置,但是我们并不需要将app的路径也挂载上去,因为这个最终只会作为SCRIPT_FILENAME变量转发给hhvm,最终由hhvm来定位文件。

只有使用了links指定连接的服务后,我们才能从相应的容器中ping通另一个容器,而相应的ip则是它们的服务名称,如blog_web等,它们都位于同一个子网内。

总结

这是对compose的首次应用,部署的时候在网络部分走了一点歪路,还曾想过在内部再开个DNS服务,但后来发现还是自己想多了。

目前尚存在的欠缺在于日志的汇聚和分析服务(或许之后会更新本文),至于监控部分,有dnspod辅助,则显得不是那么重要。

hub中存在形形色色的镜像,然而它们的部署方式却没有得到真正的统一,这一点让人很是苦恼和遗憾。

说两句: