ch02 pipeline 入门
2.1 pipeline 是什么
部署流水线 (deployment pipeline) 是从软件版本控制库到用户手中这一过程的自动化表现形式.
一般 pipeline 被称为流水线, 也会被称为部署流水线. 也在早期被称为任务.
Jenkins 1.x 仅支持界面化的操作. 2.x 支持了 pipeline as code, 即开始支持代码的操作.
pipeline as code 被称为流水线即代码. 我到觉得这里不翻译比较好.
使用 代码的优势:
- 可以版本化
- 方便协作
- 易于重用
实际上任何事务最后文化以后都有这个好处. 比如 word 在 xml+gzip 后, 比起早期的 二进制 格式更容易控制. 再比如 LaTeX 源码对最终成书的版本控制. 文本化最大最大的优势便是版本化.
2.2 Jenkinsfile 又是什么
一个文本文件, 是流水线部署的表现形式.
Jenkinsfile 对 Jenkins, 如同 Dockerfile 对 Dockerfile.
Jenkins 默认是不支持 Jenkinsfile 的, 需要安装 pipeline 插件 (第一次运行时会安装). 本书采用的插件版本为 2.27. 安装后才可以创建 pipeline 项目.
补充: 安装插件的方法
一般有三种方法:
- 使用 GUI 工具, 搜索插件, 然后选择安装, 这个过程是自动的.
- 另外是使用 CLI 命令, 例如:
jenkins-plugin-cli --plugins dotnet-sdk:1.4.0
. - 使用 GUI 工具中, 插件管理的部署插件功能.
第三种方法可以通过将插件下载到本地后安装, 对于一些没有外部网络的环境比较适用.
第三种操作步骤:
- 进入插件页面, 选择 Releases, 然后下载插件 (后缀名为
hpi
). - 进入 Jenkins 的插件管理页面, 选择高级选项卡, 其中会有部署插件.
- 选择下载后的插件, 然后点击部署.
- 最后重启 Jenkins 即可.
重启的办法是使用 http://localhost:8080/restart
, 会得到提示, 确认后就会重启了.
Jenkins 只是一个服务容器, 所有的功能都是利用插件来实现的. 第一次启动时默认安装的插件有:
2.3 pipeline 语法的选择
有两种语法格式 (pipeline 2.5 版本之后同时支持两种语法):
- 脚本式 (Scripted), 基于 Groovy 脚本语言. 代码中可以有 try-catch 等语句.
- 声明式 (Declar-ative), 逻辑上似乎要简洁一些.
说实话, 没明白形式上有什么区别, 感觉差不多. 2023年11月7日
脚本式语法示例:
node {
stage('Build') {
// 执行构建
}
stage('Test') {
// 执行测试
}
stage('Deploy') {
try {
// 执行部署
} catch (err) {
currentBuild.result = "FAILURE"
mail body: "project build error is here: ${env.BUILD_URL}"
from: 'xxxx@yyyy.com',
replyTo: 'yyyy@yyyy.com'
subject: 'reoject build field'
to: 'zzzz@yyyy.com'
throw err
}
}
}
声明式的实例:
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building ...'
}
}
stage('Test') {
steps {
echo 'Testing ...'
}
}
stage('Deploy') {
steps {
echo 'Deploying ...'
}
}
}
}
本书均使用声明式语法.
对比两个语法后, 感觉:
- 脚本语法似乎每一个 Step 都是一个函数. 因为 Groovy 是可以省略结尾的分号的. 所以看起来与声明式写法类似.
- 声明式按照特定的语法结构来书写. 每一个阶段内都包含步骤, 每一个步骤内分多个语句.
2.4 创建第一个 pipeline
前提是安装 pipeline 插件.
操作步骤:
- 新建任务 (或
Create a job
). - 在向导中选择
pipeline
(流水线). 设置任务名称"pipeline-hello-world"
. - 然后进入配置页面, 在流水线节点下填入
pipeline
的内容. 然后保存. - 最后点击执行, 在输出中可以看到运行结果.
该案例没有实质性的作用, 仅仅作为了解 pipeline 操作流程来展示. 已提供感官认识.
详细步骤
在 Dashboard 页面, 点击左边菜单栏中的 "新建任务" 或者是页面中间的 Create a job
.
然后输入任务名称, 选择任务类型为流水线, 然后点击确定.
然后进入设置页面, 直接选择流水线节点, 在右侧模板中选择 Hello World 模板来创建 pipeline 代码:
然后保存, 进入任务页面. 然后点击立即构建, 开始执行 pipeline, 可以在左侧下方看到构建进度.
构建结束后可以看到阶段视图, 以展示成功与否, 以及构建次数等信息. 鼠标悬浮阶段之上可以显示构建日志.
也可以点击左边构建历史进入某个固定历史, 在控制台输出中查看构建日志.
2.5 从版本控制库拉取 pipeline
基本步骤:
- 在代码中添加文件
Jenkinsfile
, 并在其中编写pipeline
- 然后将代码上传至 git 仓库.
- 由 Jenkins 拉取代码, 并读取其中的
Jenkinsfile
, 然后执行其中的pipeline
.
前提:
- Jenkins 安装 Git 插件. 为了可以从 git 仓库拉取代码.
- 需要将本地私钥上传至 Jenkins 系统, 以便给 git 仓库进行校验.
将私钥存储与 Jenkins 中
操作步骤:
- 依次进入 系统管理, 凭据管理, 系统, 全局凭据 (添加凭据).
- 然后在类型中选择:
SSH Username with private key
(使用用户名和密码应该也行) - 依次设置范围 (默认即可), ID (用于标识, 可随意填), 描述 (按需求随意编写), Username.
- 然后点击 私钥前的单选框, 点击输入即会出现粘贴私钥的文本框.
- 填入私钥后点击创建按钮即可.
详细步骤:
进入凭据管理页面
点击系统, 进入后点击添加凭据. 也可以直接点击凭据后, 添加凭据
或者是
添加秘钥
添加完成后显示
补充: 生成私钥的命令
ssh-keygen -t rsa
项目结构
- 这里创建一个空项目
hello-world
, 即一个空文件夹即可. - 然后在文件夹中创建
Jenkinsfile
文件. 注意区分大小写.
mkdir hello-world
cd hello-world
touch Jenkinsfile
在 Jenkinsfile 中编写
pipeline {
agent any
stages {
stage('hello') {
steps {
echo 'hello world'
}
}
}
然后将其上传至 Git 仓库中, 我这里采用 Gitee 仓库.
编辑 Pipeline 任务
- 找到 pipeline 任务 (原有的, 或新建均可).
- 定位到流水线.
- 在定义中选择
Pipeline script from SCM
, 然后会切换界面. - 在界面中 SCM 下拉中选择 Git, 会展示出需要填写的仓库信息.
- 在界面中输入仓库地址, 以及凭据 (通过下拉选择). 然后是脚本名 (默认为
Jenkinsfile
不用改, 区分大小写). - 必要时可以修改需要构建的分支等.
- 最后保存后开始执行任务, 可以查看其控制台输出.
这里需要注意, 默认情况下 Jenkins 会对秘钥进行拦截. 需要配置. 例如:
会提示秘钥不正确. 这里需要配置一下, Jenkins 如何处理未知主机的校验 (实际上就是 ssh 中的 known_hosts 的问题)
只需要一次进入 系统管理 -> 全局安全配置 -> 然后找到 GIT 主机 key 校验配置 (最下方), 修改为 第一次连接允许即可, 或不校验:
可以进行一个简单的验证: 进入容器后, 进入家目录, 检查
.ssh
目录, 以及下面的 known_hosts 文件 (第一次运行是没有的)
然后修改为
Accept first connection
后, 再次配置 GIT 仓库, 就不会报错了
然后再看家目录下的
.ssh
文件夹 (之前是没有该目录的)
即可看到, 系统已经记录了该地址. 所以就不会再报错了.
运行该任务, 会优先校验 SCM, 然后拉取代码, 最后执行 Jenkins 中的代码
2.6 使用 Maven 构建 Java 应用
书中本节介绍如何使用 Maven 构建 Java 应用程序. 基本处理步骤是:
- 在全局工具配置中配置 Maven (可以动态安装, 也可以本地安装后再配置路径) 以及 JDK.
- 然后在 pipeline 配置, 构建 Java 程序.
- 通过观察任务的日志, 可以查看 Maven 下载与打包.
这里我不懂 Java, 没办法演示与展示, 以及分辨配置是否正确.
而且概述无头无尾的内容很多, 很多代码无法直接使用.
这里使用 node 项目和 .NET 项目来演示.
通过 pipeline (Jenkinsfile) 来执行命令行程序
在书中介绍的 pipeline 的任务使用 sh 来执行命令行.
stages {
stage('Build') {
steps {
sh 'xxxxx'
sh 'xxxx'
}
}
}
这里可以激活 shell 来执行脚本.
案例: 创建流水线任务执行 shell
步骤:
- 创建流水线任务
run-shell
. - 在流水线中输入 Jenkins 脚本.
- 执行任务.
运行完成后可以查看日志
构建 Node 项目
配置 Node 工具
本节采用自动安装的方式来配置 node 工具, 然后拉取 Git 中的 vue 代码, 并进行构建.
Jenkins 仅仅是一个容器, 编排的载体. 具体的任务需要具体的程序来执行, 然后利用插件将命令与 Jenkins 连接起来.
Jenkins 并不执行构建的命令, 它只是将我们手动构建部署的交互行为, 以 pipeline 的形式进行编排, 然后依次运行.
Jenkins 的核心仅仅是一个载体.
要构建 vue 项目, 需要安装 node 工具. 今天 (2023年11月14日), 我的本地电脑 node 版本为 18, 也在 Jenkins 中安装这个版本:
首先安装插件
进入 "系统管理", "插件管理", 在可用插件中搜素 node, 查看列表与说明. 这里应该选择 NodeJS, 描述为: NodeJS 插件在构建阶段执行 NodeJS 脚本.
在安装之前可以查看 "系统管理" > "全局工具配置" 页面, 可以看看此处不存在 NodeJS 工具, 这里已有的工具为:
- Maven
- JDK
- Git
- Gradle
- Ant
然后选择安装插件, 就会进入安装过程页面
然后可以进入 "全局工具配置" 页面查看
有关插件的用法, 可以点击插件, 进入其官网查看其文档: https://plugins.jenkins.io/nodejs/
然后安装 node 环境
点击 "全局工具配置" 页面中的 新增 NodeJS
, 选择自动安装. 然后依次填入别名, 用于标识, 后期在选择工具时使用.
然后选择 Node 版本, 然后输入需要提前安装命令的脚本. 最后选择确定.
需要注意这里 名字中不允许含有空格.
如何这里不使用自动安装, 需要提供程序的路径. 也就是说可以使用手动安装, 然后将应用的路径填入即可.
这里使用自动安装, 不会立即安装, 而是会在构建时安装.
新建任务测试 node 命令
步骤:
创建任务 test-node-cli
编写 pipeline
pipeline { agent any tools { nodejs 'node-18.17.0' } stages { stage('Test Node Cli') { steps { sh 'node -v' sh 'npm -v' sh 'yarn -v' } } } }
其中 tools 指令标识在执行到这里时会安装 nodejs 对应版本(如果已存在就不用安装)
创建一个 vue 项目并上传至 gitee
操作步骤略
然后将其上传至 Gitee (确保秘钥已配置好)
编写 Jenkinsfile 代码
pipeline {
agent any
tools { nodejs 'node-18.17.0' }
stages {
stage('build') {
steps {
echo 'start build'
sh 'yarn'
sh 'yarn build'
echo 'build finished'
}
}
}
}
创建 pipeline 任务
执行任务
开始执行
查看阶段视图
进入容器中查看项目代码 (在日志输出中可以看到项目地址)
至此完成构建.
构建 .NET 项目
基本步骤:
- 下载插件 (第一次需要)
- 安装 dotnet SDK (第一次需要)
- 创建 dotnet 项目, 编写 Jenkinsfile, 上传至 git 仓库
- 创建 pipeline 任务, 配置仓库信息
- 执行任务
下载插件
通过查阅文档可以看到 tools 中使用 dotnetsdk 这个名字
配置 dotnet SDK
不要考虑在 Docker 中的 Jenkins 里手动安装软件. 目标不是这么用的, 应该使用自动安装
由于 Docker 中的镜像是精简版系统, 很多软件不存在, 也没有 root 账户.
所以在离线环境, 或内网环境中需要部署 Jenkins, 可以考虑在有网络环境下安装, 然后将容器导出成镜像在使用.
创建项目与 Jenkinsfile
创建 pipeline 任务
执行构建任务
第一次执行会首先安装 dotnet sdk.
这里有一个 Bug, 缺少 icu 库
提示需要安装 icu library, 但是在 Jenkins 的 Docker 环境中, 没有管理权限, 如法安装该程序.
解决办法:
- 基于 jenkins/jenkins 构建自定义镜像, 在构建时安装对应库. 然后使用新的镜像来运行容器.
- 以固定模式运行, 即配置环境变量
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
为 1.
这里采用第二种方案, 文档可以参考用于全球化的运行时配置选项.
在 "系统管理", "系统配置" 中添加环境变量:
然后再构建:
然后可以查看 Jenkins 的工作空间文件夹
至此完成构建.
补充: 构建 .NET 项目
安装 .NET 项目无论是自动安装还是手动安装, 均会出现 icu 的报错问题. 配置环境变量即可解决.
可以使用手动安装的方法, 安装到本地后, 再配置路径即可.
进入容器后安装; 或在本地下载后, 使用
docker cp 本地文件 容器名:路径
拷贝到容器中, 再配置.安装的过程可以参考微软官方文档.