马哥 Linux SRE + AIOps智能运维文档
第 41 章 / 42

CICD DevOps

← 上一章:Prometheus | 返回总目录 | 下一章:SRE →


http://www.magedu.com

关于马哥教育

  • http://www.magedu.com

 https://github.com/ikubernetes

http://www.magedu.com

Thank You!

CICD 与 DevOps

  • 讲师:马永亮(马哥)

  • http://www.magedu.com  https://github.com/ikubernetes/

软件开发生命周期

  • 软件开发生命周期

    • Software Development Life Cycle,简称为SDLC,帮助人们组织和实施软件开发管理的框架,有助于定义系统工程师和开发人员在软件开发和维护工作中的工作阶段

    • 由多个阶段组成,大致包括需求收集、可行性研究、设计、编码、测试、部署和维护等

  • SDLC模型

    • Waterfall

    • Iterative Development

    • Agile

    • Lean Software Development

    • DevOps

    • Spiral Development

    • V-Model Development

http://www.magedu.com

瀑布模型

  • 关于瀑布模型

    • 瀑布模型中的开发过程是线性的,所有阶段界限分明且逐个完成,就像瀑布一样,开发的进度由上而下流动

    • ◼ 瀑布是软件开发史上第一个、最简单、也是最好的SDLC方法之一

    • 适用场景

      • 复杂领域的项目(例如飞机制造、医疗),法规和要求相对稳定

      • 要求明确,有严格的截止蜞,有固定的成本

    • 但是

      • 瀑布模型不允许返回到以前的开发阶段来纠正或实施更改

      • 做到这一点的唯一方法是在下一个Waterfall迭代过程中进行

http://www.magedu.com

迭代/增量模型

  • 关于迭代增量模型

    • 先以相对较低的价格快速创建产品版本,然后通过快速和连续的迭代过程对其进行测试和增强

    • ◼ 每次迭代都会生成更新、更可靠的版本;一般需要历经多次迭代,直到最终软件版本成型 ◼ 典型特征:人们可以在未完全了解需求的情况即启动开发过程

    • 适用场景

      • ERP系统等复杂项目

      • 需要已明确定义,项目的目标已经确定,但未来可能会有细微的变化

http://www.magedu.com

敏捷模型

  • 关于敏捷模型

    • 敏捷模型结合了增量和迭代方法,旨在更好地适应灵活的应用需求进行软件开发

    • 在软件开发的敏捷方法中,项目被分成小的子部分并在迭代中交付

      • 在每次迭代结束时,都会提供一个版本供客户审查和反馈

      • 对每个版本的测试都提供了有价值的信息,这些信息可能会被合并到下一个版本中

    • 存在多种流行的实践方法

      • Scrum

      • SAFe

      • Extreme Programming (XP)

      • Kanban

http://www.magedu.com

DevOps模型

  • 关于DevOps模型

    • DevOps产生的背景:传统SDLC的团队模型

      • 大型IT组织中传统上存在完全不同的几个团队—— 产品设计 、 开发 、 测试 、 运维

      • 每个岗位都有自己的价值追求,测试人员关注找出更多Bug、开发人员关注技术和高效开发功能、运维关心系统稳定

      • ◆ 结果:分工带来的好处,就是复杂的任务可以分给不同的人来做,这也有助于技能的专业化,提高工作效率;但如果只站在自己的立场去考虑问题,没有人关注整体价值,就容易相互误解,产生矛盾、增加成本

    • DevOps模型

      • 在竞争日益激烈的环境中改善客户体验和底线结果的压力越来越大,持续交付成为大势所趋
    • DevOps旨在将几个需要协同但目标不同的团队完全聚集在一起,让每个团队都可以通过共同实现目标而更加成功

    • ◼ DevOps组织优先推动的目标

      • 一组标准化的环境

      • 降低新版本的失败率

      • 缩短版本之间的交付时间

      • 更快的平均版本恢复时间

http://www.magedu.com

DevOps模型(2)

  • DevOps的好处

    • 采用DevOps模型的团队能够增加交付周期,以更快的速度创建新功能,同时推动创新并增加员工参与度和沟通,最终,也确保了应用程序更加安全和稳定

    • 利用DevOps并实施持续集成和持续交付(CI/CD),组织可以看到部署频率、交付周期、网络安全漏洞和缺陷检测、平均修复时间和平均恢复时间方面的巨大改进

    • 允许快速实验和不确定性,同时专注于任务最终目标

    • 支持快速原型设计和A/B 测试或金丝雀发布

    • 得益于自动化测试和实时扫描,通过不断修复错误和安全问题来避免技术债务

  • DevOps的关键指标

    • 平均恢复时间:Mean-time to recovery (MTTR)

    • 平均投产时间:Mean-time to production

    • 平均提前时间:Average lead-time

    • 部署速度:Deployment speed

    • 部署频率:Deployment frequency

    • 生产失败率:Production failure rate

http://www.magedu.com

DevOps与CICD的联系与区别

  • CICD是软件工程实践的方法

  • DevOps是一种文化:也正是容器、容器编排、微服务等技术使得DevOps最终能够以应有的方式得以

  • 落地;

  • 通常,在开发环境中自动化持续集成和持续交付(CI / CD)是DevOps团队的最终目标

http://www.magedu.com

CICD Pipeline

 CI: 持续集成,用于实现开发工作的流程自动化

  • CD:持续交付/持续部署,前者常用于描述在自动化的CI流程之后,自动将已验证的代码发布到存储

  • 库中(而后流程转移至运维团队),后者则指的是自动将开发人员提交的代码变更部署到生产环境中, 以提供给客户使用;

http://www.magedu.com

CICD中的典型阶段

http://www.magedu.com

再看CI/CD

  • CI/CD是一种在应用开发阶段引入自动化实现以较高频度向客户交付应用的方法

    • 广为接受的模型,存在三个典型阶段:持续集成、持续交付和持续部署

    • CI/CD可以让持续自动化和持续监控贯穿于应用的整个生命周期(从集成到测试、到交付,再到部署)

    • 这些关联的事务通常被统一称作CI/CD Pipeline,它一般需要由开发和运维团队以敏捷方式协同支持

  • CI和CD的关系

    • CI是指持续集成,它属于开发人员的自动化流程

    • CD指持续交付和持续部署,两者都事关Pipeline后续的自动化,但有时也会单独使用以评估自动化程度

http://www.magedu.com

持续交付和持续部署

  • 持续交付

    • 通常是指开发人员对应用的更改会自动进行错误测试并上传到存储库(如GitHub或Image Registry),然后由运维团队将其部署到实时生产环境中

    • 旨在解决开发和运维团队之间可见性及沟通较差的问题,目标在于确保尽可能地减少部署新代码时所需的工作量

  • 持续部署

    • 通常是指自动将开发人员的更改从存储库发布到生产环境,以供客户使用;

    • 主要解决因手动流程降低应用交付速度,从而使运维团队超负荷的问题

    • 以持续交付为前提,完成Pipeline后续阶段的自动化

  • CI/CD术语

    • 通常,CI/CD这一术语既可能仅指持续集成和持续交付构成的关联环节,也可以指持续集成、持续交付和持续部署这三项构成的关联环节

    • 甚至于,很可能有些人口中所谓的"持续交付"也包含了持续部署流程

http://www.magedu.com

CI/CD Pipeline

  • CI/CD Pipeline

    • 为了交付新版本的软件而必须执行的一系列步骤

    • 一套专注于使用DevOps或SRE方法来改进软件交付的实践

    • 加入了监控和自动化来改进应用开发过程,尤其是在集成和测试阶段,以及交付和部署过程中

      • 即便可以手动执行CI/CD Pipeline的每个步骤,但CI/CD Pipeline的真正价值就在于自动化
  • CI/CD Pipeline的要素

    • 构成CI/CD Pipeline的步骤被划分为不同的任务子集 (subsets of tasks),称之为Pipeline Stage

    • ◼ Pipeline中典型的Stage包括

      • Build(构建):应用编译

      • Test(测试):代码测试

      • Release(发布):将应用交付到存储库

      • Deploy(部署):将代码部署到生产环境

      • Validation和Compliance(验证与合规):镜像安全性扫描(例如Clair)等,具体的步骤取决于实际需求

  • 最初,传统的CI/CD系统是为使用虚拟机的Pipeline而设计,但云原生技术却为CI/CD Pipeline的价值实现带来了新的突破

    • 使用Tekton项目,用户可以构建Kubernetes风格的Pipeline,控制微服务的生命周期

http://www.magedu.com

Simple Version of CICD Workflow

UAT:User Acceptance Test,用户接受度测试,即验收测试环境

http://www.magedu.com

CICD简单工作流程中的6个步骤

  • Commit Change:开发人员提交代码至代码仓库中;

  • Build Binary:CI Server针对最新的变更构建应用程序;

  • Deploy UAT:CI Server将二进制程序部署到UAT环境中;

  • Test UAT:在UAT环境中针对测试计划完成测试;

  • Deploy PROD:CI Server将二进制程度部署到PROD环境中;

  • Test PROD:在PROD环境中针对测试计划完成测试

http://www.magedu.com

自动化的CICD工作流示例

http://www.magedu.com

多分支Release流水线示意图

http://www.magedu.com

DevOps方法示例一

 CI/CD Pipeline Workflow with Kubernetes (Push Pipeline)

图片来源:https://thenewstack.io/

http://www.magedu.com

DevOps方法示例二

  • CI/CD With Kubernetes and Helm (Push Pipeline)

Push
Pull Request
Merge

图片来源:https://dzone.com/

http://www.magedu.com

Weave Cloud的DevOps方法

  • Weave Cloud的DevOps方法使用Pull机制,它依赖于两种特殊组件

    • Config Updater:用于监视image的变动并更新配置清单;

    • Deploy Synchronizer:维护应用的当前状态;

  • 工作机制:Pull Pipeline模型的中心是配置中心或配置仓库(config repo)

    • 开发人员推送代码变更至代码仓库中;

    • CI Server 自动完成CI Pipeline并生成Docker Image;

    • Config Updater,注意到Image的变动,并以此更新config repo中的配置清单;

    • Deploy Synchronizer 在察觉到集群当前状态已过期后,将从配置仓库中pull到变更的配置清单并部署到集群上;

图片来源:https://geekflare.com/

http://www.magedu.com

Pipeline 模型的演进

  • Push Pipeline

    • 传统上的大多数CI/CD工具都使用基于Push的模型,即代码从CI系统开始,可以经由一系列脚本代码自动化完成其执行路径,或手动完成相关的Stage;

CD的步骤中可能会用到凭据,将这些凭据保存于代码中可能会导致潜在的风险;

  • Pull Pipeline

    • WeaveNet倡导一种新的基于Image Pull的Pipeline模型,并且将凭据直接保存于集群之上

CI Pipeline根据开发人员提交的代码变更构建并推送新的Image后,负责监视代码仓库的Deployment Automator负责拉取该Image并更新config repo,而 Deployment Synchronizer随后会察觉到集群上的应用状态已然落后于config repo,遂获取config repo中的配置文件并将新的Image更新到集群之上;

GitOps

http://www.magedu.com

一个典型的GitOps Pipeline

  • GitOps模型中存在两个Git仓库

    • 代码仓库(code repo):开发人员使用

      • 推送代码变更
    • 配置仓库(config repo):运维人员使用

      • 推送配置变更

      • 包括基础设施配置以及应用配置

  • 简要工作流程

    • 开发人员推送代码变量至代码仓库

    • CI工具链完成测试和构建

    • CD工具链完成测试和交付(新版本的Image推送至工件仓库)

  • Config Update(即Deployment Automator)将 Image的变更信息推送至配置仓库

  • 随后,根据使用的分支和发布策略,完成应用的部署

http://www.magedu.com

Git 和版本控制

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

版本控制和版本控制系统

  • 关于版本控制

    • 版本控制(Version control)是维护工程蓝图的标准做法,能追踪工程蓝图从诞生一直到定案的过程

    • ◼ 版本控制也是一种软件工程技巧,借此能在软件开发的过程中,确保由不同人所编辑的同一程序文件都得到同步

    • 软件工程师常利用版本控制来跟踪、维护原始码、文档以及配置文件等的改动

  • 软件版本控制的方法

    • 最简单的情况下,软件设计师可以自己保留一个程序的许多不同版本,并且为它们做适当的编号 ◆ 这种简单的方法曾被用在很多大型的软件项目中

      • 虽然可行,但效率较低

      • 必须同时维护很多几乎一样的原始码备分,而且极度依赖软件设计师的自我修养与开发纪律

    • 使用版本控制系统,实现部分或全部版本控制工作的自动化

  • 关于版本控制系统(VCS)

    • 版本控制系统,又叫修订控制或源控制系统,是一种软件实用程序,用于跟踪和管理对文件系统的更改

    • VCS 还提供协作功能,用于与其他VCS 用户共享和集成这些对文件系统的更改

    • 常见的软件行业VCS 的实现包括Git、Mercurial 和SVN 等

http://www.magedu.com

版本控制系统基础

  • VCS 是一种非常重要的工具,可为协作性的软件团队工作流带来众多好处 ◼ 解决冲突

    - 在团队驱动型软件项目的生命周期中,很可能有多位团队成员需要同时对同一个源代码文件进行更改
    
    • VCS能跟踪多位开发人员之间的冲突并帮助解决这些冲突,并将操作过程记入审计跟踪记录,形成变更历史

    • ◼ 回滚和撤消对源代码的更改

      • VCS会记录其管控的源代码的变更历史,并支持“撤消”变更或回滚到此前的记录的某个历史状态

      • 如果在已上线的应用中发现缺陷,代码可以快速恢复到已知的稳定版本

    • 异地源代码备份

      • 使用VCS 时,需要创建一个VCS 的远程实例,以在开发人员之间共享更改

      • 这个远程VCS 实例可以由值得信赖的第三方(如GitHub)进行异地托管;然后,它就会成为安全的异地备份;

  • 任何有多位开发人员维护源代码文件的软件项目都应该使用VCS

  • 即便只有一位维护人员的项目也能从使用VCS 中获得巨大好处

http://www.magedu.com

VCS的远程架构

  • VCS 工具有两种主要的远程架构类型,分别是集中式和分布式

    • 集中式VCS 有单一故障点,即远程中央VCS 实例

      • 若该实例丢失,可能会导致工作效率下降和数据丢失,需要使用其他源代码副本替换它

      • 在实例的不可用期间,开发人员就无法推送、合并或回滚代码

    • 分布式模型架构在每个VCS 实例中都保存源代码的完整副本

http://www.magedu.com

版本控制软件对比

 以下是常见VCS 选项的概述和对比

◼ VCS 行业已全面转向分布式模型

图源:bitbucket.org

http://www.magedu.com

Git和传统版本控制系统对比

http://www.magedu.com

Git简介

  • Git是分布式版本控制系统(Version Control System,VCS)

  • 的一种实现,由Linux之父Linus Torvalds于2005年创建

    • 数据仓库 (Repository) 是记录文件或目录状态的地方,存储着内容修改的历史记录

      • 远程数据库 : 配有专用的服务器,为了多人共享而建立的数据库

      • ◆ 本地数据库 : 为了方便用户个人使用,在自己的机器上配置的数据库

    • git有很多命令用于基于本地和远程仓库的代码管理

http://www.magedu.com

Git基础概念

  • Git将管控的源代码置于一个目录中,目录名即为项目名称,因而该目录即为项目的“根(起始位

  • 置)”

  • Git在其项目目录中会为版本控制机制划分出工作区、暂存区和版本库三个空间

    • 工作区(working directory)

      • 项目目录内部的空间即为工作区

      • 项目目录内部还会存在一个隐藏的子目录“.git”,这个子目录就是暂存区和版本库的存放位置

    • 暂存区(staging area)

      • 暂存区git开始跟踪和保存文件中发生的更改的地方

      • 用户在工作区做出一些更改后,可以运行命令(git add) 把这些更改先复制到暂存区中暂存

      • 暂存区只会记录用户执行暂存命令之前的更改,后来再做的变更需要再次运行暂存命令完成暂存

    • 版本库(repository)

      • 暂存区中的更改累积到一定程度后,即可使用命令

      • (git commit)将这些更改一并提交至版本库中持久保存

      • 提交(commit)只是一个检查点,用于告诉git将暂存区的内容同前一次的提交进行比较,并记录下来生成的所有更改

  • 提交操作完成后,会自动清空暂存区

http://www.magedu.com

Git基础概念(2)

  • Git本地版本控制的基本工作流程

    • 开始使用git时,需要先于项目目录中运行“git init”命令,生成.git目录结构,完成版本库初始化

    • ◼ 暂存和提交两个步骤是周期类操作,可根据城要重复运行

      • 随着用户在工作区编码工作的展开,可随时按需运行“git add”命令将工作区中的更改暂存,该区域通常也称为索引

      • ◆ 暂存区累积的更改操作,可由用户使用“git commit”命令一次性地提交到版本库中

    • ⚫ 每次提交操作完成后会生成一个反映到提交操作这一该工作区的状态快照,并可拥有名称和标识,即commit name和commit id

    • ◼ 每个commit,都可由用户使用“git checkout”命令按需检出

      • checkout命令执行了同commit命令相反的操作,它将版本中存储的commit所代表着的工作区状态反映到工作区中

      • ◆ checkout命令完成后,工作区中的内容与其检出的提交那一刻的状态相同

        • ⚫ 若工作中存储此前未被提交的新文件,这些文件不计入在此刻的状态表示中

        • ⚫ 当然,用户也可以暂存这些新文件,并将带有新文件的工作区提交到版本库中,这将是新的暂存和提交循环

Working Working Working Working
(unmodified) X (modified) X (unmodified) X (unmodified)
.git Staging Staging Staging Staging
(unmodified) (unmodified) add X (modified) commit X (unmodified)
C1 C2 C3 C4 Local Repo Local Repo Local Repo
(C4) (C4) (C5) ΔX

http://www.magedu.com

git命令基础

  • git提供了一组简单、独立的命令

    • 这些独立的命令都做为git命令的子命令存在

    • 依照“Unix工具包”理念开发,该理念倡导构建小型和互操作的工具

  • 命令格式

◼ git

  • 常用的子命令

◆ init, clone, config:启动版本库

  • add, mv, rm:暂存文件变动

  • status, log, diff, grep, show:查看状态

  • checkout, branch, merge, push, fetch, pull

◼ 获取命令帮助

◆ git help 或

  - git <command> --help

  - man git-<command>
  • git在线文档

    • http://git-scm.com/docs

http://www.magedu.com

安装并配置git

  • 安装git

    • 下载页面https://git-scm.com/download/linux

    • 主流Linux发行版在其程序仓库均提供了可用的程序包

  • 配置Git

    • 命令:git config

    • git配置有三个级别,分别对应三个文件

      • --system:系统级,全系统范围有效,对应文件/etc/gitconfig

      • --global:全局级,当前用户范围有效,对应文件为$HOME/.gitconfig

      • --local:本地级,仅对当前一个项目有效,对应文件为项目目录下的.git/config

    • 配置文件使用ini格式,存在一至多个[section],各配置参数可以section为前缀引用

    • 列出已有配置:git config -l | --list

http://www.magedu.com

配置git环境

 常用的配置变量

  • user.name

    • 用户名

    • 另外还可以使用author.name标记作者,以及使用committer.name标记提交者

  • user.email

    • 用户的邮箱

    • 另外还可以使用author.email标记作者邮箱,以及使用committer.email标记提交者邮箱

  • color.ui

    • 为color.diff和color.grep设定默认值

    • true或auto表示启用语法着色功能

    • false或never表示关闭语法着色功能

  • core.editor

    • 配置git默认使用的文本编辑器

    • 也可由环境变量GIT_EDITOR指定,且优先级更高

http://www.magedu.com

从本地版本库开始

  • 启动一个基于git进行版本控制的项目的常用途径有两种

    • 本地初始化并创建一个自有项目

◼ 从某个Git Server上克隆一个项目

 从一个空的项目和本地版本库开始 ◼ 创建项目目录并将其切换为当前工作目录

◆ mkdir ~/deploy-demoapp && cd ~/deploy-demoapp ◼ 初始化本地版本库

◆ git init

◼ 编写源代码文件,并查看代码跟踪状态

◆ git status

~/deploy-demoapp$ git status On branch master No commits yet Untracked files: (use "git add ..." to include in what will be committed) README.md deployment-demoapp.yaml

http://www.magedu.com

从本地版本库开始(2)

 将变更存入暂存区

◼ 添加文件至暂存区

 创建提交

◼ 创建第一次提交,并添加提交message

~/deploy-demoapp$ git add README.md ~/deploy-demoapp$ git status On branch master No commits yet Changes to be committed: (use "git rm --cached ..." to unstage) new file: README.md Untracked files: (use "git add ..." to include in what will be committed) deployment-demoapp.yaml

~/deploy-demoapp$ git commit -m "First commit" [master (root-commit) adb4b8a] First commit 2 files changed, 19 insertions(+) create mode 100644 README.md create mode 100644 deployment-demoapp.yaml

 查看提交日志

◼ git会为每个commit保存一组信息,包括日志、 时间戳、作者名称及email信息等 ◼ git log命令能够列出commit信息,而且使用-stat选项还可给出文件变动相关的统计数据

◼ git add命令支持使用文件通配符

◆ git add *.yaml

每个commit都会有一个40hex-digit SHA-1格式的hash 码,但我们一般使用前7位 hex digits即引用commit;

~/deploy-demoapp$ git log --stat commit adb4b8a1654467ef1ff445b52acd34d1e3e31339 (HEAD - > master) Author: MageEdu mage@magedu.com Date: Sat Nov 26 16:04:29 2022 +0800 First commit README.md | 1 + deployment-demoapp.yaml | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+)

http://www.magedu.com

从本地版本库开始(3)

 查看提交的详情

 其它常用的用于查看提交的命令

◼ git log -p命令

$ git log --oneline // Display EACH commit in one line. ~/deploy-demoapp$ git log -p commit adb4b8a1654467ef1ff445b52acd34d1e3e31339 (HEAD -> master) $ git log --author="" Author: MageEdu mage@magedu.com // Display commits by author Date: Sat Nov 26 16:04:29 2022 +0800 $ git log First commit // Display commits for particular file(s) diff --git a/README.md b/README.md // EXAMPLES new file mode 100644 $ git log --author="MageEdu" -p deployment-demoapp.yaml index 0000000..58e4c51 commit adb4b8a1654467ef1ff445b52acd34d1e3e31339 (HEAD -> master) --- /dev/null Author: MageEdu mage@magedu.com +++ b/README.md Date: Sat Nov 26 16:04:29 2022 +0800 @@ -0,0 +1 @@ +# Deployment resources for demoapp First commit diff --git a/deployment-demoapp.yaml b/deployment-demoapp.yaml new file mode 100644 diff --git a/deployment-demoapp.yaml b/deployment-demoapp.yaml index 0000000..36f2ff4 new file mode 100644 --- /dev/null index 0000000..36f2ff4 +++ b/deployment-demoapp.yaml --- /dev/null @@ -0,0 +1,18 @@ …… +++ b/deployment-demoapp.yaml ……

http://www.magedu.com

项目中文件的状态

  • 在git版本库,一个被跟踪的文件可能处于下面三种状态之一

◼ unstaged (in Working Tree) - called unstaged changes

◼ staged (in Staging Area or Index or Cache) - called staged changes

◼ committed (in local repo object database)

  • 处于工作区或暂存区中的文件,在使用git status命令查看时,可能会显示为多种状态

    • unmodified

    • added

    • modified

    • deleted

    • renamed

    • copied

http://www.magedu.com

项目中文件的状态(2)

 文件状态变动(新增文件)

  • 工作区中新添加的文件会被标识为untracked状态

◼ 添加到暂存区后,即在暂存区中标识为“new(added)”状态,而工作区则变回unmodified状态 ◼ 提交后,暂存区和工作区中,该文件均为unmodified状态

  • 文件状态变动(修改文件)

    • 处于跟踪状态的某文件变动后,工作区状态变为modified,而暂存区为unmodified

    • ◼ 添加到暂存区后,暂存区中将其标识为modified状态,而工作区则变回unmodified状态

◼ 提交后,暂存区和工作区中,该文件均为unmodified状态

Working Working Working Working Working Working
X (modified) X (unmodified) X (unmodified) X (modified) X (unmodified) X (unmodified)
Staging Staging Staging Staging Staging Staging
(untracked) add X (modified) commit X (unmodified) (unmodified) add X (modified) commit X (unmodified)
Local Repo Local Repo Local Repo Local Repo Local Repo Local Repo
(C4) (C4) (C5) ΔX (C4) (C4) (C5) ΔX

http://www.magedu.com

对比文件的变动

 查看文件的变动

  • git diff命令

  • git diff

    • 显示自前一次提交之后尚未暂存的文件变动

    • 比较的是工作区和暂存区

  • git diff --staged | --cached [...] ◆ 显示暂存但尚未提交的文件变动

    • 比较的是暂存区与前一次的提交
  • git diff [...] ◆ 比较指定的提交与工作区

  • git diff --cached [...]

    • 比较暂存区与指定的提交

~/deploy-demoapp$ git diff diff --git a/deployment-demoapp.yaml b/deployment-demoapp.yaml index 36f2ff4..e08495d 100644 --- a/deployment-demoapp.yaml +++ b/deployment-demoapp.yaml @@ -16,3 +16,4 @@ spec: containers: - name: demoapp image: ikubernetes/demoapp:v1.0

    •    imagePullPolicy: Always
      

~/deploy-demoapp$ git add ~/deploy-demoapp$ git diff //二者之间不再有差异 ~/deploy-demoapp$ git diff --staged diff --git a/deployment-demoapp.yaml b/deployment-demoapp.yaml index 36f2ff4..e08495d 100644 --- a/deployment-demoapp.yaml +++ b/deployment-demoapp.yaml @@ -16,3 +16,4 @@ spec: containers: - name: demoapp image: ikubernetes/demoapp:v1.0 + imagePullPolicy: Always

~/deploy-demoapp$ git commit -m "Second commit" ~/deploy-demoapp$ git log -p -1 commit e8a165d13526ff0b77fa300e8d7de14f739fd315 (HEAD -> master) Author: MageEdu mage@magedu.com Date: Sat Nov 26 17:08:53 2022 +0800

Second commit ……

http://www.magedu.com

忽略项目中的某些文件

 项目目录中,临时文件或由构建操作产生的文件,通常不应该纳入跟踪库中

  • .gitignore文件可用于完成这种功能

  • 每行指定一个文件名称,或glob形式的pattern

  • 文件名模式也支持使用叹号取反,即排队指定的文件

  • ◼ #开头的信息为注释行

◼ .gitignore文件自身应该纳入版本库

~/deploy-demoapp$ git add .gitignore ~/deploy-demoapp$ git status On branch master Changes to be committed: (use "git restore --staged ..." to unstage) new file: .gitignore ~/deploy-demoapp$ git commit -m "Added .gitignore" [master a2b53a9] Added .gitignore 1 file changed, 17 insertions(+) create mode 100644 .gitignore

.gitignore # Java class files *.class # vim swap file *.swp # Executable files *.exe # Object and archive files # Can use regular expression, e.g., [oa] matches either o or a *.[oa] # temp sub-directory (ended with a directory separator) temp/

http://www.magedu.com

提交历史和提交链

  • 版本库上的commit历史组合起来会形成一个提交链

    • 除了初始commit,每个commit都会都会有一个父commit

    • 除了最新一次的commit,每个commit都会有一个子commit

    • 这个提交链上的commit还可以使用字符串进行引用

      • 通常,Git会为默认创建的提交链上的最新一次提交创建一个基于字符串的引用master

      • 而该提交链也称为版本库的一个分支(Branch),master也是分支的名称标识

      • 另外自动创建的还有一个HEAD引用,它代表提交链的“头”,表示的是工作区所关联到的提交链上的特定提交,通常是最新一次提交

      • 基于HEAD指向的commit,还能够以相对方式引用历史中的提交,例如HEAD~表示前一个提交

    • git show HEAD命令可以查看HEAD当前所指向的commit的信息

提交链的“头”,用来指向工作区当前关联到的
commit
分支名称,会自动指向提交历史中的最新一次提交

http://www.magedu.com

撤消操作

  • 撤消文件变更

    • 撤消已经加入暂存区中的文件变更:git restore --stage

    • 撤消已跟踪但尚未加入暂存区中的文件变更:git restore

    • 从某个提交中恢复文件:git restore -s

      • 例如,从前一次提交中恢复README.md文件:git restore -s HEAD~ READEME.md
  • 撤消提交

    • 命令:git reset

      • 本质上是将HEAD和master引用移到指定的commit上

      • 是否基于指定的commit连同重置暂存区和工作区则取决于使用的选项

    • 三种不同的行为

      • --soft:仅移动HEAD和master指针的指向,不会重置暂存区或工作区

      • --mixed:仅重置暂存区,自commit之后暂存到暂存区的修改将移回工作区

      • --hard:同时重置暂存区和工作区,这意味着自commit之后所做出的的有修改都将会丢失

        • ⚫ 危险操作,会导致数据丢失

http://www.magedu.com

使用远程仓库

  • 推送代码至远程仓库的简明步骤

    • 在某个Git托管服务上注册一个账号

      • GitHub

      • Gitee

    • 在Git托管服务上创建一个仓库,例如名称为deploy-demoapp

    • 在本地版本库上,使用git remote add 命令添加关联的远程库

      • 远程仓库,一般默认名称为origin

      • 相关的url在远程库上可以直接获取到

相关的url在远程库上可以直接获取到 ~/deploy-demoapp$ git remote add origin git@github.com:iKubernetes/deploy-demoapp.git ~/deploy-demoapp$ git remote -v origin git@github.com:iKubernetes/deploy-demoapp.git (fetch) origin git@github.com:iKubernetes/deploy-demoapp.git (push) ~/deploy-demoapp$ git branch -M main ~/deploy-demoapp$ git push -u origin main 随后,每次本地提交完成后, Enumerating objects: 10, done. 再次运行git push命令即可完 Counting objects: 100% (10/10), done. 成向远程仓库的推送 Delta compression using up to 8 threads Compressing objects: 100% (9/9), done. Writing objects: 100% (10/10), 1.18 KiB | 1.18 MiB/s, done. Total 10 (delta 1), reused 0 (delta 0) remote: Resolving deltas: 100% (1/1), done. To github.com:iKubernetes/deploy-demoapp.git * [new branch] main -> main Branch 'main' set up to track remote branch 'main' from 'origin'.

http://www.magedu.com

使用远程仓库(2)

 从Git Server上克隆一个项目是初始化本地版本库的第二种常用方式  克隆操作使用git clone命令进行

◼ git clone []

◆ 克隆仓库至当前目录中

◆ 远程仓库的名称,即为本地创建项目目录名称

◆ 若要在本地使用一个不同的项目目录名称,直接在命令后面指定即可

  • 提示

◆ 远程仓库没有工作区,也不需要工作区

◆ 克隆至本地后会自动区分为工作区、暂存区和版本库

~$ git clone git@github.com:iKubernetes/deploy-demoapp.git test-project Cloning into 'test-project'... remote: Enumerating objects: 10, done. remote: Counting objects: 100% (10/10), done. remote: Compressing objects: 100% (8/8), done. remote: Total 10 (delta 1), reused 10 (delta 1), pack-reused 0 Receiving objects: 100% (10/10), done. Resolving deltas: 100% (1/1), done. ~$ cd test-project/ ~$ git remote -v origin git@github.com:iKubernetes/deploy-demoapp.git (fetch) origin git@github.com:iKubernetes/deploy-demoapp.git (push)

http://www.magedu.com

使用远程仓库(3)

  • 抓取远程仓库上的变动

    • 命令:git fetch

    • 它只会抓取远程仓库中的变动至本地版本库中,但不会修改工作区

  • 拉取远程仓库上的变动

    • 命令:git pull

    • 它会拉取远程仓库中的变动至本地版本库中,而且会通过合并(merge)操作修改本地工作区

  • 其它操作

    • 重命名远程仓库:git remote rename

    • 删除本地仓库上配置的远程仓库:git remote remove

http://www.magedu.com

Tags

  • 关于Tag

    • 为某个commit添加一个标签,从而对其完成特殊标记,例如标记特定的版本信息

    • 常用的版本标记格式

      • version-number.release-no.modificaton-no (e.g., v1.3.2)

      • version-number.release-no.upgrade-no_modificaton-no (e.g., v1.9.3_6)

    • 通常,用户应该每天下班前提交代码并完成推送,以备份代码;待需要发一个版本时,基于tag对相应commit 进行标记即可

    • Git支持使用两种标签:轻量标签(lightweight)与附注标签(annotated)

      • 轻量标签:仅为某个commit的引用

      • 附注标签:存储在Git 数据库中的一个完整对象,其中包含打标签者的名字、电子邮件地址、日期时间,此外还会包含一个message

http://www.magedu.com

Tags(2)

 管理标签

◼ 创建标签

◆ 轻量标签:git tag

◆ 附注标签:git tag -a -m

◆ 给指定的commit打标签:git tag -a -m

◼ 删除标签

◆ git tag -d

◼ 显示标签

◆ 列出:git tag -l

◆ 显示标签的详细信息:git show

◼ 检出标签

◆ git checkout

◆ 注意:检出到标签,会导致分离头指针,且新创建的提交也将处于分离的状态 ◼ 推送标签至远程仓库

◆ 推送特定标签:git push origin

◆ 推送所有标签:git push --tags

◼ 删除远程仓库上的标签

◆ git push --delete origin

http://www.magedu.com

Git的内部数据存储机制

  • Git有两个主要的数据结构

    • 存储所有commit和文件内容的不可变、仅附加的对象数据库(即本地版本库)

    • 暂存数据的可变暂存区(也称为index或cache)

      • 充当对象数据库与工作树(工作区的目录结构)之间的连接

      • 通过允许暂存commit之前的所有更改避免了每文件更改的提交

      • 执行提交时,Git会将状态更改复制到对象数据库并清除暂存区,未暂存的更改仍保留在工作区

  • 对象数据库主要存储如下类型的对象

    • blob对象

      • 存储文件内容,对象名称为文件内容的SHA1 hash码

      • 文件的每个版本都会存储为一个blob

      • blob对象仅包含文件数据,并不会存储文件的任何元数据,包括文件名

      • 命令git show可用于查看任何blob对象的对象

    • tree对象

      • 存储单级目录结构,即一个目录及其目录中可直接引用到的文件或子目录

      • git show命令也可用于查看tree对象,但git ls-tree命令能显示更丰富的信息

        • ⚫ git ls-tree <Tree_Object>

http://www.magedu.com

Git的内部数据存储机制

  • 对象数据库主要存储如下类型的对象(续)

    • commit对象

      • 指向一个tree对象,它指向的是创建提交时暂存到暂存区的工作树状态的快照

      • 包含时间戳、message、username和email等信息

      • 还存储有其前一级提交(父提交)的引用

      • 有的commit会存在多个父提交,也可能会有多个子提交

      • git show命令或git log --pretty=raw命令可用于查看commit对象

    • tag对象

      • 某个特定commit的引用,用于将该commit标记为特殊用途

      • 包含对象名称、对象类型、标签名称、创建标签的人的姓名、message等

      • git cat-file tag 命令能查看tag对象的内容

http://www.magedu.com

Git的对象模型

git log --pretty=raw git ls-tree git cat-file blob

http://www.magedu.com

Branches

  • 关于Branch

    • Branch用于跟踪commit,它就像是指定特定提交链上最近一次commit的轻量级可移动的指针

    • 每当创建新的commit时,Git都会设定Branch指向新建的commit

    • 对于初始commit,Git会为其分配一个名为master的默认分支

    • 一个版本库上可以创建多个branch,并且大多数开发人员会为他们处理的每个任务创建一个新的branch

    • 为了便于引用版本库上当前正在使用的分支,Git 还使用一个名为HEAD的特殊指针

      • 用来跟踪当前正在处理的分支,始终指向的是当前分支上的最新提交

      • 切换分支时,HEAD也会自动指向目标分支上的最新提交

Tag也是commit的引用,但它并不会自动跟随commit移动

http://www.magedu.com

管理branch

  • 创建分支

    • 命令:git branch

      • git branch devel

 切换分支

  • 命令:git checkout

    • git checkout devel

添加分支
devel

在devel分支上创建了新的提交commit4

http://www.magedu.com

管理branch(2)

 各分支按分别按自己的更改向前演进

在master分支上生成了新提切换master为交commit5
当前分支

  • 分支合并

    • 命令:git merge

      • 将指定的其它分支合并至当前分支,下面的两个命令能够将devel分支合并至master分支

        • ⚫ git checkout master

        • ⚫ git merge devel

    • 分支合并存在两种情形

      • 快进式合并(Fast-Forward Merge)

      • 三路合并(3-Way Merge)

http://www.magedu.com

分支合并

  • 快进式合并

被合并的分支master只需被合并的分支master相对于合要将其分支指针指向devel
并的分支devel来说,自创建分分支的最新一次提交即交支之后并生成任何新的变动
3-Way合并

  • 3-Way合并

    • 两个分支各自沿着自己的演进路线分别创建了新的提交

    • 合并时需要共同的祖先提交,以及各分支的最新一次提交进行合并

      • 如图,它需要commit3、commit4和commit5参与合并操作

      • 合并时,若某文件存在无法合并的修改,则意味着存中“冲突”,这里需要用户手动解决冲突后创建提交完成合并

被合并的分支master相对于合并的分支devel来说,自创建分支之后并生成任何新的变动

http://www.magedu.com

变基(rebase)

 关于rebase

◼ 相较于merge操作将一个分支上的所有变动一次性完成合并来说,rebase操作可以保留一个线性的变更历史 ◼ 命令:git rebase

  • git checkout feature

  • git rebase master

  • git checkout master

  • git merge feature

  • rebase操作也能完成分支合并

http://www.magedu.com

Git中的引用(reference)

  • 引用(reference)是间接指向commit的方式

    • 直接指向commit的方式是commit对象的sha1 hash码

    • reference也可被认为是commit hash的别名,对用户来说更友好

    • git版本库上的各reference以文本文件的形式存储于.git/refs/目录中下的子目录中

      • head目录:HEAD引用,内部的文件名为其指向的分支的名称,内容为相应分支最新一次提交的hash码

      • tags目录:标签引用,内部的文件名为创建的各Tag的名称

      • remotes/目录:remoteRepoName为远程仓库的名称

    • 带有引用的commit,也可以直接使用“ref/X/Y”路径的形式引用,例如“ref/heads/main”

  • 几个特殊的引用

    • HEAD:当前签出的提交/分支

    • FETCH_HEAD:最近从远程仓库中获取的分支

    • MERGE_HEAD:在git merge操作中,要合并到当分支的那个分支的HEAD

http://www.magedu.com

引用规范(refspec)

  • refspec

    • 全称为Reference Specification,即引用规范

    • git通过这种格式来表示本地分支与远程分支的映射关系

    • 引用规范的格式“+: ”,其中的+可选

      • 是一个模式(pattern),代表远程版本库中的引用,即远程分支

      • 是本地跟踪的远程引用的位置,即本地远程分支

        • 号告诉Git 即使在不能快进的情况下也要(强制)更新引用
    • 本地远程分支就像是远程分支的一个本地镜像,在本地版本库与远程版本库之间起到一个桥梁的作用

    • 例如本地远程分支:git branch -r

    • 查看分支间的关联关系:git branch -vv

图源:https://www.cnblogs.com/AhuntSun-blog/

http://www.magedu.com

远程仓库使用总结

  • 设定远程仓库

    • 添加:git remote add

    • 列出:git remote -v

    • 删除:git remote rm

    • 重命名:git remote rename

  • 克隆远程仓库

    • 克隆:git clone

    • 克隆到指定工作目录:git clone

  • 远程协作

    • 抓取远程仓库所有分支上的变更:git fetch

    • 抓取远程仓库指定分支上的变更:git fetch

    • 列出所有远程分支:git branch -r

    • 将远程分支合并至本地分支,通常应该将存在映射关系(通常为同一个分支名称)的分支进行合并

      • git checkout

      • git merge origin/

http://www.magedu.com

远程仓库使用总结(2)

 推送本地变更到远程仓库

◼ 命令语法:git push [--all | --tags] [< repository > [< refspec >...]]

◆ repository:要推送的目标远程仓库

◆ refspec:引用规范,格式为“+:”

  • ⚫ 为要推送的本地分支

⚫ :为目标远程分支,省略时表示与同名的远程分支

  • 几个运用示例

◆ 推送当前分支至上游(由remote.origin.merge参数指定):git push origin

  • 推送指定的分支:git push

◆ 在origin中创建expermental分支并推送当前的master分支:git push origin master:refs/heads/experimental

◆ 推送匹配的分支至origin:git push origin :

◼ 推送本地仓库中的所有分支:git push --all

◼ 推送本地仓库中的所有标签:git push --tags

 拉取或抓取远程分支

◼ 拉取命令:git pull [] [ [...]]

◼ 抓取命令:git fetch [] [ [...]]

http://www.magedu.com

Git 分支模型和工作流模型

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Git分支模型

  • 分支管理是现代版本控制系统在记录版本和变更记录之外的另一个非常重要的功能

    • 团队于同一个项目上协作时,分支管理是不可或缺的重要功能,因为它能够

      • 隔离不同开发人员的改动,为每个人提供一个相对独立的空间

      • 隔离团队根据布节奏要实现的代码提交、审核、集成和测试等工作

  • 分支策略

    • 分支策略是软件协作项目的灵魂,是软件协作模式和发布模式的风向标

    • 选择一种符合DevOps 开发模式的分支策略,对于DevOps 的实践落地也会大有帮助

    • ◼ 常见的分支策略

      • 主干开发,分支发布

      • 分支开发,主干发布

      • 主干开发,主干发布

http://www.magedu.com

简单的Git工作流

 假设tom和jerry作为同一项目的团队成员进行开发协作

◼ 项目使用了一个名为master的分支,用于维护项目生产部署和源代码文件

  • 工作流程

    • master分支用于跟踪部署到生产环境的源代码

    • 需要开发新功能时,tom和jerry各自创建一个feature分支

    • 日常开发中,他们将各的代码分别提交到各自的feature分支

    • 完成功能开发后,独立进行构建源代码在本地和测试环境中测试变更的代码

    • 测试通过后,他们将代码变更从自己的feature分支合并回master分支

    • 代码合并回master分支后,完成测试

    • 测试和验证完成后,master中的最新代码将部署到生产环境中,新功能上线

    • 在这一切完成后,各feature分支会被删除,从而清理存储库以防止任何短期分支弄乱版本库

http://www.magedu.com

基于GitHub的工作流

  • GitHub引入了PR机制

    • “Pull Request”或“PR”实际上并不是Git版本控制系统的功能,它是GitHub在其系统中创建的实现和支持 Git工作流程的机制

    • PR在简化的Git流程中间添加了另外几个步骤,以创建所谓的GitHub流程

    • 下图中流程中的紫色元素代表着GitHub流程中的特有内容,在开发流程主要步骤不变的情况下,这种模型为开发人员在feature开发上添加了PR机制,从而能够从团队的其他成员那里获得反馈

    • 然后,开发人员可以使用此反馈进行进一步的更改并提交到分支,然后最终测试并最终将代码变更合并到 master分支

http://www.magedu.com

Git分支模型

 几种常见的分支模型

  • master

  • master/develop

  • master/develop/feature

  • master/develop/feature/release

  • git-flow:master/develop/feature/release/bugfix

http://www.magedu.com

分支模型

 单分支模型 ◼ 开发、测试和发布都在master分支上完成 ◼ 工作流程 ◆ ~$ git checkout master ⚫ 完成开发、测试和发布 ◼ 特性:简单,但开发、测试和发布彼此影响,仅适用于单feature且无构建过程的场景  master/develop ◼ 工作模型 ◆ master:主分支 ◆ develop:开发分支,完成后合并至master分支;短期分支 ◼ 工作流程 ◆ ~$ git checkout -b develop # from master ◆ ~$ git rebase master ⚫ 完成开发、测试和发布 ◆ ~$ git checkout master

◆ ~$ git merge develop ◆ ~$ git branch --delete develop

  • 特性:develop分支的开发不会影响到master分支的构建过程,但不利于同时开发多个feature;适用于单feature,

  • 可从master执行构建的场景;

http://www.magedu.com

分支模型

 master/develop/feature

  • 工作模型

  • master 和develop是主分支

◆ 开发人员工作在各自的feature分支上

⚫ feature分支经过开发、模块测试后合并到develop分支

  • develop分支代码经过系统测试,release之后合并到master分支

    • ⚫ release是短期分支
  • 工作流程

    • git chechout -b feature # from develop

      • ⚫ 完成开发和特性测试
    • git checkout develop

    • git merge feature

    • git branch --delete feature

      • ⚫ 完成集成测试和发布
    • git checkout master

    • git merge develop

  • 特性:多个feature有利于更大规模的合作,但release独立分支中的bug修复变更与develop上的变更可能会导致

  • 冲突;因而,适用于多feature,develop在release过程中不会修改的场景;

http://www.magedu.com

分支模型

 master/develop/feature/release

  • 工作模型

    • 在前一分支模型的基础上,使用单独的release分支进行构建和bug修复
  • 工作流程

    • git chechout -b feature # from develop

      • ⚫ 完成开发和特性测试
    • git checkout develop

    • git merge feature

    • git branch --delete feature

    • git checkout -b release # from develop

      • ⚫ 完成测试、bug修复和发布
    • git checkout develop

    • git merge release # 将release合并至develop

    • git checkout master

    • git merge release # 将release合并至master

    • git branch --delete release # 删除releae分支

  • 特性:避免了因发布操作而阻塞了develop分支上的变更,但release分支存在的时间越长,导致develop合并冲突的可能性越大;因此,适用于多feature开发,但develop功能不受release影响的场景

http://www.magedu.com

分支模型(git flow模型)

 master/develop/feature/release/hotfix

  • 特性

    • 从master单独拉一个短期的hotfix分支进行问题修复
  • 工作流程

◆ git checkout -b hotfix # from master

  • ⚫ 完成修复和测试

  • git checkout master

  • git merge hotfix # 合并hotfix分支至master

  • git checkout develop

  • git merge hotfix # 合并hotfix分支至develop

  • git branch --delete hotfix # 删除hotfix分支

  • git checkout release # from develop

  • git rebase develop # release分支变基

    • ⚫ 在release分支上完成测试和发布
  • git checkout develop

  • git merge release # 将release分支合并至develop

  • git checkout master

  • git merge release # 将release分支合并至master

  • git branch --delete release # 删除release分支

  • 特性

    • 解决了前一模型中hotfix和develop冲突的问题

    • 适用于多feature开发的场景,release不受线上版

    • 本hotfix的影响

  • 这其实就是git-flow模型

http://www.magedu.com

git-flow模型

  • git-flow的要点

    • master 只能用来存储产品代码

      • 不能直接工作在master 分支上,而是在其他指定的、独立的特性分支

      • 中

      • 避免直接提交改动到master 分支上也是很多工作流程的一个共同准则

    • develop 是进行任何新的开发的基础分支

      • develop是任何feature分支的父分支

      • 用于汇集所有feature上的代码,并在必要时合并至master分支

    • develop分支上的代码来自于feature、release 和hotfix 分支

    • master分支上的代码来自于release 和hotfix 分支

    • master和develop都是长期分支,它们会存活在项目的整个生命周

    • 期中,而各feature分支、release分支和bugfix分支均为临时分支, 每次的使命完成后即被删除

http://www.magedu.com

git-flow模型(2)

  • 特点

    • 存在5个分支:master/develop, feature/release/hotfix

    • 开发活动最初在develop分支上进行,然后转移到release分支,并最终合并(merge)到main分支

    • 定义了一套明确的标准,清晰可控,单一版本首选,git提交历史简洁、清晰、易读

  • 存在的问题:对于大部分使用场景来说太复杂

    • 需要同时维护两个长期分支

    • 但大多数工具都将master作为默认分支,而开发是在develop分支进行的,这将导致经常要切换分支,非常令人恼火

    • ◼ 更大问题在于,这个模式是基于”版本发布”的,目标是一段时间以后产出一个新版本

      • 大部分组织在实践持续交付(continuous delivery),这也就意味着默认分支是可以被部署的

      • 很多网站项目是“持续发布”,代码的每次发生变动,就部署一次;这种情况下,master分支和develop分支的差别不大,没必要维护两个长期分支

      • 而且,持续交付没有了hotfix和release分支的需求,这些分支带来的繁琐流程也就一并移除了(比如,合并回release 分支)

    • 不适合持续交付或持续部署的项目,也不适用多版本共存的项目

http://www.magedu.com

GitHub flow和GitLab flow

 GitHub flow

  • 最大优势就是简单,只有master一个长期分支,对于“持续发布”的产品较为适合

  • 问题在于,它假设master分支的更新与产品的发布完全一致,也就是master分支的最新代码默认即为部署到线上的代码

    • GitHub flow 默认每当合并一个feature分支时,就能够部署到生产,特别适用于“持续发布”的场景

    • ◆ 但是,对于有特定发布窗口的场景中,可能会导致二者存在不一致的情形

  • 6条原则

    • master分支永远是随时可部署发布的

    • 需求新增基于master分支,并创建一个语义化的feature分支进行开发

    • 定期推送本地分支到远端

    • 合并到master需要提PR

    • master一旦接收到合并请求,即可立即部署发布

http://www.magedu.com

GitHub flow和GitLab flow(2)

 GitLab flow

  • 兼收并蓄了GitHub flow和Git flow的优势,既能适应不能开发环境的弹性需求,又有单一分支的简单和便利

  • ◼ 相对GitHub flow来说增加了环境分支,且代码必须由上游(master)向下游(staging)发展(上游优先原则),并且针对持续发布和版本发布都提出了相应的准则

图源:https://segmentfault.com/

http://www.magedu.com

GitLab flow下的环境分支

  • 专用的环境分支

    • 若存在staging、pre-prod和production三个分支,则可以为每个环境创建一个专用分支

      • 从master分支拉起staging分支用于部署到临时环境

      • 将staging分支合并到pre-prod分支,部署到预生产环境

      • 将pre-prod分支合并到production分支,部到生产环境

    • 该模型中,相关的commit,只允许向下游 (downstream)分支流动,以确保变更完成了所有环境中的测试

    • 但是,需要基于某个特定的commit创建cherry-pick做热修复时,应该建一个feature分支进行开发,并在完成后合并到production分支

      • 随后,在production分支上的测试完成后,还需要将 feature分支再合并到其它分支上

      • 不过,若需要进行更多的手动测试,则应该将用于修复的feature分支请求合并到下游分支

http://www.magedu.com

GitLab flow下的发布分支

  • 需要将软件向外界(组织外部)发布软件时才应该使用发布分支

    • 从main/master 创建一个stable分支作为起点,并且这个分支要尽可能的新,从而可减少后续不得不将漏洞修复代码部署到多个分支的情况

    • 声明了一个发布分支后,这个分支只会合并严重的漏洞修复更新

      • 尽可能先将漏洞修复的更新合并到main,然后拣选(cherry-pick)到发布分支

        • ⚫ 因为,若是先合并到release 分支,可能会忘记将它们拣选(cherry-pick)到main,然后在后续的发布时候再次遇到相同的漏洞

        • ⚫ 先合并到main,然后拣选到发布分支,也是在践行“上游优先(upstream first)”原则,也被Google和RedHa实践

      • 每次将漏洞修复包含到一个release 分支,需要通过设置新的标签的方式提升补丁(patch)版本

http://www.magedu.com

一个可用的持续发布实例

  • 持续发布分支模型及流水线模型

持续发布模型示例:

  • ① 由Open MR事件触发CI Pipeline;

  • ② 由Accept MR事件触发CICD Pipeline;

  • ③ 多环境中,需要给合并生成的Commit打Tag触发 CD Pipeline;

http://www.magedu.com

Git项目团队协作的工作流模型

  • 团队内部共享远程仓库的工作流模型

    • 常见小型的私有团队成员间的协作

    • 所有成员被授权push代码到一个共同的远程仓库

    • 彼此间基于各自专用的feature(或topic)分支进行隔离

    • 项目维护者在远程仓库上启动master分支

    • 所有开发人员克隆远程master分支至本地仓库

    • 每个开发人员创建一个本地feature分支(例如feature/user1-x)进行特性开发

    • 某位开发人员的特性开发完成后,创建一个pull request请求通知其它人review他的代码,所有人都可以提出反馈和建议

    • 一旦被接受,其分支将由项目维护者合并至远程仓库的master分支

  • 基于Fork的工作流模型

http://www.magedu.com

Git项目团队协作的工作流模型

  • 团队内部共享远程仓库的工作流模型

    • 常见小型的私有团队成员间的协作

    • 所有成员被授权push代码到一个共同的远程仓库

    • 彼此间基于各自专用的feature(或topic)分支进行隔离

    • 工作流程

      • 项目维护者在远程仓库上启动master分支

      • 所有开发人员克隆远程master分支至本地仓库

      • 每个开发人员创建一个本地feature分支(例如feature/user1-x)进行特性开发

      • 某位开发人员的特性开发完成后,创建一个pull request请求通知其它人review他的代码,所有人都可以提出反馈和建议

      • 一旦被接受,其分支将由项目维护者合并至远程仓库的master分支

http://www.magedu.com

Git项目团队协作的工作流模型(2)

  • 基于Fork的工作流

    • 该模型无须共享的远程版本库,每位开发人员将会fork协作时使用的远程仓库至自己的个人账户下,生成一个个人专有的远程仓库

    • 开发人员克隆自有的远程仓库至本地,并基于一个feature分支完成feature开发

    • 工作流

      • 项目维护者将本地仓库推送至远程主机,并授权各贡献者有权读取该仓库

      • 各代码贡献人员fork项目至同一远程主机上的个人账户下

      • 某开发人员克隆自己账户下基于fork生成的仓库至本地

        • ⚫ 本地远程分支将指向自己账户下的远程分支,而非上游(fork的项目)仓库中的远程分支
      • 在本地仓库上添加名为upstream的上游仓库,以跟踪原始仓库,并拉取原始仓库中的所有变更至本地

      • 在本地仓库创建一个新的feature分支进行feature开发,并日常推送变更至自己的远程仓库

        • ⚫ 启动编码日常的“编辑、暂存、提交和推送”循环
      • feature开发完成后,通过pull request通过项目维护者review代码

        • ⚫ 创建 pull request 时,需要明确指定自己的仓库名和分支名,以及上游的仓库名和分支名
      • 项目维护者审核代码

        • ⚫ 打回并要求原作者更正时,开发人员启动开发任务修正代码并再次创建PR请求

        • ⚫ 接受代码时,项目维护者可通过merge操作完成分支合并

      • 所有的代码贡献者需要拉取上游仓库中的变更至本地版本库

http://www.magedu.com

Git项目团队协作的工作流模型(3)

 基于Fork的工作流(续)

基于fork的工作流示意图

http://www.magedu.com

GitLab

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

GitLab简介

  • Gitlab即是Git远程存储库的一种实现,支持存储用户的代码

  • 仓库,并向用户提供远程访问服务

  • 除了托管代码之外,这些服务还提供帮助管理软件开发生命

  • 周期的附加功能,例如

    • 代码共享

    • 分支合并请求

    • 错误跟踪

    • ……

http://www.magedu.com

GitLab组件介绍

  • GitLab系统各组件的简要功用说明

◼ Gitaly:Git RPC service for handing all Git calls made by GitLab

  • GitLab Exporter:GitLab指标暴露器

  • GitLab Page:GitLab的静态Web站点

◼ GitLab self-monitoring的多个组件:Prometheus、Alertmanager、Grafana、Sentry和Jaeger

  • GitLab shell:处理基于ssh会话的git命令

  • GitLab Workhorse:智能反向代理,处理高并发的HTTP请求

  • Inbound emails(SMPT):接收用于更新issue的邮件

  • Outbound email (SMTP):向用户发送邮件通知

◼ LDAP Authentication:LDAP认证集成

  • Mattermost:开源的Slack

  • MinIO :对象存储服务

◼ NGINX:将请求路由到正确的组件上,并终止SSL会话

http://www.magedu.com

GitLab组件介绍(2)

 GitLab系统各组件的简要功用说明(2)

◼ Praefect:Git客户端和Gitaly存储节点之间的透明代理

◼ Node Exporter:节点指标暴露器

◼ PostgreqSQL:数据库,还有一个用于暴露其指标的PostgreSQL Exporter组件 ◼ Puma (GitLab Rails):处理发往Web接口和API的请求

◼ Redis:缓存服务,还有一个用于暴露其指标的Redis Exporter组件

◼ Registry:容器注册表,支持Image的push和pull操作

◼ Runner:执行GitLab的CI/CD作业

◼ Sentry integration:跟踪部署的各应用的错误信息

◼ Sidekiq:后台作业处理器

http://www.magedu.com

部署GitLab

  • GitLab包含了众多组件,其中的多个组件都有着特定的部署要求

◼ https://docs.gitlab.cn/jh/install/requirements.html

  • 安装方法

    • Linux安装包:官方的deb/rpm 安装包(也被称作Omnibus GitLab)包含极狐GitLab 和依赖的组件,包括 PostgreSQL、Redis 和Sidekiq

    • Helm Chart:用于在Kubernetes 上安装极狐GitLab 及其所有组件的云原生Helm chart

    • Docker:Docker 容器化的极狐GitLab 软件包

    • Source:源码安装,在GitLab没有提供适用的安装包的平台上(例如各类BSD系统)只能采用这种安装方式

    • GitLab Environment Toolkit(GET):自动化工具集,用于在主流的公有云(Azure、GCP和AWS)上部署 GitLab

    • GitLab Operator:Kubernetes Operator风格的部署模式

http://www.magedu.com

Omnibus GitLab architecture and components

  • Omnibus GitLab是基于Chef的应用编排工具,它基于Chef的cookbooks和recipes等组件自动化编排GitLab 的各组件,避免了用户复杂的配置过程

    • 相关项目https://gitlab.com/gitlab-org/omnibus-gitlab

配置模板用于为GitLab中的每个组件提供配置信息,每个组件配置参数格式为:
[''] =

管理各组件的统一命令为 gitlab-ctl ,例如
gitlab-ctl reconfig或gitlab-ctl restart等能统一执行各组件的重新配置及重启操作;此外还有一些各组件专用的命令,如gitlab-pgsql、
gitlab-rails和gitlab-rake等;

http://www.magedu.com

Jenkins 基础

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Jenkins Pipeline Workflow

http://www.magedu.com

Jenkins基础

  • Jenkins 2用于泛指支持流水线即代码及其他类似Jenkinsfile等新特性的新版Jenkins,DSL是Jenkins 2的核

  • 心组件,作为构建模块让其他核心的用户导向特性成为可能

    • 支持将原本写在Jenkins中的代码提取到一个Jenkinsfile文件中,从而以一种更加结构化的方法来创建工作流—

    • —声明式流水线,它比传统的脚本式流水线有着更加清晰、可预期的结构,以及更强大的DSL元素和结构体;

    • ◼ 称为Blue Ocean的全新用户界面,为流水线的每个阶段添加了图形化展示,能够显示成功/失败和进展等标识, 并对每个任务都提供了点选式日志查看功能;

    • 组织:用于支持源码控制平台上将多个代码库聚合成“组织"的功能,目前已经支持Github和Bitbucket平台上

    • 的“组织”功能,未来将会逐步支持其他的平台;

    • 多分支流水线:在有着Jenkinsfile的项目中,若创建了一个新的分支,Jenkins将自动基于这个新分支创建一个

    • 新项目,此类型的项目可应用于任何Git或SVN代码库。

http://www.magedu.com

Jenkins 2系统组件

  • 在Jenkins 2中,节点是一个基础概念,代表了任何可以执行Jenkins任务的系统

  • 节点中包含主节点(master)和代理节点(agent)两种类型,但主节点一般用于完成任务分配等管理

  • 功能,而代理节点才会执行各类具体的任务

    • 主节点:Jenkins的一个部署实例的核心控制系统,它能够完全访问所有Jenkins配置的选项和任务(job)列

    • 表,而且,若不存在其他代理节点,主节点也是默认的任务执行节点;

    • 代理节点:在早先版本的Jenkins中,代理节点被称为从节点(slave),它代表着所有的非主节点;

      • 这类节点由主节点管理,按需分配或指定执行特定的任务,例如不同的构建任务或测试任务等

      • 脚本式流水线中,节点特指一个运行代理节点的系统,而在声明式流水线中,它则是分配的一个来作为代理节点的

      • 特定节点

    • 执行器(Executor):简单来说,Executor只是节点或代理节点用于执行任务的一个槽位;

      • Executor的数量定义了该节点可以执行的并发任务量,一个节点上可以有任务数量的槽位,但也允许管理员按节点资

      • 源定义合适的数量

      • 在主节点将任务分配给特定节点时,该节点上必须有可用的Executor来立即执行该任务,否则,只能等到有空闲槽位

      • 可用

http://www.magedu.com

获取Jenkins

  • 下载Jenkins

    • 下载页面:https://www.jenkins.io/download/

    • 镜像站点:mirrors.HuaweiCloud.com、mirrors.Aliyun.com、……

http://www.magedu.com

部署Jenkins

 Ubuntu Server 18.04、20.04或22.04

~# JDK='openjdk-11-jdk'

  • ~# apt install ${JDK}

~# JENKINS_VERSION=‘2.361.2’

~# wget https://mirrors.huaweicloud.com/jenkins/debian-stable/jenkins_${JENKINS_VERSION}_all.deb

~# apt install ./jenkins_${JENKINS_VERSION}_all.deb

 随后即可通过节点IP默认的8080端口访问Jenkins服务

  • http://Jenkins_HOST:8080/

  • 提示

    • Jenkins初始化时通常需要安装一些插件,这些插件需要通过Jenkins官方的插件服务进行下载,速度较慢

    • 建议在打开Jenkins页面完成Jenkins代码初始之后,先通过下面的步骤将插件替换为国内镜像服务后再进行插件安装的步骤

 调整插件更新站点,以加速插件部署

~# cd /var/lib/jenkins/

  • ~# sed -i 's@https://updates.jenkins.io/download/@https://mirrors.huaweicloud.com/jenkins/@g' updates/default.json

  • ~# sed -i 's@www.google.com@www.baidu.com@gi' updates/default.json

  • ~# sed -i 's@https://updates.jenkins.io/update-center.json@https://mirrors.huaweicloud.com/jenkins/updates/current/update-center.json@i' hudson.model.UpdateCenter.xml

而后重启Jenkins服务:

http://Jenkins_HOST:8080/restart

http://www.magedu.com

部署Jenkins(2)

  • CentOS 7 或Rocky Linux 7

~]# JDK=‘java-11-openjdk'

  • ~]# yum install ${JDK}

  • ~]# JENKINS_VERSION=‘2.361.2’

  • ~]# curl -LO https://mirrors.huaweicloud.com/jenkins/redhat-stable/jenkins-${JENKINS_VERSIONS}-1.1.noarch.rpm

  • ~]# yum install ./jenkins-${JENKINS_VERSIONS}-1.1.noarch.rpm

~]# systemctl start jenkins

  • 调整插件更新站点,以加速插件部署

~]# cd /var/lib/jenkins/

  • ~]# sed -i 's@https://updates.jenkins.io/download/@https://mirrors.huaweicloud.com/jenkins/@g' updates/default.json

  • ~]# sed -i 's@www.google.com@www.baidu.com@gi' updates/default.json

~]# sed -i 's@https://updates.jenkins.io/update-center.json@https://mirrors.huaweicloud.com/jenkins/updates/current/update-center.json@i' hudson.model.UpdateCenter.xml

  • 随后即可通过节点IP默认的8080端口访问Jenkins服务

    • http://Jenkins_HOST:8080/

http://www.magedu.com

容器化运行Jenkins

 获取LTS或Edge版本的Jenkins镜像并运行为容器

http://www.magedu.com

解锁Jenkins

获取解决密码的文件路径

http://www.magedu.com

安装社区推荐的插件

http://www.magedu.com

创建Jenkins的管理账户

http://www.magedu.com

设定Jenkins对外通信时使用的URL

该URL将会成为Jenkins生成的各类对外提供服务时的URL中的主机地址,例如Webhook路径、分布式环境中的Agent联系主服务器时使用的地址等;

http://www.magedu.com

Jenkins UI的主页

http://www.magedu.com

Jenkins UI 及 Job 类型

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

如何使用Jenkins创建CICD任务?

  • 我们知道,一个典型的CICD操作过程可以抽象为Pipeline形式

    • 这种类型的Pipeline一般由构建、测试和打包等几个典型阶段组成

      • 每个阶段的具体操作过程都可能需要特定工具程序的参与

      • 例如maven工程项目多半要依赖maven和jdk环境,而node.js项目则要用到npm工具等,这些工具需要事先经由“系统管理 → 全局工具配置”进行配置;

    • 为便于用户定义CICD的具体步骤,Jenkins为特地提供了不同类型的Job,例如自由风格的作业、Pipeline作业、 Maven工程作业、多配置项目、多分支流水线等;

  • 通常,一个典型的CICD过程拥有输入和输出

    • 从某个代码仓库中“克隆”代码作为输入,并将生成的结果打包成特定的格式(例如jar、exe、elf或image等) 进行输出,甚至还要推送到目标工件库中(例如DockerHub)以便于存储和分发

    • 若需要事先完成认证才能访问代码仓库服务及工件库服务时,Jenkins支持将这些认证凭据以安全方式事先定义,并在Pipeline自动化执行时自动引用;

      • 系统管理 → 管理凭据

http://www.magedu.com

Jenkins的系统管理页面

http://www.magedu.com

通过插件扩展Jenkins

  • 若要扩展Jenkins的功能,就需要为其安装合用的插件

    • 插件Hub:https://plugins.jenkins.io/

    • 支持按类别搜索和关键词搜索等

  • Jenkins内置的插件管理页面如下图所示

1、“可用插件”即为可安装使用的插件
2、安装和制裁插件需要重启Jenkins,
但重启操作应该在Jenkins空闲时进行

http://www.magedu.com

通过插件扩展Jenkins(2)

 示例:安装BlueOcean插件,为Jenkins提供新的用户界面

http://www.magedu.com

使用“凭据”保存敏感数据

 Jenkins的Job中可能会使用到敏感数据,例如

◼ 基于ssh连接目标主机时使用的私钥,或者用户名与密码

  • 从私有代码仓库中克隆代码时使用的认证信息

◼ 将构建后的Package推送至目标存储服务时使用的认证信息

  • 为确保自动化的Job能自动访问到这些信息,Jenkins则通过“凭据”来保存它们 ◼ 创建的“凭据”可基于其名称等进行引用

以上这些是在Jenkins系统部署了社区推荐的插件体系下所支持的凭据的类型

http://www.magedu.com

如何使用Jenkins创建CICD任务?(2)

  • 如何触发任务?

    • 使用触发器(Trigger)指定触发机制

    • 支持的触发机制

      • 手动触发

      • 定时触发

      • 由其它流水线的执行结果触发

      • 由特定的事件触发,例如代码仓库上的PR事件等

      • ……

  • 将CICD流水线交付的结果部署到目标环境中

    • 部署新版本的操作过程,是触发系统故障的常见原因之一

    • 因而,部署操作通常需要人工介入,或借助专用的部署工具遵循特定的部署策略进行 ◆ 滚动部署和金丝雀发布

      • 蓝绿部署
    • 部署操作通常还需要同流量迁移机制协同进行

    • 需要执行自动化部署时,在Jenkins流水线的定义中,添加一个调用部署工作的步骤即可

  • 流水线执行结束后,其状态通常要存档,并在必要时通知给相关人员

    • Jenkins使用“构建后操作”来定义这部分操作

http://www.magedu.com

Jenkins项目类型

  • 无论是哪个版本的Jenkins,都要通过新建一个指定类型的项目来添加一个新“job”;

  • Jenkins中所谓的“项目类型”的定义,主要是用于分类一个具体的CI任务在其“构建”定义上的区别,

  • 例如,对于自由风格类型项目的构建部分来说,典型的特征之一便是对shell脚本及Windows批处理脚本的支持

  • 但Jenkins的项目类型也可以根据不同的标准再次划分为不同的类别,比方说下面这些归类: ◼ 开放式配置可用于执行任何任务:自由风格类型的项目、流水线项目

    • 针对高级或具有复杂场景的用例:多配置项目

    • 针对组织的任务:文件夹、多分支流水线、GitHub组织、Bitbucket团队等项目

    • 自动配置和构建的任务:多分支流水线、GitHub组织、Bitbucket团队等项目

http://www.magedu.com

Create a job

http://www.magedu.com

自由风格类型项目

  • 顾名思义,自由风格类型项目指在提供一种相对开

  • 放的项目构建途径,以完成各类任务

    • 事实上,在“流水线”风格的项目出现之前,自由

    • 风格的类型项目也被认为是最为灵活的项目类型, 是大多数Jenkins任务的传统选择

    • 它有关“构建”的配置如右图所示

    • 不同插件配置下,其可用的环境亦会有所不同

  • 一个脚本化自由风格任务的示例

http://www.magedu.com

自由风格类型项目(2)

  • 在创建的自由风格的项目上,通过“立即构建”即可立即触发流水线的执行

◼ 任务执行结束后,即可通过其“构建号”相应的控制台输出了解构建状态,如下面的右图所示

我们可以编写脚本执行任何期望并能够通过脚本完成的操作,其“自由风格”也由此可见一斑

http://www.magedu.com

自由风格类型项目(3)

 BlueOcean的界面

http://www.magedu.com

流水线类型项目

  • 这是Jenkins 2最重要的项目类型之一,它用于将CICD流水线集成到Jenkins之中,从而由Jenkins完成特

  • 定软件项目的自动化持续交付

  • 流水线项目的步骤和逻辑定义在结构化的Groovy脚本之中(而非Web表单中),该脚本支持脚本式和

  • 声明式两种结构,并保存于名为Jenkinsfile的文本文件中

脚本式
Pipeline
声明式
Pipeline

http://www.magedu.com

流水线类型项目(2)

 Pipeline Job 示例

http://www.magedu.com

流水线类型项目(3)

  • 流水线项目也支持从SCM中获取Jenkinsfile脚本,而不是在如上图的文本输出区域中输入脚本 ◼ 因此,选定SCM时,还需要输入或选择额外的字段在哪里获取脚本

该方式还有一个“轻量级检出”
选项,它是指SCM插件在流水线开始时仅检出Jenkinsfile
文件而不是整个项目,而后由Jenkinsfile中的相关步骤来检出整个项目,以避免两次都检出整个项目率。

http://www.magedu.com

多配置项目类型

  • 多配置项目类型是为了简化运行一组仅在参数方面有所不同的项目构建而设计

    • 例如,在需要针对一组有5种不同的浏览器(IE、Firefox、Safari和Chrome等),以及一组5咱不同操作系统

    • (Debian、CentOS、Windows和MacOS X等)运行测试构建时,若没有多配置项目类型,将不得不运行25个任务来完成构建测试

    • 而使用多配置项目类型,只需要一个任务便能执行各种可能的组合

      • 具体的做法,根据所使用的每个不同的“坐标轴”参数定义基础任务,以完成我们需要做的任何事情

      • 例如,我们使用x轴表示浏览器类型,而使用y轴表示操作系统类型,即能组合出要执行的任务的矩阵

事实上,除了用户自定义坐标轴外,Jenkins也允许用户选择节点坐标
(Slaves),以及通过节点标签进行节点筛选的坐标轴(Label Expression)。

http://www.magedu.com

多分支流水线项目类型

  • 多分支流水线是Jenkins 2提供的一种全新的项目类型,它支持针对源码版本控制仓库中检测到的每个

  • 分支创建新的流水线项目

    • 一旦将版本控制系统中的指定的项目识别为Jenkins项目,多分支流水线可自动管理和构建所有的分支

    • ◼ 显然,在Jenkins上创建多分支流水线项目时,需要将任务指向SCM仓库,而非项目的某个特定分支

  • 目前,多分支流水线的Build Configuration部分只有“by Jenkinsfile”一个选项,它的意思是在Jenkins将

  • 通过在检出的项目的根目录中查找名为Jenkinsfile的文件,以确认它是否可以自动构建项目的分支

    • Jenkins会在项目建立后通过运行“分支索引”功能,在项目的分支中查找Jenkinsfile文件。

    • 无论在任何分支中找出Jenkinsfile,它都将会自动为该分支创建并构建一个任务,因而,分支索引完成后,将为多分支流水线项目中的每个匹配分支各自创建一个单独的任务;

    • 另外,一旦有新的分支进入,Jenkins也能够自动检测新分支,并为它们创建相应的任务;

http://www.magedu.com

文件夹类型的项目

  • 不难想到,文件夹代表一个组织结构,而不是任务项目

    • Jenkins 2之前的版本使用视图来过滤仪表板上的项目列表,而视图提供了一种可以通过配置创建有限的任务

    • 列表的能力

    • 与视图不同的是,文件夹实际上增加了将项目分组到共同的名称空间、结构和环境中的能力;

  • 具体来说,文件夹允许一组任务共享如下几个部分

    • 容器:创建文件夹时,将会创建一个容器来容纳一组任务;

    • 名称空间:自定义的名称空间也是任务路径的一部分;

    • 共享库:文件夹可以有专用于内部项目间共享一组共享库;

    • 单独权限:若Jenkins安装了基于RBAC的授权策略插件,并配置了基于角色的权限,则可以使用这些插件;

http://www.magedu.com

文件夹类型项目的定义界面

http://www.magedu.com

文件夹类型的项目

  • 创建完文件夹后,随后即可在其中创建新项目,这同直接创建项目的方式几乎没有太大区别,惟一的

  • 不同之处仅在于,这些项目均组织于文件夹提供的名称空间之下,新项目的全名将包含该名称空间

  • 因此,文件夹功能类似于操作系统上的目录,而于文件夹中创建新项目的功能也类似于在目录中创建

  • 其它类型的文件;而且,我们也可以将其它现存的项目移入一个文件夹中,这同在目录中移动文件的功用类似;

  • 另外,Jenkins文件夹也支持RBAC授权管理机制,我们可以在Jenkins上安装RBAC授权插件后基于角色

  • 来分配文件夹的管理权限;

http://www.magedu.com

Github组织或Gitlab组类型的项目

  • GitHub组织项目,是专用于管理托管于GitHub之上的项目集合的一种组织结构,而非专门的项目类型 ◼ GitHub组织的一个典型用途是,将一个公司或一个人的所有项目集合统一进行分组,而为了便于整合 GitHub组织,Jenkins提供了GitHub组织项目类型

    • GitLab Group类型的功能之与类似,只不过,它对应的是GitLab上的Group的概念

http://www.magedu.com

构建流水线快速入门

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

构建、构建系统和构建工具

  • 构建:将程序源码转换成一个可用的目标(target)的过程,该过程可能会包括获取依赖、编译和打

  • 包等环节;目标可以包括库、可执行文件及生成的脚本等,该类文件即是所谓的“制品”,它们通常应该存储于制品库中 ◼ Nexus就是著名的制品库服务之一

  • 程序开发完成后,程序员完全可以在本地进行构建,但基于有着标准、统一构建环境的构建系统完成

  • 应用程序的构建,能有效确保制品质量

    • Jenkins是构建服务器,自身并未提供构建工具

    • ◼ 但Jenkins可集成用户所需要的大部分主流构建工具

    • 提示

      • 在流水线中“执行shell脚本”进行的构建步骤,其依赖的工具程序是操作系统上的可用shell命令

      • ◆ 其它步骤多数依赖于通过插件集成到Jenkins中的工具

  • 构建工具与源程序的编程语言及工程工具有密切关系,因而,在Jenkins中具体需要集成的构建工具,

  • 取决于用户的实际需要

◼ SBT:Scale

  • Babel、Browserify、Webpack、Grunt及Gulp等:javascript

  • Gradle:Java、Groovy和Kotlin等;

◼ Maven: Java

◼ …

http://www.magedu.com

全局工具配置

  • 构建步骤所依赖的构建工具

    • 在流水线中,调用shell脚本执行构建步骤时,需要事先确保运行构建任务的主机上部署了相关的工具并完成了相应的配置

    • Pipeline类型的任务中,调用的构建工具通常源自于“全局工具配置”中定义的各构建工具,这类的构建工具通常存在两种情形

      • 主机操作系统(或容器)上部署的应用程序,可由“全局工具配置”进行引用

      • 由Jenkins管理并部署在${JENKINS_HOE}/tools目录下的程序文件

    • 由部署的插件提供

全局工具配置中配置的工具既可以源自于操作系统的包管理器管理的应用程序,也可以是由Jenkins自动安装在

  • $JENKINS_HOME/tools下的程序

有些工具程序可以同时存在多个版本, Pipeline任务中可以通过配置的程序的名称进行调用

http://www.magedu.com

JDK

  • 配置JDK构建环境

    • JDK支持4种自动安装方式

      • 运行批处理命令

      • 从java.sun.com安装

⚫ Oracle JDK,需要输入用户名和密码 ⚫ Oracle Java SE 11+ 不再授权商用

◆ 解压*.zip/*.tar.gz

◆ 运行命令

  • Manage Jenkins → Global Tool Configuration → JDK

  • ◼ 无论使用何种自动安装方式,配置完成后, Jenkins都不会立即进行安装,而是在第一次被用时才安装

  • 若Jenkins节点无法连接互联网,也可以选择在

  • 系统上通过其它方式部署好JDK,而后在Jenkins 中经由JAVA_HOME配置引用

http://www.magedu.com

Maven简介

  • 一款专用于Java语言项目的主流的管理和构建工具,它为开发者提供了一套完整的构建生命周期框架,

  • 开发团队稍微投入一些时间就能够自动完成工程的基础构建配置

  • 在有多个开发团队环境的情况下,Maven 能够在很短的时间内使得每项工作都按照标准进行,这主要

  • 是因为大部分的工程配置操作都非常简单并且可复用

  • Maven基于项目对象模型(POM project object model),它可以通过一小段描述信息(配置)来管理项目

  • 的构建

◼ 这个项目描述信息保存在一个名为pom.xml的文件中

◼ 项目的通用目录结构通常包括如下几个

◆ src/main/

  • ⚫ java:项目的源代码所在的目录

  • ⚫ resources:项目的资源文件所在的目录

⚫ filters:项目的过滤器文件所在的目录

◆ src/test/

  • ⚫ java:测试代码所在的目录

  • ⚫ resources:测试相关的资源文件目录

  • ⚫ filters:测试相关的过滤器文件目录

http://www.magedu.com

Maven通用构建构架

  • 本质上,每个Maven项目都包含一个POM文件,该文件定义项目的各个要点;

  • Maven使用POM来决定不同的构建动作,及制品的生成等;

    • 首先,它将在本地repo搜索指定的依赖,而后是Maven的repo服务;

    • 若配置了远程repo服务,Maven还是搜索该repo;

  • Maven默认使用的是其官方存储库,在因内的下载速度较慢,因而建议使用因内的Maven镜像仓库,

  • 例如阿里的镜像仓库等;

http://www.magedu.com

Maven项目构建简介

 Maven工程构建的常用阶段

◼ validate:验证项目是否正确且所有必须信息是可用的 ◼ clean:将以前编译得到的旧文件class字节码文件删除;

◼ compile:将java源程序编译成class字节码文件;

◼ test:自动测试,例如,自动调用JUnit程序;

◼ report:报告测试程序执行的结果;

◼ package:应用打包,动态Web工程打成war包,java工程打成jar包;

◼ install:Maven特定的概念,是指将打包得到的文件复制到“仓库”中的指定位置 ◼ deploy:将动态Web工程生成的war包复制到Servlet容器下,使其可以运行

 Maven构建的基本工作流程

◼ 读取pom.xml文件

◼ 从repository中下载pom.xml文件定义的依赖项

◼ 根据需求构建项目、生成报告,并处理生命周期、 阶段、目标、插件和其他任务

http://www.magedu.com

Maven构建工具

  • 类似于JDK,Maven的自动安装也支持四种方式,Jenkins节点能接入互联的情况下,直接从Apache安

  • 装最为简单;

    • 运行批处理命令

    • 从Apache安装

    • 解压*.zip/*.tar.gz

    • 运行命令

  • 本示例选择从Apache自动安装

    • Name:为部署的Maven构建工具的版本
  • 安装过程发生在构建工具首次被调用时

http://www.magedu.com

案例:目标流水线示意图

 基于“自由风格的软件项目”和Maven快速了解Jenkins的用法

克隆代码构建测试部署
Deploy to container插件本地git程序本地maven程序基于SSH完成应用部署

http://www.magedu.com

自由风格的CI流水线示例

 完全由脚本实现整个Pipeline

脚本里用到的各程序,源自
Jenkins部署在主机环境;这同直接在一个主机上执行
shell脚本的逻辑相同;

示例中,流水线的各阶段都由脚本代码完成;
提示:这些代表着流水线不同阶段的操作,也可以放置于同的Build Step中;

克隆代码构建测试部署

http://www.magedu.com

自由风格的CI流水线示例—源码管理

克隆代码构建测试部署

 把源码的clone和checkout交由“源码管理”完成

克隆和分支检出的操构建步骤里需要的执行的代作,将由Jenkins上配码也不需要再包括代码克隆置的Git插件完成; 的和检出的操作;

http://www.magedu.com

自由风格的CI流水线示例—部署操作

  • 将部署操作交由“Deploy to container”插件完成

    • 该插件专用于将war文件部署至servlet容器上,例如 tomcat等;

      • 非war类型的应用,需要由其它部署工具完成;
    • 需要先在Jenkins上安装“Deploy to container plugin”插件;

  • 访问servlet容器的管理接口时,通常要先完成认证;

  • 用到的认证要以“凭据”形式创建于Jenkins之上

    • 如右图所示,创建了一个“Username with password”类型凭据

    • 其作用范围为“全局”

    • 凭据的ID为“tomcat-manager-credential”

克隆代码构建测试部署

http://www.magedu.com

自由风格的CI流水线示例—部署操作(2)

 在自由风格的项目上添加“构建后操作”,选择“Deploy war/ear to a container”

  • WAR/EAR files:指定要部署的war文件, 它通常位于Jenkins上当前作业目录下的 target目录中

  • Context path:Servlet服务器上的context 路径;

  • Containers:目标Servlet容器的配置

    • 先选定Container的类型,这里以Tomcat 为例

    • Credentials:认证凭据

    • Tomcat URL:Tomcat的入口URL

  • 其它部署方式

    • ssh命令

    • Ansible、SaltStack或其它编排工具

http://www.magedu.com

构建一个Maven项目(Maven Job)

  • Jenkins能通过“Maven Integration”插件创建专用于构建Maven项目的流水线 ◼ 可以使用“构建一个Maven项目”替换此前通过执行shell命令完成的Maven项目构建操作

    • 该插件提供了更高级的集成特性,并具有以下几个附加功能

      • 自动配置报告的插件(Junit,Findbugs,...)

      • 基于已发布的SNAPSHOT 进行跨作业自动触发

      • 增量构建- 仅构建更改的模块

      • 在多个执行器/节点上并行构建模块

      • ...

  • 提示

    • 因存在安全风险Jenkins官方已经不建议直接使用Maven作业

    • 应该使用自由风格的项目或者Pipeline作业

http://www.magedu.com

配置Maven使用因内的repo镜像

 Maven作业支持通过“ Config File Provider ”插件进行Maven环境配置

 配置文件位于Maven安装目录下的conf子目录中,名为settings.xml;

◼ 镜像服务定义在配置段中,右侧的示例定义了使用阿里云的镜像; ◼ 用户不具有Jenkins节点的主机文件系统访问权限时,可借用Config File Provider插件进行 ◆ Managing Jenkins → Managed Files(新增的菜单项)

  • nexus-aliyun

  • central

  • Nexus aliyun

http://maven.aliyun.com/nexus/content/groups/public

在Maven作业中可调用该设定,让Maven使用 Aliyun的镜像的Maven Repository;随后,在流水线作业中,可通过“构建环境”中的“Provide Configuration files”配置使用该文件

http://www.magedu.com

配置Maven作业

 配置Maven作业项目

◼ 指定pom.xml文件路径 ◼ 配置构建目标和选项

在Build步骤的高级选项中,支持用户自行指定要使用的Settings file和Global Settings file,下面的示例就选择使用了此前面自定义的MyGlobalSettings

◼ “高级”选项中,还可定义更多的配置

◼ Maven作业支持在“构建后操作”的步骤中通过 “Deploy artifacts to Maven repository”将jar/war文件发布到Maven仓库中;

http://www.magedu.com

配置Maven作业

 Demo

  • 使用Maven作业构建spring-boot-helloworld项目,并自动发布至Tomcat实例

克隆代码构建测试部署
Deploy to container插件
Git工具 Maven工具基于Ansible或SSH完成应用部署

http://www.magedu.com

环境变量和构建参数

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

环境变量基础

  • Jenkins支持在流水线中使用环境变量和参数 ,进而让流水线的定义和运行更具灵活性

  • 环境变量可分为Jenkins内置变量和用户自定义变量两类

    • Jenkins提供了多个内置的变量

    • Jenkins内置的全局环境变量可被所有的pipeline引用,它们以“env.”为前缀

    • 我们可将环境变量视作pipeline与Jenkins系统交互的媒介

    • 引用全局环境变量格式有三种:

      • ${env.<ENV_VAR_NAME>}、$env.<ENV_VAR_NAME>和${ENV_VAR_NAME}
  • 下面是Jenkins内置的几个常用的环境变量

    • BUILD_NUMBER:构建号,递增的整数值;打包时,经常用作制品名称的一部分

    • BRANCH_NAME:在多分支pipeline中,需要根据不同的分支施加不同的操作时较为常用

    • BUILD_URL:当前构建页面的URL,常用于邮件通知中

    • GIT_BRANCH:基于git拉取的源码进行构建时使用该变量

    • JENKINS_HOME:Jenkins的家目录

    • JENKINS_URL:Jenkins服务的URL

    • JOB_NAME:当前作业的名称

    • ……

http://www.magedu.com

获取可用的内置环境变量

 Jenkins在不同作业类型通常都提供了获取系统内置环境变量的方法,下面的来自于自由风格作业中 Build Steps中“运行shell脚本”中的链接;

http://www.magedu.com

自定义全局环境变量

 自定义环境变量的功能与内置环境变量相同

◼ 系统管理 → 全局属性 → 环境变量

自定义环境变量与全局环境变量同名时,全局环境变量将被覆盖;这可能会引起错误,必要时,可为自定义环境变量使用固定的前缀,例如“_ _”等;

http://www.magedu.com

参数化构建

  • 参数化构建的目标在于为流水线提供基于参数值的灵活构建机制,从而让一个流水线的定义可以适

  • 用于多种需求情形

  • 其功能与引用方式与环境变量类似

  • 在触发作业运行之时,需要向各参数赋值

  • 常用的参数类型

    • 凭据参数

    • 字符参数

    • 密码参数

    • 布尔值参数

    • 文件参数

    • 文本参数

    • 运行时参数

    • 选项参数

    • 由其它插件引入的参数类型

http://www.magedu.com

参数示例

 字符参数和布尔值参数

http://www.magedu.com

参数示例(2)

 选项参数和凭据参数

http://www.magedu.com

运行参数化构建作业

 参数化构建作业脚本和执行结果

参数的使用方式类似于环境变量, 只是其参数值需要在流水线启动时进行传递;

http://www.magedu.com

自由风格的CI流水线示例—参数化构建

为流水线指定要构建的代码分支,
此处使用的是字符参数;
一般说来,代码仓库的分支根据其分支模型,名称通常是固定的,例如main/master、develop、release
等,因此也可以使用选项参数;

http://www.magedu.com

自由风格的CI流水线示例—参数化构建(2)

  • 使用参数化构建的两个关键步骤:一是在流水线的定义中引用参数,二是在触发流水线运行时向参数传递期望使用的值

在流水线定义的在触发流水线执行时,向参数传递一个某处引用定义的期望的目标值,从而让流水线基于该参参数; 数值运行,达到参数化运行的目标;

http://www.magedu.com

其它常用的扩展参数类型的插件

 Jenkins上还有一些用于扩展参数类型的插件

  • Git Parameter

◆ 用于在构建中将git branch、tag、pull request或revision number用作参数

  • Extensible Choice Parameter

    • 可扩展的选择参数

    • 支持“文件选择参数”、“全局选择参数”和“Textarea 选择参数”等类型

  • Persistent Parameter

    • 支持字符串、文本、布尔和选择参数,其默认值取自先前的构建作业
  • Date Parameter

    • 将动态生成的日期作为参数
  • JDK Parameter

  • Dynamic Extended Choice Parameter

  • List Git Branches Parameter

http://www.magedu.com

Git Parameter

  • 更易于将代码仓库信息定义为参数的方式是基于“Git Parameter”插件定义“Git参数” ◼ 依赖于“Git Parameter”插件

如此,定义的Git Parameter的使用机制与其它机制类似,只是其可用值会自动从代码仓库获取,且仅可选择使用列表中的相关值;

http://www.magedu.com

Extensible Choice Parameter

 可扩展的选择参数之文件选择参数示例

  • Base Director:文件搜索起始路径

◼ File Name Pattern:文件名称模式

  • *:通配符

◆ **:多级路径通配符

◼ Exclude Pattern:用于排除文件的模式

  • Type:搜索的文件类型

根据右侧图中的定义,基于springboot-helloworld代码仓库所生成的文件选择列表如下;自动生成的列表中的第一个文件是为默认选项

http://www.magedu.com

构建和推送 Docker Image

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

在流水线中构建和推送Docker Image

  • 现如今,越来越多的组织以容器形式运行应用

    • 应用交付形式统一为Container Image

    • 交付的Container Image由Registry存储和分发

应用以容器化形式由Kubernetes编排运行
Jenkins的多款插件都能实现Image构建和推送
Registry
Pull Image
CloudBees Docker Build and Publish Plugin
Push
Image
Deploy
构建推送部署至克隆代码构建测试
Image Image K8S

  • 应用以容器化形式由Kubernetes编排运行

  • Jenkins的多款插件都能实现Image构建和推送

    • docker-build-step Plugin

    • Docker Plugin

    • CloudBees Docker Build and Publish Plugin

Pipeline

http://www.magedu.com

示例基础环境

 Maven工程项目

  • Spring-Boot-HelloWorld

  • ◼ 基于Jenkins自由风格项目流水线 ◼ 脚本化运行构建和测试步骤

http://www.magedu.com

使用docker-build-step插件构建和推送Docker Image

 由脚本和docker-build-step插件实现

  • Pipeline

    • 构建Image的步骤可以由shell命令直接完成,也可以使用docker-build-step插件完成

    • 推送Image通常应该使用docker-build-step 插件完成

  • 配置docker-build-step插件

    - 安装完成插件后,需要为其配置docker daemon的URL
    
    - 系统管理 → 全局配置
    

构建推送克隆代码构建测试
Image Image

http://www.magedu.com

使用docker-build-step插件构建和推送Docker Image(2)

 利用docker-build-step插件构建Image

  • 在构建步骤中选择“Execute Docker command”

  • 选择Docker command类型为“Create/build image”

此处指定Build Context,通常是指
Dockerfile文件所在的目录,该文件通常位于代码仓库中;
目标Image的完整格式的标签:
server:port/namespace/repository:tag;
此处引用的变量PROJECT_NAME是自定义的字符参数;
构建推送克隆代码构建测试
Image Image

http://www.magedu.com

使用docker-build-step插件构建和推送Docker Image(3)

 利用docker-build-step插件推送镜像构建推送克隆代码构建测试
◼ 需要事先将访问Registry的认证凭据保 Image Image
存为Jenkins Credential
Docker command类型为“Push image”
Image Name和Image Tag要同前面构建步骤中生成的Image保持一致
Registry Server的地址,需要事先确保
Jenkins主机上的docker客户端可正常与该Registry Server进行通信访问Registry时使用的Credential

http://www.magedu.com

使用Docker插件构建和推送Docker Image

 配置过程

  • 安装Docker Plugin

◼ 添加至少一台Docker主机

  • 以Jenkins所在的主机为例,安装部署 Docker Engine

◼ 配置Jenkins Docker插件以UnixSock的方式访问Docker Daemon

◆ 系统管理 → 节点管理 → Configure

Clouds → Docker

http://www.magedu.com

使用Docker插件构建和推送Docker Image(2)

 在作业上添加构建步骤“Build / Publish Docker Image”

下图是为该流水线一次构建操作的状态集

选择执行Image构建推送的Docker Host

若要进行推送Image标识要遵循可推送的标准格式进行定义

勾选“Push image”,并指定可访问目标Registry 的Credential

http://www.magedu.com

部署容器化应用

 Docker插件支持于流水线构建步骤管理容器

  • 配置方式如右侧上图所示

    • 在构建步骤中选择“Start/Stop Docker Containers”

    • 运行容器的目标主机需要由Docker Cloud事先定义

    • 需要事先定义好容器运行模板

  • 该插件也支持在“构建后操作”中关闭指定的容器

  • Docker-build-step插件也能够在流水线构建步骤中管理容器

    • 配置方式如右侧下图所示

      • 在构建步骤中选择“Execute Docker Command”

      • 简单指定要使用的镜像即可运行容器

    • 该插件能够在构建步骤中支持多种容器管理操作

  • 将容器运行于Kubernetes集群

    • 需要事先定义好资源配置文件

    • Push Pipeline的方式

      • 基于shell运行本地的kubectl

      • 基于ssh或ansible于远程主机运行kubectl

    • Pull Pipeline的方式

      • 使用ArgoCD或者Flux以GitOps的方式完成CD

http://www.magedu.com

案例:使用kubectl命令自动部署应用

 通过Credential,将访问Kubernetes的token带入Shell脚本中 ◼ 首先,准备好ServiceAccount,并将其Token创建为凭据

在目标Kubernetes集群上,生成要使用的ServiceAccount ~# kubectl create namespace hello ~# kubectl create serviceaccount hello-admin -n hello ~# kubectl create rolebinding hello-admin --clusterrole=cluster-admin \ --serviceaccount=hello:hello-admin -n hello

apiVersion: v1 kind: Pod metadata: name: test namespace: hello spec: containers: - image: ikubernetes/admin-box:v1.2 name: sleep command: ["/bin/sh","-c","sleep 99999"] serviceAccountName: hello-admin

测试用的Pod启动完成后,运行如下命令获取Token即可; ~# TOKEN=$(kubectl exec -it test -n hello -- \ cat /var/run/secrets/kubernetes.io/serviceaccount/token) ~# echo $TOKEN

http://www.magedu.com

案例:使用kubectl命令自动部署应用(2)

  • 通过Credential,将访问Kubernetes的token带入Shell脚本中

    • 而后,在流水线的“构建环境”中的“Use secret text(s) or file(s)”通过变量引用前面创建的凭据

      • 提示:也可以将Credential定义为流水线的参数,并在构建环境中通过将参数赋值给变量进行间接引用

依赖于Credentials Binding插件,“社区推荐的插件”默认即会安装

引用定义的同类型凭据,从列表中选取

http://www.magedu.com

案例:使用kubectl命令自动部署应用(3)

  • 为此前完成Docker Image构建的流水线添加构建步骤

    • 首先更新资源部署文件

◼ 而后完成资源部署

基于参数化构建的方式提供kubernetes API Server的地址等配置;

http://www.magedu.com

流水线的触发机制

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

触发任务

  • 自动化的流水线作业会按照一定的规则自动启动并运行,这类的规则便是所谓的触发条件;

  • 部署“社区推荐的插件”后,默认Jenkins即为支持如下触发器

    • 定时构建

    • 轮询SCM

    • GitHub hook trigger for GITScm polling

    • 在其它工程构建后触发

    • 触发远程构建(例如,使用脚本)

      • 在远程主机上,通过URL来触发当前作业;

  • 可用插件中,“构建触发器”类别还提供了众多可用的触发机制

    • GitLab

    • Generic Webhook Trigger

    • GitHub Integration

    • Parameterized Trigger

      • 由当前作业通过一个build step来触发其它job,并可传递参数给目标job
    • URLTrigger

    • MultiBranch Action Trigger

    • ……

http://www.magedu.com

周期性构建

  • 这是一种cron类型的构建机制,它按照预定义的时间周期启动任务;

    • 对于期望能够基于代码变更进行触的CI场景来说,周期性构建并非其最佳选项,但对于有些类型的任务,它

    • 却也能够通过精心编排的周期性构建来避免资源冲突;

  • Jenkins cron语法遵循Unix cron语法的定义,但在细节上略有差别;

    • 一项cron的定义包含由空白字符或Tab分隔的5个字段,用于定义周期性的时间点;

  • Jenkins cron还可以使用以下特定字符,一次性指定多个值

      • specifies all valid values
    • M-N specifies a range of values

◆ M-N/X or */X steps by intervals of X through the specified range or whole valid range(以X为步长)

◆ A,B,…,Z enumerates multiple values(逗号分隔的枚举值)

  • 此外,H也可用于任何字段,它能够在一个时间范围内对项目名称进行散列值计算出一个唯一的偏移量,以

  • 避免所有配置相同cron值的项目在同一时间启动;

◆ 例如triggers { cron(H(0,30) * * * *) }

http://www.magedu.com

upstream:由上游作业触发

  • 若job-x依赖于job-y的执行结果,则称为job-y为job-x的upstream(上游);

  • Jenkins自2.22版本开始支持在triggers中定义upstream类型的触发条件;

    • 当前任务依赖到的upstream任务定义在upstreamProjects参数中,多个任务彼此间以逗号分隔;

    • ◼ 触发条件为upstream的执行状态

关注的上游项目
upstream的执行状态

http://www.magedu.com

GitLab通知触发

  • GitLab通知触发,是指流水线关联的GitLab Repository上的代码出现变更时,由GitLab将相关事件经由

  • Webhook通知给Jenkins,从而触发Jenkins执行指定Job的构建操作

    • 避免了pollSCM的频繁轮询依然存在滞后可能性的问题

    • 依赖于GibLab插件和Git插件

http://www.magedu.com

GitLab触发流水线的自动化CICD流水线简要工作逻辑

  • 基于Feature、Develop和Master分支构建内

  • 部研发工作逻辑是较为常见的工作流模型

    • Developer通过具体的feature分支开发新的功

    • 能,并向feature提交代码;

    • 每当开发人员从feature分支提PR至develop

    • 分支时,Jenkins pipeline都应触发以运行单元测试和静态代码分析;

    • feature分支中的代码测试成功后,开发人员

    • 将PR合并到develop分支;

    • 在将要发布代码时,开发人员将PR从

    • develop分支提到master,此时将触发Jenkins 上的pipeline运行单元测试、代码分析等, 并将代码部署到dev/QA环境;

http://www.magedu.com

代码仓库各分支上的流水线

  • 右图示例中的仓库共有master、develop和feature

  • 三个分支

    • 三个分支分别有其不同的pipeline

      • master分支有完整的CI/CD pipeline

      • develop分支仅有CI pipeline

      • feature分支仅有单元测试的功能

  • Jenkins Server会自动从仓库中发现所有分支,并

  • 提取每个分支,而后根据Jenkinsfile运行pipeline;

  • 之后,每当git仓库上的任何分支发生新的代码变更时,Jenkins Server将自动触发相应的pipeline

http://www.magedu.com

整合GitLab和Jenkins

  • 配置要点

    • 前提:GitLab和Jenkins同在本地网络时,需要以管理员权限设置“外发请求”,启用“允许Webhook和服务

    • 对本地网络的请求”

      • 授予Jenkins访问GitLab上仓库中特定用户的代码权限

      • (可选)Jenkins可基于SSH协议访问GitLab API,从而将构建状态推送至GitLab

    • GitLab API访问授权

      • (可选)配置GitLab API访问认证(Access Token)及操作权限

      • 配置Jenkins启用/project端点认证

      • (可选)配置Jenkins能通过配置的Access Token接入GitLab API

    • Jenkins pipeline项目的通知授权

      • 创建流水线任务,选择使用的“GitLab Connection”,并选定使用“Build when a change is pushed to GitLab.”触发器

      • 而后为构建触发器生成Secret token

      • 配置GitLab Repository能通过Webhook,基于该Secret Token触发构建

  • 具体配置过程相关文档

    • https://docs.gitlab.com/ce/integration/jenkins.html

http://www.magedu.com

配置GitLab允许外发

  • 以GitLab管理员的身份,设置系统在外发请求中,允许Webhook和服务对本地网络的请求;

http://www.magedu.com

配置Jenkins项目可经由GitLab上的事件触发

  • 在流水线的“构建触发器”中,选

中“Build when a change is pushed to GitLab”,并按需勾选支持接收的触发事件类型

  • Push Events

  • Accepted Merge Request Events

触发该作业的Webhook端点

http://www.magedu.com

配置Jenkins项目可经由GitLab上的事件触发(2)

  • 接下来,点击如前页图中的“高级”按钮,配

  • 置允许触发的分支和Token等信息

    • Set build description to build cause

      • 在构建中标识作业被触发的原因,例如Push事件或者MR事件等
    • Allowed branches

      • Allow all branches to trigger this job

      • Filter branches by name

      • Filter branches by regex

      • Filter merge request by label

    • Secret token

      • 生成可访问该Webhook的Secret

      • 该Token将被GitLab用作触发时的认证信息

http://www.magedu.com

在GitLab的代码仓库上配置Webhook

Jenkins上对应流水线上的GitLab
触发器的Webhook端点
Jenkins上对应流水线上的GitLab
触发器的Secret Token
推送给Jenkins流水线的事件类型,常见的CICD事件主要包括推送事件、标签推送事件和合并请求事件等,具体要根据实际的需求进行选择

http://www.magedu.com

测试Push事件的自动触发

  • Webhook定义完成后,可手动测试触发机制;选择支持的某类触发事件中的一种,即可触发一次

  • Pipeline的构建操作;触发方式如下面的左图所示;

  • 整个触发及构建链路连通后,即可于Jenkins上的相关项目的详情中看到,被GitLab触发的构建都会标

  • 记为“Started by GitLab by Administrator”,如下面的右图所示;

http://www.magedu.com

测试PR事件的自动触发

  • 测试流程

    • 克隆代码仓库至本地

    • 从develop分支创建一个新的feature分支

    • 在feature分支上进行代码修改

    • 推送feature分支

    • 在GitLab代码仓库的页面上,创建分支合并请求

    • 在GitLab代码仓库的页面上,确认分支合并

    • 检查是否自动触发流水线的执行

  • 提示

  • 必要时,可以在流水线上定义条件式Build Step,以确保部署操作能与相应的环境匹配

  • ◼ 条件式构建需要用到“Conditional BuildStep” 插件

http://www.magedu.com

推送构建状态信息至GitLab

  • Jenkins也能将流水线上的构建状态结果通过Webhook推送至GitLab进行显示,这需要配置GitLab Connection

  • 配置步骤简要说明

    • 在GitLab上,以仓库所关联的用户生成Access Token,并选择可访问的API

    • 在Jenkins上,将GitLab生成的Access Token保存为Credential

    • 在Jenkins的全局配置中,添加GitLab Connection的定义

    • 在FreeStyle类型的流水线上,选择要使用的GitLab Connection

    • 在FreeStyle类型的流水线上,添加“构建后操作”

http://www.magedu.com

在GitLab上创建生成用户的Access Token

 以root用户为例

提示:必须保存好生成的 Access Token,离开该页面后,将无法再次拿到该 Token信息;

http://www.magedu.com

将Access Token保存为Jenkins的Credential

 将Access Token保存为Jenkins的Credential,类型为“GitLab API token”

http://www.magedu.com

在Jenkins上创建GitLab Connection

 系统配置 → 全局属性 → GitLab

提示:添加完成后,可以“Test Connection”来检查连接状态

http://www.magedu.com

在Jenkins上配置FreeStyle流水线作业

 选择要使用的GitLab Connection,并添加“构建后操作”

用于向GitLab的MR操作发送信息;
支持要发送的自定义信息按需添加要使用的构建后操作

http://www.magedu.com

生成MR事件,测试发送结果

  • 在spring-boot-helloworld项目上生成MR事件,触发流水线,并在GitLab上查看相关的动态

http://www.magedu.com

Generic Webhook Trigger基础应用

 Generic Webhook Trigger插件

  • 简称为GWT

  • 提供的是一种通用的触发机制,它允许直接经由该插件暴露的API

(<JENKINS_URL>/generic-webhooktrigger/invoke)接收JSON或XML格式的HTTP POST请求进行触发

  • 触发的Jenkins项目则由配置的规则和POST请求进行定义

◆ 支持从POST请求的JSONPath和Xpath中提取数据

  • 支持从query parameters中提取数据

◆ 支持从headers中提取数据

  • 依赖关系

    • 需要安装Generic Webhook Trigger插件;

    • 支持白名单

  • 系统管理 → 系统配置 → Generic Webhook Trigger

http://www.magedu.com

示例:在FreeStyle类型的作业上使用GWT

 启用Generic Webhook Trigger,指定触发条件,例如,通过加载请求报文中的某个变量值进行触发

在POST请求报文中,获取JSON格式的请求体中的ref键的值,并赋值给变量ref

自定义的Token信息,可以使用 “openssl rand -base64 32”命令生成,token信息不能太短

出于调试的目的,可在Job的日志中记录触发该任务的POST请求的内容,以及贡献(即前面自定义)的变量及其值;

http://www.magedu.com

示例:在FreeStyle类型的作业上使用GWT(2)

 配置好Job的Build Steps之后,即可进行远程触发测试

◼ 可由GitLab等一类的SCM上的Repo事件进行触发,也可手动进行触发

~# curl -X POST -H "Content-Type: application/json" -d '{ "ref": "refs/heads/main" }' -vs http://jenkins.magedu.com:8080/generic-webhooktrigger/invoke?token="wfHVjXAZ7f7MLucV6Bjg4NGQDMSi29JHVCt0Nw8eX2E" * Trying 172.29.7.1:8080... * TCP_NODELAY set * Connected to jenkins.magedu.com (172.29.7.1) port 8080 (#0) > POST /generic-webhooktrigger/invoke?token=wfHVjXAZ7f7MLucV6Bjg4NGQDMSi29JHVCt0Nw8eX2Em HTTP/1.1 > Host: jenkins.magedu.com:8080 > User-Agent: curl/7.68.0 > Accept: / > Content-Type: application/json > Content-Length: 28 > * upload completely sent off: 28 out of 28 bytes * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Mon, 07 Nov 2022 11:25:51 GMT < X-Content-Type-Options: nosniff < Content-Type: application/json;charset=utf-8 < Content-Length: 209 < Server: Jetty(10.0.12) < * Connection #0 to host jenkins.magedu.com left intact {"jobs":{"spring-boothelloworld":{"regexpFilterExpression":"","triggered":true,"resolvedVariables":{"ref":"refs/heads/main"},

Job日志中打印了接收到的POST请求的内容,以及贡献的变量及其值;

http://www.magedu.com

通知与报告

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

通知与报告概述

  • Jenkins通知:将任务的执行状态、事件或信息推送给相关用户,这些通常发生在pipeline的“构建后处

  • 理(post-processing)”时期;

    • Email是Jenkins内置支持的通知方式,它也能够通过webhook扩展支持其它的即时通信媒介,例如Slack、钉钉

    • 等;

    • Jenkins支持的通知插件,可以搜索“ Build Notification ”关键字在插件列表中获取

  • Jenkins使用的许多插件或工具都会为其支持的多种任务生成HTML报告,相关的任务有如代码分析、

  • 代码覆盖率和单元测试等;

    • 其中一些工具(如SonarQube和JaCoCo等)甚至可以和Jenkins任务输出做定制集成,这些工具甚至会采用直

    • 观的图标给出相关报告的链接;

    • 对于那些在报告相关的功能方面支持的不是特别好的工具来说,我们也可以借助于HTML Publisher插件进行

    • 定制;

http://www.magedu.com

配置Jenkins的邮件通知(Mailer插件提供)功能

 Jenkins管理员的邮箱地址在“Jenkins Location”系统配置段中的定义

◼ 该邮箱地址将为作为发给项目owner的通知邮件的发件人地址(From)

使用SSL协议时,相关的端口一般默认为465
◼ 邮件通知启用SMTP认证时,此二者要保持一致

http://www.magedu.com

测试Email 通知功能

  • 在流水线上添加“构建后操作”

    • 在“构建后操作”里选择“E-mail Notification”即可在流水线上启用Email通知功能

为了有意进行失败的构建从而触空白字符分隔指定邮发通知以便进行测试,这里在件接收人列表 shell脚本中使用了exit命令用于将邮件单独发给提交代码而导致了构建失败的责任人

http://www.magedu.com

测试构建通知功能(2)

 接收邮件,验证构建通知功能

通过链接可跳转至Job的构建状态页面;
分隔线下面的内容是附加的构建日志;

http://www.magedu.com

扩展的Email 通知机制

  • 扩展的Email通知功能简介

    • 另一种高级的Email通知机制,由另一种通知插件“Extension Email”提供

    • 提供了更多的高级选项和控制级别,包含有类似Mailer插件的基础配置,并增加了其它几个功能区,配置选项较多

Extension Email与Mailer
功能各自独立,需要分别进行配置邮件接收人所属的“域名”白名单通过”User and Password”类型的Credential,配置邮件账户及其认证密码

http://www.magedu.com

扩展的Email 通知机制(2)

 配置默认的邮件内容及通知触发机制

指定用进行邮件内容在发送前进行预处理的脚本完成邮件发送之后,基于发送结果运行的脚本

http://www.magedu.com

测试Extended Email 通知功能

 在流水线上添加“构建后操作”

  • 在“构建后操作”里选择“Editable Email Notification”即可在流水线上启用Extended Email通知功能

内容类型,默认从全局配置继承邮件标题和内容都可以按需编辑,也可以从全局默认配置继承指定邮件接收人,缺省值为全局配置的“默认接收人”,
各接收人之前可使用“CC:”或
“BCC:”前缀指定回复邮件的接收人,默认为全局配置的“Reply-TO”

http://www.magedu.com

测试Extended Email 通知功能(2)

 指定触发机制,并测试接收邮件通知

从全局配置继承的默认触发机制,相应的邮件发给Developer组内的用户注意:请确保该组内的用户存在,否则,可能无法正常接收邮件新增的自定义触发机制,
触发条件为Always,并将邮件发送给接收人列表中的用户

http://www.magedu.com

DingTalk 通知

  • 使用钉钉机器人发送构建通知

    • ① 在接收构建通知的钉钉群上,创建机器人

    • ② 在Jenkins上部署“DingTalk”插件

    • ③ 在Jenkins上的“系统管理”中,配置“钉钉”

    • ④ 在Jenkins流水线上,配置使用DingTalk进行构建通知

  • 配置钉钉群机器人的方法

    • “群设置” → “智能群助手” → “添加机器人” → “自定义”

Webhook即为接收消息推送的URL端点

为机器人选择合适的安全设置, 加签的方式类似于为接口设置了调用密钥,该密钥需要在客户端配置以完成认证

http://www.magedu.com

配置Jenkins的DingTalk插件

  • 在Jenkins上安装DingTalk插件;

 而后配置钉钉插件

◼ Manage Jenkins → Configure System → 钉钉

http://www.magedu.com

配置Jenkins的DingTalk插件(2)

 在Jenkins上配置钉钉
◼ 添加机器人
◼ 指定Webhook和密钥
Webhook为钉钉群机器人上自动生成的Webhook的访问地址加密密钥,需要填入钉钉群机器人上的“加签”信息

http://www.magedu.com

配置freestyle 作业使用钉钉机器人通知

 FreeStyle作业中配置钉钉机器人通知的方法

◼ General → 钉钉机器人

可以指定要在群里@的用户列表,
也可勾选“atAll”通知给群里的所有人

可在此处自定义要通知的内容,需要使用Markdown格式

http://www.magedu.com

企业WeChat 通知

 使用企业微信群机器人发送构建通知

① 在接收构建通知的企业微信群上,创建机器人

② 在Jenkins上部署“Qy Wechat Notification”插件

③ 在Jenkins流水线上,在“构建后操作中”配置使用企业微信进行通知

 配置企业微信群上的机器人,并获取其Webhook

http://www.magedu.com

配置freestyle 作业使用企业微信群机器人通知

 在freestyle作业上,通过“构建后操作”选择“企业微信通知”

企业微信群机器人的Webhook端点地址

http://www.magedu.com

SonarQube和代码质量分析

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

SonarQube简介

  • SonarQube是一款开源的代码质量管理系统,支持代码自动审查,用于检测代码中的错误、漏洞和代

  • 码异味,它集成到现有的工作流程,以便在项目分支和拉取(PR)请求之间进行连续的代码检查;

  • 特征(摘自WikiPedia)

    • 支持超过25种编程语言[2]:Java、C/C++、C#、PHP、Flex、Groovy、JavaScript、Python、PL/SQL、COBOL 等,但有些是商业软件插件

    • 提供重复代码、编码标准、单元测试、代码覆盖率、代码复杂度、潜在Bug、注释和软件设计报告

    • ◼ 提供了指标历史记录、计划图(“时间机器”)和微分查看

    • 提供了完全自动化的分析:与Maven、Ant、Gradle和持续集成工具(Atlassian Bamboo(英语:Bamboo (software))、Jenkins、Hudson等)

    • 支持与Eclipse开发环境集成,以及与JIRA、Mantis、LDAP、Fortify等外部工具集成

    • 支持扩展插件

    • 利用SQALE计算技术债务

      • 指开发人员为了加速软件开发,在应该采用最佳方案时进行了妥协,改用了短期内能加速软件开发的方案,从而在未来给自己带来的额外开发负担

      • 这种技术上的选择,就像一笔债务一样,虽然眼前看起来可以得到好处,但必须在未来偿还

      • 软件工程师必须付出额外的时间和精力持续修复之前的妥协所造成的问题及副作用,或是进行重构,把架构改善为最佳实作方式

http://www.magedu.com

SonarQube简介

  • SonarQube有四个关键组件

    • SonarQube Server运行有三个组件

      • Web Server:UI

      • Search Server:为UI提供搜索功能,基于ElasticSearch

      • Compute Engine Server:处理代码分析报告并将之存储到SonarQube Database中

    • SonarQube Database:负责存储SonarQube的配置,以及项目的质量快照等

    • SonarQube Plugin

    • Code analysis Scanners:代码扫描器,扫描后将报告提交给SonarQube Server

http://www.magedu.com

SonarQube生态集成

http://www.magedu.com

SonarQube生态集成

  • ① Developers code in their IDEs and use SonarLint to run local analysis.

  • ② Developers push their code into their favourite SCM : git, SVN, TFVC, ...

  • ③ The Continuous Integration Server triggers an automatic build, and the execution of the SonarScanner required to run the SonarQube analysis.

  • ④ The analysis report is sent to the SonarQube Server for processing.

  • ⑤ SonarQube Server processes and stores the analysis report results in the SonarQube Database , and displays the results in the UI.

  • ⑥ Developers review, comment, challenge their Issues to manage and reduce their Technical Debt through the SonarQube UI.

  • ⑦ Managers receive Reports from the analysis. Ops use APIs to automate configuration and extract data from SonarQube. Ops use JMX to monitor SonarQube Server.

http://www.magedu.com

部署的先决条件(以9.7为例)

  • 最小硬件需求

    • 小规模应用场景中,至少需要2GB的RAM,且额外要有至少1G的空闲内存

    • 磁盘空间取决于SonarQube分析的代码量

    • 必须部署在读写性能较好的磁盘上

      • 存储数据的目录中包含了ElasticSearch的索引,服务器启动并运行时,将会在该索引上进行大量I/O操作
  • 生产环境硬件需求

    • 8核心的CPU:更好地支持并行运行多个Compute Engine工作线程

    • 16GB的内存:更高效地完成数据存储和索引处理

  • Java版本需求

SonarQube Server和Scanner 对Java的版本依赖有所不同

http://www.magedu.com

部署的先决条件(2)

 SonarQube支持Microsoft SQL Server、Oracle和PosgreSQL三种数据库 ◼ 目前,支持PostgreSQL 9.6、10、11、12和13几个版本 ◼ 要求必须配置使用UTF-8字符集

 部署于Linux平台的特殊需求

◼ vm.max_map_count 内核参数值要大于等于524288

◼ fs.file-max 内核参数值要大于等于131072

◼ SonarQube进行的用户身份至少要能打开131072 个文件描述符,以及至少8192个线程

配置的持久生效:

• 前两个参数需要通过/etc/sysctl.conf配置文件完成

  • 后两个参数的需要通过/etc/security/limits.conf配置文件进行

http://www.magedu.com

部署步骤1:安装Postgresql 12

  • 安装PostgreSQL

◼ CentOS 7,以postgresql 12为例;

  • 设置yum仓库

⚫ ~]# rpm -i https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repolatest.noarch.rpm

  • 安装postgresql12-server、postgresql12和postgresql12-libs

⚫ ~]# yum install postgresql12-server postgresql12 postgresql12-libs

  • 初始化

⚫ ~]# postgresql-12-setup initdb

  • 配置文件在/var/lib/pgsql/12/data/目录下;

  • Ubuntu Server 20.04直接从程序包仓库中安装即可,默认为postgresql 12

    • ~# apt install postgresql

    • 配置文件在/etc/postgresql/12/main/目录下

http://www.magedu.com

部署步骤2:配置Postgresql 12

 修改监听的IP和端口

◼ 主配置文件postgresql.conf

默认监听于localhost主机地址之上,“”代表本机监听的所有地址; listen_addresses = '’ port = 5432

 修改远程连接规则

◼ 配置文件pg_hba.conf,将连接规则修改为类似如下内容

Database administrative login by Unix domain socket local all postgres peer # TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all peer # IPv4 local connections: host all all 127.0.0.1/32 md5 host all all 0.0.0.0/0 md5 # IPv6 local connections: host all all ::1/128 md5 # Allow replication connections from localhost, by a user with the replication privilege. local replication all peer host replication all 127.0.0.1/32 md5 host replication all ::1/128 md5

  • 启动postgresql服务

◼ CentOS 7: systemctl start postgresql-12

◼ Ubuntu 20.04: systemctl restart postgresql

http://www.magedu.com

部署步骤3:为SonarQube初始化数据库

 SonarQube依赖于特定的数据库,该数据库应该有特定用户相关的授权

安全起见,我们限制仅能够通过postgres系统用户来基于本地Socket地址来登录postgresql的管理账户postgres,因而这里需要先切换系统用户,而后登录 [root@master01 ~]# su - postgres -bash-4.2$ psql -U postgres psql (12.12 (Ubuntu 12.12-0ubuntu0.20.04.1)) Type "help" for help. # 创建数据库角色sonarqube postgres=# CREATE USER sonarqube WITH ENCRYPTED PASSWORD 'magedu.com'; CREATE ROLE # 创建数据库sonarqube,并设定其隶属于sonarqube角色; postgres=# CREATE DATABASE sonarqube OWNER sonarqube; CREATE DATABASE # 授权sonarqube用户在sonarqube数据库上拥有全部权限 postgres=# GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube; GRANT # 若有必要,可以为管理员postgres用户设置必要的密码 postgres=# ALTER USER postgres WITH ENCRYPTED PASSWORD 'www.magedu.com'; ALTER ROLE postgres=# \q -bash-4.2$ exit logout

http://www.magedu.com

部署步骤4:测试Postgresql数据库的连通性

 使用sonarqube用户进行连接测试

测试从localhost和127.0.0.1发起连接请求; [root@master01 ~]# psql -U sonarqube -h localhost Password for user sonarqube: # 此处需要输入该用户的密码 psql (12.12 (Ubuntu 12.12-0ubuntu0.20.04.1)) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) Type "help" for help. sonarqube=> sonarqube=> \q [root@master01 ~]# psql -U sonarqube -h 127.0.0.1 Password for user sonarqube: psql (12.12 (Ubuntu 12.12-0ubuntu0.20.04.1)) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) Type "help" for help. sonarqube=> \q # 测试远程发起连接请求 [root@master01 ~]# psql -U sonarqube -h 172.29.1.12 Password for user sonarqube: psql (12.12 (Ubuntu 12.12-0ubuntu0.20.04.1)) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) Type "help" for help. sonarqube=> \q

http://www.magedu.com

部署步骤5:安装SonarQube

  • 安装11或以上版本的JDK

    • CentOS 7: java-11-openjdk

    • Ubuntu 20.04: openjdk-11-jdk

  • 下载合适的SonarQube版本并解压到指定的目录下,这里以9.7.1版本为例;

    • ~]# curl -LO https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-9.7.1.62043.zip

    • ~]# unzip sonarqube-9.7.1.62043.zip -d /usr/local/

    • ~]# ln -sv /usr/local/sonarqube-9.7.1.62043 /usr/local/sonarqube

  • 创建用于运行SonarQube的普通用户,并将安装目录下的文件授权该用户访问

    • ~]# useradd -m sonarqube

    • ~]# chown -R sonarqube.sonarqube /usr/local/sonarqube/*

http://www.magedu.com

部署步骤6:配置SonarQube

 配置SonarQube,编辑conf/sonar.properties配置文件,修改关键参数

修改连接数据库的账号和密码 sonar.jdbc.username=sonarqube sonar.jdbc.password=magedu.com

修改数据库相关的URL,这里以此前配置的postgresql为例,其中的localhost为DB服务器的地址,而sonarqube为数据库名称; sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube

设定Web Server监听的地址和端口 sonar.web.host=0.0.0.0 sonar.web.port=9000

如有必要,可修改SonarQube持久存储数据的位置,以下两个相对路径,均起始于sonarqube的安装目录,我们也可以使用绝对路径; sonar.path.data=data sonar.path.temp=temp

 若有必要,可编辑conf/wrapper.conf配置文件,指定java的路径

◼ wrapper.java.command=java

 以普通用户的身份,启动SonarQube

◼ ~]# su - sonarqube -c "/usr/local/sonarqube/bin/linux-x86-64/sonar.sh start"

http://www.magedu.com

部署步骤7:访问SonarQube的Web UI

  • 访问SonarQube的Web UI

    • 根据此前的设定,SonarQube的Web Server监听于本机所有地址的9000端口上,通过浏览器直接访问该服务即

    • 可,默认的用户名和密码是“admin/admin”;

    • 可安装中文语言插件,以支持中文显示,部署完成后,要重启SonarQube生效;

http://www.magedu.com

部署步骤8(可选):手动启用sonar-scanner

  • Sonar Scanner是独立的组件,需要单独部署,并配置其能够关联到SonarQube之上

    • 下载地址:https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
  • 下载合适版本的sonar-scanner-cli程序,直接展开后简单配置即可使用;

    • 安装

      • ~]# curl -LO https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.7.0.2747-linux.zip

      • ◆ ~]# unzip sonar-scanner-cli-4.7.0.2747-linux.zip -d /usr/local/

◆ ~]# ln -sv /usr/local/sonar-scanner-cli-4.7.0.2747-linux /usr/local/sonar-scanner

  • 分析参数配置

  • 全局属性:适用于所有的Project,在SonarQube Server上进行配置

    • Administration > Configuration > General Settings
  • 项目属性:仅应用于单个项目

    • Project Settings > General Settings
  • 项目的分析参数:定义在项目里的项目分析配置文件中或者扫描器的配置文件中

  • 分析参数/命令行参数:在分析命令上,通过“-D”进行指定

http://www.magedu.com

部署步骤9(可选):定义分析参数

 配置sonar-scanner的全局属性定义(conf/sonar-scanner.properties文件)

  • 服务器地址

◆ sonar.host.url=http://localhost:9000 # 指定SonarQube Server的地址

  • 认证参数

◆ sonar.login= # 认证到SonarQube的用户名

◆ sonar.password= # 指定用户名认证的密码

◼ 分析日志,必要时可启用DEBUG

◆ sonar.log.level=INFO

  • sonar.verbose=false

  • 项目相关的配置参数有很多,而且可以定义在项目源码目录中sonar-project.properties配置文件中

    • sonar.projectName= # Maven项目的名称,也可以使用sonar.projectKey进行定义

◆ sonar.projectVersion= # Maven项目的版本,其它的可以使用“not provided”,不要使用Build ID

◆ sonar.sources=</PATH/TO/SOURCE_DIR> # 项目的源码目录,当前目录使用“.”

完整的参数定义请参考官方文档

https://docs.sonarqube.org/latest/analysis/analysis-parameters/

http://www.magedu.com

部署步骤10(可选):手动启动代码扫描

  • 随后,即可针对特定的项目启动代码扫描

    • 在需要代码扫描的项目根目录下,为sonar-scanner建立必要的配置文件sonar-project.properties,需要提供的参

    • 数类似如下所示

项目的惟一标识 sonar.projectKey= spring-boot-helleworld # 项目的名称,用于显示在sonar web中 sonar.projectName=spring-boot-helleworld # 项目的版本 sonar.projectVersion=1.0 # 需要分析的源码所在的目录 sonar.sources=. # targe的位置 sonar.java.binaries=. # 指定项目中使用的编程语言 sonar.language=java #编码格式 sonar.sourceEncoding=UTF-8

  • 而后,在项目根目录下,运行sonar-scanner程序即可 ◆ ~]# /usr/local/sonar-scanner/bin/sonar-scanner

    • 命令运行完成后,即可到SonarQube Web UI上查看扫描结果;

http://www.magedu.com

部署步骤11(可选):查看扫描结果

  • 扫描结果在SonarQube Web UI的“项目”标签下

  • 项目下的二级页面有更详细的信息输出

http://www.magedu.com

SonarQube质量阈简介

  • 在SonarQube中,质量阈是一组预定义的评估条件;代码质量扫描结果可满足这组条件时,项目才会

  • 被标记为“passed”;

    • 管理员也可以在SonarQube上按需自定义并调用质量阈;

http://www.magedu.com

Jenkins和SonarQube

  • Jenkins借助于SonarQube Scanner插件将SonarQube提供的代码质

  • 量检查能力集成到pipeline上,从而确保质量阈检查失败时,能够避免继续进行后续的操作,例如发布等;

    • Jenkins pipeline启动;

    • SonarQube Scanner分析代码,并将报告发送至SonarQube Server;

    • SonarQube Server分析代码检测的结果是否符合预定义的质量阈;

    • SonarQube Server将通过(passed)或者失败(failed)的结果发送

    • 回Jenkins上的SonarQube Scanner插件暴露的Webhook;

    • 质量域相关的阶段成功通过或可选地失败时,则Jenkins pipeline

    • 续费后面的Stage;否则,pipeline将终止;

  • 然而,Jenkins的SonarQube Scanner插件将代码分析报告提交给

  • SonarQube Server时,它不会同步响应质量阈的检测结果,为此, 我们必须在SonarQube Server上配置一个webhook以回调Jenkins;

http://www.magedu.com

配置Jenkins接入SonarQube进行代码质量评估

  • 配置Jenkins使用sonar-scanner进行代码质量扫描,并

  • 将结果报告给SonarQube Server的主要步骤如下

    • 首先,在Jenkins上安装 SonarQube Scanner 插件

    • 其次,配置Jenkins对接到SonarQube Server

    • 第三,配置Jenkins的全局工具sonar-scanner

    • 第四,在SonarQube上添加回调Jenkins的Webhook

    • 第五,在Jenkins项目上调用sonar-scanner进行代码质

    • 量扫描

    • 最后,通过SonarQube确认扫描结果的评估;

http://www.magedu.com

认证到SonarQube Server

  • SonarQube Server拒绝匿名访问时,需要配置Jenkins上的Sonar-Scanner工具可自动完成认证 ◼ 在SonarQube上创建用户账号(不建议使用admin账号)

    - 配置 → 权限 → 用户
    
    • 为用户账号赋予相应的权限,例如执行分析和置备项目

      • 配置 → 权限 → 全局权限

设定用户权限

  • 以新建用户的身份生成令牌,该令牌将被Jenkins用于通过相应的URL打开SonarQube

为用户生成认证用的token

Token在创建完成并离开创建页面后无法再次获取

http://www.magedu.com

将SonarQube令牌存储为Jenkins凭证

 在Jenkins上保存SonarQube上Jenkins用户的令牌为凭证,凭证类型为Secret text;

 Manage Jenkins → Manage Credentials

http://www.magedu.com

在Jenkins上添加SonarQube Server

 在Jenkins的配置中,添加SonarQube Server,并选择打开该Server时使用的令牌凭证

  • Manage Jenkins → Configure System → SonarQube Servers

该URL需要明确指定使用协议、 主机地址和端口号;

http://www.magedu.com

为Jenkins添加sonar-scanner工具

 为Jenkins添加全局工具sonar-scanner,以便在构建任务中调用

  • Manage Jenkins → 全局工具配置

也可以选择“解压*.zip/*.tar.gz” 方式,直接给出sonar-scanner 程序包的URL进行自动化安装;

http://www.magedu.com

在SonarQube添加Jenkins的回调接口

  • 在SonarQube上添加webhook(网络调用),以便于Jenkins通过SonarQube Quality Gate插件调用其“质

  • 量阈”信息;

/sonarqube-webhook是由Jenkins的 SonarQube Scanner插件的回调接口固定使用的PATH; 密码可自行生成通信时的签名密钥,以防止中间人攻击;

http://www.magedu.com

在freestyle作业上使用SonarQube进行代码质量检查

 在Maven工程相关的Job上添加构建后操作

◼ “SonarQube analysis with Maven”

这种方式能直接为流水线添加基于sonar的代码分析功能,类似如下命令 $ mvn -f /var/jenkins_home/workspace/spring-boot-helloworld/pom.xml -e -B sonar:sonar -Dsonar.host.url=http://sonar.magedu.com:9000 ********

http://www.magedu.com

在freestyle作业上使用SonarQube进行代码质量检查(2)

 检查流水线的运行状态

http://www.magedu.com

Maven工程的另一种代码分析方法

 直接在mvn命令中作为target

将Sonar Server的地址定义为参数将SonarQube的Token
绑定到流水线上

http://www.magedu.com

Maven工程的另一种代码分析方法(2)

 在mvn命令中,直接把代码分析作为一个target

在命令行中指定要使用的
Sonar Server及登录凭据

http://www.magedu.com

Jenkins分布式构建环境

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Jenkins系统架构

  • 在Jenkins 2中,节点是一个基础概念,代表了任何可以执行Jenkins任务的系统

    • 采用master/agent架构,因而其节点可划分主节点(master)和代理节点(agent)两种类型,代理节点也被称

    • 为从节点(slave)

    • 主节点负责提供UI、处理HTTP请求及管理构建环境等,而代理节点则主要负责执行构建任务

http://www.magedu.com

Node and Executor

  • 主节点:Jenkins的一个部署实例的核心控制系统,它能够完全访问所有Jenkins配置的选项和任务

  • (job)列表,而且,若不存在其他代理节点,主节点也是默认的任务执行节点;

    • 2020年8月,Jenkins项目投票决定将master一词替换为controller
  • 代理节点:在早先版本的Jenkins中,代理节点(agent)也被称为从节点(slave),它代表着所有的非

  • 主节点;

    • 这类节点由主节点管理,按需分配或指定执行特定的任务,例如不同的构建任务或测试任务等

    • 脚本式流水线中,节点特指一个运行代理节点的系统,而在声明式流水线中,它则是分配的一个来作为代理

    • 节点的特定节点

  • 执行器(Executor):简单来说,Executor只是节点或代理节点用于执行任务的一个槽位; ◼ Executor的数量定义了该节点可以执行的并发任务量,一个节点上可以有任务数量的槽位,但也允许管理员按节点资源定义合适的数量

    • 在主节点将任务分配给特定节点时,该节点上必须有可用的Executor来立即执行该任务,否则,只能等到有

    • 空闲槽位可用

http://www.magedu.com

Agent的常见形式

  • 节点Agent

    • 在特定节点上部署的Jenkins实例

    • 配置其作为Master上的Slave节点使用

  • Docker Agent

    • 静态Docker

      • 基于特定Image运行的Agent

      • 同节点Agent的区别仅在于Jenkins的部署和运行方式有所不同

      • 也可使用专用的Image作为Agent运行,例如jenkins/ssh-gent和jenkins/inbound-agent

    • 动态Docker

      • 由Jenkins Master按需在Docker Host启动容器作为Agent,并在任务完成后予以销毁

      • Agent规模能够动态伸缩,具体取决于Docker Host的可用资源量

  • Kubernetes Pod Agent

    • 以Pod形式按需运行Agent执行构建任务

    • Agent规模可动态伸缩

http://www.magedu.com

节点标签

  • Jenkins中的标签(tag)指的是附加在节点之上的标识符,而后可由pipeline中的agent指令等进行过滤

  • 和选择;

  • agent节点较多时,出于便捷管理之需,通常应该给这些节点添加能够暴露其某种特性或功能的标签,

  • 以便于在构建任务中能基于标签过滤出符合条件的agent来;

    • 一个agent上可附加多个标签
  • 标签名称不允许使用空白字符,也不允许使用标签表达式中预留的关键字,例如!、&、|、<、>、) 和( 等;

  • 常用的标签纬度有如下几个

    • 操作系统类型:linux、windows、macos等;

    • 系统位数:32bit、64bit;

    • 集成的工具链:jdk、go、python、nodejs等;

http://www.magedu.com

Master与Agent间的连接方式

  • 为了能让master将一个主机识别为agent,需要事先在各agent上运行特定的代理程序以使得其能够与

  • master之间建立双向通信

  • 有多种方法实现master与agent之间的连接建立

    • SSH连接器(Launch agents via SSH):基于SSH连接的Agent

      • 首选且最稳定的双向连接机制,它依赖于Jenkins内置的SSH客户端,要求各agent要部署并启动了SSH服务;

      • 支持基于密钥及口令的两种认证方式,但认证信息要保存为master之上的凭证;

        • ⚫ 基于密钥认证时,master主机上私钥凭证对应的公钥要正确配置到各agent主机之上;
    • JNLP-HTTP连接器(通过Java Web启动代理):在agent上以手动或系统服务的方式经由JNLP协议触发双向

    • 连接的建立;

    • 在Controller上远程运行命令启动Agent(Launch agent via execution of command on the controller):在Master上

    • 以远程运行命令的方式来启动Agent,依赖于SSH或RSH

http://www.magedu.com

配置和使用jnlp Agent

  • Jenkins基于一个TCP端口通过JNLP代理节点(例如Windows Agent等)进行通信,比如基于Windows等的Agent

    • 由系统随机选择使用的端口能有效避免冲突,但是这种不固定又可能会给防火墙设置等带去困扰

    • ◼ 未使用JNLP代理的情况下,建议关闭Jenkins上的该端口

◼ Jenkins默认为JNLP使用的固定端口是50000/TCP

在使用JNLP代理之前,请确保开启了代理服务的端口:

系统管理 → 全局安全配置

安全起见,建议启用TLS加密的Java Web Start Agent Protocol

http://www.magedu.com

配置JNLP Agent(2)

  • 配置各种类型的Agent的关键之处在于启动Agent的方式

    • JNLP Agent对应着“通过Java Web启动代理”这种方式

    • Master与Slave之间建立一个基于HTTPS协力的Web连接

    • Slave首次接入Master时,需要提供用于认证的Secret以完成 Bootstrap

  • 配置JNLP Agent创建分布式构建环境的简要步骤 ◼ 准备Agent节点,部署好Jenkins

    • 在Master节点上,添加Agent节点的定义

    • 在Master节点上,获取将Agent节点连接至Master时需要执行的命令

    • 在Agent节点上,打开命令终端,运行Master提示的命令

  • 在Master节点上验证添加的结果

http://www.magedu.com

添加节点:创建节点

  • 在Jenkins Master上,Manage Jenkins → Manage Nodes

    • 键入节点名称

      • 节点名称是正在添加的agent节点的标识,仅用于标识该agent;
    • 选择“固定节点”

http://www.magedu.com

配置Agent的属性

 关键配置项

  • 描述:节点的说明信息

    • 通常要标明当前Agent的规格以便于识别
  • Executor的数量

    • 该Agent可同时运行的构建任务数量

    • 通常应该同CPU核心数相同

  • 远程工作目录

    • 授权Master运行构建任务时使用的工作空间

    • Agent端不会存储关键数据,作业配置、构建日志和制品等都会存储在Master上

    • 一般应该使用绝对路径

  • 标签

    • 用于对节点进行逻辑分组

    • 多个标签之间以空白字符分隔

  • 用法 :控制Jenkins如何在该agent上安排构建任务

    • 尽可能的使用这个节点

    • 只允许运行绑定到这台机器的Job

http://www.magedu.com

配置Agent的属性(2)

  • 关键配置项

    • 启动方式 :Master识别该agent主机并与其建立双向

    • 连接的方式;

      • 选定连接方式后,需要给定该方式下的具体配置

      • 若无特殊需要,JNLP的各配置项都可使用缺省配置

    • 可用性 :master与agent间的连接保持机制;

      • 尽量保持代理在线

      • 有需的时候保持代理在线,当空闲时离线

      • 根据时刻表让代理上线

    • 节点属性:

      • 工具位置:配置Agent的构建工具及安装位置,仅 agent端需要安装在一个不同的目录里才应该进行配置

      • 环境变量:配置Agent使用的环境变量

http://www.magedu.com

将jnlp Agent接入Master

 Agent需要基于生成的
Secret接入Master

在Agent的命令行中下载agent.jar,并直接在命令行给出secret信息以认证到Master

在Agent的命令行中,首先将secret保存于文件中,并在下载agent.jar后,引用secret文件内容向Master认证

http://www.magedu.com

将jnlp Agent接入Master(2)

 JNLP Agent的常用部署方式

◼ 部署一个完整的Jenkins实例,并在其命令行中运行命令以JNLP方式接入Master作为Agent使用

  • 需要让进程转入后台运行时,可以使用nohup命令完成

  • 基于jenkins/inbound-agent Image启动一个静态容器实例,直接在容器启动时接入Master

◆ docker run --init jenkins/inbound-agent -url http://jenkins-server:port -workDir=/home/jenkins/agent

~# docker run \ --add-host jenkins.magedu.com:172.29.7.1 \ --hostname agent01.magedu.com \ --init \ jenkins/inbound-agent:alpine-jdk11 \ -url http://jenkins.magedu.com:8080 \ -workDir=/home/jenkins/agent \ 5c06bf2f3c27a63b51061d051fc060109a3433a3c5806c7c4d60e2571dbc1a23 \ agent01.magedu.com Nov 14, 2022 1:05:12 PM hudson.remoting.jnlp.Main createEngine INFO: Setting up agent: agent01.magedu.com Nov 14, 2022 1:05:12 PM hudson.remoting.jnlp.Main$CuiListener INFO: Jenkins agent is running in headless mode. …… Nov 14, 2022 1:05:17 PM hudson.remoting.jnlp.Main$CuiListener status INFO: Remote identity confirmed: 74:e1:3d:54:74:18:6c:1b:5a:0a:87:a3:0e:56:af:04 Nov 14, 2022 1:05:17 PM hudson.remoting.jnlp.Main$CuiListener status INFO: Connected

http://www.magedu.com

将jnlp Agent接入Master(3)

  • Agent端进程的运行者身份决定了其访问权限,以及可以在客户端运行的shell命令

    • Agent端更安全的运行身份是普通用户,例如Jenkins

      • 以docker容器运行agent默认使用jenkins用户账号

      • 为运行远程命令使用/home/jenkins/agent目录

    • 若需要构建任务中运行特权shell命令,则要以管理员身份启动agent

      • ~# docker run \ --add-host jenkins.magedu.com:172.29.7.1 \ --user root \ --init \ jenkins/inbound-agent:alpine-jdk11 \ -url http://jenkins.magedu.com:8080 \ -workDir=/appdata/jenkins/ \ 3da41b028c213b95c354241cffcfaa512337ddbb84a63d6f989f5fff5c9803cb \ agent02.magedu.com

 提示

  • Agent端容器可能缺少各种shell工具,例如git、maven等

    • 可以为agent配置使用jgit或jgitapache,并在任务指定要使用的Git程序文件
  • 若没有定制Image,则需要在Master上配置好全局工具,而后使用非shell命令的方式进行构建

http://www.magedu.com

调用jnlp Agent进行构建

 如何调用jnlp Agent执行任务构建

◼ 由Controller自行按调度逻辑动态分配

  • 在Job中指定要使用的节点

    • 一般情况下,仅某些特定的任务必须要在特定类型的Agent(例如特定操作系统,或安装有特定的工具)上构建时, 才需要手动指定

◆ 可以基于节点标签筛选目标节点

 标签表达式(label expressions)操作符

◼ !expression:表达式条件取

◼ a && b:表达式间“与”联结

◼ a || b :表达式间“或”联结

◼ a -> b:等同于“!a || b ”,意味着如果满足a表达式,则同时必须满足b表达式;

◆ 例如,linux -> x64,意味着,如果操作系统为linux,则它也必须是x64的系统环境

◼ a <-> b:表两个条件要么同时满足,要么同时都不满足,即等同“a && b || !a && !b”

◼ (expression):表达式分组,常在需要改变操作符间的优先级顺序时使用

http://www.magedu.com

调用jnlp Agent进行构建(2)

 限制项目运行的节点

◼ Job的General配置段中进行配置

Jenkins Master上也为每个Agent提供了构建历史记录

http://www.magedu.com

配置ssh Agent

  • 静态运行ssh Agent的方式有两种

◼ 在常规的Jenkins节点上,将运行jenkins进程的用户账号(例如jenkins)设定为可通过sshd远程连接和访问 ◼ 基于jenkins/ssh-agent Image运行Docker容器

  • Jenkins Controller连接ssh Agent的方式

    • 对于运行有sshd服务的常规Jenkins节点,可选择使用口令认证或密钥认证的方式

      • 将认证信息保存为Jenkins上的凭据

      • 启动方式:“Lanch agent via SSH”

    • 对于容器化运行的ssh Agent,通常只能使用密钥认证的方式

      • 使用ssh-keygen生成一对密钥,并将公钥通过环境变量传递给ssh-agent容器

      • 将私钥保存为Jenkins上的凭据

http://www.magedu.com

配置常规Jenkins节点成为ssh Agent

  • 设定常规Jenkins节点成为ssh agent时,需要事先准备用户的认证信息,并创建成为Jenkins Master节点上的认证凭据;

    • 具体可用的认证方式取决于ssh Agent节点上的sshd的配置

    • 以口令认证为例:在agent主机上,为agent设定一个工作目录,授权给jenkins用户,并给jenkins用户设定登录口令,具体步骤类似如下命令;

      • ~# usermod -s /bin/bash jenkins

      • ~# mkdir -p /appdata/jenkins

      • ~# chown -R jenkins.jenkins /appdata/jenkins

◆ ~# passwd jenkins

  • Jenkins Master的设定

    • 先在Jenkins Master上,将认证信息创建为凭据

    • 而后在Jenkins Master上,为该agent选择启动方式为

      • “Launch agents via SSH”,并使用的凭据;

http://www.magedu.com

以静态容器形式运行ssh Agent

 在Jenkins Master端的配置

◼ 以ssh-keygen命令生成一对儿密钥

◆ ~# ssh-keygent -t dsa|ecdsa|ecdsa-sk|ed25519|ed25519-sk|rsa [-b bits] [-f output_keyfile] ◼ 将私钥内容创建为“SSH Username with private key”类型的凭据 ◼ 添加好SSH Agent节点

◆ 启动方式:“Launch agents via SSH” ◆ 选择合适的认证凭据

 SSH Agent端的配置

◼ 使用jenkins/ssh-agent Image创建容器实例

◼ 在创建容器时,将SSH公钥传递给容器,

◆ docker run jenkins/ssh-agent ""

◼ SSH公钥也可通过JENKINS_AGENT_SSH_PUBKEY环境变量进行传递

◆ docker run --env "JENKINS_AGENT_SSH_PUBKEY=''" jenkins/ssh-agent ""

http://www.magedu.com

以静态容器形式运行ssh Agent(2)

  • 添加节点

    • 新建Agent节点,多数配置方式同jnlp Agent

    • 选择连接类型为“Launch agents via SSH”

  • 配置ssh连接的属性

    • 主机

    • Credentials

    • Host Key Verification Strategy:选择Jenkins校验远程主机提供的ssh key的方式

  • 端口

  • Java路径:java可执行程序文件路径,容器中的默认位置为:

    • /opt/java/openjdk/bin/java

http://www.magedu.com

以静态容器形式运行ssh Agent(3)

 创建、启动ssh Agent容器,并在接入Controller成功后分配任务进行测试

~# JENKINS_AGENT_SSH_PUBKEY='ssh-rsa ……Wc= root@lab03.magedu.com' ~# docker container run \ --add-host jenkins.magedu.com:172.29.7.1 \ --hostname ssh-agent01.magedu.com \ --publish 22022:22 \ jenkins/ssh-agent:jdk11 \ ${JENKINS_AGENT_SSH_PUBKEY} + [[ '' == ssh-* ]] + [[ '' == ssh-* ]] + env + grep _ + [[ 1 -gt 0 ]] + echo 'setup-sshd params: ssh-rsa …

… + local ID_GROUP ++ stat -c %U:%G /home/jenkins + ID_GROUP=jenkins:jenkins + mkdir -p /home/jenkins/.ssh … + exec /usr/sbin/sshd -D -e Server listening on 0.0.0.0 port 22. Server listening on :: port 22.

http://www.magedu.com

动态Agent

  • Jenkins也支持基于Cloud环境使用动态Agent

    • Jenkins能通过“集群管理和分布式构建”插件组中插件,在远程的基础设施之上创建并运行虚拟机或容器实例

    • 在这些虚拟机或容器实例上运行支持JNLP或SSH协议接入Jenkins,从而为其提供分布式构建功能的临时节点使用时,即为“动态Agent”

  • 常用的集群管理和分布式构建插件示例

    • Docker插件:在Docker Engine上,基于容器模板,动态创建并运行容器作为Agent节点

    • Kubernetes:在Kubernetes集群上,基于Pod模板,动态创建并运行Pod作为Agent节点

    • OpenStack Cloud:基于OpenStack运行动态Agent

    • Libvirt Agents:基于libvirt服务,动态创建Xen或QEMU/KVM虚拟机作为Agent节点

    • Amazon Elastic Container Service (ECS) / Fargate:基于Amazon EC2 Container服务运行动态Agent

    • Azure VM Agents

    • Alibaba Cloud ECS

    • ……

http://www.magedu.com

基于Docker容器的动态Agent

 基于Docker插件,Jenkins能够在指定的Docker Engine上,按需创建并运行容器作为Agent使用,并在任务结束后,自动终止Agent容器

基于容器的Agent,至少需要能够基于JNLP或SSH等方式接入到Jenkins Controller

图片来源:https://medium.com/

http://www.magedu.com

配置基于Docker容器的动态Agent

  • 基于Docker容器创建和运行动态Agent的简明步骤

    • 准备一台部署了Docker Engine的主机

    • (远程主机)配置Docker Engine支持远程接入

      • Jenkins与Docker Daemon可基于SSL/TLS协议加密通信

  • 在Jenkins上的节点管理中,配置Cloud环境

  • 添加基于Docker的Cloud环境

  • 设定Docker Engine接收远程请求

    • 修改Docker的Unit File,在其ExecStart中添加监听的地址和端口

[Service] ExecStart= ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376

  • 重载Unit File后,重启Docker Service

    • ~# systemctl daemon-reload && systemctl restart docker.service
  • 测试远程访问Docker Engine

3276
32768至60999

  • ~# curl -Ss docker01.magedu.com:2376/version | jq .

http://www.magedu.com

配置基于Docker容器的动态Agent(2)

  • 在Jenkins上,添加节点,配置Docker Clouds

  • 配置Docker Cloud细节

    • Docker Host URI:目标Docker主机的URI

      • 可通过DOCKER_HOST环境变量设置

      • 格式:unix:///var/run/docker.sock 或

tcp://127.0.0.1:2376

  • Server credentials:认证到Docker Host的凭据

  • 高级配置项

    • Docker API Version:用于指定要使用的Docker API版本,在URL中的用法为“/v${VERSION}”

    • Docker Hostname or IP address:在某些自动生成URL的路径中,替换为此处指定的主机名或IP地址

  • Container Cap:最大允许同时运行的容器数,默认为 100

  • 而后,需要在该Docker Cloud上添加至少一个Docker Agent Template

http://www.magedu.com

在Docker Cloud上添加jnlp Agent模板

选择要使用的连接方式,需要同容器中的能力保持一致
Jenkins上的Job通常需要依赖于标签来激活动态Agent
指定目标Jenkins的地址,需要确保容器能直选择的Image决定了其支持的连接方式, 接访问到该地址,尤其是使用主机名时,需使用私有Registry中的Image 还要为其提要为容器配置DNS服务器或解析记录供认证凭据为容器提供各类配置细节,保持要使用的
DNS服务器,额外添加的hosts记录等为Agent选择一个其工作目录,要确保该镜像中进程的运行身份有权限读写该目录;
提示:默认使用/workspace,非root用户对该目录不具有写权限

http://www.magedu.com

在Docker Cloud上添加ssh Agent模板

选择的Image决定了其支持的连接方式,
使用私有Registry中的Image 还要为其提由Jenkins自动为每个Agent生成和注入ssh key
供认证凭据指定以SSH方式接入到agent中的用户身份,需要注意的是,选定的用户必须要在容器中存在;
使用jenkins/ssh-agent镜像,通常需要以 jenkins
用户进行,否则可能会认证失败;
Image下载策略,三个选项特性类似于Always、
IfNotPresent和Never

http://www.magedu.com

测试动态容器Agent中的作业构建

 配置

限制运行于docker jnlp agent之上

限制运行于docker ssh agent之上

http://www.magedu.com

K8S上的Jenkins 分布式构建

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Kubernetes插件

  • 能够让Jenkins Master在Kubernetes集群上运行基于Pod的动态Agent

    • 它会为启动的每个Agent创建一个Pod,并在运行完成后停止它

    • 各Pod Agent以Inbound Agent形式运行,inbound-agent容器会自动连接到Jenkins Master

      • 这意味着在每个Pod Agent中,始终有一个自动配置的名为jnlp的特殊容器

      • 要运行的其它容器可由用户在Pod模板上自行按需添加和配置

      • 默认情况下,命令都会在jnlp容器中执行

    • inbound-agent容器会被注入一些以下几个环境变量,以便它了解Jenkins Master的信息

      • JENKINS_URL

      • JENKINS_SECRET

      • JENKINS_AGENT_NAME

      • JENKINS_NAME

  • 该功能依赖的条件

    • Kubernetes v1.14及以上版本

    • 在Jenkins上安装了Kubernetes插件

    • 在Kubernetes上为Jenkins配置了具有足够权限的ServiceAccount

http://www.magedu.com

Kubernetes集群上的Jenkins分布式构建

Slave
Master
Slave
Slave

http://www.magedu.com

利用Kubernetes进行分布式构建

  • 简明配置步骤

    • ① Jenkins上安装好Kubernetes插件

    • ② 确认Jenkins开启了jnlp-agent端口

    • ③ 在Kubernetes创建专用的ServiceAccount

    • ④ 在Kubernetes上为该ServiceAccount授予在特定名称空间(如jenkins)下创建和管理Pod等资源的权限 a) 运行分布式构建的Pod时所需

    • ⑤ 在Jenkins上添加Cloud,配置要接入的Kubernetes集群

    • ⑥ 在Jenkins上添加Pod Template,以定义如何运行Pod Agent

http://www.magedu.com

添加Kubernetes Cloud

 在Jenkins上,添加Kubernetes Cloud

◼ 系统管理 → 节点管理 → Configure Clouds → Add a new cloud

http://www.magedu.com

配置Jenkins上添加的Kubernetes集群

  • Jenkins Master接入Kubernetes的方式,根据Jenkins Master 的部署位置会分成两种情形

    • Jenkins Master部署在Kubernetes集群上,而Jenkins Agent 也会创建并运行在该集群上

    • Jenkins Master部署在以Pod形式运行Jenkins Agent的集群之外

  • Jenkins Master部署在Kubernetes上

    • 可使用集群内的名称进行访问API Server

      • https://Kubernetes.default.svc
    • Jenkins Pod的ServiceAccount能够直接认证到API Server, 因此亦无须在Jenkins上添加认证凭据

    • 而且,各Pod化运行的Jenkins Agent也可以直接通过 Jinkins的Service与Jenkins Master通信,以Jenkins部署于 jenkins namespace为例

运行Jenkins Agent Pod的名称空间;

Jenkins Master关联的ServiceAccount需要被授予了在该名称空间中管理Pod等多种类型的资源对象的权限

  • Jenkins: http://jenkins.jenkins.svc:8080

  • JNLP: jnlp.jenkins.svc:50000

http://www.magedu.com

配置Jenkins上添加的Kubernetes集群(2)

 Jenkins Master部署在Kubernetes集群外

  • Jenkins Master需要通过Kubernetes API Server节点的外部地址发起访问请求,例如

    • https://kubeapi.magedu.com:6443
  • 需要在Kubernetes上创建一个专用于Jenkins Master认证到 API Server的ServiceAccount,并授予其必要的权限

    • 将Service Account的Token保存为Jenkins上的认证凭据

    • Jenkins凭据的类型为“secret text”

    • 在Kubernetes授予该ServiceAccount在某名称空间中具有创建Pod等运行Jenkins Agent的必要权限

  • 为Jenkins Master提供检验API Server数字证书的 Kubernetes CA的证书,或者“禁用HTTPS证书检查”

创建并选择认证到Kubernetes API Server的认证凭据

http://www.magedu.com

配置集群

 添加Jenkins地址和Pod Labels

Jenkins Master部署在Kubernetes集群之上的情况下,Jenkins的地址可以直接定义为Jenkins和JNLP的Service

Jenkins Master部署在Kubernetes集群之外的情况下,Jenkins的地址需要配置为 Jenkins和JNLP的实际可达地址,该地址可被Jenkins Agent Pod访问到

连接属性可保持使用默认值,容器数量可按实际需要进行调整

http://www.magedu.com

添加Pod模板

 Pod模板的作用

  • 配置要运行的Jenkins Agent Pod的相关属性

  • 指定在Pod上创建或添加的Containers、 Volumes、Environments和Annotations等信息

  • ◼ 可以不添加任何容器,其默认即会基于 jenkins/inbound-agent Image创建一个容器

  • ◼ 明确定容器的Pod模板运行为Agent Pod时, Jenkins Master也会自动为其添加inboundagent一类的JNLP容器

    • 这是基于Pod建立起Master-Agent分布式构建环境的必要条件

    • 若要自定义要使用的jnlp agent,需要定义一个名为jnlp的容器,并自行指定使用的Image

Pod模板名称,仅用于模板继承(inherit)时作为引用符号

此处标签的功用,与手动添加的各类Agent上的标签类似;多个标签间以空白分隔

  • 注意

    • 尽管Freestyle Job也能运行在多容器的Pod Agent中,但却无法在除默认的inbound-agent 之外的其它容器中运行命令

    • 基于Kubernetes的Jenkins分布式构建更适合运行Pipeline风格的Job

http://www.magedu.com

添加容器模板

 容器模板是Pod模板中的配置段

注意:Freestyle作业难以使用默认容器之外的其它容器

http://www.magedu.com

测试Pod Agent

 添加个简单的freestyle作业,限制项目运行的节点于kubeagent标签表达式之上,即可进行测试

Pod Label中的第一项来自于“配置集群”时设定的Pod Label,后两项则是基于Pod Template的定义自动生成

在Agent Pod中默认运行的容器为jnlp,而环境变量JENKINS_URL和JENKINS_TUNNEL 则来自于配置集群上的指定的参数。

http://www.magedu.com

测试Pod Agent(2)

 添加Maven Job,通过使用配置的全局maven工具,在jnlp容器内部安装工具,并完成作业构建

http://www.magedu.com

Pipeline Job

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Pipeline 是什么?

  • “从某种抽象层次上讲,部署流水线(Deployment pipeline)是指从软件版本控制库到用户手中这一

  • 过程的自动化表现形式。” ——《持续交付——发布可靠软件的系统方法》

  • Jenkins原本就支持pipeline,只不过最初该功能被称为“任务”

    • Jenkins 1.x仅支持于界面中手动配置流水线(Freestyle Job),而2.x则实现了“流水线即代码(Pipeline as a

    • Code)”的机制,它支持通过“代码”来描述部署整条流水线

◼ 使用“代码”而非UI完成pipeline定义的意义在于

  • 更好地版本化:支持版本控制

◆ 更好地协作:pipeline的修改对所有人可见,且支持代码审查

  - 更好的可重用性
  • 在Jenkins 2.x中,用于保存pipeline代码并可被Jenkins加载的文件称为Jenkinsfile;

    • 流水线既可以在pipeline类型的任务中创建,也可以定义在一个称为Jenkinsfile的外部文件中,它可以同代码

    • 保存在一起

    • Jenkinsfile就是一个文本文件,它是部署流水线概念在Jenkins中的表现形式

http://www.magedu.com

流水线语法初步

  • Jenkins 2.x支持两种pipeline语法:脚本式语法和声明式语法

    • 脚本式语法:Jenkins最先支持pipeline语法,它采用命令式风格,直接在流水线脚本中定义逻辑和程序流程;

    • ◼ 声明式语法:CloudBees公司为Jenkins引入的一种“流水线即代码”的pipeline语法,它允许用户在pipeline的定义中将更多的精力关注于期望pipeline的状态和输出之上,而非实现逻辑;

//脚本式流水线:node用于脚本式流水线,从技术层面上来说, //声明式流水线:agent用于声明式流水线,它作为一个指令用于分配节点;
//它是一个步骤,代表可以用于流水线中执行活动的资源 pipeline {
node('node01') { agent {label 'node01'}
stages {
stage('Build') { stages {
steps { stage('Build') {
echo 'Building...' steps {
} echo 'Building...'
} }
}
stage('Test') {
steps { stage('Test') {
echo 'Testing...' steps {
} echo 'Testing...'
} }
} }
} }
}

http://www.magedu.com

pipeline的组成

  • pipeline实际上就是基于Groovy语言实现的一种DSL(Domain-Specific

  • Language),用于描述代码编译到打包发布的整个流水线是如何进行的;

  • pipeline的定义有一个明确的、必须遵循的结构,它由一些指令及嵌套的代码块组成,该结构存在以下几个基本元素

◼ pipeline:流水线的最外层结构,代表整条pipeline,包含着pipeline的完整逻辑; ◼ stages:用于包含所有stage的定义;

◼ stage:阶段,代表流水线的一个单独的功能完成时期,例如编译等;

  • steps:用于在stage中定义完成该阶段功能所需要经历的一系列步骤,并能够把

  • 这些步骤同该stage中的其它定义(如环境的定义等)分隔开;

  • agent:pipeline中的单独指令,用于指定流水的执行位置,它可能是代表着slave

  • 主机的某个物理机、虚拟机或者容器;

◼ post:用在stage代码块,或者是整个pipeline执行完成后附加的步骤;  在上面给出的几个配置中,post是配置语法中惟一可省略的,但在实际应用中,通常不能省略;

Pipeline { agent any

stages { stage(‘name1’) { steps {

} post { …

} } stage(‘name2) {

}

} post {

} }

http://www.magedu.com

创建一个pipeline项目

  • 创建pipeline项目时,将首先打开一个基于Web表单形式的新项目配置页面

    • 每个主要的配置部分都有一个对应的选项卡

    • 底部还会有一个用于输入pipeline code的文本框,这是Jenkins内置的流水线编辑器

流水线脚本编辑区域

http://www.magedu.com

Pipeline编辑器的特性

  • 语法检查

    • 编辑器会尝试检查Groovy语法和引用的有效性,所有问题都会在对应代码行前面通过红色“X”方框标记提

    • 示出来;

    • 然而,并非所有的错误标记都代表真正的错误,在某些时候脚本可能无法解析依赖或最近创建的输入,这是

    • 一个异常而非规则;

  • 完整的错误信息

    • X标记在提供快速识别问题行的同时,还支持鼠标悬停时展示完整的错误信息;
  • 自动补全

    • 编辑器还提供了一定程度上的自动补全功能,比如自动补全括号;
  • 提供了“代码片断生成器”

    • 代码片断生成器提供了一种搜索可用的DSL步骤的方法,以帮助用户随时借鉴和查阅感兴趣步骤的主义和语

    • 法

http://www.magedu.com

Pipeline基础及代码示例

  • 流水线一般由多个阶段组成,包括获取源代码、编

  • 译、集成测试、代码分析、应用打包和部署等;

    • Jenkins 2.x能够代码化整个流水线;如右侧的代码示例

    • 所示;

    • 第一次保存流水线定义时,UI会提示流水线尚未执行;

    • 在项目上通过“立即构建”,可手动触发构建过程;

      • 任务执行结果在阶段视图中以方块的形式显示;

        • ⚫ 一次构建用一行方块来表示,其中每个方块代表流水线中的一个stage;

        • ⚫ 每个方块都代表了一个特定阶段的一次执行结果;

    • 方块颜色的意义

      • 蓝色条纹:运行中

      • 白色:stage尚未执行

      • 红色条纹:state执行失败

      • 绿色:stage执行成功

      • 浅红色:stage执行成功,但是下游的某个stage出现失败

pipeline {

agent any

stages {

stage('Source') { steps {

echo 'Get code from Git Repository...'

  • }

  • }

stage('Build') {

steps {

echo 'Building...'

}

  • }

stage('Test') {

steps {

echo 'Testing...'

  • }

}

stage('Deploy') {

steps {

echo 'Deploying...'

}

}

}

}

http://www.magedu.com

运行一条pipeline

  • 以前面示例中的代码保存为一个pipeline的定义,通过左边菜单中的“立即构建”便可触发pipeline的

  • 一次运行,具体结果如下图所示;

http://www.magedu.com

控制台输出

  • 在传统的Jenkins中,通过点出控制台输出链接或者构建历史窗口中的构建旁边状态球来查看控制台输

  • 出,新式的stage视图同样支持该功能;

  • 另外,将鼠标悬停于stage视图中的某个方块上,还会出现该阶段相关的日志信息的按钮,点击该按钮,

  • 即可显示该stage的日志;

http://www.magedu.com

运行失败的视图

  • 多次运行构建任务时,最新一次的运行位于视图中的最上方;

    • 当某个stage因任何原因运行失败时,Jenkins会将其标记为红色条纹背景;

    • 鼠标悬停于stage方块上方,会有错误信息提示;

    • 例如,我们将此前pipeline示例代码的“Build”阶段有意改为错误格式,例如将echo换成bat命令等,其构建

    • 结果将输出为类似如下视图;

http://www.magedu.com

流水线步骤

 Pipeline Job中的流水线步骤可以分解显示每个步骤的执行状态

http://www.magedu.com

回放(Replay)

  • 对于错误的构建任务,Jenkins提供了一种称为“回放”的机制,它允许用户无须改变已保存的原有代

  • 码的基础上进行试验和调试;

    • 回放为用户提供了一种在原有代码基础上修改代码并再次触发pipeline的功能,以便于在正式提交代码之前进

    • 行一次变更的快速快速验证并查看效果;

      • 点击构建菜单中的“回放”,会弹出编辑窗口,并允许用户任意修改程序,而后点击“运行”按钮来验证变更效果;

      • ◆ Jenkins会在回放窗口中运行编辑后的代码,并保存一次全新的构建记录,但原始代码依然保持从前的状态;因此, 回放操作能帮用户验证变更,但真正的变更依然需要用户手动更新pipeline的代码完成;

http://www.magedu.com

Pipeline 语法

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

声明式pipeline的结构

  • pipeline的定义有一个明确的、必须遵循的结构,它由一些directive和section

  • 组成,每一个section又可包含其它的section、directive和step,以及一些 condition的定义;

    • Section:用于将那些在某个时间点需要一同运行的条目(item)组织在一起 ◆ agent section:指定负责运行代码的节点

      • stages section:组织一到多个stage

      • steps section:组织一至多个DSL格式的步骤;

      • post section:在stage或整个pipeline的尾部封装一些需要被执行的步骤或者检验条件

    • Directive(指令):负责完成特定功能的语句或代码块,如environment、tools、

    • triggers、input和when等;

  • Steps:steps本身就是一个标识特定section的名称,其内部可以使用任何合法的

  • DSL语句,例如git、sh、bat和echo等;

  • 右图中的实线部分,为必选的配置参数

pipeline { agent any stages { stage(‘<stage_name>’) { steps { … } } } }

http://www.magedu.com

Pipeline支持的指令

 Jenkins Pipeline支持指令主要有如下这些

  • environment:设定环境变量,可用于stage或pipeline代码块中;支持credentials()函数,用于通过标识符访问预

  • 定义的凭证;

  • tools:指定需要在agent上下载并配置的工具,例如git、maven、jdk等,这些工具可经由PATH环境变量指定

  • 的位置访问到;可用于stage或pipeline中;

  • parameters:用户在触发pipeline时应该提供的参数列表;仅可用于pipeline级别;

  • options:仅可用在pipeline级别来配置pipeline自身的选项,支持的参数可由pipeline自身提供,也可由其它插件

  • (例如timestamps)提供;

◆ 例如“retry(2)”允许在pipeline失败时重试两次;

  • triggers:用于指定负责自动启动pipeline的触发器,对于集成了Github或Gitlab等自带触发机制的系统场景来

  • 说,triggers并非必须的指令;仅可用于pipeline级别;

  • libraries:当前pipeline可以导入的共享库,该共享库内部的代码则可被该pipeline调用;

  • stage:负责在stages配置段中封装steps配置段,以及其它可用于stage中的指令;

  • input:stage中的专用指令,用于暂停pipeline并提示用户输入内容后继续;

  • when:stage中的专用指令,用于设定该stage的运行条件;

http://www.magedu.com

Section: agent

  • agent用于指明使用哪一个节点去执行pipeline或stage中的代码;

    • 在pipeline代码块的顶部, 必须要有一个agent来指定“默认”的执行节点

    • 而一个stage的顶部也可以有一个agent的定义,用来指定负责运行该stage中的代码的节点

  • agent可接受多种形式的参数

    • any:任何可用节点

    • none:用于pipeline顶端时表示不定义默认的agent,这就需要为每个stage单独指定

    • ◼ label { label "

    • node { label "

    • docker:在指定的容器中运行pipeline或stage代码,该容器动态创建并运行于预配置的可运行容器的node上,

    • 或能够匹配到指定label的node上;可用参数如下

      • image、label、args、rgistryUrl和registryCredentialsId;
    • dockerfile:功能上类似于上面docker参数,但容器镜像通过指定的docker进行构建;该参数要求Jenkinsfile必

    • 须从Multibranch Pipeline或者Pipeline from SCM中加载;可用参数如下

      • filename、dir、label、additionalBuildArgs、args、registryUrl和registryCredentialsId;
    • kubernetes:于Kubernetes集群上指定的Pod中运行stage或pipeline代码,该参数同样要求Jenkinsfile必须从

    • Multibranch Pipeline或者Pipeline from SCM中加载;

      • 需要在kubernetes参数中指定Pod模板;
  • 详情请参考:https://www.jenkins.io/doc/book/pipeline/syntax/

http://www.magedu.com

Section: post

  • post section在stage或pipeline的尾部定义一些step,并根据其所在stage或pipeline的完成情况来判定是否

  • 运行这些step;

 post section支持的condition如下

  • always:总是运行

  • changed:其所处的stage或pipeline同前一次运行具有不同状态时,才运行该post

  • fixed:stage或pipeline本次运行成功,但前一次为failed或unstable时,才运行该post

  • regression:stage或pipeline前一次运行成功,但本次为failure、unstable或aborted时,才运行该post

  • aborted:stage或pipeline的运行状态为aborted时,才运行该post;在Web UI中灰色显示

  • failure:stage或pipeline的运行状态为failed时,才运行该post

  • success:stage或pipeline的运行状态为success时,才运行该post

  • unstable:因测试失败或代码冲突导致stage或pipeline的运行状态为unstable时,才运行该post;在Web UI中以

  • 黄色显示

  • unsuccessful:stage或pipeline的运行不成功时,才运行该post

  • cleanup:在其它所有的post的条件均被评估后(无论stage或pipeline的状态为何)才运行该post

http://www.magedu.com

Section: stages和steps

  • stages:封装了用于定义pipeline主体和逻辑的所有stage的定义,它包含一个或多个stage指令, ◼ stages负责描述pipeline中绝大部分的实际工作(work)

  • 事实上,stages中至少需要包含一个stage指令来定义CD过程的每个离散部分,例如构建、测试和部署等

  • steps:负责在stage中定义一到多个DSL语句,这些语句负责完成该stage中特定的功能;但能够同其它的语句分隔开,如environment等

pipeline {
agent any
stages {
stage('Example’) {
// stage中必须要包含steps;
steps { // step中至少应该有一个DSL语句;
echo 'Hello World'
}
}
}
}

http://www.magedu.com

Steps

  • Pipeline的基本结构决定了pipeline的整体流程,但真正“做事”的还是其内部一个个具体的step,因而

  • steps是pipeline中最核心的组成部署;

◼ 除了script,几乎所有的step在pipeline中都是不可拆分的原子操作;

◼ pipeline内置了大量的step,具体请参考https://www.jenkins.io/doc/pipeline/steps;

◼ 除此之外,有相当一部分插件可直接当作step来用;

  • script{}步骤负责将脚本引入到steps{}配置段中,但它非为必要的步骤,且复杂的脚本应该单独组织为

  • Shared Libraries,并由Pipeline导入后使用;

pipeline { agent any stages { stage('Example') { steps { echo 'Hello World' script { def browsers = ['chrome', 'firefox'] for (int i = 0; i < browsers.size(); ++i) { echo "Testing the ${browsers[i]} browser" } } } } } }

http://www.magedu.com

Pipeline内置的常用step

  • 文件/目录相关

    • deleteDir:删除当前目录;

    • dir("/path/to/dir"):切换到指定目录;

    • fileExists ("/path/to/dir") :判断文件是否存在;

    • isUnix:判断是否为类Unix系统;

    • pwd:打印当前目录;

    • writeFile:将内容写入指定的文件中,支持如下几个参数

      • file:文件路径,支持相对路径和绝对路径;

      • text:要写入的内容;

    • encoding:目标文件的编码,空值为系统默认的编码;支持base64编码格式;可选参数;

    • ◼ readFile:读取文件的内容;支持如下几个参数;

      • file:文件路径,支持相对路径和绝对路径;

      • encoding:读取文件内容时使用的编码格式;可选参数;

http://www.magedu.com

Pipeline内置的常用step

  • 消息或控制

    • echo("message"):打印指定的消息;

    • error("message"):主动报错,并中止当前pipeline;

    • retry(count){}:重复执行count次在{}中定义的代码块;

    • sleep:让pipeline休眠一段时间,支持如下参数;

      • time:整数值,休眠时长;

      • unit:时间单位,支持NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES、HOURS和

      • DAYS,可选参数;

    • timeout:代码块的超时时长,支持如下参数;

      • time:整数值,休眠时长;

      • unit:时间单位,支持NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES、HOURS

      • 和DAYS,可选参数;

      • activity:布尔类型,值为true时,表示在该代码块不再有日志活动时才算真正超时;可选参数;

    • waitUntil:等待指定的条件满足时执行定义的代码块;

      • initialRecurrencePeriod:初始的重试周期,即测试条件是否满足的重试周期,默认为250ms;可选参数;

      • quiet:是否禁止将每次的条件测试都记入日志,默认为false,即记入日志;可选参数;

http://www.magedu.com

Pipeline内置的常用step

  • 发送通知

    • mail:向指定邮箱发送邮件;

      • subject:邮件标题;

      • body:邮件正文;

      • from (optional):发件人地址列表,逗号分隔;

      • cc (optional) :CC email地址列表,逗号分隔;

      • bcc (optional):BCC email地址列表,逗号分隔;

      • charset (optional):编码格式;

      • mimeType (optional):Email正文的MIME类型,默认为text/plain;

      • replyTo (optional):回件地址,默认为Jenkins设置的全局配置中的邮箱地址;

http://www.magedu.com

Pipeline的常用步骤

  • Node和Process相关

    • bat:Windows的批处理脚本;

    • powershell:运行指定的PowerShell脚本,支持Microsoft PowerShell 3+;

    • pwsh:PowerShell Core Script

    • node:在指定的节点上运行后续的脚本;

    • sh:运行shell脚本,支持的参数如下

      • script{}:脚本代码块,支持指定脚本解释器,例如“#!/usr/bin/perl,否则将使用系统默认的解释器,且使用了-xe选

      • 项”;

      • encoding (optional):脚本执行后输出的日志信息的编码格式,未定义时使用系统默认编码格式;

      • label (optional):显示在Web UI中的详细信息;

      • returnStdout (optional):布尔型值,true表示任务的标准输出将作为step的返回值,而不是打印到日志中;若有错误,

      • 依然会记入日志;

      • returnStatus (optional):正常情况了命令执行失败会返回非零状态码,设定该参数值为true时,表示将返回该step的结

      • 果,而非状态码;

    • ws:分配工作空间;

http://www.magedu.com

Stages和Stage

  • 显然,states是pipeline中最重的section,Jenkins会按照stages中

  • 定义的顺序自下而后执行各个stage;

  • stage内部还能再嵌套一个stages{}或一个parallel{}代码块,而

  • 后在这些代码块内部再嵌套stage,以指定stage的运行顺序; ◼ stage内部嵌套stages{},用于指定以顺序(串行)方式依次运行该stages{}内部的各stage;

    • 而stage内部嵌套的parallel{},用于指定以并行方式运行该

    • parallel{}内部的各stage;

  • 需要注意以下几点

    • stage内部仅能定义steps、stages、parallel或matrix四者其中之一,

    • 且多层嵌套只能用在最后一个stage中;

    • 对于本身已经嵌套在parallel或matrix内部的stage来说,不支持在

    • 其内部再使用parallel或matrix;但仍能使用agent、tools和when等其它指令,甚至是stages{}配置段以顺序运行stage;

pipeline { agent none stages { stage('Sequential') { stages { stage('In Sequential 1') { steps { echo "In Sequential 1“ } } stage('In Sequential 2') { steps { echo "In Sequential 2“ } } stage('Parallel In Sequential') { parallel { stage('In Parallel 1') { steps { echo "In Parallel 1“ } } stage('In Parallel 2') { steps { echo "In Parallel 2“ } } } } } } } }

http://www.magedu.com

pipeline代码片断生成器

 pipeline代码生成器对于初学者来说,是不可多得的辅助工具,从“流水线语法”处即可打开

代码片断生成器可用于帮助用户生成step

http://www.magedu.com

pipeline指令配置段生成器

 指令配置段生成器能够帮助用户生成配置指令,包括agent、stages等

http://www.magedu.com

Pipeline示例1: 使用自定义工具的Maven工程

 调用名为“maven-3.8.6”全局构建工具

  • 构建工具程序默认安装在${JENKINS_HOME}/tools/目录下

◼ “maven-3.8.6”就位于该目录下的hudson.tasks.Maven_MavenInstallation/maven-3.8.6/子目录中;

pipeline { agent any tools { maven 'maven-3.8.6' } stages { stage('Source') { steps { git branch: 'main', url: 'http://gitlab.magedu.com/root/spring-boot-helloWorld.git' } } stage('Build') { steps { sh 'mvn -B -DskipTests clean package' } } stage('Test') { steps { sh 'mvn test' } } } }

该仓库中的应用是一个基于spring boot的简单示例,它默认监听8080 端口,通过http协议提供服务;

http://www.magedu.com

Pipeline示例1: 使用自定义工具的Maven工程(2)

 运行Pipeline Job,并验证其运行结果状态

BlueOcean中的结果状态

http://www.magedu.com

Pipeline 应用进阶

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

本节话题

  • 在Pipeline Job上使用环境变量

  • 在Pipeline Job的Step中使用认证凭据

  • 在Pipeline Job中构建和推送Docker Image

  • 参数化Pipeline

http://www.magedu.com

在Pipeline上使用环境变量的方法及示例

  • Jenkins环境变量可分为内置变量和用户自定义变

  • 量两类

    • pipeline{}和stage{}中用于定义环境变量的指令是

    • environment,但定义位置的不同,也意味着其作用域的不同;

      • 定义在pipeline{}顶部的环境变量可被其后的各stage

      • 所引用;

      • Jenkins全局环境变量可被所有的pipeline引用,它们

      • 以“env.”为前缀;

◼ 引用全局环境变量格式有三种:

  • ${env.<ENV_VAR_NAME>}

  • $env.<ENV_VAR_NAME>

◆ ${ENV_VAR_NAME}

  • 右侧是在Pipeline中使用环境变量的简单示例

pipeline { agent any tools { maven 'maven-3.8.6' } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" } stages { stage('Source') { steps { git branch: 'main', url: "${GitRepo}" } } stage('Build') { steps { sh 'mvn -B -DskipTests clean package' } } stage('Test') { steps { sh 'mvn test' } } } }

http://www.magedu.com

在Pipeline中使用认证凭据

  • 类似于Freestyle Job,同外部服务交互时,Pipeline Job也可能需要为steps提供凭证来获取服务,以完成

  • steps中必要的操作步骤

 依赖于Credential Binding Plugin,该插件通常在安装社区推荐的插件时会由Jenkins自行部署

 Pipeline在其定义上使用withCredentials( ){ // code }来引用凭据,不同类型凭据的引用操作存差异

  • Username with password

    • withCredentials([usernamePassword(credentialsID: '',

passwordVariable: '',

usernameVariable: '')])

  • 其中,无论用户名和密码使用变量名可自行指定,而后,Jenkins都会通过credentialsID从指定的凭证填充用户名和密

  • 码;

  • 下面是一个简单的示例;

withCredentials([usernamePassword(credentialsId: ‘gitlab-root-credential', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { // available as an env variable, but will be masked if you try to print it out any which way // note: single quotes prevent Groovy interpolation; expansion is by Bourne Shell, which is what you want sh 'echo $PASSWORD'

// also available as a Groovy variable echo USERNAME // or inside double quotes for string interpolation echo "username is $USERNAME" }

http://www.magedu.com

在Pipeline中使用认证凭据(2)

 在Pipeline中,要使用withCredentials( )来引用凭证

  • SSH密钥

◆ withCredentials([sshUserPrivateKey(credentialsId: '’, keyFileVariable: 'MYKEYFILE’, passphraseVariable: 'PASSPHRASE’, usernameVariable: 'USERNAME')])

  • { // some block }

  • 另外,若安装了SSH Agent Plugin,还可以使用“sshagent([]) { }”代码块;

Stage(‘Update Source’) { sh 'git config user.name iKubernetes' sh 'git config user.email mage@magedu.com' sshagent(['ssh-private-key-gitlab-user-magedu']) { sh "git tag –a ${env.BUILD_TAG} –m 'iKubernetes push of tags'" sh "git push ${sshRepodef} –tags" } }

http://www.magedu.com

在Pipeline中使用认证凭据(2)

 在Pipeline中,要使用withCredentials( )来引用凭证;

  • Secret text

    • withCredentials([string(credentialsId: 'secretText', variables: 'varName')]) { // code }
  • Secret file

    • withCredentials([file(credentialsId: 'secretFile', variable: 'FILENAME')]) { // code }

http://www.magedu.com

优雅地使用认证凭据

  • 显然,每次调用凭证时都使用withCredentials( )有点过于麻烦;为些,声明式pipeline提供了credentials

  • helper方法,它允许在environment{}代码段中通过credentials('credentialsId')直接取出凭证并保存于指定的变量中;

pipeline { agent any environment { ding_robot_token = credentials('dingtalk-robot-token') } stages { stage('debug') { steps { sh "printenv" } } } post { success { script { echo "${env.ding_robot_token}" } dingTalk accessToken: "${env.ding_robot_token}", imageUrl: '', jenkinsUrl: '', message: ‘Build Successfully.', notifyPeople: '' } } }

http://www.magedu.com

在Pipeline中使用认证凭据示例

pipeline {
agent any
tools {
maven 'maven-3.8.6'
}
environment {
GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git"
}
stages {
stage('Source') {
steps {
withCredentials([gitUsernamePassword(credentialsId: 'gitlab-root-credential',
gitToolName: 'jgitapache')]) {
sh 'git clone $GitRepo'
} 提示:该示例使用的是shell步骤,直接
} 在shell中运行git命令,而且用到的git
} 具为全局安装的jgitapache
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
}
}

http://www.magedu.com

在Pipeline中使用认证凭据示例(2)

 其实,git步骤自身便能支持直接加载Credential

pipeline { agent any tools { maven 'maven-3.8.6' } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" } stages { stage('Source') { steps { git branch: 'main', credentialsId: 'gitlab-root-credentail', url: "${GitRepo}" } } 有些步骤本身就支持直接使 stage('Build') { 用凭据,例如git步骤就支持 steps { 直接使用credentialsId参数加 sh 'mvn -B -DskipTests clean package' 载认证凭据 } } stage('Test') { steps { sh 'mvn test' } } } }

http://www.magedu.com

在Pipeline的Step中构建Docker Image

  • 事前准备

    • 在目标agent上(Jenkins主机)有部署可用的 Docker Daemon和Docker CLI

    • 在sh step中执行docker image build命令即可完成 Docker Image的构建

pipeline { agent any tools { maven 'maven-3.8.6' } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" ImageUrl="ikubernetes/spring-boot-helloworld" ImageTag="latest" } stages { stage('Source') { steps { git branch: 'main', url: "${GitRepo}" } } stage('Build') { steps { sh 'mvn -B -DskipTests clean package' } } stage('Test') { steps { sh 'mvn test' } } stage('Docker Build') { steps { sh 'docker image build -t ${ImageUrl}:${ImageTag} .' } } } }

http://www.magedu.com

在Pipeline的Step中推送Docker Image

 事前准备

pipeline {

agent any tools {

  • 在目标agent上(Jenkins主机)有部署可用的Docker Daemon和Docker CLI

maven 'maven-3.8.6'

}

  • 有可用的Docker Registry,本示例中使用的是本地部署的Harbor服务,主机为 hub.magedu.com

environment {

GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" ImageUrl="ikubernetes/spring-boot-helloworld“

HarborServer='hub.magedu.com'

ImageTag="latest"

  • 在sh step中执行docker image push命令即可完成Docker Image推送

}

stages {

stage('Source’) { steps { git branch: 'main', url: "${GitRepo}" } } stage('Build’) { steps { sh 'mvn -B -DskipTests clean package’ } }

stage('Test’) { steps { sh 'mvn test’ } }

stage('Docker Build’) { steps { sh 'docker image build -t ${HarborServer}/${ImageUrl}:${ImageTag} .’ } } stage('Docker Push') {

agent any steps {

withCredentials([usernamePassword(credentialsId: 'harbor-user-credential’, \ passwordVariable: 'harborUserPassword', usernameVariable: 'harborUserName')]) { sh "docker login -u ${env.harborUserName} -p ${env.harborUserPassword} ${HarborServer}" sh 'docker image push ${HarborServer}/${ImageUrl}:${ImageTag}'

}

}

} } }

http://www.magedu.com

在Pipeline上使用参数

  • 声明式Pipeline中,parameters指令用于为Pipeline声明参数

    • 该指令用于pipeline{}之中,且常见于agent指令之后

    • 其功用与Freestyle Job上的参数类似

  • 一般来说,常用的参数类型有如下这些

    • string

      • 字符串类型的参数,例如: parameters { string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: ' ') }
    • text

      • 文本类型的参数,支持多行文本,示例: parameters { text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: ' ') }
    • booleanParam

      • 布尔型参数,示例: parameters { booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: ' ‘) }

      • ◆ 值传递也是string类型;

    • choice

      • 选项型参数,示例: parameters { choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: ' ') }
    • password

      • A password parameter, for example: parameters { password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') }

http://www.magedu.com

使用示例:string类型的参数

  • string方法默认用于定义一个字符串类型的参数,它接收三

  • 个配置项

    • name:参数名;

    • defaultValue:默认值;

    • description:参数的描述信息;

  • 传入的参数会放在一个名为params的对象中,该参数可以

  • 在pipeline中引用;例如下面的示例中,params.userRole就是对引用了名为userRole的参数;

pipeline { agent any parameters {

string(defaultValue: “OpsMaster",

description: 'Enter user role:', name: 'userRole')

}

stages { stage('listVals') { steps { echo "User's role = ${params.userRole}" } } }

}

http://www.magedu.com

多参数

  • Pipeline也支持同时接受多个参数来定义pipeline的具体行为;

    • 下面示例中的pipeline就支持isPublishVersion、whichBranch和deployEnvironment三个参数;

pipeline { agent any parameters { booleanParam(name: '是否发布该版本', defaultValue: false, description: '默认不发布') choice(name: 'whichBranch', choices: ['origin/release-bugfix', 'origin/release', 'origin/master'], description: '构建分支选择,默认origin/release-bugfix') choice(name: 'deployEnvironment', choices: ['dev', 'test', 'staging'], description: '请选择部署环境') } stages { stage('buildFramework') { steps { echo "GIT_LOCAL_BRANCH: ${params.whichBranch}" echo "isPublishVersion: ${params.isPublishVersion}" echo "deployEnvironment: ${deployEnvironment}" } } } }

http://www.magedu.com

input步骤

  • input步骤是Pipeline与用户交互的接口,用于实现根据用户输入改变pipeline的行为;

    • 遇到input步骤时,Pipeline会暂停下来并等待用户的响应;

    • input步骤是特殊的参数化pipeline的方法,它常用于实现简易的审批流程,或者是手动实施后续的步骤等;

    • 为了接收用户输入的不同数据,Jenkins提供了不同类型的参数;

      • input步骤默认打印出的表单是打印一条消息并为用户提供一个选择:Proceed或者Abort;

pipeline {
agent any
stages {
stage('Example') {
steps {
echo "Example Stage..."
input 'Continue to next stage?'
}
}
}
}

http://www.magedu.com

input步骤的参数

 input步骤的可用参数

  • message,String类型;

    • 其内容将打印给用户,并要求用户选择Proceed或Abort;

    • 若input仅提供了该参数时,还可以省略message参数名称;

  • id (optional),String类型;

    • 每个input都有一个惟一的ID标识,用于生成专用的URL,以便于根据用户输入继续或中止pipeline;

      • ⚫ <JENKINS_URL>/job/[job_name]/[build_id]/input/[input_id]/

      • ⚫ 该URL可通过POST方法进行请求,后跟proceedEmpty表示空输入并继续,而abort则表示中止;

    • 未定义时,Jenkins将自动为input生成ID;

  • ok (optional) ,String类型;

    • 用于自定义Proceed按钮的标签名称;例如,下面的示例中,Proceed按钮的名称为“Yes” ⚫ input message: '<message text>', ok: 'Yes'
  • parameters (optional)

    • 要求用户手动输入一个或多个参数列表;

    • pipeline中,parameters指令支持的参数类型仅是input步骤支持的参数类型的一个子集,因而,那些参数类型都会被input步骤

    • 所支持;

  • submitter (optional) ,String类型;

    • 可以进行后续操作的用户的ID或用户组列表,彼此间以逗号分隔,且前后不允许出现空格;
  • submitterParameter (optional),String类型;

    • 用于保存input步骤的实际操作者的用户名;

http://www.magedu.com

在input步骤中使用参数

 input步骤中,通过参数接收到的用户输入可以保存在变量中,而后进行调用; ◼ 变量作用域仅为当前stage,例如,下面示例中的userInput变量仅能于当前步骤中调用; ◼ 若要跨stage使用变量,则需要在pipeline代码外部先用def声明变量,而后再于stage中使用该变量;

pipeline { agent any stages { stage('Example') { steps { script { def userInput = input(submitterParameter: "approver", id: "approve", message: "Provide your approval to proceed", parameters: [string(defaultValue: "approved", description: 'Please provide the message why your are approving', name: 'remarks')]) echo "Remarks: ${userInput['remarks']}" echo "It was ${userInput.approver} who approved this job" } } } } }

http://www.magedu.com

input参数的全局作用域

 跨多个stage使用input参数

◼ 将声明变量的语句放在pipeline{}代码段外部之上;

def approvalMap pipeline { agent any stages { stage('PreDeploy') { steps { script { approvalMap = input(message: ‘目标环境', ok: '确定', parameters: [ choice(choices: ['dev', 'test', 'prod'], description: ‘发布到哪个环境中?', name: 'ENV'), string(defaultValue: '', description: '', name: 'myparam')], submitter: 'admin,releaseGroup', submitterParameter: 'APPROVER' ) } } } stage('Deploy') { steps { echo “操作人员: ${approvalMap['APPROVER']}" echo “目标环境: ${approvalMap['ENV']}" echo "自定义参数:${approvalMap['myparam']}" } } } }

提示:用于接受参数的变量还可以声明在environment{}中,而后在stage中调用该环境变量即可;

http://www.magedu.com

输入等待超时

  • input步骤与timeout步骤协同使用,可实现超时自动中止

  • pipeline,以避免无限等待;

pipeline {

agent any

stages {

◼ timeout(time, activity, unit) {}

stage('Example') { steps { echo "Example Stage..." timeout(time: 1, unit: 'MINUTES') { input 'Continue to next stage?'

  • time: The length of time for which this step will wait before cancelling the

  • nested block. 整型数据

  • activity (optional): Timeout after no activity in logs for this block instead of

  • absolute duration. 布尔型数据

}

}

  • unit (optional):The unit of the time parameter. Defaults to 'MINUTES' if

  • not specified.

}

  • }

}

  • ⚫ Values: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS

 右侧的示例中,为input步骤指定了1分钟的等待时长; ◼ 生产中,发布操作的等待时长通常可能会具有更长的时间,例如 1小时等

http://www.magedu.com

When:条件式运行

 when{}是用在stage{}段中的指令,用于限定当前stage{}的运行条件

◼ when指令中至少要含有一个条件

◼ 若同时定义了多个条件,它们之间的隐含关系为“与”,即必须同时满足,才会运行当前stage{} ◼ when{}也允许嵌套定义条件的逻辑操作:not、allOf和anyOf

 Jenkins内置支持的常用条件

◼ branch:满足给定的分支模式时运行当前stage{}

◆ 格式为“branch pattern: , comparator: ”,该指令仅适用于多分支流水线

  • ⚫ equals:即完全相同,例如“branch equals: main”

  • ⚫ glob:文件名路径格式的通配符,默认值,例如“branch glob: origin/ref/*”

⚫ regexp:正确表达式模式,例如“branch regexp: release-\\d+

◼ environment

  • 给定的变量满足指定的值时,运行当前stage{}

  • 格式为“environment name: , value: ”

  • 例如:when { environment name: 'DEPLOY_TO', value: 'production' }

◼ expression

  • 给定的groovy表达式结果为true时,运行当前stage{};

  • 表达式需要为布尔型,或者返回值为true或false的字符串

◆ 例如:expression { BRANCH_NAME ==~ /(production|staging)/ }

http://www.magedu.com

When:条件式运行(2)

 Jenkins内置支持的常用条件(续)

◼ tag

◆ 给定的TAG_NAME匹配指定的模式时,运行当前stage{}

◆ 例如:when { tag "release-*" }

  • changeRequest

◆ 当前构建因某个指定的“change request(例如Pull Request或Merge Request)”触发时,运行当前分支

  • 空的参数值,表示任意的change request均满足条件,例如when { changeRequest() }

◆ 支持使用过滤器属性,包括id, target, branch, fork, url, title, author, authorDisplayName和authorEmail

  • ⚫ 例如:when { changeRequest target: 'master’ }

  • 在过滤器属性上,还支持使用可选的comparator参数

⚫ 例如:when { changeRequest authorEmail: "[\\w_-.]+@example.com", comparator: 'REGEXP’ }

◼ not:嵌套的条件结果为false时执行当前stage{}

◆ 例如:when { not { branch 'master' } }

◼ allOf:嵌套的所有条件均为true执行当前stage{}

◆ 例如:when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } } ◼ anyOf:嵌套的条件至少有一个为true时执行当前stage{}

  • 例如:when { anyOf { branch 'master'; branch 'staging' } }

http://www.magedu.com

When:条件式运行(3)

  • Jenkins内置支持的常用条件(续)

    • triggeredBy

◆ 当前的构建Job由指定的Trigger触发时运行当前stage{}

  • 例如:when { triggeredBy 'BuildUpstreamCause’ }

  • 在进入stage{}内的agent之前评估when条件

    • 默认情况下, 如果在stage{}定义了agent,则在进入该stage{}的agent后才会评估其内部的when条件
  • 但也可以显式将beforeAgent选项的值设定为true来更改此默认行为,即先评估when条件,且结果为true时才进入agent

  • ◼ 在运行stage{}内的input之前评估when条件

    • 默认情况下, 如果在stage{}定义了input,则在运行该stage{}的input后才会评估其内部的when条件
  • 但也可以显式将beforeInput选项的值设定为true来更改此默认行为,即先评估when条件,且结果为true时才执行input

  • ◼ 在运行stage{}内的options之前评估when条件

    • 默认情况下, 如果在stage{}定义了options,则在运行该stage{}的options后才会评估其内部的when条件

    • 但也可以显式将beforeOptions选项的值设定为true来更改此默认行为,即先评估when条件,且结果为true时才执行 options

http://www.magedu.com

When条件式运行的简单示例

 条件式运行的示例

pipeline { pipeline {
agent none agent any
stages { stages {
stage('Example Build') { stage('Example Build') {
steps { steps {
echo 'Hello World' echo 'Hello World'
} }
} }
stage('Example Deploy') { stage('Example Deploy') {
when { when {
beforeInput true expression { BRANCH_NAME ==~ /(production|staging)/ }
branch 'production' anyOf {
} environment name: 'DEPLOY_TO', value: 'production'
input { environment name: 'DEPLOY_TO', value: 'staging'
message "Deploy to production?" }
id "simple-input" }
} steps {
steps { echo 'Deploying'
echo 'Deploying' }
} }
} }
} }
}

http://www.magedu.com

参数和条件式执行综合案例

 布尔型参数的选择结果决定了是否推送镜像

未勾选推送选项时,
流水线的最后一步将不会执行

pipeline { agent any tools { maven 'maven-3.8.6’ } parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" ImageUrl="ikubernetes/spring-boot-helloworld“ HarborServer='hub.magedu.com' ImageTag="latest" } stages { stage('Source’) { steps { git branch: 'main', url: "${GitRepo}" } } stage('Build’) { steps { sh 'mvn -B -DskipTests clean package’ } } stage('Test’) { steps { sh 'mvn test’ } } stage('Docker Build’) { steps { sh 'docker image build -t ${HarborServer}/${ImageUrl}:${ImageTag} .’ } } stage('Docker Push’) { when { expression { params.PUSH } beforeAgent true } agent any steps { withCredentials([usernamePassword(credentialsId: 'harbor-user-credential’, \ passwordVariable: 'harborUserPassword', usernameVariable: 'harborUserName')]) { sh "docker login -u ${env.harborUserName} -p ${env.harborUserPassword} ${HarborServer}" sh 'docker image push ${HarborServer}/${ImageUrl}:${ImageTag}' } }

} } }

http://www.magedu.com

在Pipeline中实现GitLab trigger

  • 在Pipeline代码中配置GitLab Trigger会用到如下几个step

    • triggerOnPush:GitLab仓库推送push事件时是否执行构建

    • triggerOnMergeRequest:GitLab仓库推送mergeRequest事

    • 件时,是否执行构建

    • branchFilterType:只有符合条件的分支才会被触发;必

    • 选配置,否则将无法实现触发,支持如下值

      • NameBaseFilter:基于分支名进行过滤,多个分支名彼此间

      • 以逗号分隔

      • RegexBaseFilter:基于正则表达式模式对分支名过滤

      • All:所有分支都会被触发

    • includeBranchSpec:基于branchFilterType值,输入期望包

    • 括的分支的规则

    • excludeBranchSpec:基于branchFilterType值,输入期望排

    • 队的分支的规则

    • secretToken:在回调时使用的token

  • 更详细的配置参数请参考GitLab-Plugin项目的描述

    • https://github.com/jenkinsci/gitlab-plugin

pipeline {

agent any tools { maven 'maven-3.8.6'

}

triggers { gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All', secretToken: '9iH0tq33ROMS07przzLiclNmfqSaoIeTOolHYf1E')

}

parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" HarborServer='hub.magedu.com' ImageUrl="ikubernetes/spring-boot-helloworld" ImageTag="latest" } stages { stage('Source') { steps { git branch: 'main', url: "${GitRepo}"

  • }

  • }

…… } }

http://www.magedu.com

在Pipeline中实现GitLab trigger(2)

 注意

◼ Pipeline Job需要至少先手动触发一次,而后才能被自动触发

http://www.magedu.com

Generic Webhook Trigger示例

  • 创建一个Pipeline项目,定义其使用Generic Webhook

  • Trigger触发器,一个示例代码如右侧所示

  • 使用如下命令即可触发构建操作

~]# curl -X POST -H "Content-Type: application/json" -d '{ "ref": "refs/heads/main" }' -vs http://jenkins.magedu.com:8080/generic-webhooktrigger/invoke?token="fClZ0e/kTcqL2ARh7YqxW/3ndOCZA2SqfKnRTLat“ * Trying 172.29.7.9:8080... * TCP_NODELAY set * Connected to jenkins.magedu.com (172.29.7.9) port 8080 (#0)

POST /generic-webhook-trigger/invoke?token=fClZ0e/kTcqL2ARh7YqxW/3ndOCZA2SqfKnRTLat HTTP/1.1 > Host: jenkins02.magedu.com:8080 > User-Agent: curl/7.68.0 …… * upload completely sent off: 28 out of 28 bytes * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Tue, 29 Nov 2022 07:32:54 GMT …… * Connection #0 to host jenkins.magedu.com left intact {"jobs":{"pipeline-job007":{"regexpFilterExpression":"","triggered":true,"resolvedVariables":{"ref":"refs/heads/main"},"regexp FilterText":"","id":137,"url":"queue/item/137/"}},"message":"Triggered jobs."}

pipeline { agent any tools { maven 'maven-3.8.6' } triggers { GenericTrigger( genericVariables: [ [key: 'ref', value: '$.ref'] ], token: 'fClZ0e/kTcqL2ARh7YqxW/3ndOCZA2SqfKnRTLat', causeString: 'Triggered on $ref', printContributedVariables: true, printPostContent: true ) } parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" HarborServer='hub.magedu.com' ImageUrl="ikubernetes/spring-boot-helloworld" ImageTag="latest" } stages { …… } }

http://www.magedu.com

Generic Webhook Trigger示例(2)

 Generic Webhook Trigger亦可由GitLab仓库事件进行触发

http://www.magedu.com

在Pipeline Job中发送邮件通知

  • 声明式pipeline的post{}里可以使用mail step来发送

  • 通知

◼ 该步骤支持有参数有如下几个

  • subject:邮件主题;

  • to:收件人地址;

  • ◆ body:邮件正文; ◆ from:发件地址;

pipeline { agent any tools { maven 'maven-3.8.6' } triggers { …… } parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" HarborServer='hub.magedu.com' ImageUrl="ikubernetes/spring-boot-helloworld" ImageTag="latest" } stages { …… } post { always { mail to: 'mage@magedu.com', subject: "Status of pipeline: ${currentBuild.fullDisplayName}", body: "${env.BUILD_URL} has result ${currentBuild.result}" } } }

http://www.magedu.com

Dingtalk 群通知

  • dingtalk插件会引入多个step,以下是其语法格式

    • Jenkins上需要提前部署dingtalk插件,并完成配置

dingtalk ( robot: '', type: '', at: [], atAll: false, title: '', text: [], messageUrl: '', picUrl: '', singleTitle: '', btns: [], btnLayout: '', hideAvatar: false )

  • 各参数说明:

    • https://jenkinsci.github.io/dingtalk-plugin/guide/pipeline.html

http://www.magedu.com

测试向Dingtalk 群发送通知

 将此前示例中的email通知修改为dingtalk通知方式

  • 通知结果如下图中最后一条消息所示

  • 注意:即便是钉钉机器人引用错误,Jenkins的执行

  • 状态也不会报错

pipeline { agent any tools { maven 'maven-3.8.6' } triggers { …… } parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" HarborServer='hub.magedu.com' ImageUrl="ikubernetes/spring-boot-helloworld" ImageTag="latest" } stages { …… } post { always { dingtalk( robot: 'dingtalk', type: 'TEXT', text: [ "Status of pipeline: ${currentBuild.fullDisplayName}", "${env.BUILD_URL} has result ${currentBuild.result}." ]) } } }

http://www.magedu.com

Wechat 群通知

  • Qy Wechat Notification插件会引入4个step,下面的其配置参数

    • failNotify : boolean (optional)

    • mentionedId : String (optional)

    • mentionedMobile : String (optional)

    • webhookUrl : String (optional)

pipeline { agent any tools { maven 'maven-3.8.6' } triggers { …… } parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { GitRepo="http://gitlab.magedu.com/root/spring-boot-helloWorld.git" HarborServer='hub.magedu.com' ImageUrl="ikubernetes/spring-boot-helloworld" ImageTag="latest" } stages { …… } post{ success{ qyWechatNotification failNotify: true, webhookUrl: 'https://qyapi.weixin.qq.com/cgibin/webhook/send?key=c79e3215-d39f-44a7-a760-fa0ab63ca46b' } failure{ qyWechatNotification failNotify: true, webhookUrl: 'https://qyapi.weixin.qq.com/cgibin/webhook/send?key=c79e3215-d39f-44a7-a760-fa0ab63ca46b' } } }

http://www.magedu.com

在Pipeline上调用SonarQube进行代码质量评估

  • 配置Jenkins使用sonar-scanner进行代码质量扫描,并

  • 将结果报告给SonarQube Server的主要步骤如下

    • 首先,在Jenkins上安装 SonarQube Scanner 插件

    • 其次,配置Jenkins对接到SonarQube Server

    • 第三,配置Jenkins的全局工具sonar-scanner

    • 第四,在SonarQube上添加回调Jenkins的Webhook

    • 第五,在Pipeline Job上调用sonar-scanner进行代码质量

    • 扫描

    • 最后,通过SonarQube确认扫描结果的评估;

pipeline { … stages { stage('Source') { steps { git branch: 'main', url: "${GitRepo}" } } ... stage("SonarQube Analysis") { steps { withSonarQubeEnv('SonarQube-Server') { sh 'mvn sonar:sonar' } } } stage("Quality Gate") { steps { timeout(time: 30, unit: 'MINUTES') { waitForQualityGate abortPipeline: true } } } ... } post{ ... } }

http://www.magedu.com

在Pipeline上调用SonarQube进行代码质量检查

 SonarQube Scanner插件会引入两个step

◼ withSonarQubeEnv:准备SonarQube Scanner环境

◆ 至少提供一个参数:Jenkins全局配置的SonarQube Server的名称

◼ waitForQualityGate:等待SonarQube分析完成,返回质量门状态

◆ 会暂停当前Pipeline Job,并等待先前提交的SonarQube分析完成并返回质量门状态

◆ 将必选参数abortPipeline的值设置为true,表示质量门状态为非绿色时将中止当前Pipeline

http://www.magedu.com

Pipeline Job 的分布式构建

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Pipeline agent配置段语法介绍

  • 声明式Pipeline使用agent指定运行Job的目标节点

  • agent可接受多种形式的参数

    • any:任何可用节点

    • none:用于pipeline顶端时表示不定义默认的agent,这就需要为每个stage单独指定

    • label { label "

    • node { label "

    • docker:在指定的容器中运行pipeline或stage代码,该容器动态创建并运行于预配置的可运行容器的node上,

    • 或能够匹配到指定label的node上;可用参数如下

      • image、label、args、rgistryUrl和registryCredentialsId
    • dockerfile:功能上类似于上面docker参数,但容器镜像通过指定的docker进行构建;该参数要求Jenkinsfile必

    • 须从Multibranch Pipeline或者Pipeline from SCM中加载;可用参数如下

      • filename、dir、label、additionalBuildArgs、args、registryUrl和registryCredentialsId
    • kubernetes:于Kubernetes集群上指定的Pod中运行stage或pipeline代码,该参数同样要求Jenkinsfile必须从

    • Multibranch Pipeline或者Pipeline from SCM中加载

      • 需要在kubernetes参数中指定Pod模板
  • 参考:https://www.jenkins.io/doc/book/pipeline/syntax/

http://www.magedu.com

测试在指定的agent上执行任务

  • 在pipeline中可使用agent指令显式为Job指定执行位置,

  • 例如右侧的agent指令,使用“label”表达式来过滤具有指定标签的节点

pipeline { agent { label 'linux-agent' } tools { maven 'maven-3.8.6' } parameters { booleanParam(name: "PUSH", defaultValue: true) } environment { …… } stages { …… stage('Docker Build') { agent { label 'master' } steps { sh 'docker build -t ${HarborServer}/${ImageUrl}:${ImageTag} .' } } stage('Docker Push') { agent { label 'master' } steps { …… } } } post{ …… } }

http://www.magedu.com

在Pipeline上使用docker agent

  • Pipeline Plugin自2.5版(2017年2月1号发布)开始内置了与Jenkinsfile中的Docker进行交互的能力,因而支持直接使用docker容器作为动态agent

    • 它依赖于用户指定的image创建容器

    • 运行agent容器的节点取决于master调度的结果,或由用户通过label进行限定

  • 在Docker容器中运行stage的方法

    • 使用agent docker

      • 语法:agent { docker {…}}

      • 至少要通过image参数指定运行容器时使用的镜像

    • 它可能会在可用的jenkins现有的分布环境的任一节点上尝试创建容器

      • 若要限制仅在那些支持创建docker容器的环境上运行容器,需要额外使用label标签

      • label标签可限制要运行指定的容器的目标节点,例如那些配置了Docker Engine的节点

http://www.magedu.com

Jenkins Pipeline与Docker集成

  • 在计划运行Docker容器的各Jenkins节点上完成如下设定

    • 安装并设定好Docker环境

    • (可选)将jenkins用户加入到docker组,以确保其有权限运行docker命令创建容器 ◆ ~# usermod -a -G docker jenkins

  • 随后,可在master上,创建一个pipeline 进行测试,示例代码如下

pipeline {
agent {
docker {
image 'eclipse-temurin:17-jre-alpine'
label 'master'
}
}
stages {
stage('Test') {
steps {
sh 'java --version'
}
}
}
}

http://www.magedu.com

在Pipeline中使用多个容器

 agent指令也可用于stage配置段中,用于为该配置段指定专用的节点

pipeline { agent none stages { stage('JDK') { agent { docker { image 'eclipse-temurin:17-jdk-alpine' label 'master' } } steps { sh 'java --version' } } stage('Maven') { agent { docker { image 'maven:3.8.6-eclipse-temurin-17-alpine' label 'master' } } steps { sh 'mvn --version' sh 'java --version' } } }

}

http://www.magedu.com

容器的其它可用参数

 以docker{}为动态agent时,除了image外,我们还可以为docker设定更多的参数

◼ label:docker容器可运行于任何运行有Docker Damon的主机上,label选项便可基于标签过滤出这样一组特定的主机来运行临时的docker agent;因而,它与agent上的label的作用相同;

  • args:在创建容器的命令上,传递的自定义参数,例如,使用“-v Con_PATH:Host_PAHT”来使用存储卷;

  • ◼ registryUrl:特定镜像registry服务的URL;

  • registryCredentialsId:存储有认证到镜像registry上的Credential的ID;

  • 下面示例中的docker agent,就以指定的凭证认证到私有registry中来获取镜像;

agent { docker { image hub.magedu.com/node:alpine' label ‘docker_host' registryUrl 'https://hub.magedu.com/' registryCredentialsId ‘hub-user-magedu' } }

http://www.magedu.com

在Pipeline上使用Kubernetes Agent

  • Jenkins支持以Kubernetes Pod的形式运行动态agent,实现规模可伸缩的Jenkins Cluster ◼ 相应agent的功能由Pod模板通过镜像、存储卷等配置进行定义

    • Pod模板上可同时配置多个容器,Pipeline支持在stage里面使用“container(){}”指定step运行在的容器

    • ◼ 需要在Jenkins上事先安装“kubernetes”插件

配置好可用的
Kubernetes集群

http://www.magedu.com

定义Pod模板及其容器

  • Pod模板

    • 可定义要在Pod上创建或添加的Containers、 Volumes、Environments和Annotations等信息

    • 可以不添加任何容器,其默认即会基于 jenkins/inbound-agent Image创建一个容器

    • 通常可按需添加要运行的容器,用于为特定的构建步骤提供满足特殊需求的基础环境

      • 自定义了容器时,Pod上默认也会运行一个 jnlp容器

      • pipeline的各step默认运行于jnlp容器上

      • 明确使用container(){}这一step,才能在指定的容器中运行命令

此处标签的功用,与手动添加的各类Agent上的标签类似;多个标签间以空白分隔

  • Pod模板也能够直接在Pipeline中直接进行定义,而不必基于图形界面进行

  • Pod模板支持继承机制

    • 定义好的模板,可直接在kubernetes agent上继承使用

该模式默认会使用jenkins/inbound-agent 镜像做为slave Pod的基础容器,该处添加马哥教育的容器将作为第二、第三容器使用

http://www.magedu.com

基于Pod Agent的pipeline示例

 运行一个pipeline,简单测试Pod slave的运行状态 ◼ 如下的配置示例中,agent kubernetes直接继承了此前配置的kube-agent模板

// Author: "MageEdu mage@magedu.com" // Site: http://www.magedu.com pipeline { agent { kubernetes { inheritFrom 'kube-agent' } } stages { stage('Testing...') { steps { sh ''' java -version echo ${NODE_NAME} ''' } } } }

agent kubernetes中可用的各具体参数请参考Kubernetes插件文档;

http://www.magedu.com

在Pod中运行maven容器

pipeline {
agent {
kubernetes {
新增一个Pod模板, agent kubernetes继承自新建
inheritFrom 'kube-maven'
用于构建maven应用的kube-maven模板
}
}
stages {
stage('Testing...') {
steps {
container('maven') {
sh '''
mvn --version
java --version
'''
}
}
}
}
}
steps中使用了container
步骤,以指定运行命令的容器在容器模板上自定义了一个maven容器

http://www.magedu.com

示例: 在Pod中构建maven应用

 构建maven应用,并完成代码质量扫描

pipeline {

agent { kubernetes { inheritFrom 'kube-maven' } }

... stages {

stage('Source') {

steps { git branch: 'main', url: "${GitRepo}" }

}

stage('Build') {

steps {

container('maven') { sh 'mvn -B -DskipTests clean package' }

}

} stage('Test') {

steps {

container('maven') { sh 'mvn test' }

}

} stage("SonarQube Analysis") {

steps {

withSonarQubeEnv('SonarQube-Server') {

container('maven') { sh 'mvn sonar:sonar' } } } } stage("Quality Gate") { steps {

timeout(time: 30, unit: 'MINUTES') { waitForQualityGate abortPipeline: true

} } } } }

http://www.magedu.com

添加Dind(docker in docker)容器以构建和推送Image

再添加一个容器dind,它基于
docker in docker的机制,支持在容器内构建并推送容器镜像在Pod模板上添加一个用于缓存
maven扩展的卷,从而支持跨
Pod共享缓存将Pod所在节点上的Docker
Engine的套接字文件挂载至容器内部以支持在容器内部执行
docker客户端命令

http://www.magedu.com

示例: 在Pod中构建maven应用并推送Image

 构建Maven工程,而后制作Image,并完成推送

pipeline {

agent { kubernetes { inheritFrom 'kube-maven’ } }

... stages {

... stage('Build Image') { steps { container('dind') { sh 'docker build -t ${HarborServer}/${ImageUrl}:${ImageTag} .' }

}

} stage('Push Image') { when { expression { params.PUSH } beforeAgent true } steps {

withCredentials([usernamePassword(credentialsId: 'harbor-user-credential', ...)]) { container('dind') {

sh “docker login -u ${env.harborUserName} -p …" sh 'docker image push ${HarborServer}/${ImageUrl}:${ImageTag}'

} } } } } post{

... } }

http://www.magedu.com

推送Docker Image至Registry的安全方法

 问题和解决方案

  • 在stage中,直接运行docker login命令引用认证凭据向Registry进行认证存在安全风险

  • docker-build-step插件引入的step能够以更安全的方式推送Image

在stage中使用docker login命令直接引用credential的警告信息

pipeline { agent { kubernetes { inheritFrom 'kube-maven’ } } ... environment { ... RegistryCredential='harbor-user-credential' RegistryUrl="https://${HarborServer}" } stages { ... stage('Build Image') { steps { container('dind') { script { dockerImage = docker.build("${HarborServer}/${ImageUrl}:${ImageTag}") } } } } stage('Push Image') { … steps { container('dind') { script { docker.withRegistry( RegistryUrl, RegistryCredential ) { dockerImage.push() } } } } } } }

http://www.magedu.com

部署应用至Kubernetes集群

pipeline {
 添加kubectl容器以完成应用部署
agent { kubernetes { inheritFrom 'kube-maven’ } }
...
environment {
...
RegistryCredential='harbor-user-credential'
RegistryUrl="https://${HarborServer}"
}
stages {
...
stage('Update-manifests') {
steps {
container('jnlp') {
sh ‘sed -i “s#IMAGE#${HarborServer}/${ImageUrl}:${ImageTag}#gi” <br>deploy/all-in-one.yaml'
}
}
}
stage('Deploy') {
steps {
container('kubectl') {
withKubeConfig([credentialsId: 'k8s-hello-admin-token‘, <br>serverUrl: 'https://kubernetes.default.svc']) {
sh 'kubectl apply -f deploy/all-in-one.yaml'
}
}
}
}
}
}

http://www.magedu.com

Jenkinsfile入库

  • Jenkins能以轻量级检出的方式从SCM(Source Control

  • Management)中获取Jenkinsfile,并根据该文件自动配置流水线

  • Pipeline Job从SCM中加载Jenkinsfile,还支持轻量级检出的方式,即仅从代码仓库中获取Jenkinsfile文件

http://www.magedu.com

多分支流水线

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

多分支流水线概述

  • 多分支(multi-branch)流水线是基于git

  • 分支创建Jenkins pipeline的机制,它可以自动在SCM中发现新分支,并自动为新分支创建pipeline

    • 不期望出现在pipeline中的分支需要通过

    • 排除机制予以排除在外

  • Jenkins的多分支流水线项目类型支持

  • Github、GitLab和Bitbucket等

  • 多分支pipeline基于PR(pull request)进行分

  • 支发现

    • 有人从branch中执行PR操作时,Pipeline

    • 会自动发现分支

    • PR上升将自动触发构建操作

http://www.magedu.com

多分支和pipeline

  • 右图示例中的仓库共有master、develop和

  • feature三个分支

    • 三个分支分别有其不同的pipeline

      • master分支有完整的CI/CD pipeline

      • develop分支仅有CI pipeline

      • feature分支仅有单元测试的功能

  • Jenkins Server会自动从仓库中发现所有分支,

  • 并提取每个分支,而后根据Jenkinsfile运行 pipeline;

  • 之后,每当git仓库上的任何分支发生新的代

  • 码变更时,Jenkins Server将自动触发相应的 pipeline

http://www.magedu.com

多分支pipeline的简要工作逻辑

  • 基于Feature、Develop和Master分支构建内

  • 部研发工作逻辑是较为常见的工作流模型

    • Developer通过具体的feature分支开发新的

    • 功能,并向feature提交代码;

    • 每当开发人员从feature分支提PR至develop

    • 分支时,Jenkins pipeline都应触发以运行单元测试和静态代码分析;

    • feature分支中的代码测试成功后,开发人

    • 员将PR合并到develop分支;

    • 在将要发布代码时,开发人员将PR从

    • develop分支提到master,此时将触发 Jenkins上的pipeline运行单元测试、代码分析等,并将代码部署到dev/QA环境;

http://www.magedu.com

创建Multibranch Pipeline

 选定项目类型为“多分支流水线”

http://www.magedu.com

设置代码仓库地址

  • 仍以Spring-Boot-HelloWorld项目为例

    • Multibranch Pipeline的脚本必须定义在名

    • 为“Jenkinsfile”的文件中

◼ 该文件一般是直接存储于项目源码的根路径下,例如,存储于spring-boothelloworld/目录下

http://www.magedu.com

触发Multibranch Pipeline

  • 未在Jenkinsfile中定义的多分支流水线,

  • 可以通过手动,或者周期性扫描触发;

    • 右图是扫描并触发分支发现和流水线操作

    • 后的示例界面;

main分支

develop分支

http://www.magedu.com

孤儿任务(Orphaned Item)处理策略

  • 代码仓库中删除了某分支之后,Jenkins也应该在多分支流水线中将该分支相关的任务予以删除; ◼ 删除时间取决于下次扫描的时间,而在此之前,Jenkins上的该任务就称为孤儿任务;

    • 孤儿任务的保存时长也可由用户自行定义;

http://www.magedu.com

Multibranch Pipeline中的GitLab Trigger

  • 与其它项目类型不同的是,Multibranch Pipeline

  • 不需要触发器设置,用户只需要在GitLab项目上创建一个webhook(表现为一个URL)即可; 当GitLab向该URL发送POST请求时,将会触发相应的Jenkins多分支流水线上的分支索引扫描, Jenkins随后会根据需要进行必要的构建操作

  • 需要在其它情形中使用触发器时,也可遵循类

  • 似如右侧的语法进行

http://www.magedu.com

GitOps 简介

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Pipeline 模型的演进

  • Push Pipeline

    • 传统上的大多数CI/CD工具都使用基于Push的模型,即代码从CI系统开始,可以经由一系列脚本代码自动化完成其执行路径,或手动完成相关的Stage;

CD的步骤中可能会用到凭据,将这些凭据保存于代码中可能会导致潜在的风险;

  • Pull Pipeline

    • WeaveNet倡导一种新的基于Image Pull的Pipeline模型,并且将凭据直接保存于集群之上

CI Pipeline根据开发人员提交的代码变更构建并推送新的Image后,负责监视代码仓库的Deployment Automator负责拉取该Image并更新config repo,而 Deployment Synchronizer随后会察觉到集群上的应用状态已然落后于config repo,遂获取config repo中的配置文件并将新的Image更新到集群之上;

GitOps

http://www.magedu.com

Weave Cloud的DevOps方法

  • Weave Cloud的DevOps方法在CD阶段使用Pull机制,它依赖于两种特殊组件 ◼ Config Updater:用于监视image的变动并更新配置清单;

    • Deploy Synchronizer:维护应用的当前状态;
  • 工作机制:Pull Pipeline模型的中心是配置中心或配置仓库(config repo)

    • 开发人员推送代码变更至代码仓库中;

    • CI Server 自动完成CI Pipeline并生成Docker Image;

    • Config Updater,注意到Image的变动,并以此更新config repo中的配置清单;

    • Deploy Synchronizer 在察觉到集群当前状态已过期后,将从配置仓库中pull到变更的配置清单并部署到集群上;

图片来源:https://geekflare.com/

http://www.magedu.com

一个典型的GitOps Pipeline

  • GitOps模型中存在两个Git仓库

    • 代码仓库(code repo):开发人员使用

      • 推送代码变更
    • 配置仓库(config repo):运维人员使用

      • 推送配置变更

      • 包括基础设施配置以及应用配置

  • 简要工作流程

    • 开发人员推送代码变量至代码仓库

    • CI工具链完成测试和构建

    • CD工具链完成测试和交付(新版本的Image推送至工件仓库)

  • Config Update(即Deployment Automator)将 Image的变更信息推送至配置仓库

  • 随后,根据使用的分支和发布策略,完成应用的部署

http://www.magedu.com

GitOps的实施要点

  • GitOps强调的重心在于,它要求对应用程序、环境、部署操作和基础架构进行的所有变更 ,都应以声

  • 明式描述文件存储于Git中;

    • 基础设施:例如,以Terraform模块或Cloudformation脚本形式存在的声明,此外,aws也支持使用Kops在基础

    • 设施上拉起一个集群等;

    • Kubernetes的资源配置:主要包括Deployments、Services、StatefulSets、PVC和用到的镜像等相关的配置 ◆ 使用Helm包管理器打包管理一个应用程序相关的配置应该是更好的选择;

    • 环境配置:这里仍然是指Kubernetes配置,它主要包括Kubernetes上的ConfigMap资源对象

      • 这些配置同样可以打包在Helm Chart之中;
    • 应用程序代码:存储于git之中,但需要通过声明式的Dockerfile打包为docker image

      • Dockerfile自身同样也样存储于程序的代码仓库中;
  • 基于Pull Request完成所有需要进行变更

    • master(或main)分支用于反映系统的当前状态;

    • 在master分支上打开新的PR即可完成可能需要的任何更新;

    • PR合并后,将触发CD/GitOps管道;回滚同样由PR触发;

  • 自愈

    • Git配置仓库保存有应用的预期状态,而Kubernetes上保存有应用的当前状态

    • 需要一个专用的Operator来负责实现该功能

http://www.magedu.com

如何实施GitOps

  • 遵循GitOps的标准流程

 基于OAM框架模型,DevOps团队协同管理声明式配置清单

  • 选择合理的工具集

  • 从变更频率高或易于中断的应用程序开始

图片来源:https://itnext.io/

http://www.magedu.com

GitOps工具集

  • 除了Kubernetes集群外,GitOps的实施通常还要依赖于如下工具

    • Git和Git Server:显然,这是实施GitOps的基础和中心;GitHub、GitLab或任何形式的支持自动化Pipeline必

    • 要功能的Git Server均可;

    • CI Server:CI Pipeline的基础设施,如Jenkins和Tekton等;

    • Agent Operator(Deploy Operator):CD Pipeline的基础组件

      • GitOps中,可用的解决方案包括ArgoCD、Flux、Jenkins X、WKSctl和Gitkube等;
    • Canary Deployer

      • flux提供的名为Flagger的Kubernetes Operator支持金丝雀发布

      • 它能够结合Istio、Linkerd、App Mesh、NGINX、Skipper、Contour、Gloo或Traefik等自动实施流量路由和流量迁移, 以及根据Prometheus实现Canary分析

图片来源:https://itnext.io/

http://www.magedu.com

GitOps基础

  • 什么是GitOps?

    • 一套使用Git来管理基础架构和应用配置的实践,一项事关部署流程的技术

    • 在运行过程中以Git为声明性基础架构和应用的单一事实来源

    • 使用Git拉取请求来自动管理基础架构的置备和部署

    • Git存储库包含系统的全部状态,因此系统状态的修改痕迹既可查看也可审计

    • 与DevOps相比,GitOps更侧重于基于工具和框架的实践

    • 简单来说:GitOps = IaC + MRs + CI/CD

      • MRs:Merge Requests
  • 如何开始使用GitOps?

    • 存在支持声明式管理的基础架构

      • 天然适配Kubernetes和云原生开发的运维模式

      • 原生支持基于Kubernetes的持续部署

  • 用于构建开发流程、对应用进行编码、管理配置、置备 Kubernetes 集群以及在Kubernetes 或容器注册中心进行部署

http://www.magedu.com

GitOps示例一:FluxCD

 Manage Helm releases with Flux

http://www.magedu.com

GitOps示例二:ArgoCD

 ArgoCD:专用于Kubernetes的声明式GitOps CD工具;

图片来源:https://nortal.com/

http://www.magedu.com

Flagger

  • 支持Canary releases、A/B testing、Blue/Green mirroring等部署策略,它依赖于Service Mesh或Ingress Controller实现流量策略

  • 支持基于Prometheus、Datadog等进行发布分析,以及基于Slack等进行告警;

图片来源:https://github.com/fluxcd/flagger

http://www.magedu.com

GitOps示例:Tekton and ArgoCD

 Modern CI/CD workflows for serverless applications with Red Hat OpenShift Pipelines and Argo CD

  • Tekton:CI Pipeline

◼ ArgoCD: CD Pipeline

图片来源:https://developers.redhat.com/

http://www.magedu.com

基于Tekton和ArgoCD的GitOps示意图

  • Tekton负责构建CI Pipeline

 ArgoCD负责构建CD Pipeline

http://www.magedu.com

ArgoCD 快速入门

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

ArgoCD概览

 Argo项目于2017年由Applatix公司创立,2018 年初被Intuit 收购;

 之后,BlackRock为Argo项目贡献了Argo Events这一子项目;

 Argo及其子项目为Workflow、Trigger和Application的管理提供了一种简单便捷的方式

◼ Argo的所有组件都通过专用的Kubernetes CRD实现

◼ 支持使用或集成其他CNCF项目,如gRPC、Prometheus、NATS、Helm和CloudEvents等

 Argo生态目前主要由四个子项目组成

◼ Argo Workflows

◆ 第一个Argo项目

◆ 基于Kubernetes平台的原生工作流引擎,支持DAG和step-based工作流

  • Argo Events

◆ Kubernetes上的基于事件的依赖管理器,用于触发Kubernetes中的Argo工作流和其他操作

  • Argo CD

◆ 由Argo社区和Intuit维护的开源项目

◆ 支持GitOps范式的的声明式Kubernetes资源管理

  • Argo Rollouts

    • ArgoCD的高级交付策略工具

◆ 支持声明式渐进式交付策略,例如canary 、blue-green等

http://www.magedu.com

ArgoCD简介

  • ArgoCD是什么?

    • 将应用程序部署到Kubernetes之上的GitOps工具

    • 核心组件:Application Controller及相关的一组CRD

    • 基础工作模型

      • 以特定 Repository (配置仓库)为应用程序部署和管理的惟一可信源,该Repository负责定义Application的期望状态

      • Application Controller负责将Repository中定义的Application运行于一个特定的目标 Kubernetes Cluster 之上

      • Application Controller持续监视、对比Application的期望状态和实际状态,并确保实际状态与期望状态一致

Application
Application

http://www.magedu.com

声明式配置

  • Application CRD

    • 定义由ArgoCD管理的应用程序

    • 定义的这些应用程序受控于Application Controller

  • ApplicationSet CRD

    • 以模板化形式自动生成由ArgoCD管理的应用程序

    • 支持从多个不同的角度构建模板,例如不同的Git Repo,或者不同的Kubernetes Cluster等

    • ApplicationSet受控于专用的ApplicationSet Controller

  • AppProject CRD

    • 为Application提供逻辑分组,同时提供如下功能

      • 限制可用部署的内容,例如指定受信任的Git Repository白名单

      • 限制应用程序可以部署到目标位置,包括目标集群和目标名称空间

      • 限制可以部署或者不能部署的资源类型,例如RBAC、CRD、DaemonSet等

    • 每个Application都必须隶属某个AppProject,未指定时,则隶属于名为“default”的默认项目

    • default项目可以被修改,但不能删除

http://www.magedu.com

核心工作模型

  • ArgoCD的两个核心概念为 Application 和 Project ,它们可分别基于Application CRD和AppProject CRD创建

  • Application

    • 从本质上来说,它包含如下两个部分

      • 一组在Kubernetes上部署和运行某个应用的资源配置文件

      • 这组资源相关的source和destination

        • ⚫ source:定义从何处获取资源配置文件,包括repoURL和配置文件所在的目录

        • ⚫ destination:定义这组资源配置文件中定义的对象应该创建并运行于何处,其中的Cluster可以是ArgoCD所在集群之外的其它集群

Application
Source
指定获取资源配置文件的位置
repoURL Repository
path
Destination
指定资源要部署到的目标位置
cluster Repository
namespace

  • 支持的配置管理工具

    • Helm、Kustomize、Jsonnet

http://www.magedu.com

核心工作模型(2)

 Application(续)

◼ ArgoCD Application还存在两个非常重要的属性:Sync Status和Health Status

◼ Sync Status:Application的实际状态与Git Repo中定义的期望状态是否一致;

  • Synced:一致

◆ OutOfSync:不一致

◼ Health Status:Application的健康状态,是各资源的健康状态的聚合信息

  • Healthy:健康

◆ Processing:处于尝试转为健康状态的进程中

◆ Degraded:降级

◆ Missing:缺失,即在GitRepo中存在资源定义,但并未完成部署

http://www.magedu.com

核心工作模型(3)

 Project

  • 能够将Application进行分组的逻辑组件

  • 主要用于将租户或团队间的Application彼此隔离,并且支持在组内进行细粒度的权限管控

  • ◼ 支持为内部Application上的Source和Destination分别指定各自的黑白名单

图源:《GitOps and Kubernetes》

http://www.magedu.com

ArgoCD架构示意图

http://www.magedu.com

ArgoCD程序组件

  • ArgoCD API Server

    • ArgoCD Server API接口,为Web UI、CLI,以及相关的CI/CD系统提供服务,相关功能包括

      • 管理应用程序并报告其状态

      • 调用并发起应用程序的特定操作,例如sync、rollback以及用户定义的其它行为

      • 管理Repository和Cluster相关的凭据

      • 将身份认证与授权功能委派给外部IdP(identity providers)服务

      • 强制实施RBAC

◆ 监听及转发Git Webhook相关的事件等

  • Repository Server

    • 内部服务,用于为相关的Git仓库维护一个本地缓存

    • 负责根据以下输入生成和返回Kubernetes资源配置

      • repository URL、revision (commit, tag, branch)及application path等

      • template specific settings: parameters, ksonnet environments, helm values.yaml

  • Application Controller

    • 负责为管理的目标应用程序提供遵循Kubernetes控制器模式的调谐循环

    • 它持续监视正在运行的应用程序,并将其当前的活动状态与定义在GitRepo中的期望状态进行比较

    • ◼ 确保活动状态不断逼近或等同于期望状态

http://www.magedu.com

ArgoCD程序组件

  • ApplicationSet Controller

    • 以模板化形式自动生成由ArgoCD管理的应用程序

    • 支持从多个不同的角度构建模板,例如不同的Git Repo,或者不同的Kubernetes Cluster等

    • ApplicationSet受控于专用的ApplicationSet Controller

  • Notification Controller

    • 持续监控ArgoCD管理的Application,并支持通过多种不同的方式将其状态变化通知给用户

    • ◼ 支持Trigger和Template

  • Redis和Dex-Server

    • Redis负责提供缓存服务

    • 而Dex-Server则主要用于提供in-memory Database

  • Argo Rollouts

    • 可选组件,需要单独部署,由一个控制器和一组CRD组成

    • 与Ingress Controller和ServiceMesh集成,为Application提供高级部署功能,如blue-green、canary、canary analysis 和渐进式交付等

http://www.magedu.com

ArgoCD的部署要点

  • ArgoCD有两种部署方式:多租户部署和核心化部署

  • 多租户

    • 常用于为多个应用程序开发团队提供服务,并由平台团队维护的场景

    • 有两类可选择的部署方式

      • 非高可用性部署:适用于演示和测试的目的

      • 高可用部署:适用于生产用途

    • 支持用户通过Web UI或CLI进行访问

    • 支持集群级部署和名称空间级两种安装机制

      • 配置文件install.yaml:具有集群管理员访问权限的集群级安装;

      • 配置文件namespace-install.yaml:仅需要名称空间级别权限的安装;

  • 核心化部署

    • 安装的组件较小且更易于维护,它不包含API Server和UI,且不提供高可用机制

    • 仅适用于独立使用ArgoCD且不需要多租户特性的集群管理员

    • 用户要通过Kubernetes的访问权限来管理ArgoCD

http://www.magedu.com

ArgoCD的部署步骤

  • 在Kubernetes集群上部署ArgoCD

    • 采用的示例环境

      • 集群级别的部署

      • 非高可用模式

    • 默认的部署配置使用argocd名称空间,资源引用的路径亦使用该名称空间

      • kubectl create namespace argocd

      • kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

  • 在管理节点上安装ArgoCD CLI

  • 将ArgoCD API Server相关的Service暴露到集群外部

    • LoadBalancer Service、Ingress或者Port Forwarding
  • 使用ArgoCD CLI或Web UI完成登录

◼ 默认密码:kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

  • 登录:argocd login <ARGOCD_SERVER>

  • 修改密码:argocd account update-password

  • 添加一个部署Application的目标Kubernetes Cluster

    • Application部署的目标集群与ArgoCD自身在同一集群时,该步骤可选

http://www.magedu.com

管理Application的方式

 命令式命令:argocd app命令

 Application CRD资源配置文件

 Web UI

http://www.magedu.com

通过Web UI添加Application

GENERAL用于配置Application
的元数据及Sync策略

http://www.magedu.com

通过Web UI添加Application(2)

argocd-example-apps是由ArgoCD提供的示例程序guestbook
https://kubernetes.default.svc
指向的目标集群是ArgoCD自行所在的Kubernetes集群

http://www.magedu.com

自动同步策略

  • 自动同步策略允许ArgoCD在检测到GitRepo与实际状态之间存在差异时自动启动同步操作 ◼ Prune Resource(自动修剪):集群上某个资源在GitRepo中找不到对应的配置时,自动删除集群上的该资源 ◼ Self Heal(自愈):因各种原因(如手动修改)集群上资源的实时状态而导致与GitRepo不匹配时,自动将实际状态与GitRepo的期望状态同步;

    • 1、自动同步仅发生在应用处于OutOfSync状态时,ArgoCD并不会对处于Synced或Error状态的Application执行自动同步; 2、对于GitRepo上的一次提交,自动同步仅会执行一次,除非同时启用Self-Heal机制; 3、启用了自动同步的Application不支持RollBack;

http://www.magedu.com

同步选项

 同步选项(Sync Options)用于禁用或启用同步过程中的某些特性

  • ApplyOutOfSyncOnly

◆ 仅对那些处于OutOfSync状态的资源执行同步操作

  • PrunePropagationPolicy

    • 资源修剪传播策略,默认使用foreground策略

    • 另外可选的策略还有background和orphan

  • PruneLast

  • 在同步操作的最后再执行修剪操作,即其它资源已经部署且转为健康状态后再进行Prune

  • ◼ Replace

    • 对资源的修改,以replace方式进行,而非默认的apply
  • FailOnSharedResource

    • 默认的同步操作不会考虑GitRepo中定义的资源是否已经被其它Application所使用

    • 将该选项设置为true,意味着在发现资源已经被其它Application所使用时,则将同步状态设置为fail

  • RespectIgnoreDifferences

    • 在同步阶段忽略期望状态的字段
  • CreateNamespace

◆ 创建缺失的名称空间

  • Validation

    • 是否执行资源规范格式的校验,相当于“kubectl apply --validate={true|false}”,默认为true

http://www.magedu.com

使用argocd CLI管理Application

 管理Application的命令为“argocd app”

  • 子命令

    • 基础命令:create、delete、edit、get、list

    • 日常管理类命令:diff、logs、sync、rollback、history、terminate-op

◼ 其它管理命令:manifests、delete-resource、patch、patch-resource、unset、wait

  • 向ArgoCD上添加Application

    • argocd app create APPNAME [flags]

    • 常用的flags

◆ --repo string:Git Repository URL

◆ --path string:Git Repository中含有配置文件的子目录路径

  • --directory-recurse:对目录进行递归

◆ --revision string:要使用的Revision,通常是指源码库上的branch、tag、commit或Helm chart版本 ◆ -f, --file string:部署Application用到的配置文件路径或URL,优先级高于“--repo”和“--path”选项

  • --release-name string:配置为Helm Charts时,为其指定release的名称

  • --project string:隶属的Project,默认为default

  • --dest-server string:目标Kubernetes集群的URL(API Server的URL);

  • --dest-namespace string:目标名称空间

http://www.magedu.com

Argo Rollouts

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

Argo Rollouts概览

  • Argo Rollouts

◼ 由一个控制器和一组CRD组成,可为Kubernetes提供高级部署功能,包括

  • blue-green

◆ canary

  • canary analysis

◆ experimentation

◆ progressive delivery

  • 支持与Ingress Controller(Nginx和ALB)及ServiceMesh(Istio、Linkerd和SMI)集成,利用它们的流量治理能力实现流量迁移过程

◼ 能够查询和解释来自多种指标系统(Prometheus、Kubernetes Jobs、Web、Datadog等)的指标来验证BlueGreen或Canary部署结果,并根据结果自动决定执行升级或回滚

◼ 几个相关的CRD

◆ Rollout 、AnalysisTemplate、ClusterAnalysisTemplate和AnalysisRun

 基本工作机制

◼ 与Deployment相似,Argo Rollouts控制器借助于ReplicaSet完成应用的创建、缩放和删除;

◼ ReplicaSet资源由Rollout的spec.template字段进行定义

http://www.magedu.com

Blue-Green和Canary部署

http://www.magedu.com

Argo Rollouts架构

  • Argo Rollout主要由Argo Rollout Controller、Rollout CRD、ReplicaSet、Ingress/Service、

  • AnalysisTemplate/AnalysisRun、Metric providers和CLI/GUI等组件构成

http://www.magedu.com

Argo Rollouts架构组件

 Rollout Controller

◼ 负责管理Rollout CRD资源对象

  • Rollout CRD

    • 由Argo Rollout引入的自定义资源类型,与Kubernetes Deployment兼容,但具有控制高级部署方法的阶段、阈值和方法的额外字段

    • 并不会对Kubernetes Deployment施加任何影响,或要使用Rollout的功能,用户需要手动将资源从Deployment迁移至Rollout

  • Ingress/Service

    • Argo Rollouts使用标准的Kubernetes Service,但需要一些额外的元数据

    • 针对Canary部署,Rollouts支持多种不同的ServiceMesh和Ingress Controller,实现精细化的流量分割和迁移

  • AnalysisTemplate和AnalysisRun

    • Analysis是将Rollout连接至特定的Metric Provider,并为其支持的某些指标定义特定的阈值的能力,于是,这些指标的具体值将决定更新操作是否成功进行;

    • 若指标查询结果满足阈值,则继续进行;若不能满足,则执行回滚;若查询结果不确定,则暂停;

    • 为了执行Analysis,Argo Rollouts提供了AnalysisTemplate和AnalysisRun两个CRD

http://www.magedu.com

部署Argo Rollouts

  • 部署Argo Rollouts

    • kubectl create namespace argo-rollouts

    • kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

      • 会生成一个services/ argo-rollouts-metrics、一个deployments/argo-rollouts,以及一组CRD
  • 部署Dashboard

◼ kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/dashboard-install.yaml ◼ 安装生成的services/argo-rollouts-dashboard默认监听于TCP/3100端口

 部署kubectl argo rollouts插件

  • argo rollouts专用的kubectl插件为可选组件,但安装该组件将能够非常便捷地使用Argo Rollouts

  • ◼ 安装

◆ curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-darwin-amd64 ◆ chmod +x ./kubectl-argo-rollouts-darwin-amd64

  • sudo mv ./kubectl-argo-rollouts-darwin-amd64 /usr/local/bin/kubectl-argo-rollouts

  • 测试

◆ kubectl argo rollouts version

http://www.magedu.com

实战案例1:结合Service进行Canary部署

 案例环境说明

  • 应用:spring-boot-helloworld

    • 微服务,默认监听于80/tcp

    • 相关的path:/、/version和/hello

  • 使用Argo Rollouts提供的Rollout资源编排运行该应用

    • 使用Canary更新策略

    • 推出一个Canary Pod后即暂停,需要用户手动Promote

  • 相关的常用命令

    • 更新应用

      • kubectl argo rollouts set image ROLLOUT_NAME CONTAINTER=NEW_IMAGE
    • 继续更新

    • kubectl-argo-rollouts promote ROLLOUT_NAME [flags]

    • ◼ 中止更新

      • kubectl-argo-rollouts abort ROLLOUT_NAME [flags]
    • 回滚

      • kubectl-argo-rollouts undo ROLLOUT_NAME [flags]

apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollouts-spring-boot-helloworld spec: replicas: 10 strategy: canary: steps: - setWeight: 10 - pause: {} - setWeight: 20 - pause: {duration: 20} - setWeight: 30 - pause: {duration: 20} - setWeight: 40 - pause: {duration: 20} - setWeight: 60 - pause: {duration: 20} - setWeight: 80 - pause: {duration: 20} revisionHistoryLimit: 5 selector: matchLabels: app: spring-boot-helloworld template: metadata: labels: app: spring-boot-helloworld

http://www.magedu.com

实战案例1 :结合Service进行Canary部署(2)

http://www.magedu.com

实战案例2:结合Ingress Nginx进行Canary流量迁移

 Istio环境中支持两种流量分割模式

  • 更新期间,使用不同的Service分别承载新旧版本的流量

    • Canary和Stable版本分别对应一个独立的Service

      • ⚫ canaryService:待发布的新版本

      • ⚫ stableService:待更新的旧版本

    • 分别为Canary和Stable的Pod添加rollouts-pod-template-hash标签, 其值为相应的RS模板的hash值

  • 通过Ingress完成流量分割和迁移

    • 更新期间,默认创建的Ingress用于承载旧版本的请求流量

    • 另外生成一个专用的Ingress用于承载Canary流量,并将这些流量转发到canaryServer相关的EndPoint之上

    • 动态调整canaryIngress和stableIngress的weight进行流量迁移

  • 更新完后,所有流量回转至stableIngress和stableService,此时相关的后端EndPoint已经切换为发布的新版本

  • 提示:这种Canary期间VS的动态调整可能会导致通过 GitOps自动化部署时的问题:权重的瞬时摆动

apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollouts-helloworld-with-traffic-shifting spec: replicas: 10 strategy: canary: canaryService: spring-boot-helloworld-canary stableService: spring-boot-helloworld trafficRouting: nginx: stableIngress: spring-boot-helloworld steps: - setCanaryScale: matchTrafficWeight: true - setWeight: 5 - pause: {duration: 1m} - setWeight: 10

  • pause: {duration: 1m}

  • pause: {duration: 20}

  • setWeight: 20

  • pause: {duration: 40}

  • setWeight: 40

  • pause: {duration: 20}

  • setWeight: 60 - pause: {duration: 20}

http://www.magedu.com

实战案例2:结合Ingress Nginx进行Canary流量迁移(2)

http://www.magedu.com

请求分析和渐进式交付

  • Argo Rollouts中的分析(Analysis)是用于根据阶段性交付效果的测量结果来推动渐进式交付的机制 ◼ 分析机制通过分析模板(AnalysisTemplate CRD)定义,而后在Rollout中调用它

    • 运行某次特定的交付过程时,Argo Rollouts会将该Rollout调用的AnalysisTemplate实例化为AnalysisRun(CRD)

图源:https://spot.io/

http://www.magedu.com

AnalysisTemplate资源与AnalysisRun CRD

 示例说明

  • 定义了一个名为service-name的参数

    • 用于传递要测量的服务的名称
  • 定义了success-rate指标

    • 测试指定服务的请求成功率
  • 每隔20s查询一次prometheus服务,共执行三次

  • 成功条件为:第1个指标(下标为0)的结果值大于等于0.95

  • 遇到3次错误即终止进一步的测试

  • AnalysisRun CRD

    • 配置格式与AnalysisTemplaste大致相同,所不同的是,AnalysisRun用于调用并实例化分析模板

apiVersion: argoproj.io/v1alpha1 kind: AnalysisTemplate metadata: name: success-rate spec: args: - name: service-name - name: namespace metrics: - name: success-rate # NOTE: prometheus queries return results in the form of a vector. # So it is common to access the index 0 of the returned array to obtain the value successCondition: result[0] >= 0.95 interval: 20s count: 5 failureLimit: 3 provider: prometheus: address: http://prometheus.prom.svc.cluster.local:9090 query: | sum(irate(nginx_ingress_controller_requests{service=~"{{args.servicename}}",namespace=~"{{args.namespace}}",status!~"[4-5].*"}[1m])) / sum(irate(nginx_ingress_controller_requests{service=~"{{args.servicename}}",namespace=~"{{args.namespace}}"}[1m]))

http://www.magedu.com

AnalysisTemplate资源示例(2)

 以前面部署的服务spring-boot-helloworld为例,在某个场景中,其成功率查询结果如下图所示

http://www.magedu.com

实战案例3:结合Prometheus指标进行analysis

  • 在Canary发布中,调用AnalysisTemplate进行分析的常用方法有

    • 定义spec.strategy.canary.analysis字段进行引用,而后内嵌 startingStep字段指明启动分析的step位置

      • 如右边的示例
    • 通常,此时应该取消AnalysisTeplate上metric的采样次数限制

    • ◼ 使用spec.strategy.canary.steps.analysis字段,直接引用 AnalysisTemplate作为一个步骤使用

spec: ... strategy: ... canary: steps: - setWeight: 5 - pause: {duration: 2m} - analysis: templates: - templateName: success-rate args: - name: service-name value: spring-boot-helloworld - setWeight: 10 - pause: {duration: 1m} - setWeight: 30 - pause: {duration: 1m}

  • setWeight: 60

  • pause: {duration: 1m}

apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollouts-helloworld-with-traffic-shifting spec:

replicas: 10 strategy: canary: analysis: templates: - templateName: success-rate args: - name: service-name value: spring-boot-helloworld - name: namespace value: default

canaryService: spring-boot-helloworld-canary stableService: spring-boot-helloworld trafficRouting: nginx: stableIngress: spring-boot-helloworld steps:

  • setCanaryScale: matchTrafficWeight: true - setWeight: 5 - pause: {duration: 2m} - setWeight: 10 - pause: {duration: 1m} - setWeight: 20 - pause: {duration: 40} - setWeight: 40

  • pause: {duration: 20}

  • setWeight: 60

  • pause: {duration: 20}

http://www.magedu.com

实战案例3:结合Prometheus指标进行analysis(2)

根据定义,AnalysisRun将在第二步之后启动,并一直运行至发布完成;若分析结果不满足成功条件,则会自动回滚发布过程;

http://www.magedu.com

实战案例4:结合Service进行Blue-Green部署

 案例环境说明

  • 应用:spring-boot-helloworld

    • 微服务,默认监听于80/tcp

    • 相关的path:/、/version和/hello

  • 使用Argo Rollouts提供的Rollout资源编排运行该应用

    • 使用blueGreen更新策略

    • 更新后,推出所有Preview Pod后即暂停,需要用户手动Promote

  • 相关的常用命令

    • 更新应用

      • kubectl argo rollouts set image ROLLOUT_NAME CONTAINTER=NEW_IMAGE
    • 继续更新

      • kubectl-argo-rollouts promote ROLLOUT_NAME [flags]
    • 中止更新

      • kubectl-argo-rollouts abort ROLLOUT_NAME [flags]
    • 回滚

apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollout-helloworld-bluegreen spec: replicas: 3 revisionHistoryLimit: 5 selector: matchLabels: app: rollout-helloworld-bluegreen template: metadata: labels: app: rollout-helloworld-bluegreen spec: containers: - name: spring-boot-helloworld image: ikubernetes/spring-boot-helloworld:v0.9.3 ports: - containerPort: 80 strategy: blueGreen: activeService: spring-boot-helloworld previewService: spring-boot-helloworld-preview autoPromotionEnabled: false

  • kubectl-argo-rollouts undo ROLLOUT_NAME [flags]

http://www.magedu.com

实战案例4:结合Service进行Blue-Green部署(2)

Promote之前,
Promote之后,流流量都由下面量都由当前的的stable旧版
stable新版本承载,
本承载旧版本的Pod副本数会在倒计时结束后被置0

http://www.magedu.com

实战案例5:在Blue-Green部署上使用Analysis

 案例环境说明

  • 应用:spring-boot-helloworld

  • 使用Argo Rollouts提供的Rollout资源编排运行该应用

    • 使用blueGreen更新策略

    • 更新后,首先推出所有Preview Pod

    • 紧接着将调用analysistemplate/success-rate进行分析

      • ⚫ prePromotionAnalysis所定义
    • 满足成功条件后即自动进行Promote,从而将preview版本提升为stable

      • ⚫ 此时,流量也将由提升后的preview版本承载
    • 随后,将再次调用analysistemplate/success-rate进行分析

      • ⚫ postPromotionAnalysis所定义
    • 满足成功条件后即自动缩减旧版的RS规模到0实例,否则,将流量切换回此前的版本;

      • ⚫ 旧的版本将重新变为stable
  • 功能:可根据分析的结果自动完成整个部署过程

apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: rollout-helloworld-bluegreen-with-analysis spec: replicas: 3 revisionHistoryLimit: 5 selector: matchLabels: app: rollout-helloworld-bluegreen template: ... strategy: blueGreen: activeService: spring-boot-helloworld previewService: spring-boot-helloworld-preview prePromotionAnalysis: templates:

  • templateName: success-rate args:

  • name: service-name value: spring-boot-helloworld

  • name: namespace value: default

  • postPromotionAnalysis: templates:

  • templateName: success-rate args:

  • name: service-name value: spring-boot-helloworld

  • name: namespace value: default autoPromotionEnabled: true

http://www.magedu.com

实战案例5:在Blue-Green部署上使用Analysis(2)

处于自动处于自动
Promote之后的
Promote之前分析过程中的分析过程中

http://www.magedu.com

在ArgoCD中使用Argo Rollouts

 应用的部署操作使用Rollout定义,而后由ArgoCD完成从Git Repo至Cluster的同步  可实现完全意义上的自动化

◼ ArgoCD自动进行Sync

◼ Argo Rollouts部署应用于基于分析进行渐进式交付

Git Repo的部署配置文件中使用Rollout定义部署操作

http://www.magedu.com

实战案例6:ArgoCD和Argo Rollouts自动化部署应用

 案例环境说明

  • 使用Argo Rollouts部署spring-boot-helloworld应用

    • 使用Rollout部署spring-boot-helloworld

    • 采用canary部署策略

    • 结合Analysis进行渐进式交付

    • 结合Istio VirtualService进行自动化流量分割和流量迁移

  • 使用ArgoCD进行自动化部署

    • 使用Application监视Git Repository

    • 自动在Repository和Destination之间进行同步

  • 测试

    • Kubernetes集群环境要求

      • 可用的ArgoCD环境

      • 可用的Argo Rollouts环境

      • 可用的Istio环境

    • 直接将右侧的Application部署于准备好相应环境的 Kubernetes集群上即可

apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: spring-boot-helloworld namespace: argocd spec: project: default source: repoURL: https://gitee.com/mageedu/spring-boot-helloworld-deployment.git targetRevision: HEAD path: rollouts/helloworld-canary-with-analysis destination: server: https://kubernetes.default.svc # This sample must run in demo namespace. namespace: demo syncPolicy: automated: prune: true selfHeal: true allowEmpty: false syncOptions:

  • Validate=false

  • CreateNamespace=true

  • PrunePropagationPolicy=foreground

  • PruneLast=true

  • ApplyOutOfSyncOnly=true retry: limit: 5 backoff: duration: 5s factor: 2 maxDuration: 3m

http://www.magedu.com

实战案例6:ArgoCD和Argo Rollouts自动化部署应用(2)

http://www.magedu.com

Thank You!

SRE

 讲师:马永亮(马哥)  http://www.magedu.com  https://github.com/ikubernetes/

什么是SRE?

  • 全称为:Site Reliability Engineering,由Google工程副总裁Ben Treynor Sloss首次提出

◼ “SRE就是让一个软件工程师来主导设计一个新型运维团队的结果。”

 SRE是一门工程科学 ,旨在帮助组织在其基础设施和应用系统中可持续地达成预设的可靠性目标

当你试图将运维视作软件问题时,你就会得到SRE。我们的使命是保护、提供和改进Google的所有公共服务背后的软件和系统——Google搜索、广告、Gmail、Android、YouTube和App Engine等——时刻关注着它们的可用性、延迟、性能和容量。

http://www.magedu.com

SRE的具体原则

  • 运维是一个软件问题(Operations Is a Software Problem)

    • 做好运维工作,需要采用软件工程的方法来实现;
  • 依照SLO进行服务管理

    • SRE并不试图为所有东西提供100%的可用性,这是错误的目标