在 GitLab CI、GitHub Actions、Tekton 等新品频出的今天,Jenkins 依然是许多团队 CI/CD 流水线的基石。它成熟、插件生态庞大、对私有化与复杂编排的支持无人能及。本文用一条可复制的路线,带你从零用 Jenkins 搭建自动化 CI/CD 流水线:从 Docker 部署、声明式 Pipeline,到 Java 构建、镜像推送与 Kubernetes 动态节点,全部给出可直接套用的配置。
一、为什么还要学 Jenkins
云厂商的托管 CI 很方便,但一旦涉及内网构建、多分支策略、自定义 Agent 矩阵、与老旧构建系统对接,Jenkins 的灵活性仍是天花板级。它的 Pipeline as Code 让你把交付过程完整版本化,配合上千款插件几乎能对接任何工具链。对需要稳定掌控构建环境的中大型团队,它依然是性价比最高的选择。
举个直观对比:托管 CI 像租来的流水线,开箱即用但定制受限;Jenkins 像自己盖的工厂,初期要铺水电(部署、插件、节点),一旦建成就能按任意图纸生产。如果你的交付链路里混用了 Java、前端、Go 多语言,还要求在合并前跑安全扫描、在发布后回传质量门,Jenkins 的 stage 组合能力会比割裂的多套 SaaS 更顺手。这也是为什么大量金融、政企内网至今仍以它为主。
二、快速起步:用 Docker Compose 部署 Jenkins
最干净的部署方式是用 Docker Compose 把 Jenkins 跑起来,数据持久化到卷,再用反代暴露。下面这份 docker-compose.yml 已包含常用端口与持久卷:
version: "3.8"
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
restart: unless-stopped
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
environment:
JAVA_OPTS: "-Dhudson.plugins.git.GitSCM.credentialsMetadata.ignore=true"
volumes:
jenkins_home:
启动后用 docker logs jenkins 取初始管理员密码,访问 http://localhost:8080 完成初始化。生产环境建议套一层 Nginx 反代并开启 HTTPS(可参考本站 Nginx 反向代理实战)。
初始化向导会让你装「推荐插件」。对国内网络,这一步常因默认更新站拉不动而超时,可先把插件源换成清华或华为镜像,再重跑安装。初始化完成后第一件事是到「系统管理 → 全局安全配置」关掉匿名读权限,并给构建节点配置足够的内存上限——默认 JVM 堆并不大,跑大项目很容易被 OOM killer 干掉。把这些底座打牢,后续加任务才会顺。
三、第一个 Pipeline:从拉代码到构建
Jenkins 推荐用声明式 Jenkinsfile 描述流水线。把下面文件放进仓库根目录,便是最朴素的 CI:
pipeline {
agent any
stages {
stage('Checkout') {
steps { git branch: 'main', url: 'https://github.com/your/repo.git' }
}
stage('Build') {
steps { sh 'make build' }
}
stage('Test') {
steps { sh 'make test' }
}
}
post {
success { echo '流水线成功 ✅' }
failure { echo '流水线失败 ❌' }
}
}
在 Jenkins 新建一个 Pipeline 任务,选择「Pipeline script from SCM」指向仓库,Jenkins 会自动读取 Jenkinsfile 执行。
关于 agent 有个常见误区:写成 agent any 表示在任意可用节点运行,适合单机构建机;但当你有多个标签不同的节点(如 linux / windows / arm)时,应写成 agent { label 'linux' } 精确指定,避免任务跑错环境。声明式语法还支持 options 块配置超时、重试与构建保持天数,例如 timeout(time: 30, unit: 'MINUTES') 能防止某个卡死的 stage 把节点长期占住。把这些约束写进 Jenkinsfile,比在界面上手动点更不容易遗忘。
四、核心概念拆解
理解下面几个概念,你就能组合出任意复杂流程:
| 概念 | 作用 |
|---|---|
| agent | 指定在哪类节点上执行(any / 指定 label / docker) |
| stage | 流水线的阶段,如构建、测试、部署 |
| steps | 阶段内的具体步骤,可含 sh、git、script |
| post | 流水线结束后统一处理成功/失败/始终动作 |
| when | 条件判断,控制某 stage 是否执行 |
五、实战:Java 项目自动化构建与测试
以 Maven 项目为例,用 withMaven 自动管理工具链,构建并归档产物:
pipeline {
agent any
tools { maven 'maven-3.9' }
stages {
stage('Build & Test') {
steps {
sh 'mvn -B clean package -DskipTests=false'
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
}
注意 -B 批处理模式能减少日志噪音,fingerprint 让 Jenkins 追踪产物来源。若团队已用 GitHub Actions 做云端 CI,可把重构建留给 Jenkins 私有节点,形成混合架构。
真实的 Java 流水线远不止打包。建议把单元测试报告、覆盖率、静态扫描都挂进 stage:用 junit '**/target/surefire-reports/*.xml' 收集测试报告,用 JaCoCo 插件产出覆盖率趋势,再用 SonarQube 做质量门。当这些结果直接显示在构建页面,开发者不用切到别处就能看到回归。对多模块 Maven 工程,记得开 --also-make 与增量编译,能显著缩短大仓的构建时长。
六、集成 Docker 镜像构建并推送
构建完应用,顺手打成镜像并推送到仓库,是交付闭环的关键一步:
stage('Docker Build & Push') {
steps {
script {
docker.withRegistry('https://registry.example.com', 'docker-cred') {
def img = docker.build("registry.example.com/app:${env.BUILD_ID}")
img.push()
}
}
}
}
凭证统一在 Jenkins「凭据」里管理,永远不要硬编码密码。镜像构建建议配合 Docker Compose 做本地联调,保证构建环境一致。
镜像标签别只打 latest,否则回滚时无迹可寻。推荐用 ${env.BUILD_ID} 或 Git commit 短哈希做不可变标签,再在部署端引用具体版本。构建阶段用多阶段 Dockerfile,把编译器和运行时拆开,最终镜像只含运行所需文件,体积能从上 G 缩到几十 M,拉取更快也更安全。配合私有镜像仓库的清理策略,避免废弃标签无限堆积。
七、参数化构建与触发
给流水线加参数,支持手动选择环境或版本;再配 Webhook 实现 Push 即构建:
properties([
parameters([
choice(name: 'ENV', choices: ['dev','staging','prod'], description: '目标环境'),
string(name: 'VERSION', defaultValue: 'latest', description: '发布版本')
]),
pipelineTriggers([githubPush()])
])
GitHub 仓库配置 Webhook 指向 /github-webhook/,每次 Push 即触发对应分支构建,体验与托管 CI 无异。
除了 Webhook,定时构建用 triggers { cron('H 2 * * *') } 可跑夜间全量回归;多分支仓库则直接用「Multibranch Pipeline」+ Jenkinsfile,让每个分支自动拥有独立流水线,合并后自动清理。别忘了在 options 里加 buildDiscarder(logRotator(numToKeepStr: '20')),否则历史构建与日志会慢慢吃满磁盘。对于发布类任务,用 when { branch 'main' } 限定只在主分支执行部署,避免开发分支误发生产。
八、用 Kubernetes 动态 Agent 弹性扩容
构建峰值靠固定节点会浪费资源。通过 Kubernetes 插件,Jenkins 能为每个 stage 动态拉起 Pod 作为 Agent,跑完即回收:
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.9-eclipse-temurin-21
command: ['cat']
tty: true
"""
}
}
stages {
stage('Build in Pod') {
steps { container('maven') { sh 'mvn -B package' } }
}
}
}
这种方式与 Tekton 的 K8s 原生思路异曲同工,但复用你已有的 Kubernetes 集群 即可,无需另起炉灶。
动态 Agent 的价值在弹性:平时不占节点,构建高峰自动扩容 Pod,结束即回收,成本近乎按需。实践中要给容器设好 resources.requests/limits,否则一个贪婪的构建可能挤垮同节点其他负载;用 workspaceVolume 挂载 PVC 还能在 stage 间保留产物。配合 HPA 让构建集群自身也能随队列长度伸缩,整套私有 CI 既省钱又扛压。
九、安全与权限基线
Jenkins 直接握着代码与凭据,安全不能马虎。至少落实以下基线:
此外务必开启 CSRF 防护与「代理到控制器访问控制」(Agent-to-Controller Security),防止被攻陷的构建节点反过来调用主控 API 窃取凭据。凭据一律走 Jenkins 凭据 store 并限定可见范围(Credentials Domain),让不同项目只看到自己的密钥。对外暴露时配合反向代理做访问白名单与限流,别把 8080 裸奔在公网——这点在历史上引发过大量挖矿入侵事件。
| 项目 | 建议 |
|---|---|
| 凭据管理 | 统一用 Jenkins 凭据 store,禁止明文写在 Jenkinsfile |
| 授权策略 | 启用「矩阵授权」按角色收权,禁用匿名读 |
| 插件更新 | 定期升级,修复 CVE(如 Log4j、XSS 类) |
| 网络暴露 | 仅内网或经反代 + 访问控制暴露 8080 |
十、常见排障清单
| 现象 | 排查方向 |
|---|---|
| 卡在「仍在等待 Jenkins 启动」 | 检查 jenkins_home 卷权限与磁盘空间 |
| Pipeline 无 git 权限 | 确认凭据 ID 与分支受保护规则匹配 |
| Docker 构建报 permission denied | 将 jenkins 用户加入 docker 组或用 socket 挂载 |
| K8s Agent Pod 一直 Pending | 检查命名空间配额与节点资源 镜像拉取 |
结语
Jenkins 不性感,却足够可靠。掌握声明式 Pipeline、凭据管理、Docker 集成与 K8s 动态 Agent 这四件事,你就拥有了可私有化、可扩展、可审计的CI/CD 自动化流水线。把它和 GitHub Actions、ArgoCD 等工具按场景组合,才是现代交付链的最优解。
最后给运维一句忠告:给 Jenkins 自身也接上监控。把构建成功率、平均时长、队列等待画进 Prometheus + Grafana 看板,队列持续变长往往预示节点不足或某 stage 变慢;磁盘告警则能提前拦住「构建历史吃满空间」这种低级事故。可观测的 CI,才是真正可靠的 CI。



