本文记录一个前端部署Gitlab的CI。不是在自己的服务器上面搭建的Gitlab。使用的是Gitlab.com的Gitlab的CI,在腾讯云撸的羊毛的小水管也搭不起Gitlab,做个CI的服务器还是能勉勉强强的。
Gitlab和Github
Github 一个网站,提供给用户空间创建git仓储,保存用户的一些数据文档或者代码等。
Gitlab 一个基于git实现的在线代码仓库软件,你可以用Gitlab自己搭建一个类似于Github一样的系统,一般用于在企业、学校等内部网络搭建Git私服。
什么是持续集成
阮一峰的这个文章写的挺好的持续集成是什么?
持续集成指的是,频繁地(一天多次)将代码集成到主干。
持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
Gitlab的CI
从 GitLab 8.0 开始,GitLab CI 就已经集成在 GitLab 中,我们只要在项目中添加一个 .gitlab-ci.yml 文件,然后添加一个 Runner,即可进行持续集成。 而且随着 GitLab 的升级,GitLab CI 变得越来越强大。
首先明白Gitlab CI 几个基本的概念
GitLab-CI
这个是一套配合GitLab使用的持续集成系统,是GitLab自带的,也就是你装GitLab的那台服务器上就带有的。无需多考虑。.gitlab-ci.yml的脚本解析就由它来负责。
GitLab-Runner
这个是脚本执行的承载者,.gitlab-ci.yml的script部分的运行就是由runner来负责的。GitLab-CI浏览过项目里的.gitlab-ci.yml文件之后,根据里面的规则,分配到各个Runner来运行相应的脚本script。这些脚本有的是测试项目用的,有的是部署用的。
.gitlab-ci.yml
这个是在git项目的根目录下的一个文件,记录了一系列的阶段和执行规则。GitLab-CI在push后会解析它,根据里面的内容调用runner来运行。
简单来说就是,你利用Git版本管理Push了本地代码到Remote上(这里就是你gitlab.com),然后Gitlab,就通知你的服务器,也就是Gitlab-runner来运行构建任务。然后跑测试用例,测试用例通过了就生成Build出相应的环境的代码,自动部署上不同的环境服务器上面去。
安装Gitlab Runner
如果想要使用Docker Runner,则需要安装Docker。(可选)
curl -sSL https://get.docker.com/ | sh
安装 GitLab Runner 太简单了,按照着 官方文档 的教程来就好拉! 下面是 Debian/Ubuntu/CentOS 的安装方法,其他系统去参考官方文档:
# For Debian/Ubuntu
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
$ sudo apt-get install gitlab-ci-multi-runner
# For CentOS
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
$ sudo yum install gitlab-ci-multi-runner
然后注册Gitlab Runner Runner需要注册到Gitlab才可以被项目所使用,一个gitlab-ci-multi-runner服务可以注册多个Runner。
在 GNU/Linux 系统上注册 Runner:
运行下面命令启动注册程序:
sudo gitlab-runner register
输入 GitLab 实例 URL:
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com
输入获取到的用于注册 Runner 的 token:
Please enter the gitlab-ci token for this runner
xxx //这个token在你gitlab.com的项目的 setting >> CI/CD >> Runners settings 下
输入该 Runner 的描述,稍后也可通过 GitLab's UI 修改:
Please enter the gitlab-ci description for this runner
一个配置很低的服务器
给该 Runner 指派 tags, 稍后也可以在 GitLab's UI 修改:
Please enter the gitlab-ci tags for this runner (comma separated):
tengxun // 这个就相当于每一个runner的唯一id,记住这个tag。
选择 Runner 是否接收未指定 tags 的任务(默认值:false), 稍后可以在 GitLab's UI 修改:
Whether to run untagged jobs [true/false]:
[false]: true
选择是否为当前项目锁定该 Runner, 之后也可以在 GitLab's UI 修改。 该功能通常用于被指定为某个项目的 Runner (默认值:true):
Whether to lock Runner to current project [true/false]:
[true]: true
选择 Runner executor:
Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
docker // 我选择的docker,请记住,选择docker的之前要把docker启动,docker的使用就不是本文所讲的了
如果你选择 Docker 作为你的 executor,注册程序会让你设置一个默认的镜像, 作用于 .gitlab-ci.yml 中未指定镜像的项目:
Please enter the Docker image (eg. ruby:2.1):
alpine:latest
然后,你刷新你setting下面的配置
有个绿色的小圆点,这就表明你已经注册Runner成功了。配置.gitlab-ci.yml
配置好 Runner 之后,我们要做的事情就是在项目根目录中添加 .gitlab-ci.yml 文件了。 当我们添加了 .gitlab-ci.yml 文件后,每次提交代码或者合并 MR 都会自动运行构建任务了。
在.gitlab-ci.yml有一些需要讲解的概念
Pipeline
一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。我们的任何提交或者 Merge Request 的合并都可以触发 Pipeline。如下图:
+------------------+ +----------------+
| | trigger | |
| Commit / MR +---------->+ Pipeline |
| | | |
+------------------+ +----------------+
Stages
Stages 表示构建阶段,说白了就是上面提到的流程。 我们可以在一次 Pipeline 中定义多个 Stages,每个Stage可以完成不同的任务。 Stages有下面的特点:
- 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始
- 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功
- 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败
因此,Stages 和 Pipeline 的关系就是:
+--------------------------------------------------------+
| |
| Pipeline |
| |
| +-----------+ +------------+ +------------+ |
| | Stage 1 |---->| Stage 2 |----->| Stage 3 | |
| +-----------+ +------------+ +------------+ |
| |
+--------------------------------------------------------+
Jobs
Jobs 表示构建工作,表示某个 Stage 里面执行的工作。 我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:
- 相同 Stage 中的 Jobs 会并行执行
- 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
- 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败
所以,Jobs 和 Stage 的关系图就是:
+------------------------------------------+
| |
| Stage 1 |
| |
| +---------+ +---------+ +---------+ |
| | Job 1 | | Job 2 | | Job 3 | |
| +---------+ +---------+ +---------+ |
| |
+------------------------------------------+
这些是部署脚本里面的一些基本结构,接下来说一些.gitlab-ci.yml的基本构成
下面是一个最简单的Node项目的部署脚本。
image: node:alpine // 默认的ci部署的docker镜像
stages: // 首先按顺序定义有几个步骤。步骤下面的所有job是同步执行的
- test
- build
job1:
stage: test // 属于test的stage
script:
- npm run test // 这个job执行的脚本
only:
- master // 只监听master分支的代码提交
tags:
- tengxun // 要使用哪个runner
job2:
stage: build
script:
- npm run build
only:
- master
tags:
- tengxun
注意这里的job1,job2名字是随便取的,没有关系,只要不用Gitlab-CI的关键字就可以。
列出一些常用的关键字,掌握了这些就可以开发了。
关键字 | 是否必须 | 描述 |
---|---|---|
image | 否 | 用于docker镜像,查看docker文档 |
services | 否 | 用于docker服务,查看docker文档 |
stages | 否 | 定义构建阶段 |
types | 否 | stages 的别名(已废除) |
before_script | 否 | 定义在每个job之前运行的命令 |
after_script | 否 | 定义在每个job之后运行的命令 |
variable | 否 | 定义构建变量 |
cache | 否 | 定义一组文件列表,可在后续运行中使用 |
发现这篇文章对每个关键字对解释的好清楚,算是个抛砖引玉吧。比我写的都还要清楚。
配置之前,你还要在你gitlab.com的对应项目里面的setting >> CI/CD >> Secret variables 定义一些构建变量,因为你的Gitlab-CI要去自动的登录服务器,然后把打包出来的文件自动更新上去。
Runner 登录你的服务器是不能用传统输入账号密码的形式,(因为都自动化了,还需要输入密码,那还叫什么自动化)。只能通过走SSH登录的形式,如果不懂SSH登录,请自行谷歌。私钥这些东西肯定不能写在yml文件里面,因为yml文件是每个人都能看见的,所以Gitlab-CI就可以在项目里面自定义私有的变量名。至少项目开源出去之后,不是每个人都能看见部署服务器的私钥的。
这里的$SSH_PRIVATE_KEY 是你开发机(也就是你的的开发电脑)生成的私钥。 注意一定要复制
-----BEGIN RSA PRIVATE
-----END RSA PRIVATE KEY-----
这些东西。(这里是个坑。。。因为很少会让你复制私钥的) 下面配置的${CI_COMMIT_REF_NAME},是Gitlab CI 的默认关键字。详情见文档
最后贴上我那个腾讯云小水管的配置,亲测有用。
还真是一个很简单的vue项目。就用vue-cli生成,然后发布到服务器上面指定的目录,服务器上面的nginx配置已经配置好了。
stages:
- test
- build
- deploy
cache:
key: ${CI_COMMIT_REF_NAME}
paths:
- node_modules/
test_dev:
image: node:alpine
stage: test
only:
- dev
tags:
- tengxun
script:
- npm run test
build:
image: node:alpine
stage: build
only:
- master
- dev
tags:
- tengxun
script:
- npm set registry https://registry.npm.taobao.org # 设置淘宝镜像地址
- npm install --progress=false
- npm run build
artifacts:
expire_in: 1 week
paths:
- dist
deploy_dev:
image: alpine
stage: deploy
only:
- dev
tags:
- tengxun
script:
- echo "http://mirrors.aliyun.com/alpine/v3.7/main/" > /etc/apk/repositories
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
- chmod 600 ~/.ssh/id_dsa
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- rsync -rav --delete dist/ "$SERVER_USER_HOST:$SERVER_DEV_PATH"
deploy_master:
image: alpine
stage: deploy
only:
- master
tags:
- tengxun
script:
- echo "http://mirrors.aliyun.com/alpine/v3.7/main/" > /etc/apk/repositories
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
- chmod 600 ~/.ssh/id_dsa
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- rsync -rav --delete dist/ "$SERVER_USER_HOST:$SERVER_MASTER_PATH"
when: manual
这里用rsync来同步Build出来的代码,其实也很简单的。
rsync 是一个开源工具,可以进行快速的增量的文件传输。相关文章
简单来说就是让你源计算机和目标计算机进行文件的同步。
附上rsync的翻译的文档 点我
在GitLab-CI中, cache与artifacts比较容易混淆.
其中 cache 指的是缓存, 常用于依赖安装中, 如几个jobs都需要安装相同的依赖, 可以使用依赖, 此时可以加快依赖的安装进度; 对于artifacts则是将某个工件上传到GitLab提供下载或后续操作使用, 由于每个job启动时, 都会自动删除.gitignore中指定的文件, 因此对于依赖安装目录, 即可以使用cache, 也可以使用artifacts.
两个主要有以下几个区别:
- 虽然定义了cache, 但是如果cache和.gitignore中重复的这部分, 仍然需要重新安装
- 重新安装时因为使用的是缓存, 所以很有可能不是最新的
- 特别是开发环境, 如果每次都希望使用最新的更新, 应当删除cache, 使用artifacts, 这样可以保证确定的更新
- artifacts中定义的部分, 会自动生成, 并可以传到下面的job中解压使用, 避免了重复依赖安装等工作 如果使用Docker运行Gitlab-Runner, cache会生成一些临时容器, 不容易清理
- artifacts可以设置自动过期时间, 过期自动删除
- artifacts会先传到GitLab服务器, 然后需要时再重新下载, 所以这部分也可以在GitLab下载和浏览
因为我们这里要重复使用之前job打包出来在dist下面的文件,所以我会使用artifacts。
when: manual
这里master一般是值稳定的代码版本,所以最好手动执行的。when: manual
就是需要手动部署,所有job默认都是自动执行的。
鲁迅曾经说过:有国内加速镜像地址的一定要用国内镜像地址
这里的镜像地址配置包括Docker,APK,NPM。一定要设置啊,当时就卡在这里了很久。
然后我们push代码到master,点击你项目的CI/CD面板。
然后小水管过了2分钟才跑完Build,扎心了。 点击右面的那个播放三角形,就可以部署到我的那个腾讯云服务器上面去了。(当然,dev分支是默认自动部署和的),这就开始构建了。好啦,一个简单的前端CI尝试就完了。
that's all。
参考资料
gitlab之gitlab-ci自动部署 GitLab 中文文档 Gitlab CI yaml官方配置文件翻译 用 GitLab CI 进行持续集成