让部署变得更加的简单

平时,如果我们开发好一个laravel项目之后,纯手工部署代码的话,需要经历以下步骤:

  • 安装好服务器环境
  • 下载项目代码
  • 下载 Composer 依赖
  • 下载 Nodejs 依赖
  • 创建 .env 文件
  • 执行数据库迁移
  • 构建前端代码

如果后续要更新版本,代码变更的时候,实在是一个令人感觉不好的操作,我们可能需要做以下的工作

  • ssh 登录到服务器;
  • 使用 git 命令更新代码仓库;
  • 如果有 composer 依赖变更,需要执行 composer install;
  • 如果 .env 文件有变更,需要通过 scp 或者 vim 修改;
  • 如果有数据库变更,需要执行 php artisan migrate;
  • 如果有队列相关的代码变更,需要执行 php artisan queue:restart;
  • 如果有 Nodejs 依赖变更,需要执行 yarn;
  • 如果有前端代码变更,需要执行 yarn build

如果我们使用纯手工的方式部署会有以下问题:

  • 容易遗漏步骤或者误操作;
  • 在部署过程中站点可能不可用;
  • 如果有多台服务器需要部署则会加剧上述两个问题。

为了解决这个问题,我们可以使用Deployer 这个部署工具,Deployer 可以让我们用 PHP 代码的方式描述部署步骤并执行,对于php开发者来说真的是一个福音咯

我之前练手用的电商系统,就是用deployer部署的,支持单机跟多机部署,可戳shop

什么是Deployer

Deployer 是一个基于 SSH 协议的无侵入 web 项目部署工具,因为它不需要你在目标服务器上装什么服务之类的东西即可使用,它只需要在你的开发机,或者你的笔记本,就是发起部署动作的一方安装即可。

它的原理就是通过 SSH 到你的机器去创建目录,移动文件,执行指定的动作来完成项目的部署

跟我们shell脚本其实是一样的,只不过,我们不需要去服务器上面进行操作,而且在本地恋用熟悉的php进行编写部署脚本后,通过ssh协议,登录到指定服务器进行一系列操作,所以说还是很友好的。

Deployer 的安装与配置

Deployer的安装

Deployer的安装与配置都是在本地进行操作

1
$ composer global require deployer/deployer

安装完成后我们试试看是否安装成功:

1
$ dep

Deployer的配置

1
$ dep init

接下来的操作,选择yes就行了

dep init 命令用来创建一个部署脚本,会询问我们项目类型,我们是 Laravel 项目所以输入 1 然后回车;接下来询问 Repository 也就是我们代码仓库的地址

快速入门可参考官网Deployer

初始化后,会自动生成 deployer.php 文件。 deployer.php 文件包含了基本的部署配置和任务,且有明确的注释,你可以根据注释在适当的地方添加配置以及任务。

可参考我的部署脚本可戳shop

服务器权限的配置

在本地编写部署脚本是最简单写的,最难的就是用户权限的控制问题,刚开始使用的时候经常会遇到permission denied的问题,
以下参考自安正超的配置:

出于安全考虑,我们一般不会使用 root 用户的 SSH 登录,而是使用其它用户,比如 Ubuntu 默认的 ubuntu 用户。
我们 Deployer 是用来部署 web 应用的,所以我们也专门创建一个用户来做这件事情比较好:

1
2
$ sudo adduser deployer
# 密码什么的,按提示操作即可

我们的 web 项目通常需要一些上传,或者缓存写入这样的操作,所以 deployer 还需要有权限对目录进行修改,比如 Laravel 的 storage 目录需要可写权限,这里以 nginx 默认的用户组 www-data 举例,如果你修改过用户或者组名请对应修改下面的命令里的 www 用户组:

1
$ sudo usermod -aG www-data deployer

我们通常需要将deployer 用户权限分别设置为创建文件 644 与目录 755,这样一来,deployer 用户可以读写,但是组与其它用户只能读:

1
2
3
$ su deployer # 切换到 deployer 用户
$ echo "umask 022" >> ~/.bashrc
$ exit # 退出

我们需要将 depoloyer 用户加到 sudoers 中:

1
2
3
4
$ vim /etc/sudoers
# 在最后加入
deployer ALL=(ALL) NOPASSWD: ALL
# 保存并退出

接下来要对我们的 web 根目录授权,假设我们的 web 服务的根目录在 /var/www/ 下,那么需要将这个目录的用户设置为 deployer ,组设置为 www 用户 www-data:

1
2
3
4
$ sudo chown deployer:www-data /var/www/html # 最后这里不要加斜线哦
为了让 deployer 用户在 /var/www/html 下创建的文件与目录集成根目录的权限设定(用户:deployer,组:www-data),我们还需要一步操作:

$ sudo chmod g+s /var/www/html

OK,Deployer 的用户操作就结束了,接着你需要检查以下配置:

  • 确认 php 的可执行文件在全局 PATH 中,或者你手动添加到 deployer 用户目录的 .bash_profile PATH 中也可,使用命令确认(登录用户 deployer 后执行):php -v,如果报错的话,一般建议是将 php 的 bin 文件软链接到 /usr/local/bin/(推荐) 或者 /usr/bin/ 下。
  • 同样检查你的 Deployer 任务清单所需要用到的其它命令,比如 npm,nginx,composer 都在 deployer 用户下可以使用,否则在部署的时候会出错。

项目 git 仓库允许服务器访问

因为部署脚本需要从git服务器中获取代码,因此我们的部署服务器需要有权限可以拉取代码
如果代码不是公开的仓库,我们通常需要添加 SSH 公钥才可以从代码库 clone 代码,所以接着来创建公钥:

先切换当前登录用户到 deployer:

1
2

$ su - deployer

然后创建 SSH 密钥:

1
2
3
4

$ ssh-keygen -t rsa -b 4096 -C "deployer"
# 这里的 -C 是指定备注
# 一路回车下去即可

然后我们将生成的公钥拷贝出来:

1
$ cat ~/.ssh/id_rsa.pub # 显示公钥

请完整的复制 cat 出来的结果,然后去你的代码库添加 SSH 公钥。

OK, 现在你的服务器就可以从代码库 clone 代码了,你可以在服务器上 git clone 一下你的代码库测试,如果不成功,请检查你的公钥是否正确完全的复制与粘贴正确,不正确的话再次重复复制粘贴即可。

服务器免密码登录 deployer

在部署shop,因为使用的是阿里云服务器,因此带上了,购买时生成的密钥文件,只要在本地登录的时候带上那个密钥文件就可以免密码登录,命令如下:

1
2

$ ssh root@{你的服务器公网 IP} -i ~/.ssh/laravel-shop-aliyun.pem #你的密钥文件路径

如果我们没有生成该文件,我们可以手动使用以下的方法来:

在本地(或者开发机)执行部署任务时我们不想每次输入密码,所以我们需要将 deployer 用户设置 SSH 免密码登录:

在本机生成 deployer 专用密钥,然后拷贝公钥:

1
$ ssh-keygen -t rsa -b 4096 -f  ~/.ssh/deployerkey

然后将公钥保存到目标服务器(注意,这一步还是在本机操作):

1
2
3
$ ssh-copy-id -i  ~/.ssh/deployerkey.pub deployer@{服务器ip} # 请填写服务器 IP

# 应该会让你输入 deployer 在服务器上的登录密码,输入后回车即可

然后你应该就可以直接以 deployer 用户免密码登录到服务器了,测试方式:

1
2
$ ssh deployer@{服务器ip} -i ~/.ssh/deployerkey
# 应该就能直接进到服务器上了,然后 exit 退出

OK,这一步搞定了 deployer 免密码登录,接下来我们聊项目的部署。

其实,跟我们上一部差不多,只不过阿里云服务器帮我们省略了

关于 Deployer 部署结构

Deployer 部署完成后,在服务器上的结构会是这样子:

1
2
3
4
5
6
7

drwxr-sr-x 5 deployer www-data 4096 Jun 14 09:53 ./
drwxr-sr-x 6 deployer www-data 4096 Jun 11 14:25 ../
drwxr-sr-x 2 deployer www-data 4096 Jun 14 09:53 .dep/
lrwxrwxrwx 1 deployer www-data 10 Jun 14 09:52 current -> releases/7/
drwxr-sr-x 4 deployer www-data 4096 Jun 14 09:53 releases/
drwxr-sr-x 3 deployer www-data 4096 Jun 10 14:16 shared/

  • current - 它是指向一个具体的版本的软链接,你的 nginx 配置中 root 应该指向它,比如 laravel 项目的话 root 就指向:/var/www/demo-app/current/public

  • releases - 部署的历史版本文件夹,里面可能有很多个最近部署的版本,可以根据你的配置来设置保留多少个版本,建议 5 个。保留版本可以让我们在上线出问题时使用 dep rollback 快速回滚项目到上一个版本。

  • shared - 共享文件夹,它的作用就是存储我们项目中版本间共享的文件,比如 Laravel 项目的 .env 文件,storage 目录,或者你项目的上传文件夹,它会以软链接的形式链接到当前版本中。

因此,在nginx配置的时候,我们可以采用:,例如项目laravel-shop

1
$ vim /etc/nginx/sites-available/laravel-shop.conf

将站点根目录修改为 /var/www/laravel-shop-deployer/current/public