读完本文,你将掌握 CIDC(持续集成与持续部署)的完整落地方法,能独立搭建一套从代码提交、自动测试、镜像构建到服务器滚动更新的流水线,并避开初学者最容易踩的权限、缓存、回滚三大坑。
---

第一步:明确你的交付物与目标环境
CIDC 不是安装一个软件,而是设计一条“代码 → 产物 → 部署”的管道。先回答三个问题:
1. 你的代码托管在哪?(GitHub / GitLab / Gitee)
2. 你的部署目标是什么?(单台服务器 / Kubernetes集群 / 云函数)
3. 你的产物是什么?(Docker镜像 / Jar包 / 静态文件)
以最常见场景为例:GitHub 仓库 + Docker 镜像 + 单台云服务器(Docker Compose 管理)。本教程按此场景操作,其他环境逻辑相同。
第二步:初始化仓库与 CI 脚本
在仓库根目录创建 `.github/workflows/ci.yml`(GitHub Actions 为例)。最小可用配置:
```yaml
name: CIDC Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
- name: Run tests
run: mvn test
- name: Build jar
run: mvn package -DskipTests
```
这段代码会在每次 push 到 main 分支时自动拉取代码、跑测试、打 jar 包。注意:测试必须在这里做,不要等到部署后才验证。
第三步:构建 Docker 镜像并推送镜像仓库
在 CI 脚本末尾追加构建与推送步骤。你需要一个镜像仓库(Docker Hub / 阿里云 ACR / 腾讯云 TCR)。以 Docker Hub 为例:
```yaml
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: yourname/myapp:latest
```
关键点:
- 在 GitHub 仓库 Settings → Secrets 里添加 `DOCKER_USERNAME` 和 `DOCKER_PASSWORD`,绝不要明文写密码。
- 镜像 tag 不要只用 `latest`,建议用 `${{ github.sha }}`(提交哈希),便于回滚。
第四步:编写部署端脚本(服务器侧)
在目标服务器上准备部署脚本 `deploy.sh`:
```bash
#!/bin/bash
set -e
docker pull yourname/myapp:latest
docker compose down
docker compose up -d
```
但这样不够健壮。推荐加健康检查:
```bash
docker pull yourname/myapp:latest
docker compose up -d --no-deps --force-recreate app
sleep 10
curl -f http://localhost:8080/health || { docker compose logs app; exit 1; }
```
第五步:在 CI 中触发远程部署
两种方式:
- 方式A(简单):在 CI 最后一步用 SSH 登录服务器执行 `deploy.sh`。需要把服务器的 SSH 私钥放入 GitHub Secrets,然后:
```yaml
- name: Deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.HOST }}
username: root
key: ${{ secrets.SSH_KEY }}
script: |
cd /opt/app
bash deploy.sh
```
- 方式B(更安全):用 webhook 工具(如 webhook 或 Jenkins 的远程触发),服务器上监听 HTTP 请求后才拉取镜像。初学者先走方式A,但要注意 SSH 密钥泄露风险。
第六步:加入回滚机制
这是 CIDC 的灵魂。在服务器上保留上一次可用的镜像 tag:
```bash
# deploy.sh 改进版
LAST_GOOD_TAG=$(docker images --filter "reference=yourname/myapp" --format "{{.Tag}}" | sort -V | tail -2 | head -1)
docker pull yourname/myapp:$NEW_TAG
docker compose up -d --no-deps --force-recreate app
sleep 10
curl -f http://localhost:8080/health || {
docker compose down
docker compose up -d --no-deps --force-recreate app:$LAST_GOOD_TAG
exit 1
}
```
第七步:验证全链路
模拟一次真实发布:
1. 本地修改代码 → push 到 main
2. 打开 GitHub Actions 页面,观察 job 是否依次通过
3. 登录服务器,执行 `docker ps` 查看容器是否重建
4. 访问应用健康检查接口,确认返回 200
若失败,优先查看 CI 日志中具体步骤的红叉,定位是编译失败、镜像推送失败还是 SSH 部署失败。
---
常见坑(务必先看)
1. 镜像 tag 混乱:永远用 `${{ github.sha }}` 作为 tag,不要覆盖 `latest`,否则回滚时无法知道上一个版本是哪个。
2. SSH 权限过大:不要用 root 账户的私钥直接放 CI。创建一个只允许执行 `deploy.sh` 的受限用户,并在服务器上设置 `sudo` 白名单。
3. 健康检查缺失:很多新手 `docker compose up -d` 后不管进程是否真正可用,导致“部署成功但服务挂了”。必须加 curl 健康检查。
4. 缓存污染:CI 中如果用了 `actions/cache` 缓存依赖,当依赖版本更新时可能一直用旧缓存。给缓存 key 加上哈希(如 `${{ hashFiles('**/pom.xml') }}`)。
5. 忽略环境差异:本地能跑不代表服务器能跑。在 CI 中用同一个基础镜像构建,不要依赖本地已安装的软件。
