比较早接触docker,也翻译过一些相关的文章,但坦白说平日里用的真心不多。
自2014年博客启用至今,出于对成本和性能的平衡,我已经对网站做了近20次的迁移。期间主要面临的问题是服务商提供的Linux发行版比较有限,且并未在所有平台(例如Xen)成功实施在线的发行版替换工作,由于平台的制约,运行环境无可避免地会出现不一致的情况,细节部分自然也难以统一,为此出过不少差错。
一般情况下,我是比较懒的,除非真正想要折腾,否则能拖就拖。而这次做出了docker化的决定,出于以下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中存在形形色色的镜像,然而它们的部署方式却没有得到真正的统一,这一点让人很是苦恼和遗憾。