[T.10] 团队项目:CI/CD实践

这个作业属于哪个课程 北航2026年春季软件工程
这个作业的要求在哪里 [T.10] 实验课/团队项目:团队代码管理准备
我在这个课程的目标是 体验完整软件开发流程,交付一款真正解决科研阅读痛点的软件产品
这个作业在哪个具体方面帮助我实现目标 CI/CD实践

选项选择及理由

方案 A(GitHub Actions)

打包

理由如下:

  • 项目为前后端分离架构(Python 后端 + Vue/TypeScript 前端),GitHub Actions 支持多 Job 并行/串行、矩阵策略、环境隔离,可以很自然地为前后端分别编写独立的工作流,互不干扰
  • 使用 GitHub 原生 CI/CD 服务,无需搭建额外的基础设施
  • 团队已有在 dev 分支上协作的习惯,将自动化放在 dev 分支的 push 和 PR 事件上,可以在代码集成阶段就获得快速反馈,而不会阻塞特性分支的随意提交
  • 相比纯粹的代码检查或简单测试,打包能产出可部署的制品(后端 Docker 镜像、前端静态资源包)能为后续的自动化部署打下基础

配置文件脚本

位于 .github/workflows/ 下

后端 CI/CD (backend-cicd.yml)

name: Backend CI/CD

on:
  push:
    branches: [dev]
    paths:
      - 'src/backend/**'
  pull_request:
    branches: [dev]
    paths:
      - 'src/backend/**'

defaults:
  run:
    working-directory: src/backend

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'
          cache-dependency-path: src/backend/requirements.txt

      - name: Install dependencies
        run: |
          pip install --upgrade pip
          pip install -r requirements.txt
          pip install flake8 pytest

      - name: Lint with flake8
        run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics

      - name: Run tests
        run: pytest --maxfail=3 --disable-warnings -q

  build-and-deploy:
    needs: lint-and-test
    if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: src/backend
          push: true
          tags: |
            ghcr.io/${{ github.repository }}/backend:dev
            ghcr.io/${{ github.repository }}/backend:${{ github.sha }}

      - name: Deploy to dev server via SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /opt/backend
            docker compose pull backend
            docker compose up -d backend
            docker image prune -f

前端 CI/CD (frontend-cicd.yml)

name: Frontend CI/CD

on:
  push:
    branches: [dev]                # 仅 dev 分支 push 触发
    paths:
      - 'src/frontend/**'
  pull_request:
    branches: [dev]                # 向 dev 发 PR 时触发
    paths:
      - 'src/frontend/**'

defaults:
  run:
    working-directory: src/frontend

jobs:
  lint-and-build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
          cache-dependency-path: src/frontend/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Upload dist artifact
        uses: actions/upload-artifact@v4
        with:
          name: frontend-dist
          path: src/frontend/dist

  deploy:
    needs: lint-and-build
    if: github.event_name == 'push' && github.ref == 'refs/heads/dev' 
    runs-on: ubuntu-latest
    steps:
      - name: Download dist artifact
        uses: actions/download-artifact@v4
        with:
          name: frontend-dist
          path: dist

      - name: Deploy to dev server via rsync
        uses: easingthemes/ssh-deploy@v4.1.10
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          ARGS: "-avz --delete"
          SOURCE: "dist/"
          REMOTE_HOST: ${{ secrets.SERVER_IP }}
          REMOTE_USER: ${{ secrets.SERVER_USER }}
          TARGET: "/var/www/frontend"   # dev 环境的前端部署目录

实现方式及理由

分支范围:仅监听 dev 分支。团队采用 Git Flow 简化版,所有功能分支先合并到 dev 进行集成,稳定后才会合入 main。这种设置避免了开发阶段的频繁触发对 main 分支的干扰。

触发条件

  • push:当有代码推送到 dev 分支(且变更文件在对应模块目录下)时触发,用于持续集成和自动部署。
  • pull_request:当有 PR 指向 dev 分支时也会触发,可在合并前进行质量门禁。
  • 通过 paths 过滤器实现精准触发:后端工作流仅关注 src/backend/** 变更,前端仅关注 src/frontend/** 变更。

执行的动作

  • 后端打包与部署:使用 docker/build-push-action@v5 构建 Docker 镜像并推送到 GitHub 容器仓库(ghcr.io)。镜像打上了两个标签:dev(指向最新的开发镜像)和 github.sha(与本次提交一一对应,确保可追溯),让后端代码的每一次集成都可以直接获得一个可运行的容器。构建完成后,通过 appleboy/ssh-action@v1.0.3 SSH 连接到开发服务器,执行 docker compose pulldocker compose up -d 更新后端服务,并清理无用的旧镜像。

  • 前端打包与部署:通过 npm run build 生成静态资源,之后使用 actions/upload-artifact@v4dist 目录上传为工作流产物。该产物可在 GitHub Actions 的页面上直接下载,方便团队成员在不搭建本地环境的情况下快速查看某个版本的构建结果,也为后续的部署 Job 提供了可传递的制品(通过 download-artifact 实现)。部署阶段使用 easingthemes/ssh-deploy@v4.1.10 通过 rsync 将构建产物同步到开发服务器的 /var/www/frontend 目录,--delete 参数确保远端目录与构建结果完全一致。

  • 质量左移:在工作流中,打包之前都串行了 lint 检查(后端 flake8)和测试(后端 pytest),任意前置环节失败,打包和部署都将被阻止。前端构建步骤中,npm ci 会严格按 package-lock.json 安装依赖,确保构建环境的一致性。

CI/CD 触发结果展示

image

posted @ 2026-04-28 15:21  BBnomoney  阅读(23)  评论(0)    收藏  举报