概述
持续集成(CI)和 持续交付(CD) 是一种流行的软件开发实践,每次提交都通过自动化的构建(测试、编译、发布)来验证,从而尽早的发现错误。
持续集成实现了DevOps, 使开发人员和运维人员从繁琐的工作中解放出来。另外,这种形式极大地提高了开发者的开发效率和开发质量。 持续集成有多种工具,如Jenkins. GitLab内置了GitLab-CI,通过配置一段YAML脚本来实现持续集成.
功能
持续集成可以实现的功能:
- 代码审核: 自动化代码规范审查, 甚至代码质量检查
- 自动化测试: 单元测试, 功能测试和验收测试
- 编译发布: 将源代码编译成可执行程序, 并将程序上传到托管发布平台实现自动发布
- 构建部署: 通过构建Docker镜像, 或登录远程服务器执行相关部署命令和脚本, 实现自动化部署
原理
GitLab-CI 检测每次代码变动, 通过.gitlab-ci.yml脚本执行构建命令, 将命令发布到GitLab-Runners(运行机)上, 进而执行命令.
GitLab-Runners 基于Docker执行持续集成的每项任务, 这样就解决了环境依赖问题.
GitLab-Runners把实时将执行结果输出到GitLab网页上, 任务执行完后, 通过徽章标记和邮箱告知执行结果.
在仓库根目录创建 .gitlab-ci.yml 文件, 内容如下1
2
3job-1:
script:
- echo "Hello World"
这样, 在每次提交代码后, 都会自动执行以上脚本. 其中job-1是任务名称, 可以定义多个任务,
script下面是 shell 命令, 只要命令执行成功, 就代表本次构建通过(出现passed标记)
这样, 一次简单的持续集成已经搞定了.
如何编写GitLab-CI配置文件
见文档 如何编写GitLab-CI配置文件
远程拉取代码
使用ssh远程登录服务器, 然后执行git pull 拉取代码, 实现代码热更新
由于ssh无密码登录需要用到密钥, 所以首先需要注入私钥
如1
2
3
4release-doc:
stage: deploy
script:
- ssh root@$DEPLOY_SERVER "cd /mnt/data/docker-gollum/wiki && git pull origin master"
关键词
根主要关键词一览
关键词 | 含义 | 可选 | 备注 |
---|---|---|---|
image | 声明使用的Docker镜像 | 为空时使用默认镜像 | 该镜像应当满足脚本执行的环境依赖 |
services | Docker镜像使用的服务, 通过链接的方式来调用所需服务 | 可空 | 常用于链接数据库 |
stages | 定义构建阶段 | 为空时, 单纯定义jobs | 项目的构建分为多个阶段, 例如: 安装依赖/准备, 编译, 测试, 发布等, 同时每个阶段包含若干任务 |
before_script | 定义每个job之前执行的脚本 | 可空 | 每个job启动时会先执行该脚本 |
after_script | 定义每个job之后执行的脚本 | 可空 | 同上 |
variables | 定义变量 | 可空 | 同上 |
cache | 定义与后续job之间应缓存的文件 | 可空 | 同上 |
Demo:
1 | image: aipline |
Jobs中的关键词
jobs中存在一些与根中相同的关键词, 这些一旦定义, 则会向前覆盖, 即根中定义的则不会在该job执行
job 这里译为任务
关键词 | 含义 | 可选 | 备注 |
---|---|---|---|
image | 声明任务使用的Docker镜像 | 为空时使用根中的定义 | 该镜像应当满足脚本执行的环境依赖 |
services | 任务中Docker镜像使用的服务, 通过链接的方式来调用所需服务 | 可空 | 常用于链接数据库 |
stage | 所属构建阶段 | 为空时则不使用stages | 一个任务属于一个构建阶段 |
before_script | 定义每个job之前执行的脚本 | 可选 | 如果在job中定义则会覆盖根中的内容 |
script | 定义每个job执行的脚本 | 必须 | |
after_script | 定义每个job之后执行的脚本 | 可选 | 同上 |
variables | 定义任务中使用的变量 | 可选 | 同上 |
cache | 定义与后续job之间应缓存的文件 | 可选 | 同上 |
only | 指定应用的Git分支 | 可选 | 可以是分支名称, 可用正则匹配分支, 也可是tags来指定打过标签的分支 |
except | 排除应用的Git分支 | 可选 | 同上 |
tags | 指定执行的GitLab-Runners | 可选 | 通过匹配Runners的标签选定 |
allow_failure | 允许失败 | 默认为false 如果允许失败, 本次任务不会影响整个构建的结果 | |
when | 定义合适执行任务 | 默认为always | 有on_success, on_failure, always or manual可选 |
dependencies | 定义合任务所需要的工件 | 可空 | 需要首先定义工件 |
artifacts | 定义工件 | 可空 | 工件中指定的目录会在任务执行成功后压缩传到GitLab, 后面需要该工件的任务执行时, 再自行下载解压 |
environment | 定义环境 | 可空 | 在部署任务中, 定义该任务所属的环境 |
示例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25installing-dependencies:
script:
- composer install --prefer-dist --optimize-autoloader -n --no-interaction -v --no-suggest
- composer dump-autoload --optimize
artifacts:
- name: "vendor"
- untracked: true
- expire_in: 60 mins
- paths:
- vendor/
deleteocker-build-image:
stage: test
only:
- master
except:
- develop
tags:
- ruby
- postgres
allow_failure: true
dependencies:
- installing-dependencies
script:
- docker build -t registry.com/mops/image:latest .
- docker push registry.com/mops/image:latest
注意:
jobs的名称不能重名
同一阶段中的任务, 是并行执行的
上一阶段所有任务执行完后, 才会进入下一阶段
定义工件时, 务必定义工件的过期时间, 否则工件会一直寸在GitLab上, 占用空间
如果需要在任务中传递文件, 优先选择使用 dependencies (结合artifacts)
验证配置文件合法性
在GitLab中, 打开 /ci/lint网址, 将配置文件粘贴在些, 进行验证
通过gitlab-ci实现文件的自动部署
实现过程
文档托管在gitlab上, 每次代码更新, 会自动出发gitlab-ci构建 在构建脚本中, 通过ssh 登录远程服务器执行git拉取文档的命令
过程
生成ssh证书
在服务器上, 使用ssh-keygen生成root用户(或其他有权访问的用户)的公钥和私钥
在用户根目录(~)中, 创建authorized_keys并设置权限: chmod 600 authorized_keys
添加公钥
添加公钥: cat id_rsa.pub >> ~/.ssh/authorized_keys
id_rsa.pub为第一步生成的公钥
注意该证书的用户必须与ssh远程登录的用户一样, 例如我们的用户名是root
将公钥添加到gitlab上, 以便于该用于可以拉取代码, 在User Settings找到 SSH Keys, 添加上面拿到的公钥
设置CI/CD变量
在 CI/CD Piplines中设置 Secret Variables, 包括 DEPLOY_SERVER 和 SSH_PRIVATE_KEY
其中 SSH_PRIVATE_KEY 的内容是服务器上的私钥, DEPLOY_SERVER 是服务器地址
编写 .gitlab-ci.yml 文件, 注入密钥, 通过ssh执行远程命令
完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30# 使用alpine镜像, 该镜像很少,只有几兆
image: alpine
stages:
- deploy
before_script:
# 预先装 ssh-agent
- 'which ssh-agent || ( apk update && apk add openssh-client)'
# 启动服务
- eval $(ssh-agent -s)
# 将私钥写入deploy.key 文件
- echo "$SSH_PRIVATE_KEY" > deploy.key
# 配置较低权限
- chmod 0600 deploy.key
# 注入密钥
- ssh-add deploy.key
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
release-doc:
stage: deploy
variables:
GIT_STRATEGY: none
script:
# 连接远程服务器并执行拉取代码的命令
- ssh root@$DEPLOY_SERVER "cd /path/to/wiki && git pull origin master"
only:
- master
environment:
name: production
url: http://$DEPLOY_SERVER