GitHub Actions 自动部署问题总结
GitHub Actions 自动部署问题总结
Table of Contents
On this page
- GitHub Actions 自动部署问题总结
- 📋 目录
- 部署架构
- 目标
- 技术栈
- 问题一:Secrets 配置警告
- ❌ 错误信息
- 🔍 原因分析
- ✅ 解决方案
- 问题二:文件权限拒绝
- ❌ 错误信息
- 🔍 原因分析
- ✅ 解决方案
- 问题三:服务器网络限制
- ❌ 错误信息
- 🔍 原因分析
- ✅ 解决方案
- 问题四:docker-compose 配置冲突
- ❌ 错误信息
- 🔍 原因分析
- ✅ 解决方案(两步)
- 问题五:环境变量缺失
- ❌ 现象
- 🔍 原因分析
- ✅ 解决方案
- 最终解决方案
- 完整的 GitHub Actions 工作流
- 经验教训
- 1. 🌐 网络环境评估至关重要
- 2. 📦 Docker Compose 的两种模式
- 3. 🔐 环境变量管理
- 4. 🛠️ 自动化脚本的健壮性
- 5. 📝 权限问题预防
- 6. 🔄 分步验证
- 后续优化建议
- 总结
GitHub Actions 自动部署问题总结
本文档记录了在配置 GitHub Actions 自动部署到生产服务器时遇到的所有问题及解决方案。
📋 目录
部署架构
目标
使用 GitHub Actions 实现代码推送后自动构建 Docker 镜像并部署到生产服务器。
技术栈
- 应用:Next.js 16 + Prisma
- 容器化:Docker + Docker Compose
- CI/CD:GitHub Actions
- 部署方式:SCP 上传镜像 + SSH 远程执行部署命令
问题一:Secrets 配置警告
❌ 错误信息
Context access might be invalid: SERVER_HOST @[deploy.yml:L27]
🔍 原因分析
GitHub Actions 在静态分析时无法验证 secrets.SERVER_HOST 是否存在,因为 repository secrets 尚未配置。
✅ 解决方案
在 GitHub 仓库设置中添加以下 Secrets:
- 进入 Settings → Secrets and variables → Actions
- 添加以下 secrets:
SERVER_HOST:服务器 IP 地址(如8.166.136.59)SERVER_USER:SSH 用户名(如root)SERVER_SSH_KEY:SSH 私钥完整内容SERVER_PORT:SSH 端口(可选,默认 22)
问题二:文件权限拒绝
❌ 错误信息
tar: can't open 'cbiu-website.tar': Permission denied
exit status 1
🔍 原因分析
docker save 命令生成的 tar 文件默认权限可能不允许后续的 SCP action 读取。
✅ 解决方案
在保存 Docker 镜像后添加 chmod 命令修改文件权限:
- name: Build Docker image
run: |
docker build -t cbiu-website:latest .
docker save cbiu-website:latest -o cbiu-website.tar
chmod 644 cbiu-website.tar # 添加此行
问题三:服务器网络限制
❌ 错误信息
ERROR: failed to resolve reference "docker.io/library/mysql:8.0":
failed to do request: Head "https://registry-1.docker.io/v2/library/mysql/manifests/8.0":
dial tcp 168.143.162.58:443: i/o timeout
🔍 原因分析
生产服务器存在严重的网络限制问题:
- 无法访问 Docker Hub 官方镜像仓库
- DNS 解析失败(无法解析
mirror.ccs.tencentyun.com等镜像加速器域名) - 配置了 Docker 镜像加速器后仍然超时
- 尝试多个镜像源(腾讯云、阿里云、网易、中科大)均失败
核心问题:服务器网络环境特殊,几乎无法从外部拉取任何 Docker 镜像。
✅ 解决方案
将镜像拉取工作转移到 GitHub Actions 服务器(网络畅通),然后上传到生产服务器:
1. 修改构建步骤,同时拉取并保存 MySQL 镜像
- name: Build Docker images
run: |
# Build application image
docker build -t cbiu-website:latest .
docker save cbiu-website:latest -o cbiu-website.tar
chmod 644 cbiu-website.tar
# Pull and save MySQL image
docker pull mysql:8.0
docker save mysql:8.0 -o mysql.tar
chmod 644 mysql.tar
2. 上传两个镜像文件
- name: Upload images to server
uses: appleboy/scp-action@v0.1.7
with:
source: "cbiu-website.tar,mysql.tar" # 上传多个文件
target: "/root/projects/cbiu-website/"
3. 在服务器上加载镜像
script: |
cd /root/projects/cbiu-website
docker load -i mysql.tar
docker load -i cbiu-website.tar
问题四:docker-compose 配置冲突
❌ 错误信息
Building app
ERROR: failed to solve: node:20.9.0-alpine3.18:
failed to resolve source metadata for docker.io/library/node:20.9.0-alpine3.18
🔍 原因分析
docker-compose.yml 中 app 服务配置了 build 字段:
app:
build:
context: .
dockerfile: Dockerfile
执行 docker-compose up -d 时,Docker Compose 会尝试重新构建镜像,而不是使用已有的 cbiu-website:latest 镜像。这导致服务器再次尝试从网络拉取 Node.js 基础镜像,最终失败。
✅ 解决方案(两步)
方案 1:修改本地 docker-compose.yml
将 build 配置改为 image 配置:
app:
container_name: cbiu-website
image: cbiu-website:latest # 使用预构建镜像
restart: always
优点:一劳永逸
缺点:影响本地开发环境的构建流程
方案 2:部署时自动修改(最终采用)
在 GitHub Actions 部署脚本中自动修改服务器上的 docker-compose.yml:
script: |
cd /root/projects/cbiu-website
# Load images
docker load -i mysql.tar
docker load -i cbiu-website.tar
# Auto-fix docker-compose.yml
if grep -q "build:" docker-compose.yml; then
sed -i '/app:/,/restart:/ {
/build:/,/dockerfile:/d
/container_name:/a\ image: cbiu-website:latest
}' docker-compose.yml
fi
# Start services
docker-compose up -d
优点:不影响本地开发,每次部署自动修正
缺点:需要额外的脚本逻辑
问题五:环境变量缺失
❌ 现象
容器启动后立即退出,或应用无法连接数据库。
🔍 原因分析
GitHub Actions 只上传了镜像文件,但没有上传 .env 文件(因为 .env 在 .gitignore 中)。
应用启动时缺少必要的环境变量:
DATABASE_URLAUTH_SECRETAUTH_URLMYSQL_ROOT_PASSWORDMYSQL_DATABASE
✅ 解决方案
在服务器上手动创建 .env 文件:
cd /root/projects/cbiu-website
nano .env
填入以下内容:
# 数据库配置
DATABASE_URL="mysql://root:123456@db:3306/cbiu_webside"
# MySQL 初始化配置
MYSQL_ROOT_PASSWORD="123456"
MYSQL_DATABASE="cbiu_webside"
# NextAuth 配置
AUTH_SECRET="生成的随机密钥" # 使用 openssl rand -base64 32 生成
AUTH_URL="http://8.166.136.59:3000"
注意:
AUTH_URL必须包含http://协议前缀,否则会导致认证失败。
最终解决方案
完整的 GitHub Actions 工作流
name: Deploy to Production
on:
push:
branches: [ main, master ]
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# 构建应用镜像 + 拉取 MySQL 镜像
- name: Build Docker images
run: |
docker build -t cbiu-website:latest .
docker save cbiu-website:latest -o cbiu-website.tar
chmod 644 cbiu-website.tar
docker pull mysql:8.0
docker save mysql:8.0 -o mysql.tar
chmod 644 mysql.tar
# 同时上传两个镜像
- name: Upload images to server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
port: ${{ secrets.SERVER_PORT || 22 }}
source: "cbiu-website.tar,mysql.tar"
target: "/root/projects/cbiu-website/"
# 部署并自动修正配置
- name: Deploy on server
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
port: ${{ secrets.SERVER_PORT || 22 }}
script: |
cd /root/projects/cbiu-website
# 加载镜像
docker load -i mysql.tar
docker load -i cbiu-website.tar
# 自动修正 docker-compose.yml
if grep -q "build:" docker-compose.yml; then
sed -i '/app:/,/restart:/ {
/build:/,/dockerfile:/d
/container_name:/a\ image: cbiu-website:latest
}' docker-compose.yml
fi
# 启动服务
docker-compose up -d
# 清理
docker image prune -f
rm cbiu-website.tar mysql.tar
echo "✅ Deployment completed successfully!"
经验教训
1. 🌐 网络环境评估至关重要
在配置 CI/CD 之前,必须先评估生产服务器的网络环境:
- 能否访问 Docker Hub?
- 能否使用镜像加速器?
- DNS 解析是否正常?
如果网络受限,应该将镜像构建工作完全转移到 CI 环境。
2. 📦 Docker Compose 的两种模式
- 开发模式:使用
build配置,本地构建镜像 - 生产模式:使用
image配置,使用预构建镜像
两种模式不能混用,否则会导致部署时尝试重新构建。
3. 🔐 环境变量管理
.env文件不应提交到 Git- 生产环境需要手动或通过配置管理工具创建
.env - 考虑使用 GitHub Secrets + 部署脚本自动生成
.env
4. 🛠️ 自动化脚本的健壮性
部署脚本应该:
- 检查文件是否存在
- 处理配置文件差异
- 提供清晰的错误信息
- 支持幂等操作(多次执行结果一致)
5. 📝 权限问题预防
生成的文件(如 tar 包)应该显式设置权限,避免后续步骤无法访问。
6. 🔄 分步验证
遇到问题时,逐步验证:
- 镜像是否已构建?
- 镜像是否已上传?
- 镜像是否已加载?
- 容器是否已创建?
- 容器是否正在运行?
- 应用是否正常启动?
后续优化建议
-
使用私有镜像仓库
- 在阿里云 ACR 或腾讯云 TCR 创建私有仓库
- GitHub Actions 推送镜像到私有仓库
- 服务器从私有仓库拉取(避免传输大文件)
-
环境变量自动化
- name: Create .env file script: | cat > .env << EOF DATABASE_URL=${{ secrets.DATABASE_URL }} AUTH_SECRET=${{ secrets.AUTH_SECRET }} AUTH_URL=${{ secrets.AUTH_URL }} EOF -
健康检查 添加部署后的健康检查:
- name: Health check run: | sleep 10 curl -f http://${{ secrets.SERVER_HOST }}:3000/ || exit 1 -
回滚机制 保留上一个版本的镜像,部署失败时自动回滚。
-
通知集成 部署成功/失败时发送通知(Slack、邮件、企业微信等)。
总结
这次部署经历了从简单的配置错误到复杂的网络环境问题,最终通过将镜像构建转移到 CI 环境和自动化配置修正解决了所有问题。
关键要点:
- ✅ CI/CD 设计应适应生产环境限制
- ✅ 网络受限环境需要完整的镜像传输方案
- ✅ 自动化脚本要能处理配置差异
- ✅ 环境变量管理需要明确的流程
GitHub Actions 部署已成功运行,现在每次代码推送都会自动构建并部署到生产环境!🎉