利用 GitLab CI/CD 和 Envoy 自动化测试和部署 Laravel 项目
准备
- 目标服务器(生产服务器),运行着测试 Laravel 项目,可 ssh 登陆
- GitLab 服务器,包含了测试项目
- 本地系统(Linux/Mac)一个测试用的 Laravel 项目
目标服务器准备工作
创建新用户
# 安装 acl 软件包便于进行文件和目录权限控制
sudo apt install acl
# 添加用户 deployer 用于执行发布任务
sudo adduser deployer
# 赋予 deployer 用户目录权限
sudo setfacl -R -m u:deployer:rwx /var/www
生成 ssh 密钥对
为刚刚的新用户生成 ssh 密钥对,方便 GitLab 发布或者本地测试时用密钥登陆生产服务器执行命令,注意密钥不要用密码(passphrase)保护:
# 在生产服务器上切换到 deployer 用户
sudo su deployer
# 生成 ssh 密钥对,邮箱换成自己的
ssh-keygen -t rsa -C "your.email@example.com" -b 4096
# 把公钥复制到 deployer 用户的 authorized_keys,后续可以让 GitLab 直接用私钥登陆
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
把私钥放到 GitLab 项目Settings | CI/CD | Variables 内,供后续使用:
Envoy 使用
envoy 用来定义一些在远程服务器执行的任务,使用 blade 语法。Laravel 官方文档有介绍:Envoy Task Runner
以下 envoy 操作均在本地 Linux/Mac 机器上进行。
Envoy 安装
composer global require laravel/envoy
## 将 ~/.composer/vendor/bin 加入环境变量才能正常使用 envoy 命令
## 比如终端使用 zsh 的话,将 export PATH="$PATH:~/.composer/vendor/bin" 附加到 .zshrc 文件里
echo "export PATH=\"\$PATH:~/.composer/vendor/bin\"" >> ~/.zshrc
source .zshrc
# 检查下环境变量
echo $PATH
Envoy 任务测试
在 Laravel 项目根目录添加 Envoy.blade.php
文件,内容如:
@servers(['web' => 'deployer@remote_host'])
@task('list', ['on' => 'web'])
ls -l
@endtask
其中 @servers
定义了 ssh 登陆服务器的信息,'服务器名称=>值' 的形式,值里可以指定 ssh 参数,可以理解成一条完整的 ssh 命令除去开头的 ssh 后面的部分。
为了 envoy 命令的正常执行,需要本地机器的用户能正常 ssh 登陆到目标服务器,我们把本地的 ssh 公钥(~/.ssh/id_rsa.pub
)加到目标服务器 deployer 用户的 authorized_keys
里,过程略。
此时在项目根目录执行 envoy run list
,可以正常登陆到目标服务器并将命令ls -l
的执行结果返回:
➜ lowlog git:(master) ✗ envoy run list
[deployer@low.bi]: total 0
Envory 编写发布任务脚本
直接上示例内容 Envoy.blade.php
:
@servers(['web' => 'deployer@192.168.1.1'])
@setup
$repository = 'git@gitlab.example.com:<USERNAME>/laravel-sample.git';
$releases_dir = '/var/www/app/releases';
$app_dir = '/var/www/app';
$release = date('YmdHis');
$new_release_dir = $releases_dir .'/'. $release;
@endsetup
@story('deploy')
clone_repository
run_composer
update_symlinks
@endstory
@task('clone_repository')
echo 'Cloning repository'
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
@endtask
@task('run_composer')
echo "Starting deployment ({{ $release }})"
cd {{ $new_release_dir }}
composer install --prefer-dist --no-scripts -q -o
@endtask
@task('update_symlinks')
echo "Linking storage directory"
rm -rf {{ $new_release_dir }}/storage
ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage
echo 'Linking .env file'
ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
echo 'Linking current release'
ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
@endtask
@setup
定义了一些变量,@story
将整个流程拆分为了几个单任务,@task
定义每个任务具体的操作。
分为三个步骤:
clone_repository
git 拉取最新代码,以时间为文件夹名,每次拉取的代码分开存放在releases
文件夹内。run_composer
composer 安装依赖。update_symlinks
更新软链接。storage
文件夹不变,每次发布通过软连接链接到最新版本下,.env
同理,最后创建一个名为current
的软链接,current
将作为项目根目录,总是链接到最新的代码。
更改 nginx 配置
需要将 nginx 里配置的 root 地址从 public
改为 current/public
:
root /var/www/lowlog/current/public;
更新 载入nginx 配置
sudo nginx -t
sudo systemctl reload nginx
到目前为止,已经可以在本地机器执行 envoy run deploy
,手动将项目发布到目标服务器上了,下面开始配置 GitLab 实现自动发布。
此时目标服务器上只保留四个文件/文件夹:
- storage:存储目录
- releases:代码版本目录
- current:软链接,链到最新版本的代码
- .env:配置文件
GitLab CI
我们想要让 GitLab 建立并运行一个 Docker 镜像,镜像包含完整的运行环境,在镜像内执行单元测试,以及版本发布任务。
Dockerfile
在项目根目录下新建 Dockerfile
,内容如下:
# Set the base image for subsequent instructions
FROM php:7.1
# 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 docker-php-ext-install mcrypt pdo_mysql zip
# Install Composer
RUN curl --silent --show-error https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Install Laravel Envoy
RUN composer global require "laravel/envoy=~1.0"
这个 Docker 镜像以 php:7.1
为基础,安装了一些软件包、PHP 扩展、composer 以及 Laravel Envoy。
Container Registry
GitLab 需要启用 Container Registry 用以保存 Docker 镜像,启用方法见: GitLab Container Registry administration。
我的 GitLab 安装在内网机器,通过反向代理访问的,启用方法参考:GitLab + Container Registry 安装及反向代理配置。
之后在项目设置里开启 Container Registry:
Container Registry 启用成功后,项目菜单会出现 Registry
,里面有 Container Registry 的使用方法:
大致就是三条指令 docker login
、docker build
、docker push
,在项目根目录下执行:
docker login registry.codegeass.cc
docker build -t registry.codegeass.cc/qqjt/lowlog .
docker push registry.codegeass.cc/qqjt/lowlog
这三条指令的执行需要事先在本地机器上 安装 了 docker,如果权限不够就在前面加上 sudo
,成功之后就可以在 GitLab 看到镜像:
GitLab Runner 准备
GitLab Runner 是 GitLab CI 中的执行者,用来执行项目里的 .gitlab-ci.yml
文件中定义的指令。Runner 有三种类型:shared runners
、specific runners
、group runners
,更多介绍见: Configuring GitLab Runners。
我这里是在公网服务器上安装了gitlab runner 并注册为specific runner
。
-
安装 GitLab Runner
参照 文档 进行包安装:# For Debian/Ubuntu/Mint curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash sudo apt-get install gitlab-runner
-
注册 Runner
- 打开 GitLab 中项目的
Settings | CI/CD
,获取注册 runner 所需要的URL
和token
。
- 打开 GitLab 中项目的
- 在安装了 Runner 的机器上执行
sudo gitlab-runner register
,按照提示填入 URL 和 token 参数,其中Executor
类型选择docker
。更多介绍见 GitLab Runner Executors。
.gitlab-ci.yml
.gitlab-ci.yml
文件指定了 Runner 要执行的指令,我们在项目根目录下创建 .gitlab-ci.yml
,内容如下:
image: registry.codegeass.cc/qqjt/lowlog:latest
services:
- mysql:5.7
variables:
MYSQL_DATABASE: homestead
MYSQL_ROOT_PASSWORD: secret
DB_HOST: mysql
DB_USERNAME: root
stages:
- test
- deploy
unit_test:
stage: test
script:
- cp .env.example .env
- composer install
- php artisan key:generate
- php artisan migrate
- vendor/bin/phpunit
deploy_production:
stage: deploy
script:
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$SSH_PRIVATE_KEY")
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
- ~/.composer/vendor/bin/envoy run deploy
environment:
name: production
url: https://low.bi
when: manual
only:
- master
里面使用我们之前 push 的 Docker 镜像,附加了一个 mysql 镜像作为数据库,定义了俩个步骤:unit_test
和 deploy_production
,前者自动后者手动,其中 deploy_production
里用到了之前设置 ssh 时定义的变量 SSH_PRIVATE_KEY
。
将 .gitlab-ci.yml
commit 并 push 到 GitLab 后,会触发 Pipelines
:
点进 pipeline 可以看到具体的执行情况。
至此,利用 GitLab CI/CD 和 Envoy 自动化测试和部署 Laravel 项目全部步骤就完成了。