gitlab cicd 实战
一、什么是 CICD
软件开发与交付方式的进化史
瀑布模型
敏捷开发
马丁·福勒 Martin Fowler (重构作者 微服务之父)
- 敏捷开发的高适应性,以人为本的特性。
- 更加的灵活并且更加充分的利用了每个开发者的优势,调动了每个人的工作热情。
DevOps
DevOps(Development和Operations的组合词)是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。
通俗点来说,DevOps的目的在保证高质量的同时减少发布流程的总耗时
在敏捷开发中,对产品进行快速迭代,抢占市场以验证产品的可行性,提供更多的功能给用户使用。快速迭代意味着产品平凡部署上线,研发、测试、运维必须要克服这种平凡上线带来的诸多问题:研发质量低;测试不充分,上线后Bug层出不穷;运维上线部署慢、跟不上研发的节奏,经常由于环境、配置等问题导致应用不能正常提供服务等等等等。
一方面希望快速将产品交付给用户使用,另一方面技术人员又害怕这种快速交付,毕竟越快越容易出问题,而且压力大(身上背了很多锅)。正是在这种背景下,DevOps应运而生。为研发、测试、运维团队提供了理论性指导。
字面意思上说 DevOps 是指“开发运维一体化”,即通过工具辅助开发完成运维的部分工作,减少成本。但深入理解了 DevOps 之后,你会发现 DevOps 其实是一种软件研发管理的思想,方法论,他追求的是一种没有隔阂的理想的研发协作的状态。
Google 提出的 5 个 DevOps 原则 这套原则中必须依赖于工具辅助的部分只有后两点,更多的则是对于开发组织形式的内省:
- 精简组织架构;(扁平化)
- 愿意承担一部分试错带来的损失;(bate版)
- 分阶段地一小步一小步地进行转型;(渐进式)
- 最大化地利用工具和自动化流程;(CICD 自动化测试 docker)
- 对所有的过程和结果进行记录和分析。(ELK)
通常公司内部可能存在几百个微服务,每个部署如果都让运维去维护,人力成本与沟通成本都是无法计量的,所以运维将部署的功能抽象化,研发按一定规则进行提交,进行自动化部署。如果出现异常也可以通过日志采集等工具对生产环境的异常及时去处理,减少双方的割裂。
持续集成(CI)
重点是将各个开发人员的工作集合到一个代码仓库中。通常,每天都要进行几次,主要目的是尽早发现集成错误,使团队更加紧密结合,更好地协作。
持续交付(CD)
目的是最小化部署或释放过程中固有的摩擦。它的实现通常能够将构建部署的每个步骤自动化,以便任何时刻能够安全地完成代码发布(理想情况下)。
持续部署(CD)
是一种更高程度的自动化,无论何时对代码进行重大更改,都会自动进行构建/部署。但最终是否需要发布仍然需要人工操作。
小步快跑
二、CICD 工具选择
Jenkins?gitlab CICD?等
选择一个工具的前提是你要清楚使用的场景,开发一个前端,肯定是 js ;做高并发首选应该是 java 或者 Go。
功能JENKINSGITLAB CI/CD开源 / 商业性开源开源产品类型自托管 / 本地部署自托管 / 本地部署内置 CI/ CDJenkins 根据需求支持 CI/CD我们不需要为了 CI/CD 而安装任何东西,这是一个内置功能独特功能插件自动化 DevOps/ 允许持续集成和代码管理在同一个地方进行。安装配置简单简单自托管选项开源软件和自托管是使用它的唯一方法Yes构建 Pipelines通过 Jenkins Pipeline DSL 自定义 pipelineYes应用程序性能监控没有提供用于分析性能的功能展示所有部署的应用程序的性能指标生态系统1000 个社区插件Yes全面的 API提供了全面的 API 功能提供了在软件项目中进行深层集成的 API特定语言支持:JavaScriptYesYes集成允许与其它工具集成(例如:Slack、GitHub)很多第三方集成都可以访问,最著名的是 GitHub 和 Kubernetes。CI/ CD 部署面板部分支持项目中的 CI 和 CD 功能可以根据项目中的 pipeline 历史和最近状态为每一个用户更改一个单独的面板APIYesYes, 提供了一个 REST API & 一个(新的)GraphQL API代码质量通过 Sonarqube 插件以及其它可以用来验证代码质量的不同插件来提供代码质量检查。GitLab 也提供了一个功能来仔细检查代码的质量。
Jenkins
作为一个老牌 CICD 工具无疑是非常成熟的,牛顿曾经说过:如果说我看得比别人更远些,那是因为我站在巨人的肩膀上,Jenkins 拥有的插件量是惊人的,超过 1600 个。
彩蛋 (我来组成头部)
Jenkins 也有 java 项目的特点,非常重,能做到的功能非常多,但概念复杂,插件良莠不齐,也导致在前期编写 CICD 脚本的工作非常痛苦,那么有没有一款轻量化,对开发友好的 CICD 工具呢?
Gitlab CICD
为何选型 gitlab
- 轻量化
Gitlab 并不像 jenkins 需要安装 java 环境,或者是安装插件,仅需要下载二进制运行文件到相应的系统中,注册到 gitlab 中即可。这也决定了 gitlab 很好拓展,可以注册很多台机器做负载均衡,容错等。
- 和 git 仓库不割裂
- 学习成本低(概念简单)
流水线 pipelines ,一次完整的 CICD 就是一条流水线
作业 Jobs, 一次流水线作业中的每个 stages 就是一个作业,可以失败,可以重试
- 迁移成本低
这点也是我最终选择 gitlab CICD 的原因,在 jenkins 中你可能需要先创建一个流水线,又要安装 gitlab (代码仓库插件),又要监听 webhooks 代码推送到指定分支事件,又要配置环境变量(maven 的私有仓库之类的)。
三、CICD 怎么工作
一个Runner可以是一个虚拟机、物理机、docker容器,或者一个容器集群
GitLab与Runner之间通过API进行通信,因此只需要Runner所在的机器有网络并且可以访问GitLab服务器即可
Gitlab 在 register
可以选择多种形式,其中bash
模式中则完全依赖当前安装 gitlab 服务器的环境(目标机器)。如果想分布式扩展 gitlab ,那么 docker 下配置 gitlab 也是很好的选择。那么你在服务器执行的运维脚本,无成本的都可以迁移到 gitlab 中完成。gitlab 也无需创建一个流水线,仅需要一个 .gitlab-ci.yml
的文件放到根目录即可触发 gitlab 的流水线作业。
- 定义
.gitlab-ci.yml
- 推送提交到指定分支
- Runner 运行
- 自动或手动部署
variables:
# 是否允许 gitlab 自动拉代码 ,自动拉代码 gitlab 采用的是 https 的协议,云创部分仓库会无法拉取成功(https 文件大小与数量的问题)
GIT_STRATEGY: none
# 执行前脚本
before_script:
- echo "CI Build Start"
# 执行后脚本
after_script:
- echo "CI Build Finish"
# 自己定义阶段
stages:
- build
- deploy
- rollback
# job 名字
test-build:
# 和 stages 对应的名字
stage: build
only:
# 分支
- develop
script:
# 执行脚本
- rm -rf ./java-demo-server
- git clone git@git.xxxxxx.cn:project/server/java-demo-server.git
- cd java-demo-server
- git branch -a
- git checkout -b develop origin/develop
- git pull
- mvn dependency:purge-local-repository
- mvn clean package
- cp ./target/java-demo-server.war /webroot/log/deploy/temp/
tags:
# gitlab runner 目标及其
- inficloud
test-deploy:
stage: deploy
only:
- develop
script:
- mv /usr/local/apache-tomcat-8.5.42/webapps/java-demo-server.war /webroot/log/deploy/
- mv /webroot/log/deploy/temp/java-demo-server.war /usr/local/apache-tomcat-8.5.42/webapps/
tags:
- inficloud
tess-rollback:
stage: rollback
only:
- develop
script:
- cp /webroot/log/deploy/java-demo-server.war /usr/local/apache-tomcat-8.5.42/webapps/
tags:
- inficloud
# 是否必须要手动触发
when: manual
before_script:
- echo "CI Build Start"
after_script:
- echo "CI Build Finish"
stages:
- build
- deploy
- rollback
test-build:
stage: build
only:
- develop
script:
- mvn dependency:purge-local-repository
- mvn clean package
- mv /usr/local/apache-tomcat-8.5.42/webapps/inficloud-auth/inficloud-auth.jar /usr/local/apache-tomcat-8.5.42/webapps/inficloud-auth/old-inficloud-auth.jar
- cp ./target/inficloud-auth.jar /usr/local/apache-tomcat-8.5.42/webapps/inficloud-auth/
tags:
- inficloud
test-deploy:
stage: deploy
only:
- develop
script:
- bash /usr/local/apache-tomcat-8.5.42/webapps/inficloud-auth/restart-inficloud-auth.sh
tags:
- inficloud
tess-rollback:
stage: rollback
only:
- develop
script:
- cd /usr/local/apache-tomcat-8.5.42/webapps/inficloud-auth
- mv inficloud-auth.jar error-inficloud-auth.jar
- mv old-inficloud-auth.jar inficloud-auth.jar
- bash /usr/local/apache-tomcat-8.5.42/webapps/inficloud-auth/restart-inficloud-auth.sh
tags:
- inficloud
when: manual
name | 说明 |
---|---|
script | 由Runner执行的Shell脚本。 |
image | 使用docker镜像。也可用:image:name和image:entrypoint。image: centos:7 |
services | 使用docker services图像。也可用:services:name,services:alias,services:entrypoint,和services:command。 |
before_script | 覆盖在作业之前执行的一组命令。 |
after_script | 覆盖作业后执行的一组命令。 |
stages | 定义管道中的阶段。列表 |
stage | 定义作业阶段(默认值:) test。 |
only | 创建作业时限制(常用于分支选择)。也可用:only:refs,only:kubernetes,only:variables,和only:changes。常见用法:only: - branches #所有分支 - tags - /^issue-.*$/ #正则匹配issue-的分支 - master #master分支 |
except | 在未创建作业时限制(常用于排除分支)。也可用:except:refs,except:kubernetes,except:variables,和except:changes。 |
tags | 用于选择Runner的标签列表常用范例:tags: - runner - dev |
allow_failure | 让工作失败。失败的作业无助于提交状态。 |
when | 什么时候开始工作。参数: on_success:只有当前一个阶段的所有工作都成功时(或者因为它们被标记而被认为是成功的allow_failure)才执行工作 。这是默认值。 on_failure:仅当前一阶段的至少一个作业失败时才执行作业。 always:无论先前阶段的工作状态如何,都可以执行工作。 manual:手动执行作业(在GitLab 8.10中添加)。 |
environment | 作业部署到的环境的名称。也可用:environment:name,environment:url,environment:on_stop,和environment:action。 |
cache | 后续运行之间应缓存的文件列表。也可用:cache:paths,cache:key,cache:untracked,和cache:policy。 |
artifacts | (构建产物交给下一个阶段)成功附加到作业的文件和目录列表。也可用:artifacts:paths,artifacts:name,artifacts:untracked,artifacts:when,artifacts:expire_in,artifacts:reports,和artifacts:reports:junit。在GitLab 企业版,这些都是可供选择:artifacts:reports:codequality,artifacts:reports:sast,artifacts:reports:dependency_scanning,artifacts:reports:container_scanning,artifacts:reports:dast,artifacts:reports:license_management,artifacts:reports:performance和artifacts:reports:metrics。常用范例: artifacts: #构建完成后,构建的产物(目录或者文件),丢给后面的步骤 paths: - .nuxt/ - . |
dependencies | 作业所依赖的其他作业,以便您可以在它们之间传递工件。 |
coverage | 给定作业的代码覆盖率设置。 |
retry | 在发生故障的情况下,可以自动重试作业的次数和次数。 |
parallel | 应该并行运行多少个作业实例。 |
trigger | 定义下游管道触发器。 |
include | 允许此作业包含外部YAML文件。也可用:include:local,include:file,include:template,和include:remote。 |
extends | 此作业将继承的配置条目。 |
pages | 上传作业结果以用于GitLab Pages。 |
variables | 在作业级别定义作业变量。 |
参考资料
- 什么是DevOps https://aws.amazon.com/cn/devops/what-is-devops/
- 如何安装 Gitlab runner https://docs.gitlab.com/runner/install/linux-manually.html
- 如何配置 Gitlab runner https://git.ideamake.cn/help/ci/runners/index
- Gitlab CICD 脚本编写指南 https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/ci/yaml/index.md