在这篇文章中我们将通过 Docker 在个人本地电脑上构建一个快速、轻量级、不依赖本地电脑所安装的任何开发套件的可复制的 Laravel 和 Vue 项目的开发环境(开发环境的所有依赖都安装在 Docker 构建容器里),加入 Vue 只是因为有的项目里会在 Laravel 项目中使用 Vue 做前后端分离开发,开发环境中需要安装前端开发需要的工具集,当然前后端也可以分成两个项目开发,这个话题不在本篇文章的讨论范围内。
所以我们的目标是:
不在本地安装 Mamp/Wamp 这样的软件
不使用类似 Vagrant 这样的虚拟机
不在本地电脑全局安装 PHP 开发所需要的工具集
不在本地电脑全局安装前端开发所需要的工具集
不在本地电脑全局安装 Mysql 和 Nginx
开始前你需要先去安装一个 Docker 客户端,Docker 的官网中有详细的安装方法。
第一步:获取 Laravel 的源码包
因为我们电脑上不安装 Composer,所以就不能使用 Composer 来创建 Laravel 项目了,这里我使用 cURL 直接从 github 上下载了最新的 Laravel 源码包,你也可以使用 wget 或者 git clone 来获取源码包。
curl -L -O https://github.com/laravel/laravel/archive/v5.5.0.tar.gz /
&& tar -zxvf v5.5.0.tar.gz /
&& rm v5.5.0.tar.gz
上面的命令在 curl 下载完源码包后会解压源码压缩包,解压完成后在把源码压缩包 v5.5.0.tar.gz 删掉,执行完后你会看到一个 laravel-5.5.0 的项目目录。
第二步:添加 docker-compose.yml
在项目中创建 docker-compose.yml 文件。
Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。在这里我们会用到四个容器分别将 PHP、Mysql、Nginx 放在四个不同的容器中,通过 compose` 将四个应用容器关联到一起组成项目。
编排文件的开头如下:
version: ‘2’
services:
# our services will go here
在编排文件中,把每个容器叫做一个服务,services 下定义整个应用中用到的所有服务(即容器)。
App 服务
APP 服务的容器将执行我们项目中的代码。
app:
build:
context: ./
dockerfile: app.dockerfile
working_dir: /var/www
volumes:
– ./:/var/www
environment:
– “DB_PORT=3306”
– “DB_HOST=database”
Notes:
我们使用 app.dockerfile 这个镜像文件来构建我们的 App 容器,在镜像文件中我们会对项目中用到的 PHP 模块镜像配置,也会额外安装 NPM 用来构建前端代码。
working_dir: /var/www 把工作目录设置成了 /var/www,在容器中项目代码将会被放在 /var/www 目录下面,包括使用 docker exec app 执行的命令也都是以 /var/www 为当前工作目录的。
volumes 是容器内数据卷所挂载路径设置,在这里我们只定义一个数据卷,把宿主机项目目录挂到在容器中的 /var/www 上,这样我们在本地电脑对项目代码进行的更改就会马上同步到容器中去,反过来也是一样,容器中对代码做的更改也会及时反馈到本地电脑的项目中。
environment 设置环境变量名,这里我们设置了 DB_PORT 和 DB_HOST 这样就不用修改项目中的.env 文件里关于这两项的值了,当然任何你需要在开发环境单独设置的环境变量都可以写到这里,Laravel 读取配置使用的 DotEnv 会检测是否系统有指定环境变量的设置,有的话就不会在去读取.env 文件了。
现在我们需要创建上面 build 环节中提到的 app.dockerfile 这个文件了,具体内容如下:
FROM php:7.1.22-fpm
# Update packages
RUN apt-get update
# Install PHP and composer dependencies
RUN apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev
# Clear out the local repository of retrieved package files
# RUN apt-get clean
# Install needed extensions
# Here you can install any other extension that you need during the test and deployment process
RUN apt-get clean; docker-php-ext-install pdo pdo_mysql mcrypt zip gd pcntl opcache bcmath
# Installs Composer to easily manage your PHP dependencies.
RUN curl –silent –show-error https://getcomposer.org/installer | php — –install-dir=/usr/local/bin –filename=composer
# Install Node
RUN apt-get update &&\
apt-get install -y –no-install-recommends gnupg &&\
curl -sL https://deb.nodesource.com/setup_10.x | bash – &&\
apt-get update &&\
apt-get install -y –no-install-recommends nodejs &&\
npm config set registry https://registry.npm.taobao.org –global &&\
npm install –global gulp-cli
CMD php-fpm
Notes:
我在这里先将 NPM 和 Composer 装到了 app 容器中,因为在开发时经常需要执行他们,如果发布到生产环境,一般是使用单独的 composer 对项目代码进行构建而不是放在运行应用的容器里,容器的核心思想之一就是保持单一,这样才能做到快速增加相同角色的容器。
Web 服务
接下来,我们需要配置一个 Web 服务器用,我们把这个容器在编排文件中命名成 web
web:
build:
context: ./
dockerfile: web.dockerfile
working_dir: /var/www
volumes_from:
– app
ports:
– 8080:80
Notes:
volumes_from 用来复用在 app 服务中定义的数据卷路径
通过 ports 将本地电脑的 8080 端口映射到 web 容器的 80 端口,这样在开发环境中我们就不用设置 hosts 文件,直接通过 IP 加端口就能访问服务了。Web 服务器选用 nginx,所以我们需要用一个 nginx 镜像文件来构建这个容器,在这之前我们需要在 nginx 镜像的基础上再设置一下项目中用到的 vhost,所以我们需要一个 web.dockerfile 文件,它的定义如下:
FROM nginx:1.10
ADD vhost.conf /etc/nginx/conf.d/default.conf
根据镜像文件的定义,我们把项目中的 vhost.conf 复制到了容器的 /etc/nginx/conf.d/default.conf 中,这样基本的 nginx 配置就配置好了,vhost.conf 中的定义如下:
server {
listen 80;
index index.php index.html;
root /var/www/public;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Notes:
因为是开发环境我们就只进行最简单的配置,不做调优考虑了。
fastcgi_pass app:9000; nginx 将对 PHP 的请求通过 fastcgi 传递给了 app 服务的 9000 端口,docker-compose 会自动把 services 中定义的容器服务连接起来,各个服务相互之间使用服务名称引用。
Mysql 服务
接下来我们将配置 Mysql 服务,与上面两个服务有点不一样的是,在 PHP-FPM 和 Nginx 的容器中,我们配置本地电脑的文件可以同步到容器中供容器访问,这让我们开发时对文件作的更改能够快速的在容器中得到反馈加快我们的开发过程。但是在数据库容器中我们希望容器中创建的文件能够持久化(默认容器销毁时,容器内创建的文件也会被销毁),我们可以通过 Docker 的数据卷来实现上述功能,只不过这次不用再把本地电脑的文件挂在到数据卷上了,Docker 客户端会管理创建的数据卷的在本地电脑上具体存储的位置。
下面是编排文件中对 database 服务的设置
version: ‘2’
services:
database:
image: mysql:5.7
volumes:
– dbdata:/var/lib/mysql
environment:
– “MYSQL_DATABASE=homestead”
– “MYSQL_USER=homestead”
– “MYSQL_PASSWORD=secret”
– “MYSQL_ROOT_PASSWORD=secret”
ports:
– “33061:3306”
volumes:
dbdata:
Notes:
在文件的最下面我们通过 volumes 命令创建了一个名为 dbdata 的数据卷(dbdata 后面的冒号是有意写上去的,这是 YML 文件的一个语法限制,不用太关心)
定义完数据卷后,在上面我们使用 <name>:<dir> 的格式,通知 Docker,将 dbdata 数据卷挂在到容器中的 /var/lib/mysql 目录上
environments 中设置的是 Mysql 的 docker 镜像需要的四个必要参数。
ports 端口映射中,我们将本地电脑的 33061 端口映射到容器的 3306 端口,这样我们就能通过电脑上的数据库工具连接到 docker 内的 Mysql 了。
将所有服务编排到一起
下面是完整的 docker-compose.yml 文件,通过编排文件我们将三个应用容器关联在一起组成了项目的服务端
version: ‘2’
services:
# The Application
app:
build:
context: ./
dockerfile: app.dockerfile
working_dir: /var/www
volumes:
– ./:/var/www
environment:
– “DB_PORT=3306”
– “DB_HOST=database”
# The Web Server
web:
build:
context: ./
dockerfile: web.dockerfile
working_dir: /var/www
volumes_from:
– app
ports:
– 8080:80
# The Database
database:
image: mysql:5.6
volumes:
– dbdata:/var/lib/mysql
environment:
– “MYSQL_DATABASE=homestead”
– “MYSQL_USER=homestead”
– “MYSQL_PASSWORD=secret”
– “MYSQL_ROOT_PASSWORD=secret”
ports:
– “33061:3306”
volumes:
dbdata:
启动服务
按照上面的步骤配置好编排文件还有指定的 docker 镜像文件后,我们就可以通过下面的命令启动服务了,执行完后会启动上面文件里定义的三个服务。
docker-compose up -d
第一次启动时,由于 docker 客户端要下载上面提到的三个镜像并且构建服务所以启动速度会慢一些,等到下载完镜像并构建完成后,以后的启动都会非常快。
初始化 Laravel 项目
启动完服务后我们可以初始化 Laravel 项目了,步骤跟官方文档里介绍的一样,但是需要在启动的 app 服务的容器里执行:
docker-compose exec app composer install
docker-compose exec app npm install // 如果包含前端项目的话再执行相关命令
docker-compose exec app cp .env.example .env
docker-compose exec app php artisan key:generate
docker-compose exec app php artisan optimize
docker-compose exec app php artisan migrate –seed
docker-compose exec app php artisan make:controller MyController
Notes:
docker-compose exec 将命令发送到指定的容器中去执行
app 是定义在 docker-compose.yml 中的一个服务,它是一个运行着 php-fpm 的容器
php artisan migrate 是要在容器里执行的命令
查看 nginx 日志的方法:
docker ps 找到 nginx 服务的 container id
docker exec -it <contianer id> /bin/bash 进入 nginx 容器
nginx 日志的具体路径请查看项目中的 vhost.conf
执行完上面的命令后你就能通过 http://127.0.0.1:8080/ 访问到项目啦。
在我的 Github gist 有一组参考文件方便同学们参考 https://gist.github.com/kevin…
gist 里的文件稍微旧一些,后来在使用的过程中又加入些新的 PHP 模块和 Node,之前 composer 也单独放到了一个容器中,不过相信聪明的你看到这里应该已经会根据需求更改这些文件啦。