CI 持续集成 - 阿里云云效

735 阅读6分钟

file

前两个月给公司搭建了一套持续集成,用的是阿里云的「云效」,「云效」有免费一个月的试用版,有兴趣的朋友可以玩一玩,开阔一下知识范围。开始之前你需要简单了解一下 云效文档哦

概念

持续集成指的是,频繁地(一天多次)将代码集成到主干。它的好处主要有两个。

  1. 快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。
  2. 防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

持续集成大致流程

提交

流程的第一步,是开发者向代码仓库提交代码。所有后面的步骤都始于本地代码的一次提交(commit)。

构建

所谓构建,指的是将源码转换为可以运行的实际代码,比如安装依赖,配置各种资源(样式表、JS脚本、图片)等等。

测试

全面测试,单元测试和集成测试都要跑,有条件的话,也要做端对端测试。所有测试以自动化为主,少数无法自动化的测试用例,就要人工跑。

部署

通过了第二轮测试,当前代码就是一个可以直接部署的版本(artifact)。将这个版本的所有文件打包( tar filename.tar * )存档,发到生产服务器。

生产服务器将打包文件,解包成本地的一个目录,再将运行路径的符号链接(symlink)指向这个目录,然后重新启动应用。这方面的部署工具有 Ansible,Chef,Puppet 等。

回滚

一旦当前版本发生问题,就要回滚到上一个版本的构建结果。最简单的做法就是修改一下符号链接,指向上一个版本的目录。

更详细的说明:www.ruanyifeng.com/blog/2015/0…

云效持续集成操作流程

在云效后台中,首先为项目注册应用,并且关联代码库:

file

新建项目之后,选择当前创建的项目:

file

流水线配置

点击左侧流水线栏目,注册一条项目流水线

file

将流水线关联到当前项目的代码库之中,并且选择代码推送后触发流水线的分支

file

点击流水线第一个阶段,一般为名称设为「构建」,选项解释如下:

  1. 分支名称:这里的分支名称是在阿里云虚拟主机中构建时拉取的分支,请根据当前部署环境选择对应的分支
  2. 构建配置:有时我们需要构建产生不同内容的包,用于不同的运行环境(比如集成测试环境和生产环境)云效流水线上的构建任务根据指定 Git 库源代码根目录下的 <应用名称>.release 文件,进行构建打包工作,以便随后流水线上的部署任务进行部署 release 所有配置选项

file

在下面的高级配置之中有个「包」的概念,其意思就是构建的时候根据你配置的包生成多个环境,如配图中会生成「Testing 测试环境」「Staging 预发布环境」

file

包标签中的参数会在阿里云虚拟主机构建的时候生成系统环境变量,然后 Shell 获取 PS:构建成功之后,阿里云虚拟主机会把项目压缩打包成 tgz 格式,然后上传到一个资源空间之中,以便部署阶段下载压缩包

下一个阶段为部署阶段,当然你可以在流水线中新增其他阶段如「测试阶段」,在部署阶段选择对应的包标签配置、应用、环境即可

file

至此流水线配置结束 流水线帮助文档

部署环境配置

点击部署环境

file

在部署配置之中我们需要做如下事情,「部署流程将按照下面排序进行」

  1. 下载路径:设置下载路径,其意是将资源空间之中的压缩包下载到你企业关联的服务器上
  2. Stop:此项设置一个 Shell 或其他操作脚本,一般需要把老项目清理掉
  3. 解压目录:将下载后的项目压缩包解压到指定的目录
  4. Start:此项设置一个 Shell 或其他操作脚本,一般情况是在阿里云服务器上面初始化项目,如「数据迁移」
  5. 执行用户:在阿里云服务器的最大权限用户一般为:root

私密配置项,有时候涉及一些私密信息,不适合放在代码库中如数据库配置,以包标签前缀区分环境配置 私密配置概念

file

file

至此云效后台配置完成

代码库中构建配置脚本

构建的时候阿里云虚拟机,会以 <应用名>.release 文件执行构建方式「这个文件会放到项目根目录」

  1. code.language 是阿里云虚拟机需要的环境配置,配图中为 php 7.0
  2. build.command 为构建时自定义的 Shell 命令,配图中执行了一个 Shell 脚本

file

Build Shell 脚本,在此脚本中将仓库代码构建成一个完整可运行的项目

  1. 在此次可获取「包标签」中自定义的环境变量
  2. 获取包标签环境表里为「PACKAGE_LABEL」
  3. 私密配置项的内容会在构建时生成一个文件其名称固定为「rdc_security_config.properties」放在项目根目录下,可读取文件中的配置来填入 .env 中
  4. 注意 Shell 脚本一定要添加可执行权限
#!/bin/bash

echo "开始构建 ${PACKAGE_LABEL} 环境"

# Git 构建
git pull origin ${ENV_BRANCH}
git submodule init
git submodule update
echo "结束构建 ${ENV_BRANCH}"

# 安装依赖
echo "开始安装依赖"
composer config -g repo.packagist composer https://packagist.phpcomposer.com
composer install
echo "结束安装依赖"

# 设置配置
echo "开始配置项目"

cp .env.example.${PACKAGE_LABEL} .env
S_DB_PASSWORD=`./find.sh ${PACKAGE_LABEL}_DB_PASSWORD`
S_DB_USERNAME=`./find.sh ${PACKAGE_LABEL}_DB_USERNAME`
S_DB_DATABASE=`./find.sh ${PACKAGE_LABEL}_DB_DATABASE`
S_DB_HOST=`./find.sh ${PACKAGE_LABEL}_DB_HOST`
echo "数据库配置读取成功......"
sed -i -e "s/DB_HOST=127.0.0.1/DB_HOST=${S_DB_HOST}/g" .env
sed -i -e "s/DB_DATABASE=homestead/DB_DATABASE=${S_DB_DATABASE}/g" .env
sed -i -e "s/DB_USERNAME=homestead/DB_USERNAME=${S_DB_USERNAME}/g" .env
sed -i -e "s/DB_PASSWORD=secret/DB_PASSWORD=${S_DB_PASSWORD}/g" .env
echo "数据库配置 Done"

# 正式服务器 Redis 配置
if [ "${PACKAGE_LABEL}" == 'production' ];
then
    sed -i -e "s/REDIS_HOST=127.0.0.1/REDIS_HOST=${ENV_REDIS_HOST}/g" .env
    sed -i -e "s/REDIS_PASSWORD=null/REDIS_PASSWORD=${ENV_REDIS_PASSWORD}/g" .env
    echo "Redis 服务配置完成"
fi

# 百度地图配置
sed -i -e "s/Baidu_Map_API_KEY=/Baidu_Map_API_KEY=${ENV_BAIDU_MAP_API_KEY}/g" .env
echo "百度地图配置完成"

sed -i -e "s/WECHAT_PAYMENT_APPID=/WECHAT_PAYMENT_APPID=${ENV_WECHAT_PAYMENT_APPID}/g" .env
sed -i -e "s/WECHAT_PAYMENT_MCH_ID=/WECHAT_PAYMENT_MCH_ID=${ENV_WECHAT_PAYMENT_MCH_ID}/g" .env
sed -i -e "s/WECHAT_PAYMENT_KEY=/WECHAT_PAYMENT_KEY=${ENV_WECHAT_PAYMENT_KEY}/g" .env
echo "微信配置 Done"

sed -i -e "s/WECHAT_OPEN_PLATFORM_APPID=/WECHAT_OPEN_PLATFORM_APPID=${ENV_WECHAT_OPEN_PLATFORM_APPID}/g" .env
sed -i -e "s/WECHAT_OPEN_PLATFORM_SECRET=/WECHAT_OPEN_PLATFORM_SECRET=${ENV_WECHAT_OPEN_PLATFORM_SECRET}/g" .env
sed -i -e "s/WECHAT_OPEN_PLATFORM_TOKEN=/WECHAT_OPEN_PLATFORM_TOKEN=${ENV_WECHAT_OPEN_PLATFORM_TOKEN}/g" .env
sed -i -e "s/WECHAT_OPEN_PLATFORM_AES_KEY=/WECHAT_OPEN_PLATFORM_AES_KEY=${ENV_WECHAT_OPEN_PLATFORM_AES_KEY}/g" .env
echo "微信开放平台配置 Done"

sed -i -e "s/OSS_ID=/OSS_ID=${ENV_OSS_ID}/g" .env
sed -i -e "s/OSS_KEY=/OSS_KEY=${ENV_OSS_KEY}/g" .env
sed -i -e "s/OSS_BUCKET=/OSS_BUCKET=${ENV_OSS_BUCKET}/g" .env
sed -i -e "s/OSS_ENDPOINT=/OSS_ENDPOINT=${ENV_OSS_ENDPOINT}/g" .env
sed -i -e "s/OSS_SSL=/OSS_SSL=${ENV_OSS_SSL}/g" .env
sed -i -e "s/OSS_IS_CNAME=/OSS_IS_CNAME=${ENV_OSS_IS_CNAME}/g" .env
echo "OSS 配置 Done"

sed -i -e "s/APP_ENV=local/APP_ENV=${PACKAGE_LABEL}/g" .env
php artisan key:generate
composer du
chmod -R 777 storage
chmod -R 777 bootstrap

echo "${PACKAGE_LABEL} 环境构建成功!"

这里有个小技巧,有可能不同环境的 .env 的配置项 KEY 不一样,如:测试服务器中用 QINIU 正式服务器中用 OSS,那么可以把 .env.example 修改为对应环境的 .env.example.testing ,之后就可以获取不同环境的 .env 文件

file

cp .env.example.${PACKAGE_LABEL} .env

服务器中部署配置脚本

就是我们在部署环境中指定的脚本

file

项目中这两个脚本分别做了如下操作

clear_old.sh

#!/bin/bash
rm -rf /var/www/CI/yydy-rms
echo 'old project clear !'

init.sh

#!/bin/bash
cd /var/www/CI/yydy-rms
php artisan migrate
composer du
echo 'project is ready!'

当然上面只是一个简单的删除老项目拷贝新项目,你们可以根据自己项目实际需求初始化项目。

PS

现在推送流水线设置的分支会自动触发「流水线工作」,如果流水线某个阶段工作失败可到后台查看失败原因方便排除错误

file

最后附上一张公司实际流水线图

file

云效地址 云效文档

Good Job Done !