如何使用GitHub Actions自动部署Docker化博客系统

在现代Web开发中,拥有一套完善的CI/CD流程对于提高开发效率和保证部署稳定性至关重要。本文将详细介绍如何使用GitHub Actions为前后端分离的博客系统搭建完整的自动化部署流程,包括多个常见问题的解决方案。
项目架构
我们的博客系统由三个主要组件构成:
- 前台博客(blog-web): 基于Vue3的前端界面
- 管理后台(blog-admin): 后台管理界面
- API服务(blog-nest): 基于NestJS的后端服务
整个系统通过Docker和Docker Compose容器化,配合Nginx进行反向代理。
环境变量与敏感信息管理
在自动部署过程中,敏感信息管理是一个核心问题。以下是一些最佳实践:
敏感信息处理原则
- 构建时与运行时分离:构建镜像时不应包含敏感信息,敏感信息应在运行时注入
- 避免将环境变量硬编码到镜像中:不要在Dockerfile中使用COPY命令直接复制.env文件
- 使用GitHub Secrets存储敏感信息:所有密码、密钥等敏感信息应存储在GitHub Secrets中
实施步骤
-
在GitHub仓库中配置所需的Secrets
- 数据库凭证
- Redis密码
- JWT密钥
- Docker Hub凭证
- 服务器信息
- 第三方API密钥
-
在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 }}
- 在部署服务器上创建环境变量文件
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
- 通过Docker Compose中的
environment
和env_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进行合理的路由分发:
- 根域名 - 前台博客
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;
}
}
- admin子域名 - 管理后台
nginx
server {
listen 80;
server_name admin.conder.top;
location / {
proxy_pass http://admin:80;
proxy_set_header Host $host;
}
}
- 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时认证失败
解决方案:
- 确保Docker Hub用户名和密码正确配置在GitHub Secrets中
- 使用正确的登录步骤
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
最佳实践总结
- 镜像分层: 使用多阶段构建减小镜像体积
- 敏感信息管理: 构建时不包含敏感信息,运行时通过环境变量注入
- Docker Compose: 使用docker-compose.yml管理服务间依赖关系
- Nginx配置: 合理配置Nginx进行请求路由
- GitHub Secrets: 所有敏感信息存储在GitHub Secrets中
- 健康检查: 添加数据库健康检查确保服务正确启动
- 清理策略: 定期清理旧镜像和容器
通过以上实践,我们可以搭建一个安全、稳定、高效的GitHub Actions自动部署流程,为博客系统的开发和维护提供有力支持。
- 本文链接:https://conder.top/article/2
- 版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明文章出处!