目标:学习 CI/CD 的基本概念,GitLab CI/CD 使用方法。
前提:有 GitLab 的账号和基础知识,了解远程仓库、分支、提交、推送、合并申请等概念。如果不了解,可以学习教程 Hello World in GitLab。
内容:学习 CI/CD 的基本概念,创建并部署一个 Flutter 项目到 GitLab,使用GitLab CI/CD 自动化执行项目的测试、打包、分发。
演示平台:macOS
CI/CD 的基本概念
CI (Continuous Integration)持续集成。集成是指将代码集成到主干。
CD (Continuous Delivery,Continuous Deployment)持续交付,持续部署。交付是指将软件的某一版本交付给质量团队或用户,以供评审。部署是指软件通过评审后,进入生产阶段,部署到生产环境。
“持续”强调应用开发是一个长期的不断迭代的过程,集成、交付、部署这三个动作会不断发生。
CI/CD 是一种方法,通过在应用开发阶段引入自动化来频繁向客户交付应用。其核心概念是持续集成、持续交付和持续部署。
GitLab CI/CD 是一个内置在 GitLab 中的工具,用于通过 CI/CD 方法进行软件开发。
集成、交付、部署是一个连贯的流程。当我们在谈论 CI/CD 时,有可能仅指持续集成和持续交付,也可能指持续集成、持续交付和持续部署三者。我们没必要纠结于此,只需要记住 CI/CD 表现为一个流程(通常形象地表述为 pipeline,即管道)。
工作流程
在学习使用 GitLab CI/CD之前,我们先看看如果没有 GitLab CI/CD ,在 GitLab 的工作可能会如何进行?
以 Flutter 项目为例子来说明工作流程(步骤1需要跟做,其余步骤仅展示工作流程):
创建一个包含测试的 Flutter 项目并部署到 GitLab 仓库。
创建 Flutter 项目可参考教程 创建您的第一个Flutter应用 。
在 GitLab 网站创建一个名为 myFlutter 的新项目:
我们要把已存在的项目推送到 GitLab 的 myFlutter 项目,参考 Push an existing folder 的提示命令行:
//进入 Flutter 项目位置
cd ~/workspace/my_flutter
//初始化,把当前目录变为 Git 可以管理的仓库
git init
//指定远程 URL,Push an existing folder 命令行展示了 URL。
git remote add origin git@team.xxx.net.cn:Josie/myflutter.git
//添加文件,提交文件
git add .
git commit -m 'Initial commit'
//推送本地项目到远程
git push -u origin masterFlutter 项目原本有 README.md 文件,不需再次创建。
团队多人协作开发,每个人有自己的分支。开发人员提交代码,提交前运行测试(在终端运行命令):
flutter test
分支开发完成后,提出合并申请并处理矛盾冲突,合并前再次运行测试(在终端运行命令),如果测试通过就合并到主分支:
flutter test
完成某一版本的开发后,把 Flutter 项目构建为 APK(在终端运行命令):
flutter build apk
把 APK 分发到 AppCenter(在终端运行命令):
appcenter login
appcenter distribute release -f [APK_FILE_PATH] -g [GROUP] --app [USER_NAME]/[PROJECT]AppCenter 向测试人员交付应用,或将应用发布到应用商店。
在这个过程中,步骤3是“集成”,步骤4、5、6是“交付”“部署”。这是一个简化的开发过程。在真实开发过程中,这几个步骤会不断重复发生,并且更复杂。
GitLab CI/CD
GitLab CI/CD 可以自动执行部分操作(比如步骤3、4、5),将其流程化、规范化,减少人工操作可能带来的问题。
GitLab CI/CD 自动执行工作流程,需要两样东西:定义任务的文件,按照这份文件执行任务的程序。其中,定义任务的文件名为 .gitlab-ci.yml
,执行任务的程序是 GitLab Runner。
下面,我们先配置 GitLab Runner。
GitLab Runner
GitLab Runner 是一个允许计算机执行任务并将结果反馈给 GitLab 的程序,即 GitLab Runner 可以自动执行文件定义的任务。当一个新的提交被推送到 GitLab 或提交合并申请时,会触发 runner 执行新任务,运行特定作业,并在 GitLab 展示执行结果。
在 GitLab 的 Flutter 项目中,跳转到 Setting > CI/CD > Runners(点击 Expand) > Specific Runners。
在 Specific runners 点击按钮 Show Runner installation instructions。注意,注册 gitlab-runner 会用到这里提及的 GitLab 实例 URL 和 registration token 注册令牌。
选择当前设备环境,例如 macOS。下面提示相应的下载安装命令,按照提示在终端进行操作。
让我们来看看下载安装命令的具体意义:
下载二进制文件:
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64s
赋予可执行权限给二进制文件:
sudo chmod +x /usr/local/bin/gitlab-runner
运行刚才下载的文件,注册 gitlab-runner:
sudo gitlab-runner register --url $GITLAB_INSTANCE_URL --registration-token $REGISTRATION_TOKEN
//如果以上命令报错,请使用下面的命令
sudo gitlab-runner registerGITLAB_INSTANCE_URL 是 GitLab 实例 URL。
REGISTRATION_TOKEN 是注册令牌。其中,注册 gitlab-runner 时,需要进行一些设置:
Enter the GitLab instance URL(for example, http://gitlab.com/):
#(输入GitLab 实例 URL,按回车输入参数值)
Enter the registration token:
#(输入注册令牌,按回车输入参数值)
Enter a description for the runner:
#(输入runner的描述,直接按回车则输入[]内的默认值)
A shell runner for my flutter project.
Enter tags for the runner (comma-separated):
#(输入 runner 标签,可以有多个,用逗号隔开。标签用于识别 runner)
flutter
Enter an executor: custom, docker-ssh, shell, ssh, virtualbox, docker, parallels, docker+machine, docker-ssh+machine, kubernetes:
#(选择执行器。我们将使用shell,输入 shell 并按回车)
shell
Runner 的 description 描述、token 标签可以再次修改。
一个项目可以有多个 runner,只需要再次执行注册命令 sudo gitlab-runner register
,就能创建其他 runner。
切换到主目录,安装 gitlab-runner,启动 gitlab-runner:
cd ~
gitlab-runner install
gitlab-runner start
运行 gitlab-runner:
gitlab-runner run
如果出现以下提示:
WARNING: Running in user-mode.
WARNING: Use sudo for system-mode:
WARNING: $ sudo gitlab-runner...
请使用下面的命令:
sudo gitlab-runner run
运行 gitlab-runner run
命令后,回到 GitLab 的 Setting > CI/CD > Runners(点击 Expand ) > Specific Runners,验证 GitLab Runner 是否正常运行,如果显示绿色圆形图标,表示已经成功安装并运行 GitLab Runner 实例。
输入以下命令,获取帮助:
gitlab-runner help
下面,我们创建定义任务的文件 .gitlab-ci.yml
。
设置 CI 管道
在项目的根目录创建一个新的 GitLab 配置文件 .gitlab-ci.yml
,我们可以其中定义测试、构建、分发等操作。
job 作业是 GitLab CI/CD 最小独立运行单位,定义做什么。
stages 阶段,定义何时运行 job。一个阶段可以包含多个 job。
pipeline 管道,一个 pipeline 可以包含多个 stage 和 job。每一次 commit 或 mr(merge request) 触发执行一个 pipeline 构建任务。
为什么把执行任务的过程称为 pipeline 管道?因为执行任务的过程具有以下特点:
- 一个 pipeline 可以有多个 stage,stage 从上到下执行,只有当前 stage 执行完毕才能执行下一个 stage,否则报错。
- 一个 stage 有多个 job,其中一个 job 执行失败,stage 算是执行失败。相同 stage 中的 job 是并行执行的。
创建单元测试管道
创建文件后,可以在 myFlutter > CI/CD > Editor > Write pipeline configuration 编辑文件,点击 Commit changes 保存提交。
我们将会在文件 .gitlab-ci.yml
输入以下内容,使得 GitLab 在适当的时机自动执行 flutter test
脚本来执行单元测试。
stages:
- test # All jobs related for testing such as Unit Test
flutter_test: # Name of the lane
stage: test # type of stage
script:
- flutter test # Run Flutter test
tags:
- flutter # Tags for runner
- stages 属性定义阶段及其顺序。上文定义了一个名为 test 的阶段。
- 上文定义了名为 flutter_test 作业。
- 作业的 stage 属性定义作业属于某哪个阶段。上文定义 flutter_test 作业属于 test 阶段。
- 作业的 script 属性定义做什么。上文定义了脚本
flutter test
执行单元测试。 - 作业的 tags 属性定义哪个 runner 执行作业。上文指定了带有 tag
flutter
的 runner。
定义文件 .gitlab-ci.yml
后,如果触发 pipeline 构建任务,将会执行 test 阶段中的作业 flutter_test,由指定 runner 执行作业中的脚本 flutter test
。
myFlutter > CI/CD > Editor > Visualize 以图像展示文件 .gitlab-ci.yml
的内容:有一个 test 阶段,test 阶段下有一个作业 flutter_test。
myFlutter > CI/CD > Editor > Lint 检查语法是否正确,并以表格形式展示文件 .gitlab-ci.yml
的内容。下图提示 "Status: Syntax is correct" 语法正确。
点击 Commit changes 提交文件 .gitlab-ci.yml
到远程仓库后,在 myFlutter > CI/CD > Pipelines 可以看到这次提交触发执行一个 pipeline 构建任务。
running 表示正在执行。
passed 表示结束并且执行成功。
点击 passed 查看细节。一个 Test 阶段中有一个名为 flutter_test 的作业。点击 flutter_test 查看细节。
可以看到,runner 执行了命令 flutter test
,并提示 All tests passed!
所有测试通过。
定义构建工作
在 test 阶段下面,添加 build 阶段:
stages:
- test # All jobs related for testing such as Unit Test
- build # All jobs related for building app for Android
- 按顺序定义,先执行 test 阶段的作业,再执行 build 阶段的作业。
在 flutter_test 下面定义 flutter_build_android 作业:
####
#### flutter_test lane
####
flutter_build_android: #Job name
stage: build # kind of job
before_script:
- flutter packages get
- flutter clean
script:
- flutter build apk
artifacts:
paths:
- build/app/outputs/apk/release/app-release.apk
tags:
- flutter
- flutter_build_android 作业,该作业用于构建 Android 应用程序。
- before_script 是在作业的 script 之前执行的命令行。
flutter packages get
下载依赖项,flutter clean
清除缓存。 flutter build apk
构建可安装在Android设备上的 APK。
此时的 .gitlab-ci.yml
管道看起来应该如下图:
提交文件 .gitlab-ci.yml
到远程仓库后, GitLab CI/CD 将会自动构建 APK,点击 flutter_build_apk 查看细节。
设置 CD 管道
AppCenter 可以将应用发布到应用商店,生成应用发布,运行单元测试和设备上的测试,向测试人员交付应用,收集分析和诊断数据。
设置 CD 管道把应用程序分发到 AppCenter,我们先安装配置 AppCenter。本地安装AppCenter,可以使用命令行安装:
npm install -g appcenter-cli
或
yarn add appcenter-cli
运行命令行,输出帮助说明,证明安装成功:
appcenter help
打开 App Center 网页,注册并登录。创建新的应用 Add new > Add new app,填写应用名称 App name 为 myFlutter,选择操作系统OS为 Android,选择平台 Platform 为 Java/Kotlin。
转到此页面生成api token。填写描述GitLabToken,选择Full Access,确认生成api token。请复制并保存api token到安全的位置,因api token只会出现一次,无法再次查看。
返回GitLab菜单栏 > Setting > CI/CD > Variables。把刚才保存的api token设置为环境变量 APPCENTER_API_TOKEN
。api token将用于在 App Center 中进行身份验证。
编辑文件.gitlab-ci.yml
。在 App Center 项目中指定正确的 [username] 和 [project] 的值。
这两个值可以在项目浏览器的 URL 中找到:
在 build 阶段下面,添加 deploy 阶段:
stages:
- test # All jobs related for testing such as Unit Test
- build # All jobs related for building app for Android
- deploy
在 flutter_build_android 下面定义 deploy_android 作业:
####
#### Unit test and flutter build android
####
deploy_android:
stage: deploy
dependencies:
- flutter_build_android
script:
- appcenter login --token $APPCENTER_API_TOKEN
- appcenter distribute release -f build/app/outputs/apk/release/app-release.apk -g Collaborators —app [username]/[project]
tags:
- flutter
- deploy_android 作业,将 Android 应用程序部署到 App Center。
- dependencies 关键词声明作业 deploy_android 依赖于之前声明的作业 flutter_build_android,这使我们能够重用之前的作业生成的文件。
appcenter login --token ...
使用储存在环境变量$APPCENTER_API_TOKEN
的 api token,在 App Center 中验证身份。appcenter distribute release ...
分发 APK 到 App Center 。注意,把[username]
替换为 App Center 的 username,把[project]
替换为App Center 的 App 名称,比如刚才创建的myFlutter
。
最后,我们提交并将更新的 .gitlab-ci.yml
配置推送到存储库。您会看到分发到 App Center 的 APK。
至此,我们成功使用 GitLab CI/CD 工具来完成自动单元测试和分发的操作,以后再也不需要手动启动单元测试和分发应用到 AppCenter 了。
CI/CD 的优点
我们选择现在再介绍 CI/CD 的优点,相信您此时更能理解 CI/CD 的优点所在:
- 持续集成:产品快速迭代。
- 持续交付:不管怎么更新,软件随时可以交付。
- 持续部署:代码在任何时刻都是可部署的,随时产生一个可部署版本,可以进入生产阶段。
- 帮助开发人员专注于开发工作。
- 减少人工干预,减少引入错误的机会。
- 避免集成地狱。
卸载runner
最后,补充卸载 卸载 runner 的方法。
选择 GitLab > Settings > CI/CD > Runners(Expand) > Remove runner,移除 runner。
在终端输入以下命令,验证 runner 是否可以链接。
$ gitlab-runner verify --delete
输出以下信息,提示 runner 状态。
Verifying runner... is alive runner=axS4ek5r
Verifying runner... is alive runner=VZxX4w71
ERROR: Verifying runner... is removed runner=6uth4izn
Verifying runner... is alive runner=L2poG_qD
注意,直接删除项目,runner 不会移除。
也可以用命令行移除 runner:
$ gitlab-runner verify --delete --name xxx
$ gitlab-runner verify --url xxx
$ gitlab-runner verify --token xxx
- name 是指注册时填写的 description
注销所有 runner。
$ gitlab-runner unregister --all-runners