在现代Web开发中,拥有一套完善的CI/CD流程对于提高开发效率和保证部署稳定性至关重要。本文将详细介绍如何使用GitHub Actions为前后端分离的博客系统搭建完整的自动化部署流程,包括多个常见问题的解决方案。

项目架构

我们的博客系统由三个主要组件构成:

  • 前台博客(blog-web): 基于Vue3的前端界面
  • 管理后台(blog-admin): 后台管理界面
  • API服务(blog-nest): 基于NestJS的后端服务

整个系统通过Docker和Docker Compose容器化,配合Nginx进行反向代理。

环境变量与敏感信息管理

在自动部署过程中,敏感信息管理是一个核心问题。以下是一些最佳实践:

敏感信息处理原则

  1. 构建时与运行时分离:构建镜像时不应包含敏感信息,敏感信息应在运行时注入
  2. 避免将环境变量硬编码到镜像中:不要在Dockerfile中使用COPY命令直接复制.env文件
  3. 使用GitHub Secrets存储敏感信息:所有密码、密钥等敏感信息应存储在GitHub Secrets中

实施步骤

  1. 在GitHub仓库中配置所需的Secrets

    • 数据库凭证
    • Redis密码
    • JWT密钥
    • Docker Hub凭证
    • 服务器信息
    • 第三方API密钥
  2. 在GitHub Actions工作流中引用这些Secrets

yaml 复制代码
env:
  DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
  JWT_SECRET: ${{ secrets.JWT_SECRET }}
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
  DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
  1. 在部署服务器上创建环境变量文件
yaml 复制代码
- name: 部署到服务器 - 准备环境
  uses: appleboy/ssh-action@master
  with:
    host: ${{ env.SERVER_HOST }}
    username: ${{ env.SERVER_USERNAME }}
    key: ${{ env.SERVER_SSH_KEY }}
    script: |
      cd ${{ env.SERVER_DEPLOY_PATH }}
      
      # 创建环境变量文件
      cat > .env << EOF
      DB_HOST=mysql
      DB_PORT=3306
      DB_DATABASE=${{ secrets.DB_DATABASE }}
      DB_USERNAME=${{ secrets.DB_USERNAME }}
      DB_PASSWORD=${{ secrets.DB_PASSWORD }}
      REDIS_HOST=redis
      REDIS_PORT=6379
      REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}
      EOF
  1. 通过Docker Compose中的environmentenv_file注入环境变量
yaml 复制代码
services:
  nest:
    image: ${DOCKERHUB_USERNAME}/blog-nest:latest
    environment:
      - DB_HOST=mysql
      - DB_USERNAME=${DB_USERNAME}
      - DB_PASSWORD=${DB_PASSWORD}
    volumes:
      - ./packages/blog-nest/.env:/app/.env

Docker镜像构建与多阶段构建

为了保证镜像体积小、构建速度快,推荐使用多阶段构建:

dockerfile 复制代码
# 基础阶段 - 仅安装依赖
FROM node:19.6.1 AS deps
WORKDIR /app

# 仅复制 package.json 相关文件
COPY package.json pnpm-lock.yaml ./

# 安装依赖
RUN npm install -g pnpm && pnpm install

# 构建阶段
FROM node:19.6.1 AS builder
WORKDIR /app

# 复制依赖
COPY --from=deps /app/node_modules ./node_modules

# 复制源代码并构建
COPY . .
RUN npm run build

# 生产阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

Nginx配置与域名分发

由于我们有多个服务,需要通过Nginx进行合理的路由分发:

  1. 根域名 - 前台博客
nginx 复制代码
server {
    listen 80;
    server_name conder.top www.conder.top;

    location / {
        proxy_pass http://web:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  1. admin子域名 - 管理后台
nginx 复制代码
server {
    listen 80;
    server_name admin.conder.top;

    location / {
        proxy_pass http://admin:80;
        proxy_set_header Host $host;
    }
}
  1. api子域名 - API服务
nginx 复制代码
server {
    listen 80;
    server_name api.conder.top;

    location / {
        proxy_pass http://nest:3000;
        proxy_set_header Host $host;
    }
}

常见问题与解决方案

在实施过程中,我们遇到了许多常见问题,这里分享解决方案:

1. GitHub Actions找不到pnpm-lock.yaml文件

问题: 在执行pnpm install --frozen-lockfile时报错找不到pnpm-lock.yaml

解决方案:
确保工作流中正确地检出了完整代码库

yaml 复制代码
- name: 检出代码
  uses: actions/checkout@v4
  with:
    fetch-depth: 0

2. Docker Hub认证失败(401 Unauthorized)

问题: 推送镜像到Docker Hub时认证失败

解决方案:

  1. 确保Docker Hub用户名和密码正确配置在GitHub Secrets中
  2. 使用正确的登录步骤
yaml 复制代码
- name: 登录Docker Hub
  uses: docker/login-action@v2
  with:
    username: ${{ env.DOCKERHUB_USERNAME }}
    password: ${{ env.DOCKERHUB_TOKEN }}

3. 环境变量未设置警告

问题: 容器启动时警告环境变量未设置

解决方案:
在docker-compose.yml中正确声明所有必要的环境变量

yaml 复制代码
services:
  nest:
    environment:
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_USERNAME=${DB_USERNAME}
      - DB_PASSWORD=${DB_PASSWORD}

4. 找不到nginx配置文件

问题: 容器启动时找不到nginx配置文件

解决方案:
确保在部署服务器上创建所需的配置文件,并将其挂载到容器中

yaml 复制代码
volumes:
  - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
  - ./nginx/nginx.conf:/etc/nginx/nginx.conf

5. Docker镜像推送需要tag

问题: 推送Docker镜像时未指定tag

解决方案:
为Docker镜像指定清晰的标签,包括latest和特定版本

yaml 复制代码
- name: 构建并推送镜像
  uses: docker/build-push-action@v4
  with:
    context: .
    file: ./docker/blog-nest.Dockerfile
    push: true
    tags: |
      ${{ env.DOCKERHUB_USERNAME }}/blog-nest:${{ env.TAG }}
      ${{ env.DOCKERHUB_USERNAME }}/blog-nest:latest

完整GitHub Actions工作流示例

下面是一个完整的GitHub Actions工作流示例,包含了从构建到部署的全过程:

yaml 复制代码
name: 生产环境发布

on:
  push:
    branches: [main]
  workflow_dispatch:

env:
  NODE_VERSION: 19.6.1
  PNPM_VERSION: 9.7.1
  DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
  JWT_SECRET: ${{ secrets.JWT_SECRET }}
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
  DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
  TAG: ${{ github.sha }}

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: 检出代码
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: 设置Node.js环境
        uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}

      - name: 安装PNPM
        uses: pnpm/action-setup@v2
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: 安装依赖
        run: pnpm install --frozen-lockfile

      - name: 应用构建
        run: pnpm build

      - name: 设置Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: 登录Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ env.DOCKERHUB_USERNAME }}
          password: ${{ env.DOCKERHUB_TOKEN }}

      - name: 构建并推送镜像
        uses: docker/build-push-action@v4
        with:
          context: .
          file: ./docker/blog-web.Dockerfile
          push: true
          tags: |
            ${{ env.DOCKERHUB_USERNAME }}/blog-web:${{ env.TAG }}
            ${{ env.DOCKERHUB_USERNAME }}/blog-web:latest

      # 部署到服务器
      - name: 部署到服务器
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USERNAME }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            cd ${{ secrets.SERVER_DEPLOY_PATH }}
            docker compose pull
            docker compose up -d

最佳实践总结

  1. 镜像分层: 使用多阶段构建减小镜像体积
  2. 敏感信息管理: 构建时不包含敏感信息,运行时通过环境变量注入
  3. Docker Compose: 使用docker-compose.yml管理服务间依赖关系
  4. Nginx配置: 合理配置Nginx进行请求路由
  5. GitHub Secrets: 所有敏感信息存储在GitHub Secrets中
  6. 健康检查: 添加数据库健康检查确保服务正确启动
  7. 清理策略: 定期清理旧镜像和容器

通过以上实践,我们可以搭建一个安全、稳定、高效的GitHub Actions自动部署流程,为博客系统的开发和维护提供有力支持。

评论
默认头像
评论
沙发
May 10, 2025 at 09:45 AM0回复