gitlab CICD基础

1. Gitlab CI/CD 基础

课程主要内容

  • 为什么要做CI/CD?
  • GitLab CI/CD
  • GitLabCI vs JenkinsCI

1.1. 为什么要做CI/CD?

1.1.1. 传统应用发布署模式

  • 开发团队
    • 在开发环境中完成软件开发,单元测试,测试通过,提交到代码版本管理库
  • 运维团队
    • 把应用部署到测试环境,供QA团队测试,测试通过后部署生产环境.
  • QA团队
    • 进行测试,测试通过后通知部署人员发布到生产环境.

1.1.2. 传统应用发布署模式面临的挑战

  • 错误发现不及时
    • 很多错误在项目的早期就存在,到最后集成的时候才发现问题
  • 容易发生人工低级错误
    • 产品和服务交付中的关键活动全部需要手动操作
  • 团队工作效率低
    • 需要等待他人的工作完成后才能进行自己的工作
  • 开发运维对立
    • 开发人员想要快速更新,运维人员追求稳定,各自的针对的方向不同

1.1.3. CI/CD

  • 持续集成(CI)
    • 持续集成的目的: 尽快发现错误或问题,减少集成问题,避免复杂问题
    • 合并开发人员正在开发编写的所有代码的一种做法
    • 通常一天内进行多次合并和提交代码.
    • 从存储库或生产环境中进行构建和自动化测试,以确保没有集成问题并及早发现任何问题.
  • 连续交付(CD)
    • 持续交付的目标:每次更改都可发布,降低每次发布风险,更加频繁地交付价值,快速频繁客户反馈
    • 通常可以通过将更改自动推送到发布系统来随时将软件发布到生产环境中
    • 持续布署会更进一步,并自动将更改推送到生产中.

1.1.4. 代码版本管理 - GITLAB

  • 代码审核
  • 问题追踪
  • 动态订阅
  • 易于扩展
  • 项目wiki
  • 多角色项目管理
  • 项目代码在线预览
  • CI工具集成

2. GitLab CI/CD 特性

2.1. GitLab内置持续集成

持续集成(CI)

  • 集成团队中每个开发人员提交的代码到代码库存储中.
  • 开发人员merge或者pull请求中合并拉取新代码.
  • 在提交或者合并更改到代码存储库之前,会触发构建,测试和新代码验证的管道.
  • CI可帮助您在开发周期的早期发现并减少错误
    持续交付(CD)
  • 可通过结构化的部署管道确保将经过CI验证的代码交付给您的应用程序.
  • CD可以将经过验证的代码更快地移至您的应用程序.

CI/CD一起可以加快团队为客户和利益相关者交付成果的速度.CI和CD必须无缝协作,以使得您的团队快速有效地进行构建, 并且对于确保完全优化的开发实践至关重要.

2.2. Gitlab CI/CD 优势

  • 开源: CI/CD是开源Gitlab社区和专有Gitlab企业版的一部分.
  • 易于学习:具有详细的入门文档
  • 无缝集成:Gitlab CI/CD是Gitlab的一部分,支持从计划到部署,具有出色的用户体验.
  • 可扩展: 测试可以在单独的计算机上分布式运行,可以根据需要添加任意数量的计算机.
  • 更快的结果: 每个构建可以拆分为多个作业,这些作业可以在多台计算机上并行运行.
  • 针对交付进行了优化: 多个阶段,手动部署,环境和变量

2.3. Gitlab CI/CD 特点

  • 多平台:Unix, Windows, macOS和任何其他支持Go的平台上执行构建.
  • 多语言:构建脚本是命令行驱动的,并且可以与java, PHP, Ruby, C和任何其他语言一起使用.
  • 稳定构建:构建在与gitlab不同的机器上运行.
  • 并行构建:Gitlab CI/CD在多台机器上拆分构建,以实现快速执行.
  • 实时日志记录:合并请求中的链接将您带到动态更新的当前构建日志.
  • 灵活的管道:您可以在每个阶段定义多个并行作业,并且可以触发其他构建.
  • 版本管道: 一个.gitlab-ci.yml文件包含你的测试,整个过程的步骤,使每个人都能贡献更改,并确保分支获得所需的管道.
  • 自动缩放:您可以自动缩放构建机器,以确保立即处理您的构建并将成本降至最低.
  • 构建工件: 您可以将二进制文件和其他构建工件上载到gitlab并浏览和下载它们.
  • Docker支持:可以使用自定义Docker镜像,作为测试的一部分启动服务, 构建新的Docker映像,甚至可以Kubernets上运行.
  • 容器注册表: 内置的容器注册表,用于存储,共享和使用容器映像
  • 受保护的变量: 在部署期间使用受每个环境保护的变量安全的存储和使用机密.
  • 环境: 定义多个环境.

2.4. GitLab CI/CD工作原理

  • 将代码托管到Git存储库.
  • 在项目根目录创建CI文件.gitlab-ci.yml, 在文件中指定构建,测试,和部署脚本.
  • Gitlab将检测到它并使用名为Gitlab Runner的工具运行脚本.
  • 脚本被分组为作业,它们共同组成了一个管道.

3. Gitlab CI与Jenkins对比

Jenkins 是一个广泛用于持续集成的可视化web自动化工具,Jenkins可以很好的支持各种语言的项目构建,也完全兼容ant, maven, gradle 等多种第三方构建工具,同时跟svn, git能无缝集成, 也支持直接与知名源代码托管网站,比如github, bitbucket直接集成, 并且插件众多,在这么多年的技术积累之后,在国内大部分公司都有使用jenkins.

gitlab-CI是gitlab8.0之后自带的一个持续集成系统,中心思想是当每一次push到gitlab的时候,都会触发一次脚本执行,然后脚本的内容包括了测试,编译,部署等一系列自定义的内容.
gitlab-Ci的脚本执行,需要自定义安装对应gitlab-runner来执行,代码push之后,webhook检测到代码变化,就会触发gitlab-CI, 分配到各个Runner来运行相应的脚本script. 这些脚本有的测试项目用的,有的是部署用的.

3.1. 对比点1- 分支可配置性

分支的可配置性

  • 使用Gitlab Ci, 新创建的分支无需任何进一步配置即可立即使用CI管道中的已定义作业.
  • Jenkins 2 基于gitlab的多分支流水线可以实现,相对配置来说gitlab更加方便一些.

3.2. 对比点2- 定时执行构建

有时,根据时间触发作业或整个管道会有所帮助,例如, 常规的夜间定时构建.

  • 使用Jenkins 2可以立即使用, 可以在应执行作业或管道的那一刻以cron 式语法定义.
  • Gitlab CI 没有此功能.但是, 可以通过一种变通办法来使用WebAPI使用同一台或另一台服务器上的Cronjob触发作业和管道.
    尽管使用gitlab CI无法做到这一点,其实如果配置了提交代码即触发流水线,那么最后一次提交触发什么时候没有什么不同,反而减少未提交代码的定时构建资源浪费.

3.3. 对比点3- 拉取请求支持

拉取请求支持
如果很好地集成了存储库管理器和CI/CD平台,您可以看到请求的当前构建状态.使用这种功能,可以避免将代码合并到不起作用或无法正确构建的主分支中.

  • Jenkins没有与代码管理系统进一步集成,需要管理员自行写代码或插件实现.
  • Gitlab与CI平台紧密集成,可以方便查看每一个打开和关闭拉动请求的运行和完成管道.

3.4. 对比点4- 权限管理

权限管理
从存储管理器继承的权限管理对于不想为每个服务分别设置每个用户权限的大型开发人员或组织团队很有用.大多数情况下,两种情况下的权限都是相同的,因此默认情况下应该将它们配置在一个位置.
由于Gitlab与GitlabCi的深度整合, 权限可以统一管理.
由于Jenkins 2没有内置的存储库管理器, 因此它无法直接在存储库管理器和CI/CD平台之间合并权限.

3.5. 对比点5- 存储库交互

  • gitlab CI是git存储库管理器的固定组件, 因此在CI/CD流程和存储库功能之间提供良好的交互.
  • Jenkins 2与存储库管理器都是松散耦合的,因此在选择版本控制系统时它非常灵活.
  • 此外,就像其前身一样,Jenkins2强调了对插件的支持,以进一步扩展或改善软件的现有功能.

3.6. 对比点6 - 插件管理

  • 扩展Jenkins的本机功能是通过插件完成的.插件的维护,保护和升级成本很高.
  • Gitlab是开放式的,任何人都可以直接向代码库贡献更改,一旦合并,它将自动测试并维护每一个更改.

3.7. 总结

gitlab CI

  • 轻量级,不需要复杂的安装手段.
  • 配置简单, 与gitlab可直接适配.
  • 实时日志十分清晰UI交互体验很好.
  • 使用YAML进行配置,任何人都可以很方便的使用.
  • 没有统一的管理界面,无法统筹管理所有项目
  • 配置依赖于代码仓库,耦合度没有Jenkins低

Jenkins

  • 编译服务和代码仓库分离,耦合度低;
  • 插件丰富,支持语言众多.
  • 有统一的web管理界面.
  • 插件以及自身安装较为复杂.
  • 体量较大,不是很适合小型团队.

GitLabCI有助于DevOps人员,例如敏捷开发中,开发与运维是同一个人,最便捷的开发方式.
JenkinsCI适合在多角色团队中,职责分明,配置和代码分离,插件丰富.

4. 安装部署Gitlab

gitlab 三种按照方式

  • yum 安装
  • docker镜像安装
  • k8s安装

5. Gitlab Runner

5.1. Gitlab runner简介

  • Gitlab Runner是一个开源项目, 用于运行作业并将结果发送回gitlab.
  • 与GitlabCI结合使用,GitlabCI是Gitlab随附的用于协调作业的开源持续集成服务.
  • Gitlab Runner是用Go编写的,可以在Linux, macOS和Windows操作系统上运行
  • 容器部署需要使用最新Docker版本,GitLab Runner需要至少Docker v1.13.0
  • GitLab Runner版本应与Gitlab版本同步(避免版本不一致导致不兼容)
  • 可以根据需要配置任意数量的Runner

GitLabRunner类似于Jenkins的agent, 执行CI持续集成,构建的脚本任务.

5.2. Gitlab runner特点

  • 作业运行控制:同时执行多个作业
  • 作业运行环境:
    • 在本地,使用docker容器,使用Docker容器并通过SSH执行作业.
    • 使用Docker容器在不同的云和虚拟化管理程序上自动缩放.
    • 连接到远程SSH服务器.
  • 支持bash, Windows batch和Windows PowerShell
  • 允许自定义作业运行环境
  • 自动重新加载配置,无需重启.
  • 易于安装,可作为Linux, macOS和Windows的服务

5.3. Gitlab runner类型与状态

  • 类型
    • shared 共享类型,运行整个平台项目的作业(gitlab)
    • group 项目组类型,运行特点group下的所有项目的作业(group)
    • specific 项目类型,运行指定的项目作业(project)
  • 状态
    • locked:锁定状态,无法运行项目作业
    • paused:暂停状态,暂时不会接受新的作业

5.4. Gitlab Runner安装

5.4.1. Gitlab Runner安装环境

  • 系统环境:可以在Linux, macOS, FreeBSD和Windows上安装和使用Gitlab Runner
  • 部署方式: 二进制文件,rpm/deb软件包,Docker, Kubernetes

5.5. Gitlab Runner注册

5.5.1. timeout 超时

作业级别的超时可以超过项目级别超时, 但不能超过Runner特定的超时.
runner 超时时间在runner的配置里面设置
项目的超时在项目的配置中设置
job的超时时间在yaml配置文件中定义
example

1
2
3
4
5
6
7
build:
script: build.sh
timeout: 3 hours 30 munutes

test:
script: repec
timeout: 3h 30m

示例1: runner超时大于项目超时
runner超时设置为24小时, 项目的CI/CD超时设置为2小时.
该job将在2小时后超时

示例2: 未配置runner超时
runner不设置超时时间, 项目的CI/CD超时设置为2小时
该job将在2小时后超时.

示例3: runner超时小于项目超时
runner超时时间设置为30分钟, 项目的CI/CD超时设置为2小时
该job将在30分钟后超时.

runner超时如果小于项目定义的超时时间将具有优先权. 此功能可用于通过设置大超时(例如一个星期)来防止Shared Runner被项目占用. 未配置时, Runner超时设置将不会覆盖项目超时.

5.5.2. parallel 并行作业

配置要并行运行的作业实例数, 此值必须大于或等于2并且小于或等于50.
这将创建N个并行运行的同一作业实例. 它们从job_name 1/N 到job_name N/N依次命名.

1
2
3
4
5
6
7
8
9
10
codescan:
stage: codescan
tags:
- build
only:
- master
script:
- echo "codescan"
- sleep: 5
parallel: 5

5.5.3. only & excpet 限制分支标签

  • only和except用分支策略来限制jobs构建:
    • only定义哪些分支和标签的git项目将会执行该job
    • except定义哪些分支和标签的git项目将不会执行该job
1
2
3
4
5
6
7
job:
# use regexp
only:
- /^issue-.*$
# use special keyword
except:
- branches

5.5.4. rules 构建规则

  • rules允许按顺序评估单个规则, 直到匹配并为作业动态提供属性.
  • rules不能与only/except组合使用.

可用的规则:
if (如果条件匹配)
changs (指定文件发生变化)
exists (指定文件存在)

5.5.4.1. rules - if (如果条件匹配)

例子:
如果domain的值匹配对应的if条件, 则执行对应的运行方式
默认为on_success
条件判断从上到下, 匹配即停止
多条件匹配可以使用&& ||

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
variables: 
DOMAIN: example.com

codescan:
stage: codescan
tags:
- build
script:
- echo "codescan"
- sleep 5
rules:
- if: '$DOMAIN == "example.com"'
when: manual
- if: '$DOMAIN == "xyz.com"'
when: delayed
start_in: '5'
- when : on_success
5.5.4.2. rules - changs (指定文件发生变化)

接受文件路径数组.
如果提交中Dockerfile文件发生变化则为true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
variables: 
DOMAIN: example.com

codescan:
stage: codescan
tags:
- build
script:
- echo "codescan"
- sleep 5
rules:
- changes:
- Dockerfile
when: manual
- if: '$DOMAIN == "xyz.com"'
when: delayed
start_in: '5'
- when : on_success

5.5.5. rules - allow_failure

使用allow_failure: true
rules: 在不停止管道本身的情况下允许作业失败或手动作业等待操作.

1
2
3
4
5
6
job:
script: echo "hello, rules"
rules:
- if: "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" == "master"
when: manual
allow_failure: true

在此示例中, 如果第一个规则匹配, 则作业将具有以下when: manual和allow_failure: true

5.5.6. workflow 结合rules 进行管道创建

  • 顶级workflow关键字适用于整个管道, 并将确定是否创建管道.
  • when: 可以设置为always或never, 如果未提供, 则默认值always.
1
2
3
4
5
6
7
8
variables:
DOMAIN: example.com

workflow:
rules:
- if: '$DOMAIN == "example.ocm"'
when: always
- when: never

5.5.7. cache 缓存

存储编译项目所需的运行时依赖项, 指定项目工作空间中需要在job之间缓存的文件或目录.
全局cache定义在job之外, 针对所有job生效, job中的cache优先于全局.
job

1
2
3
4
5
build:
script: test
cache:
paths:
- target/*.jar

由于缓存是在job之间共享的, 如果不同的job使用不同的路径就出现了缓存覆盖的问题.
如何让不同的job缓存不同的cache呢?
设置不同的cache: key
可以防止缓存覆盖

1
2
3
4
5
6
7
8
9
cache:
paths:
- my/files
build:
script: echo "hello"
cache:
key: build
paths:
- target/
5.5.7.1. cache: key 缓存标记

为缓存做个标记, 可以配置job, 分支key来实现分支,作业特定的缓存.
为不同job定义了不同的cache:key时, 会为每个job分配一个独立的cache.
cache:key变量可以使用任何预定义变量,默认为default
从gitlab9.0开始, 默认情况下所有内容都在管道和作业之间共享.

按分支设置缓存
cache:
key: ${CI_COMMIT_REF_SLUG}

5.5.7.2. cache: key: files 文件变化自动创建缓存

files: 文件发生变化自动重新生成缓存files最多指定两个文件, 提交的时候检查指定的文件.
根据指定的文件生成密钥计算SHA校验和, 如果文件未改变值为default.

1
2
3
4
5
6
7
8
cache:
key:
files:
- Gemfile.clock
- package.json
paths:
- vendor/ruby
- node_modules

prefix: 允许给定prefix的值与指定文件生成的密钥组合.
在这里定义了全局的cache, 如果文件发生变化则值为rspec-xxx111122222, 未变化为rspec-default

1
2
3
4
5
6
7
8
9
10
11
12
13

cache:
key:
files:
- Gemfile.lock
prefix: ${CI_JOB_NAME}
paths:
- vendor/ruby

respec:
script:
- bundle exec rspec

5.5.7.3. cache: policy - 缓存策略

默认: 在执行开始时下载文件, 并在结束时重新上传文件.
policy: pull跳过下载步骤, policy: push跳过上传步骤.

1
2
3

cache:
policy: pull # 不下载缓存

5.5.8. Git Strategy(git策略)

你可以通过在全局变量设置位置或者job局部变量设置位置来设置GIT_STRATEGY用以获取应用最近更新的代码。如果没有指定,默认的项目设置将会被使用。

该选项有三个可能的值:clone,fetch和none

  • clone

    clone是最慢的选项,如果设置该值,每个job将会都克隆一遍仓库,确保项目工作空间总是原始的正确的。

    1
    2
    3
    4

    variables:
    GIT_STRATEGY: clone

  • fetch

    fetch是更快的操作选项,因为他重用了项目的工作空间(如果没有的话,会去clone.

    1
    2
    variables:
    GIT_STRATEGY: fetch
  • none

    none也同样重用了项目空间(但是他会跳过所有git操作,包括如果存在的gitlab runner的预克隆脚本)。其主要用于只是为了操作artifacts的job上(例如depoly部署行为)。此时Git仓库的数据可能是存在的,但它一定不是最新的。所以在设置了none的job里你应该依赖从cache或者artifacts来的数据,而不是仓库数据。

    1
    2
    3
    4

    variables:
    GIT_STRATEGY: none

6. 关联阅读

gitlab安装升级及迁移

使用gitlab issue board的四种方式

GitLab集成PlantUML

gitlab-runner安装与配置

macOS上安装gitlab-runner安装与配置

ubuntu上安装gitlab-runner安装与配置

windows上安装gitlab-runner

7. 参考文档

黑马程序员-Gitlab CICD

gitlab-ci配置详解(二)