04 篇的服务器动作链还是手动的:
ssh ubuntu@server
cd /var/www/my-site
git pull
mvn package # 或 pip install
sudo systemctl restart myapp
sleep 5 && curl -fsS http://localhost:8080/health每一步都要登录服务器、复制粘贴命令;漏一步就出问题,靠记忆。
这一篇要做的事:把 04 的动作链化——用一个声明式文件描述「要做哪些动作」,每次 git push 自动执行。带来的不只是「少敲几次命令」,而是运维动作可、可 Code Review、可沉淀——这就是「运维左移」(Shift Left)。
这一篇以 Jenkins 作为流水线引擎为代表。它不是唯一的工具,但Jenkinsfile 的语法清晰展示了「声明式流水线」的核心理念。
流水线是什么
流水线(Pipeline)是「一组运维动作按顺序串起来,按触发条件自动执行」。三个关键属性:
| 属性 | 说明 |
|---|---|
| 顺序 | 动作有先后(先拉代码、再构建、再部署) |
| 触发 | 谁来启动它——git push / 定时 / 手动 |
| 可声明 | 动作描述在文件里,不是每次手敲 |
把流水线对应回 02 篇的范式:
流水线就是 的具体实现——动作结构稳定,输入是 $x$(代码变更),输出是 $c$(部署成功)。手动的 是「人在脑子里记着步骤」,流水线化的 是「文件里写明步骤 + 引擎自动执行」。
Pipeline(首字母大写)特指具体工具:Jenkins Pipeline / GitHub Actions / GitLab CI。它们都遵循上面这三个属性,只是语法不同。
Jenkinsfile:从手动命令到声明式代码
Jenkinsfile 是 Jenkins 流水线的声明文件——把 04 篇的「ssh 上去敲命令」写成一个文本文件,由 Jenkins 引擎读取并执行。
一个对应 04 篇 Spring Boot 部署的 Jenkinsfile:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git 'https://github.com/your/your-app.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Deploy') {
steps {
sh 'sudo systemctl restart myapp'
sh 'sleep 5 && curl -fsS http://localhost:8080/health'
}
}
}
post {
failure {
echo '部署失败,请检查日志'
}
success {
echo '部署成功'
}
}
}三个核心结构
| 结构 | 作用 | 类比 |
|---|---|---|
stages | 一组有序的阶段(Checkout / Build / Deploy) | 流水线上的工位 |
steps | 阶段内的具体动作(sh 'mvn package') | 工位上的工人执行的一步操作 |
agent | 在哪台机器执行(any / docker / 指定 label) | 流水线工厂 |
post 块定义流水线结束后的动作(成功 / 失败 / 不稳定),可以用来发通知、上传日志。
Jenkinsfile 在哪
Jenkinsfile 写在你的应用代码仓库根目录——这是它跟传统「运维脚本放在跳板机」最大的区别。仓库结构大致:
your-app/
├── src/ ← 应用代码
├── pom.xml
├── Jenkinsfile ← 流水线声明(与代码同仓库)
└── README.md这样应用代码和部署它的流水线绑在一起——任何一次代码变更都伴随一次 Jenkinsfile 的可能更新(如果你希望流水线也跟着改)。
运维左移(Shift Left)
「运维左移」是这个时代最重要的运维理念之一——指把运维动作从「上线那一刻」往左移(往开发阶段移)。
| 传统模式 | 左移之后 |
|---|---|
| 运维动作在跳板机上,运维脑子里 | 运维动作在 Jenkinsfile,跟代码一起 commit |
| 新人入职要「师傅带」才能上线 | 新人 clone 仓库,git push 就触发流水线 |
| 一次上线 = 一次手动操作 | 一次上线 = 一次代码 commit + 自动流水线 |
| 升级 / 回退靠文档和记忆 | 升级 / 回退靠 Git 历史 |
| 运维事故排查靠日志 + 经验 | 流水线运行记录可追溯 |
最关键的转变:「上线步骤」从某个人脑子里的隐性知识,变成了仓库里显性、可版本管理的代码。 这就是「基础设施即代码」(Infrastructure as Code,IaC)的入门形态。
Jenkinsfile 不是完整的 IaC(完整 IaC 包括 Terraform、Ansible、Kubernetes YAML 等),但它的思想一致:把基础设施 / 运维动作写进代码、用 Git 管理、用流水线执行。
Jenkins 实战注意点
1. 触发:webhook + GitHub 集成
Jenkins 安装 GitHub 插件,在 GitHub 仓库设置 webhook → Jenkins 地址。每次 git push,GitHub 通知 Jenkins,Jenkins 自动拉代码、跑流水线。
2. 凭据管理:不要把密钥写在 Jenkinsfile 里
数据库密码、SSH 私钥、镜像仓库 token 这类敏感信息:
- ❌ 写在
Jenkinsfile明文里(提交到 Git 会被看见) - ✅ 存到 Jenkins Credentials Store,Jenkinsfile 里只引用 ID:
steps {
withCredentials([sshUserPrivateKey(credentialsId: 'my-deploy-key',
keyFileVariable: 'SSH_KEY')]) {
sh 'ssh -i $SSH_KEY ubuntu@server "systemctl restart myapp"'
}
}3. Agent 也要 Maven / JDK
Jenkins 的 agent 机器跑 mvn package 这一步,它自己也得有 Maven / JDK——这正是 04 篇「服务器变脏」的翻版,只不过现在「脏」的是 Jenkins agent,不是生产服务器。
后续篇章会用容器化 agent(agent { docker { image 'maven:3.9' } })来解决——agent 启动时拉一个带 Maven 的镜像,pipeline 跑完即销毁。这正好把 04 学到的容器知识用到 Jenkins 上。
4. 流水线失败时日志去哪查
- Jenkins 控制台:每次流水线运行有完整 stdout / stderr 日志
- 保留策略:默认保留 30 天;可调成「保留所有」+ 配置磁盘清理策略
- 通知:装 Email / Slack / 企业微信插件,失败时自动推
延伸阅读:主流流水线工具一览
Jenkins 不是唯一的流水线引擎。基础篇选 Jenkins 是因为它的「声明式流水线」语法最清晰——理解 Jenkinsfile 就理解了「流水线 = 声明式动作链」这件事;实际项目里可以根据团队情况选其他工具。
| 平台 / 技术 | 一句话定位 | 部署形态 | 推荐场景 |
|---|---|---|---|
| Jenkins | 插件最多、自托管「瑞士军刀」 | 自托管 | 传统架构、需深度定制 |
| Gitee Go | Gitee 官方 SaaS CI/CD,国内网络友好 | SaaS | 国内网络生态 |
| GitHub Actions | GitHub 原生 CI/CD,模板即开即用 | SaaS | 个人 / 开源项目首选 |
| 极狐 GitLab | 一站式 DevOps,可选 SaaS / 自管 | SaaS / 自托管 | 中小团队 All-in-One |
| Tekton | K8s 原生流水线即代码 | 自托管 | K8s 深度用户 |
| Argo CD | K8s 声明式 GitOps CD 工具 | 自托管 | 云原生 GitOps |
| 阿里云效 | 阿里云一站式研发协同,注册即用 | SaaS | 阿里云生态 |
| 腾讯云 CNB | 腾讯云 DevOps SaaS,微信扫码即开 | SaaS | 微信、腾讯云生态 |
选型速记
- Jenkins 作为入门产品可以学习,但界面复杂、体验较差;除非考虑兼容性 / 团队技术栈基础,否则新项目不推荐。
- GitLab / 阿里云效功能相似,是一站式研发协同平台。小型开发团队推荐使用;个人 / 一人公司不推荐——产品生态丰富=功能复杂、上手困难,侧重开发协同。
- GitHub Actions / Gitee Go / 腾讯 CNB主要提供代码托管 + CI 服务。GitHub Actions 功能强大但需要科学上网;后两者产品完善度较差但国内网络直连。
- Tekton / Argo CD是云原生时代产物,设计之初就与 Kubernetes 深度结合,**基础设施即代码(IaC)**理念贯彻良好。但 Kubernetes 本身门槛高,对中小企业往往是「杀鸡用牛刀」。
一句话选型
- 个人开发者:GitHub Actions
- 中小企业:阿里云效 / GitLab
- 云原生 / 大型企业:Tekton、Argo CD
更进一步:GitOps、IaC、Runner 机制
- GitOps:把部署描述(YAML / Manifest)放进 Git 仓库,集群代理(Argo CD / Flux)拉取并同步——一切变更都通过 PR 完成
- 基础设施即代码(IaC):Terraform / Pulumi 用声明式语言描述整套基础设施(服务器、网络、数据库)
- Runner 机制:流水线任务实际由 Runner 执行;Runner 可以是物理机、虚拟机、容器,甚至 K8s Pod——Jenkins 的 agent / GitHub Actions 的 runner 都是这一思想的具体实践
注:本节是流水线工具的全景概览。GitHub Actions 作为托管式流水线的代表,在下一篇 07 GitHub Actions 中展开实战。
小结
这一篇做了第三次范式升级:手动运维动作 → 流水线化。
- Jenkinsfile 把 04 的命令链从「ssh 上去敲」变成「写在仓库里的代码」
- 流水线引擎(Jenkins / Actions / GitLab CI)按
git push自动触发、自动执行 - 运维左移让「上线步骤」从隐性知识变成显性、可版本管理的代码——这是 IaC 思想的入门
下一步进入 第 07 篇 · GitHub Actions:Jenkinsfile 用 Groovy DSL,GitHub Actions 用 YAML,两者语法不同但「声明式动作链」的思想完全一致。GitHub Actions 是托管式流水线代表——零运维、模板即开即用,对个人开发者和开源项目尤其友好。
思考
- Jenkinsfile 应该和应用代码放在同一个仓库吗?如果放在独立仓库(专门的
infra仓库)有什么利弊? - Jenkins agent 机器也要装 Maven / JDK——这跟 04 篇「服务器变脏」是不是同一类问题?怎么解决?
- Pipeline 跑挂了应该通知谁?只通知提交者,还是整个团队?理由是什么?
post { failure { ... } }这一段如果通知发送本身失败了(比如 Slack 挂),你要怎么兜底?