为什么要用Docker
说实话,如果在Windows下开发PHP程序,那么XAMPP足够了,一个安装包,什么都安装好了。但是如果要增加一些额外的依赖,比如需要的扩展的DLL不存在,需要编译安装一些扩展;或者需要同时维护不同版本的PHP,那么就需要下多个版本的XAMPP。当然也有可以切换PHP版本的工具,比如WAMP。但是依赖其实无处不在,比如切换了针对Apache的PHP版本,命令行的PHP版本也得相应的切换,或者Composer的版本。在这种情况下,很容易掉坑。
另外一方面,随着各种语言的层出不穷,工作中不可能死磕一种语言。新增一种语言,势必需要安装对应的环境,比如Python,需要2.7.x版本和3.x版本,Node,各种全局安装,Go的安装也是一通配置。而随着这些语言版本的升级,卸载又安装,配置又更改,时间一长,真的很容易一团乱。
针对开发环境问题,爱折腾的程序员开发了Vagrant这个工具。一个环境一个虚拟机,然后用自动化方法去管理这些虚拟机。这样一来,可以把各个项目的开发环境相隔离,一个项目一个镜像。这样不管多么复杂的依赖,都被隔离在镜像中,不会对其他的项目的环境造成影响。要删除这些安装程序和配置,只要把镜像删除掉就行了。非常干净,保证了操作系统不会留下各种垃圾文件。
到这里其实没有Docker什么事了,Vagrant把问题解决的差不多了。但是有两个痛点:
- Vagrant镜像大,一个项目一个镜像,SSD空间本来就吃紧,很快就空间不够啦
- 性能。Vagrant启动其实就是虚拟机启动,几分钟内也就搞定了,等等其实无所谓。通常开发的时候,会把代码所在的文件夹挂载到虚拟机上,对于文件多的项目,风扇就会狂转。
虽然有上面说的两个问题,但是由于有环境隔离的好处,选择Vagrant的程序员也就忍了。本来Docker刚出来的时候,也不是为了干掉Vagrant,大家相安无事,在各自的领域发光发热,Docker主要目标集中在方便部署上,一个项目,打包成几个容器,往服务器一放就搞定了。但是最近的几个改进,让爱折腾的程序员发现了Docker在本地开发环境上的潜力:
- 使用操作系统的虚拟化技术,不在依赖于Virtualbox
- 提升了卷的地位,使得文件映射和持久化更方便
这样一来,是时候用Docker取代Vagrant进行本地开发环境搭建啦。
开发环境编排
为了追赶潮流,各个部分的版本计划是这样的:
应用服务器:Nginx 最新版本 PHP: 当然是最新的7.x啦 MySQL:最新版本 phpMyAdmin:好用的MySQL可视化管理工具,最新版本
由于Docker容器默认情况下,停止的时候,运行中产生的修改都会丢失,但是在开发过程中,代码和数据是要保存下来的,所以需要另外两个数据容器:MySQL数据容器和代码数据容器。
确定好了组成部分后,可以把项目的文件结构设置成如下样子:
项目文件夹
├── LICENSE
├── README.md
├── app
│ └── basic
├── docker-compose.yml
├── nginx
│ ├── Dockerfile
│ └── default.conf
└── php
├── Dockerfile
├── install-composer
└── sources.list.jessie
- 代码放在app目录下,这里作为示例,放了yii创建的basic应用
- niginx目录下放了单独的nginx容器构建文件,以及默认的PHP站点的nginix配置文件
- php目录下放了单独的php容器构建文件,因为Yii2有一些扩展是必须支持的,所以官方默认的php镜像是不能满足要求,所以需要基于官方的容器再安装一些必要的扩展;另外直接使用国外的源安装由于种种原因,速度实在令人遗憾,所以sources.list.jessie里放了163的源,构建的时候把这个源也放进容器
编写docker-compose.yml
version: "1.0"
services:
nginx:
build: ./nginx/
ports:
- 80:80
volumes:
- "${PROJECT_ROOT}:/var/www/html:ro"
networks:
- server
depends_on:
- php
php:
build: ./php/
expose:
- 9000
volumes:
- "${PROJECT_ROOT}:/var/www/html"
networks:
- database
- server
depends_on:
- mysql
mysql:
image: mysql:latest
volumes:
- data:/var/lib/mysql
networks:
- database
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
MYSQL_DATABASE: "${DB_NAME}"
MYSQL_USER: "${DB_USERNAME}"
MYSQL_PASSWORD: "${DB_PASSWORD}"
phpmyadmin:
image: phpmyadmin/phpmyadmin
ports:
- 8080:80
networks:
- database
depends_on:
- mysql
environment:
PMA_HOST: mysql
volumes:
data:
networks:
database:
server:
采用最新的构建语法,大部分用depends_on代替links,用volumes列出需要持久化的mysql对应的数据文件。代码已经传到码云啦。https://gitee.com/linwx/Yii2Docker.git