Ansible 解决的是“如何自动化配置和操作服务器”,而 CI/CD 解决的是“代码发生变化以后,如何自动完成构建、测试、打包、发布和回滚”。
CI/CD 的核心不是某个具体工具,而是一条稳定、可重复、可追踪的软件交付流水线。
本文从 CI、CD、Pipeline 开始,逐步介绍 Docker 镜像 CI/CD、Linux 自动部署、版本发布与回滚,并使用 Jenkins 搭建一个简单的 Pipeline。
一、什么是 CI/CD
1.1 为什么需要 CI/CD
传统的软件发布流程可能是:
开发者修改代码 ↓手动打包 ↓手动上传服务器 ↓SSH 登录服务器 ↓停止旧版本 ↓替换文件 ↓启动新版本 ↓检查当项目越来越大、发布越来越频繁时,手工流程会产生:
重复劳动人为错误环境不一致发布不可追踪回滚困难CI/CD 的目标就是把这些重复步骤自动化。
典型流程:
Git Push ↓CI ├── Build ├── Test └── Package ↓ Artifact ↓CD ├── Deploy ├── Verify └── Rollback1.2 CI
CI(Continuous Integration,持续集成)的核心思想是:
代码频繁集成+自动构建+自动测试例如:
开发者 A │ ▼git push │ ▼CI Pipeline │ ├── Checkout ├── Build ├── Unit Test └── Static Check如果构建或测试失败:
Pipeline Failed开发者就能更早发现问题。
因此:
CI 主要关注“代码提交之后能不能稳定地被构建和验证”。
二、CD:Continuous Delivery 与 Continuous Deployment
CD 在实际语境中可能表示两个相近但不同的概念:
Continuous Delivery持续交付
Continuous Deployment持续部署2.1 Continuous Delivery
持续交付强调:
代码 ↓Build ↓Test ↓Package ↓Ready for Release系统自动完成发布前流程,但正式上线可能仍然需要人工确认。
例如:
Build ↓Test ↓Staging ↓Manual Approval ↓Production2.2 Continuous Deployment
持续部署进一步自动化:
Code Push ↓Build ↓Test ↓Deploy ↓Production只要流水线通过,就自动部署生产环境。
两者区别可以简单记成:
Continuous Delivery→ “随时可以发布”
Continuous Deployment→ “通过验证就自动发布”三、Pipeline
3.1 什么是 Pipeline
Pipeline(流水线)就是把:
BuildTestPackageDeployVerify等步骤按照一定顺序组织起来。
例如:
Pipeline │ ┌────────────┼────────────┐ ▼ ▼ ▼ Build Test Deploy │ │ │ ▼ ▼ ▼ Image Test Pass Server一个非常典型的流程:
Checkout ↓Build ↓Test ↓Docker Build ↓Docker Push ↓Deploy ↓Health Check3.2 Stage
Pipeline 通常拆分成多个 Stage:
Stage 1: CheckoutStage 2: BuildStage 3: TestStage 4: PackageStage 5: DeployStage 6: Verify这样可以让:
执行过程日志失败位置更加清晰。
3.3 Artifact
Build 完成后通常会产生:
Artifact例如:
app.jarapp.tar.gzDocker Image典型流程:
Source Code ↓Build ↓Artifact ↓Deploy在容器化环境中,最常见的 Artifact 之一就是:
Docker Image四、CI/CD 与 Git
CI/CD 的起点通常是:
Git Repository例如:
Developer │ │ git push ▼Git Repository │ ▼CI Server触发方式常见:
PushPull RequestTagScheduleManual例如:
push main ↓trigger pipeline或者发布:
git tag v1.2.0 ↓build ↓release因此 Git 不只是:
代码备份它还提供:
版本提交记录分支Tag审核为 CI/CD 提供天然的版本来源。
五、Docker 镜像 CI/CD
前面已经学习过 Docker:
Dockerfile ↓docker build ↓Image ↓Container现在把它接入 CI/CD:
Git Push ↓CI ↓Docker Build ↓Docker Image ↓Registry ↓Deploy完整流程:
Git Repository │ Push │ ▼ CI Pipeline │ ┌─────────┼─────────┐ ▼ ▼ ▼ Build Test Docker Build │ ▼ Image │ ▼ Registry │ ▼ Server │ ▼ ContainerDocker 官方也提供了针对 CI 平台的 Build / Push Action 和 Buildx 等能力,用于自动构建和推送镜像。 (docs.docker.com)
六、Docker Image Tag
CI/CD 中不要简单地只使用:
latest更推荐让镜像 Tag 能体现版本。
例如:
myapp:1.0.0myapp:1.1.0myapp:1.2.0甚至:
myapp:git-8f3a21c这样:
版本 ↓Image Tag建立了明确对应关系。
例如:
v1.4.2 │ ▼myapp:1.4.2发布时:
Production→ myapp:1.4.2出了问题就可以:
myapp:1.4.1进行回滚。
6.1 为什么不要依赖 latest
如果:
myapp:latest昨天是:
1.0今天变成:
1.1那么你无法直接从:
latest知道生产环境具体运行的是哪个版本。
因此:
可追踪版本非常重要。
七、Docker Registry
镜像构建之后,需要放到 Registry:
CI │ │ docker push ▼Registry │ │ docker pull ▼Production例如:
docker build -t registry.example.com/myapp:1.0.0 .登录:
docker login registry.example.com推送:
docker push registry.example.com/myapp:1.0.0服务器:
docker pull registry.example.com/myapp:1.0.0这样生产服务器不需要自己:
Git clone ↓Maven build ↓npm build而只需要:
Pull Image ↓Run Container八、一个完整的 Docker CI Pipeline
例如 Java 项目:
Git Push ↓Checkout ↓Maven Build ↓Unit Test ↓Docker Build ↓Docker Push ↓DeployDockerfile:
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]构建:
mvn clean package
docker build \ -t registry.example.com/myapp:${VERSION} .推送:
docker push \ registry.example.com/myapp:${VERSION}最终:
myapp:1.0.0进入 Registry。
九、Linux 自动部署 Web 服务
假设服务器:
LinuxDocker需要部署:
Web Application手工方式:
ssh server ↓docker pull ↓docker stop ↓docker rm ↓docker run可以自动化成:
CI ↓Registry ↓SSH ↓Linux Server ↓docker pull ↓replace container9.1 基本部署脚本
例如:
#!/usr/bin/env bash
set -euo pipefail
IMAGE="registry.example.com/myapp:1.0.0"CONTAINER="myapp"
docker pull "$IMAGE"
docker stop "$CONTAINER" || truedocker rm "$CONTAINER" || true
docker run -d \ --name "$CONTAINER" \ --restart unless-stopped \ -p 8080:8080 \ "$IMAGE"这里:
set -euo pipefail可以减少脚本静默失败。
9.2 部署流程
Registry │ ▼docker pull │ ▼Stop Old │ ▼Remove Old │ ▼Run New │ ▼Health Check但这种:
停止旧版本→ 启动新版本存在短暂服务中断。
因此生产环境可能进一步使用:
Rolling UpdateBlue-GreenCanary等发布策略。
十、应用发布
10.1 发布版本
假设当前:
v1.2.0准备发布:
v1.3.0完整流程:
Git Tag v1.3.0 │ ▼ CI │ ├── Build ├── Test └── Docker Build │ ▼ myapp:1.3.0 │ ▼ Registry │ ▼ Production这样每一次发布都具有:
Git VersionImage VersionDeployment Version三者之间的对应关系。
十一、应用版本回滚
11.1 为什么需要回滚
假设:
v1.3.0发布之后:
5xx ↑Latency ↑Application Error这时候最快的恢复方式可能不是:
现场修改代码而是:
Rollback回到:
v1.2.011.2 Docker 回滚
因为镜像具有明确版本:
myapp:1.2.0myapp:1.3.0可以直接:
docker pull registry.example.com/myapp:1.2.0然后重新启动:
docker run ...最终:
Production │ ▼myapp:1.2.011.3 回滚的前提
回滚不是简单地:
“把旧镜像重新启动”还需要确认:
数据库 Schema配置文件依赖版本数据格式API 兼容性例如:
v1.3.0 ↓数据库迁移 ↓Schema changed这时候直接:
Application → v1.2.0可能无法工作。
因此真正可靠的回滚体系还需要考虑:
应用版本+配置版本+数据库迁移之间的兼容性。
十二、Blue-Green Deployment
为了减少发布过程中的中断,可以同时运行两个版本:
Load Balancer │ ┌────────┴────────┐ ▼ ▼ Blue v1.2 Green v1.3 Production Testing新版本:
Green v1.3部署完成后进行验证:
Health CheckSmoke Test确认正常后:
TrafficBlue → Green切换:
之前:LB → Blue
之后:LB → Green如果出现问题:
Green X │ ▼Traffic → Blue快速回滚。
十三、Canary Deployment
Canary(灰度发布)不是一次把所有流量切换到新版本。
例如:
100% Traffic │ ▼90% → v1.210% → v1.3观察:
Error RateLatencyCPUBusiness Metrics如果正常:
80 / 20再:
50 / 50最终:
0 / 100这样可以降低新版本故障的影响范围。
十四、Jenkins
14.1 Jenkins 是什么
Jenkins 是一个自动化服务器,提供大量插件和 Pipeline 能力,可以用于构建、测试和持续交付。
Jenkins 的 Pipeline 是通过代码描述交付过程的重要机制,通常使用 Jenkinsfile 保存 Pipeline 定义。Jenkins 官方推荐把 Jenkinsfile 放入源码控制,以获得代码审查、审计和单一事实来源等好处。 (jenkins.io)
可以理解为:
Jenkins │ ├── Build ├── Test ├── Package ├── Docker └── Deploy14.2 Jenkins Controller 与 Agent
Jenkins 可以通过:
Controller │ ├── Agent 1 ├── Agent 2 └── Agent 3分配任务。
简单理解:
Controller→ 管理 Pipeline
Agent→ 实际执行构建任务因此不一定所有构建工作都直接跑在 Jenkins Controller 上。
十五、Jenkins Docker 部署
Jenkins 官方提供 Docker 镜像,并推荐使用 jenkins/jenkins 镜像。当前官方 Docker 安装文档还特别说明,如果 Jenkins Pipeline 需要执行 Docker 命令,需要额外配置 Docker CLI / Docker Engine 访问。 (jenkins.io)
最简单的学习环境:
docker volume create jenkins-data运行:
docker run -d \ --name jenkins \ --restart unless-stopped \ -p 8080:8080 \ -p 50000:50000 \ -v jenkins-data:/var/jenkins_home \ jenkins/jenkins:lts查看:
docker ps查看日志:
docker logs jenkins访问:
http://<server>:808015.1 为什么需要 Volume
Jenkins 会保存:
JobCredentialsPluginsBuild InformationPipelineConfiguration这些数据需要持久化。
因此:
Jenkins Container │ ▼/var/jenkins_home │ ▼Volume不能简单把 Jenkins 当作一次性的无状态容器。
15.2 Jenkins 与 Docker
如果 Jenkins 需要:
docker builddocker push就需要让 Pipeline 所运行的 Agent 能访问 Docker。
典型架构:
Jenkins │ ▼Agent │ ▼Docker CLI │ ▼Docker Engine也可以采用 Docker-in-Docker 等方式,但安全性和架构复杂度更高。Jenkins 官方的 Docker 安装指南也提供了使用独立 docker:dind 容器的示例。 (jenkins.io)
十六、Jenkinsfile
16.1 为什么使用 Jenkinsfile
早期 Jenkins 可以直接在 Web UI 里写 Pipeline:
Jenkins UI ↓Pipeline Script但这样存在:
难以版本控制难以审查难以迁移更推荐:
Git │ └── Jenkinsfile也就是:
Pipeline as CodeJenkins 官方明确推荐将 Jenkinsfile 存入源码管理系统。 (jenkins.io)
十七、Declarative Pipeline
Jenkins Pipeline 有两种主要语法:
Declarative PipelineScripted Pipeline对于入门,通常从 Declarative Pipeline 开始。
一个最简单的结构:
pipeline { agent any
stages {
stage('Build') { steps { echo 'Building...' } }
stage('Test') { steps { echo 'Testing...' } }
stage('Deploy') { steps { echo 'Deploying...' } } }}Jenkins 官方文档将 pipeline、agent、stages、steps 作为 Declarative Pipeline 的基本结构。 (jenkins.io)
可以理解为:
pipeline │ ├── agent │ └── stages ├── Build ├── Test └── Deploy十八、编写一个简易 Jenkins Pipeline
假设项目:
Java + Maven + DockerJenkinsfile:
pipeline { agent any
environment { IMAGE = 'registry.example.com/myapp' VERSION = "${BUILD_NUMBER}" }
stages {
stage('Checkout') { steps { checkout scm } }
stage('Build') { steps { sh 'mvn clean package' } }
stage('Test') { steps { sh 'mvn test' } }
stage('Docker Build') { steps { sh """ docker build \ -t ${IMAGE}:${VERSION} . """ } }
stage('Docker Push') { steps { sh """ docker push \ ${IMAGE}:${VERSION} """ } }
stage('Deploy') { steps { sh """ ./deploy.sh ${IMAGE}:${VERSION} """ } } }}整体:
Checkout ↓Build ↓Test ↓Docker Build ↓Docker Push ↓Deploy这就是一条最基本的:
CI/CD PipelineJenkins 官方示例同样使用 Build → Test → Deploy 这样的阶段结构作为持续交付 Pipeline 的基础模型。 (jenkins.io)
十九、Pipeline 中的 Credentials
CI/CD 经常需要:
Git TokenRegistry PasswordSSH KeyCloud Credentials不能直接写:
sh 'docker login -u admin -p 123456'这样会产生严重的敏感信息泄露风险。
Jenkins 提供:
Credentials机制来管理这些凭据。
典型:
Jenkins │ └── Credentials ├── SSH Key ├── Username / Password └── TokenPipeline 再引用:
withCredentials([ usernamePassword( credentialsId: 'docker-registry', usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASSWORD' )]) { sh ''' echo "$REGISTRY_PASSWORD" | docker login \ -u "$REGISTRY_USER" \ --password-stdin \ registry.example.com '''}核心原则:
Secrets≠代码而应该:
Secrets→ Credentials Management二十、Pipeline 条件控制
20.1 测试失败不发布
最基本:
Build ↓Test ↓失败 XDeploy也就是说:
Test Failed→ Pipeline Failed→ 不应该进入 Production这就是 CI/CD 的重要价值。
20.2 Manual Approval
生产环境可能需要人工确认:
stage('Production Approval') { steps { input message: '确认发布到生产环境?' }}形成:
Build ↓Test ↓Staging ↓Manual Approval ↓Production这更接近:
Continuous Delivery二十一、自动部署与 Ansible
前一篇已经学习:
Ansible现在可以把 Jenkins 与 Ansible 组合。
Git ↓Jenkins ↓Build ↓Test ↓Docker Image ↓Registry ↓Ansible ↓Linux Server例如:
stage('Deploy') { steps { sh ''' ansible-playbook \ -i inventory \ deploy.yml \ -e image_tag=${BUILD_NUMBER} ''' }}这样:
Jenkins→ 负责 Pipeline
Ansible→ 负责服务器配置 / 部署职责非常清晰。
二十二、CI/CD 与 Kubernetes
前面已经学习 Kubernetes。
因此还可以形成:
Git ↓Jenkins ↓Build ↓Docker Image ↓Registry ↓Kubernetes ↓Deployment ↓Pods例如发布新的镜像:
containers: - name: app image: registry.example.com/myapp:1.3.0然后:
kubectl apply -f deployment.yaml或者使用:
kubectl set image deployment/myapp \ app=registry.example.com/myapp:1.3.0Kubernetes 再负责:
Rolling UpdateSelf-healingSchedulingService Discovery于是整个技术体系串起来:
Ansible→ 服务器自动化
Docker→ 容器化
Kubernetes→ 容器编排
Jenkins→ CI/CD
Prometheus→ Metrics
Grafana→ Visualization二十三、CI/CD 中的健康检查
部署完成:
Container = Running不代表:
Application = Healthy所以发布之后应该执行:
Health Check例如:
curl -f http://127.0.0.1:8080/health或者:
HTTP 200才认为:
Deploy Successful完整流程:
Deploy ↓Start ↓Health Check │ ├── PASS → Success │ └── FAIL → Rollback这就是:
自动部署+自动验证二十四、应用发布与自动回滚
可以把前面的内容组合成:
Git Push │ ▼ Jenkins │ ┌─────┴─────┐ ▼ ▼ Build Test │ │ └─────┬─────┘ ▼ Docker Build │ ▼ Registry │ ▼ Deploy │ ▼ Health Check / \ PASS FAIL │ │ ▼ ▼ Success Rollback │ ▼ Previous Version这已经是一条比较完整的 CI/CD 基础流水线。
二十五、流水线中的版本管理
一个生产环境应该尽可能做到:
Code Version │ ▼Build Version │ ▼Image Version │ ▼Deployment Version例如:
Git Tagv2.3.1
Docker Imagemyapp:2.3.1
Productionmyapp:2.3.1这样:
谁发布的?什么时候发布的?发布了什么?现在运行什么?如何回滚?都更容易回答。
二十六、CI/CD 常见故障排查
26.1 Pipeline Build 失败
首先看:
Console Output确定:
BuildTestDocker BuildDeploy哪个 Stage 失败。
不要直接重新运行:
Build #125而应该先找到失败阶段。
26.2 Docker Build 失败
检查:
DockerfileBuild ContextBase ImageNetworkDependency例如:
COPY target/app.jar但前面的:
mvn package没有生成:
target/app.jar那么 Docker Build 当然会失败。
因此流水线的 Stage 之间存在:
依赖关系26.3 Docker Push 失败
重点检查:
RegistryLoginCredentialsNetworkImage TagRepository例如:
docker push失败:
unauthorized就应该先检查:
Credentials而不是修改 Dockerfile。
26.4 Deploy 失败
例如:
docker pull成功:
Deploy却失败。
继续检查:
端口VolumeEnvironmentContainer Name旧容器权限以及:
docker logs <container>26.5 Health Check 失败
例如:
Container = running
HTTP /health→ 500此时:
Docker 正常应用异常继续检查:
Application LogsDatabaseRedisEnvironmentConfiguration而不是:
docker restart不停重启。
二十七、CI/CD 安全
CI/CD 可以操作:
源码镜像服务器生产环境Secrets因此本身就是高权限系统。
应该重点考虑:
凭据保护最小权限Registry 权限SSH KeyWebhook 安全构建环境隔离供应链安全审计例如:
Jenkins │ └── Production SSH Key如果 Jenkins 被完全控制:
攻击者 ↓Jenkins ↓SSH Key ↓Production因此:
CI/CD 系统本身必须被当作生产基础设施进行安全保护。
二十八、CI/CD 与监控
部署并不意味着流程结束。
一个完整过程应该是:
Deploy ↓Health Check ↓Metrics ↓Logs ↓Business Validation例如:
Jenkins │ ▼Deploy v1.3.0 │ ▼Prometheus │ ├── Error Rate ├── Latency └── CPU │ ▼Grafana如果:
5xx ↑就可以触发:
Rollback所以最终可以形成:
CI/CD+Monitoring+Logging自动化闭环。
二十九、CI/CD 整体架构
把前面几个章节全部连接起来:
Developer │ Git Push │ ▼ Git Repository │ ▼ Jenkins │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ Build Test Security │ │ │ └──────────────┼──────────────┘ ▼ Docker Build │ ▼ Image │ ▼ Registry │ ┌──────────┴──────────┐ ▼ ▼ Ansible Kubernetes │ │ ▼ ▼ Linux Server Pods │ │ └──────────┬──────────┘ ▼ Health Check │ ┌──────────┴──────────┐ ▼ ▼ Success Fail │ │ ▼ ▼ Monitoring Rollback │ ┌───────┼────────┐ ▼ ▼ ▼ Metrics Logs Traces后面的:
LogsELKOpenTelemetryObservability就可以继续接在这里。
三十、自动化体系中的工具分工
到这里,可以把已经学习的工具按照职责整理起来:
| 工具 | 主要解决的问题 |
|---|---|
| Ansible | 服务器和配置自动化 |
| Docker | 应用容器化 |
| Kubernetes | 容器集群编排 |
| Jenkins | CI/CD 流水线 |
| Prometheus | Metrics 监控 |
| Grafana | Metrics 可视化 |
| ELK | 日志收集与分析 |
| OpenTelemetry | 遥测数据采集与关联 |
因此它们并不是:
哪个工具最好?而是:
不同层解决不同问题例如:
代码 ↓Jenkins ↓Docker ↓Registry ↓Ansible / Kubernetes ↓Application ↓Prometheus / Grafana ↓Logs / ELK ↓OpenTelemetry三十一、从手工发布到自动化发布
最原始:
开发者 ↓SSH ↓服务器 ↓手工部署加入 Docker:
开发者 ↓Docker Build ↓Image ↓Server加入 CI:
Git Push ↓Jenkins ↓Build ↓Test ↓Image加入 Registry:
Git ↓Jenkins ↓Build ↓Registry ↓Server加入自动部署:
Git ↓Jenkins ↓Build ↓Test ↓Push Image ↓Deploy ↓Health Check加入监控:
Deploy ↓Health Check ↓Prometheus ↓Grafana最终:
自动构建+自动测试+自动发布+自动验证+自动监控+快速回滚这就是现代 DevOps / 运维自动化体系的基本雏形。
三十二、总结
CI/CD 最核心的概念可以整理成:
CI→ 持续集成
CD→ 持续交付 / 持续部署
Pipeline→ 把整个交付过程组织起来
Artifact→ 构建产生的可发布产物
Registry→ 保存和分发 Docker Image
Jenkins→ 执行 CI/CD Pipeline
Jenkinsfile→ 用代码定义 Pipeline
Deploy→ 把版本发布到目标环境
Health Check→ 验证发布结果
Rollback→ 出现问题后恢复到稳定版本一条典型流水线:
Git Push ↓Checkout ↓Build ↓Test ↓Docker Build ↓Docker Push ↓Deploy ↓Health Check │ ├── PASS → Release Success │ └── FAIL → Rollback而之前学习的内容可以组合成:
Ansible→ 自动化服务器
Docker→ 容器化应用
Kubernetes→ 管理容器集群
Jenkins→ 自动化软件交付
Prometheus→ 监控运行状态
Grafana→ 展示监控数据
ELK→ 分析日志
OpenTelemetry→ 连接 Metrics / Logs / Traces最终形成:
CI/CD 的核心目标,是把“代码发生变化”到“一个经过验证的版本安全地运行在生产环境”之间的重复工作自动化,并且让整个过程具备版本追踪、失败阻断、健康验证和快速回滚能力。