CI/CD 自动化部署完全指南(二):快速开始与配置详解
CI/CD 自动化部署完全指南(二):快速开始与配置详解
10 分钟完成环境搭建,让部署自动化起来!
在上一篇文章中,我们介绍了 CI/CD 自动化部署的方案概述和架构设计。本篇将手把手教你如何快速搭建这套系统。
快速开始
1. 前置准备
1.1 创建镜像仓库
首先需要一个镜像仓库来存储 Docker 镜像。国内推荐使用阿里云容器镜像服务 (ACR) 或 腾讯云容器镜像服务 (TCR)。
阿里云 ACR 配置步骤:
- 登录 阿里云容器镜像服务控制台
- 创建命名空间(例如:
your-company) - 创建镜像仓库(例如:
your-app) - 获取登录凭证(用户名和密码)
腾讯云 TCR 配置步骤:
- 登录 腾讯云容器镜像服务控制台
- 创建命名空间
- 创建镜像仓库
- 获取登录凭证
创建完成后,记录以下信息:
镜像仓库地址: registry.cn-hangzhou.aliyuncs.com # 或 tcr.tencentcloudcr.com
命名空间: your-company
仓库名: your-app
用户名: your-username
密码: your-password1.2 配置 GitHub Secrets
镜像仓库准备好了,现在需要把凭证配置到 GitHub 仓库中。
步骤:
- 进入你的 GitHub 仓库
- 点击
Settings → Secrets and variables → Actions - 点击
New repository secret - 添加以下 Secrets:
# 镜像仓库凭证
DOCKER_REGISTRY=registry.cn-hangzhou.aliyuncs.com
DOCKER_USERNAME=your-username
DOCKER_PASSWORD=your-password
# 开发服务器 SSH 凭证
DEV_SERVER_HOST=dev.example.com
DEV_SERVER_USER=ubuntu
DEV_SERVER_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY-----
.......................................................
-----END OPENSSH PRIVATE KEY-----
# 生产服务器 SSH 凭证
PROD_SERVER_HOST=prod.example.com
PROD_SERVER_USER=ubuntu
PROD_SERVER_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY-----
.......................................................
-----END OPENSSH PRIVATE KEY-----
# 通知配置(可选)
SLACK_WEBHOOK=https://hooks.slack.com/services/xxx/xxx/xxx如何生成 SSH 密钥对?
# 在本地机器生成密钥对
ssh-keygen -t ed25519 -C "deploy@your-company.com" -f ~/.ssh/deploy_key
# 会生成两个文件:
# ~/.ssh/deploy_key (私钥,添加到 GitHub Secrets 的 DEV_SERVER_SSH_KEY)
# ~/.ssh/deploy_key.pub (公钥,添加到服务器的 ~/.ssh/authorized_keys)将公钥添加到服务器:
# 假设你的服务器 IP 是 1.2.3.4
ssh-copy-id -i ~/.ssh/deploy_key.pub ubuntu@1.2.3.4
# 或者手动添加:
cat ~/.ssh/deploy_key.pub | ssh ubuntu@1.2.3.4 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"1.3 配置环境保护(生产环境)
为了安全起见,生产环境部署应该需要手动审批。
配置步骤:
- 进入 GitHub 仓库
Settings → Environments - 点击
New environment - 环境名称填写:
production - 勾选
Required reviewers,添加审批人 - 点击
Save
这样,每次部署到生产环境时,都需要审批人手动批准后才会执行。
2. 项目配置
2.1 修改 .github/workflows/ci-cd.yml
打开 .github/workflows/ci-cd.yml,修改以下配置:
# 在文件开头找到 env 配置
env:
DOCKER_REGISTRY: registry.cn-hangzhou.aliyuncs.com # 修改为你的镜像仓库
IMAGE_NAME: your-project-name # 修改为你的项目名示例:
如果你的镜像仓库是 registry.cn-hangzhou.aliyuncs.com/your-company/your-app,那么:
env:
DOCKER_REGISTRY: registry.cn-hangzhou.aliyuncs.com
IMAGE_NAME: your-company/your-app2.2 修改 docker-compose.yml
打开 docker-compose.yml,修改镜像名称:
services:
app-blue:
# 修改前
# image: ${DOCKER_REGISTRY:-registry.cn-hangzhou.aliyuncs.com}/${IMAGE_NAME:-your-app}:${BLUE_TAG:-stable}
# 修改后(可以直接写死,也可以通过环境变量)
image: registry.cn-hangzhou.aliyuncs.com/your-company/your-app:${BLUE_TAG:-stable}
# ... 其他配置保持不变2.3 确保应用有健康检查端点
蓝绿部署依赖健康检查来确定新版本是否正常运行。你需要在应用中添加一个健康检查路由。
Express.js 示例:
// routes/health.js
const express = require('express');
const router = express.Router();
router.get('/health', async (req, res) => {
try {
// 检查数据库连接
await checkDatabaseConnection();
// 检查 Redis 连接(如果使用)
await checkRedisConnection();
// 检查其他关键服务...
// 所有检查都通过
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
version: process.env.npm_package_version || 'unknown'
});
} catch (error) {
// 健康检查失败
res.status(503).json({
status: 'unhealthy',
error: error.message,
timestamp: new Date().toISOString()
});
}
});
module.exports = router;
// app.js
app.use('/health', require('./routes/health'));NestJS 示例:
// health/health.controller.ts
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
@Controller('health')
export class HealthController {
@Get()
async checkHealth(@Res() res: Response) {
try {
// 检查数据库连接
// ...
return res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString(),
});
} catch (error) {
return res.status(503).json({
status: 'unhealthy',
error: error.message,
});
}
}
}3. 服务器初始化
现在需要在服务器上安装 Docker 和 Docker Compose。
3.1 安装 Docker 和 Docker Compose
在服务器上执行:
# 1. 安装 Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 2. 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 3. 验证安装
docker --version
docker-compose --version
# 4. 启动 Docker 服务
sudo systemctl enable docker
sudo systemctl start docker国内服务器加速:
# 配置 Docker 镜像加速器(阿里云)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker3.2 配置服务器目录结构
# 创建项目目录
sudo mkdir -p /opt/your-app/{deploy,logs,data}
cd /opt/your-app
# 创建部署用户(推荐,提高安全性)
sudo useradd -m -s /bin/bash deployer
sudo usermod -aG docker deployer
# 设置目录权限
sudo chown -R deployer:deployer /opt/your-app
sudo chmod 755 /opt/your-app
# 切换到 deployer 用户
su - deployer3.3 首次部署(手动)
# 登录服务器
ssh deployer@your-server.com
# 克隆代码
git clone https://github.com/learnCon/blog.git /opt/your-app
cd /opt/your-app
# 创建 .env 文件
cat > .env <<EOF
DOCKER_REGISTRY=registry.cn-hangzhou.aliyuncs.com
IMAGE_NAME=your-company/your-app
BLUE_TAG=stable
GREEN_TAG=latest
GRAFANA_PASSWORD=your-secure-password
EOF
# 登录镜像仓库
docker login registry.cn-hangzhou.aliyuncs.com \
-u $DOCKER_USERNAME -p $DOCKER_PASSWORD
# 拉取并启动服务
docker-compose up -d
# 检查状态
docker-compose ps
# 测试健康检查
curl http://localhost/health如果一切正常,你应该看到:
{
"status": "healthy",
"timestamp": "2026-06-20T10:30:00.000Z",
"version": "1.0.0"
}配置详解
GitHub Actions 流水线配置
让我们深入了解 .github/workflows/ci-cd.yml 的每个部分。
触发器配置
on:
push:
branches: [ main, develop ] # 推送到这些分支时触发
pull_request:
branches: [ main ] # PR 到 main 时触发说明:
- 当推送到
main或develop分支时,触发流水线 - 当创建指向
main的 Pull Request 时,触发流水线(用于代码检查)
自定义:
# 只在特定路径变更时触发
on:
push:
branches: [ main ]
paths:
- 'src/**'
- 'package*.json'
- 'Dockerfile'
- 'docker-compose.yml'环境变量
env:
DOCKER_REGISTRY: registry.cn-hangzhou.aliyuncs.com
IMAGE_NAME: your-project-name可用的环境变量:
| 变量名 | 说明 | 默认值 |
|---|---|---|
DOCKER_REGISTRY |
镜像仓库地址 | registry.cn-hangzhou.aliyuncs.com |
IMAGE_NAME |
镜像名称 | your-project-name |
Jobs 说明
Job 1: security-and-quality - 代码质量检查
security-and-quality:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置 Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 代码 Lint 检查
run: npm run lint
- name: 安全漏洞扫描
run: |
npm audit --audit-level=high
# 可选:使用 Snyk 进行深度安全扫描
# npx snyk test
- name: 依赖许可检查
run: |
npx license-checker --onlyAllow "MIT;ISC;BSD-2-Clause;BSD-3-Clause;Apache-2.0"
continue-on-error: true作用:
- ✅ 确保代码风格一致(Lint)
- ✅ 发现依赖中的安全漏洞
- ✅ 确保依赖许可合规
Job 2: test - 自动化测试
test:
needs: security-and-quality
runs-on: ubuntu-latest
steps:
- name: 运行单元测试
run: npm test
- name: 上传测试覆盖率
uses: actions/upload-artifact@v3
if: always()
with:
name: coverage-report
path: coverage/
retention-days: 30说明:
needs: security-and-quality表示依赖前一个 Job,只有代码检查通过才会运行测试- 测试覆盖率报告会保存 30 天,方便查看
Job 3: build - 构建镜像
build:
needs: test
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v2
- name: 登录镜像仓库
uses: docker/login-action@v2
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 提取元数据
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha
- name: 构建并推送镜像
id: build
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: 镜像安全扫描
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ steps.meta.outputs.tags }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: 上传扫描结果
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'亮点:
- ✅ 多阶段构建缓存,加速构建
- ✅ 自动生成镜像标签(分支名、PR 号、commit SHA)
- ✅ 镜像安全扫描(Trivy),发现基础镜像中的漏洞
- ✅ 扫描结果上传到 GitHub Security 面板
Job 4: deploy-dev - 部署到开发环境
deploy-dev:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/develop'
environment:
name: development
url: https://dev.your-domain.com
steps:
- name: 部署到开发环境
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.DEV_SERVER_HOST }}
username: ${{ secrets.DEV_SERVER_USER }}
key: ${{ secrets.DEV_SERVER_SSH_KEY }}
script: |
cd /opt/your-app
docker-compose pull
docker-compose up -d
docker-compose ps
# 健康检查
sleep 10
curl -f http://localhost:3000/health || exit 1说明:
if: github.ref == 'refs/heads/develop'表示只在develop分支触发- 自动部署到开发环境,无需人工干预
Job 5: deploy-prod - 部署到生产环境
deploy-prod:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://your-domain.com
steps:
# ... 蓝绿部署步骤(详见上一篇)
- name: 失败时自动回滚
if: failure()
uses: appleboy/ssh-action@v0.1.5
with:
script: |
echo "检测到部署失败,开始回滚..."
sudo cp /etc/nginx/conf.d/blue.conf /etc/nginx/conf.d/active.conf
sudo nginx -s reload
docker stop your-app-green || true
echo "回滚完成"说明:
- 需要手动审批(因为配置了
environment: production) - 蓝绿部署,零停机
- 失败时自动回滚
Docker 配置详解
Dockerfile 多阶段构建
# 阶段1: 构建阶段
FROM node:18-alpine AS builder
# 设置工作目录
WORKDIR /app
# 复制依赖文件并安装(利用 Docker 缓存)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 复制源代码
COPY . .
# 运行构建(如果有构建步骤)
RUN npm run build --if-present
# 阶段2: 生产镜像
FROM node:18-alpine
# 添加非 root 用户(提高安全性)
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 设置工作目录
WORKDIR /app
# 从构建阶段复制产物
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
# 切换到非 root 用户
USER nodejs
# 暴露端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" || exit 1
# 启动应用
CMD ["node", "dist/server.js"]优化效果:
| 对比项 | 单层构建 | 多阶段构建 |
|---|---|---|
| 镜像体积 | 1.2 GB | 150 MB |
| 构建时间(首次) | 5 分钟 | 6 分钟 |
| 构建时间(增量) | 5 分钟 | 2 分钟 |
| 安全性 | 低(root 用户) | 高(非 root 用户) |
docker-compose.yml 配置
version: '3.8'
services:
# 蓝环境(当前生产版本)
app-blue:
image: ${DOCKER_REGISTRY:-registry.cn-hangzhou.aliyuncs.com}/${IMAGE_NAME:-your-app}:${BLUE_TAG:-stable}
container_name: your-app-blue
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
# 绿环境(新版本)
app-green:
image: ${DOCKER_REGISTRY:-registry.cn-hangzhou.aliyuncs.com}/${IMAGE_NAME:-your-app}:${GREEN_TAG:-latest}
container_name: your-app-green
restart: unless-stopped
ports:
- "3001:3000"
environment:
- NODE_ENV=production
- PORT=3000
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
profiles:
- green # 默认不启动,需要时才启动
# Nginx 反向代理(蓝绿切换)
nginx:
image: nginx:alpine
container_name: your-app-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
- ./logs/nginx:/var/log/nginx
depends_on:
- app-blue
networks:
- app-network
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3关键点:
- 资源限制:防止单个容器占用过多资源
- 健康检查:Docker 会自动重启不健康的容器
- profiles:绿环境默认不启动,部署时才启动
- 数据卷:Nginx 配置和日志持久化
日常开发流程
功能开发流程
# 1. 从 develop 分支创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/new-feature
# 2. 开发功能
# ... 编写代码 ...
npm run lint # 本地先检查代码规范
npm test # 本地先运行测试
# 3. 提交代码
git add .
git commit -m "feat: 添加新功能"
git push origin feature/new-feature
# 4. 创建 Pull Request
# 在 GitHub 上创建 PR:feature/new-feature → develop
# GitHub Actions 自动运行:代码检查 → 测试 → 构建镜像
# 5. Code Review
# 团队成员进行代码审查
# 6. 合并到 develop
# PR 通过后,合并到 develop 分支
# GitHub Actions 自动部署到开发环境
# 7. 验证开发环境
curl https://dev.your-domain.com/health发布到生产环境
# 1. 确保 develop 分支稳定
git checkout develop
git pull origin develop
# 2. 合并到 main 分支
git checkout main
git pull origin main
git merge develop
git push origin main
# 3. GitHub Actions 自动运行
# - 代码检查 + 测试 + 构建镜像
# - 等待审批(如果配置了环境保护)
# - 审批通过后,自动部署到生产环境(蓝绿部署)
# - 健康检查
# - 切换流量
# 4. 验证生产环境
curl https://your-domain.com/health紧急回滚
如果生产环境出现问题,需要立即回滚:
方法 1: 通过 GitHub Actions 回滚
# 1. 在 GitHub 仓库的 Actions 标签页
# 2. 找到最近的部署 workflow run
# 3. 点击 "Re-run all jobs" 或手动触发回滚方法 2: 手动回滚
# 登录生产服务器
ssh deployer@prod-server.com
# 方法 A: 使用部署脚本
cd /opt/your-app
./deploy/deploy.sh rollback
# 方法 B: 手动操作
# 切换 Nginx 配置回蓝环境
sudo cp docker/nginx/conf.d/blue.conf docker/nginx/conf.d/active.conf
docker-compose exec nginx nginx -s reload
# 停止绿环境
docker-compose --profile green stop
# 验证
curl http://localhost/health下一步
在系列的下一篇文章中,我们将详细介绍:
- 📊 监控告警:Prometheus + Grafana 配置详解
- 🔧 故障排查:常见问题及解决方案
- 💡 最佳实践:生产环境经验总结
总结
本文详细介绍了:
- 快速开始 - 10 分钟完成环境搭建
- 配置详解 - GitHub Actions 和 Docker 配置说明
- 日常开发流程 - 从功能开发到生产发布的完整流程
- 紧急回滚 - 出现问题时的应对措施
通过本文的介绍,你应该已经能够:
✅ 配置镜像仓库和 GitHub Secrets
✅ 初始化服务器环境
✅ 理解 CI/CD 流水线的每个步骤
✅ 进行日常的开发和部署
下一篇预告:《CI/CD 自动化部署完全指南(三):监控告警与故障排查》
如果觉得这篇文章对你有帮助,欢迎点赞、收藏、转发! 🙏
有任何问题或建议,欢迎在评论区留言讨论!
评论
评论需要填写昵称和邮箱。评论内容将公开显示。
评论区加载中...