DevOpsGitHub ActionsCI/CD
GitHub Actions 部署失败了?这篇帮你排查所有原因
半夜起来发现线上挂了,Actions 日志红了一片——别慌,这篇老司机带你逐条摸排,从 runner 超时到 Docker build 失败,从 secrets 漏配到 action 版本踩坑,5 分钟定位根因,对症下药。
一、常见报错场景:先定位是哪一类问题
GitHub Actions 出错的形式就那么几种,搞清楚是哪一类,排查效率翻倍。先对号入座:
| 报错表现 | 可能原因 | 优先级 |
|---|---|---|
| Job 一直 pending,超时后取消 | runner 不可用 / 无效标签 / 队列阻塞 | 🔴 高 |
| Push 代码触发了,但什么都没跑 | workflow 条件判断 / 分支过滤 / 没启用 Actions | 🔴 高 |
| Permission denied / 403 Forbidden | secrets 未配 / GITHUB_TOKEN 权限不足 / scope 限制 | 🔴 高 |
| Docker build 失败,exit code 非零 | Dockerfile 错误 / 构建上下文 / 多阶段构建问题 | 🔴 高 |
| action 版本报错(找不到 action / 版本冲突) | 版本 tag 写错 / major 版本 breaking change / 未指定版本 | |
| cache 失效,每次都重新构建 | cache key 变了 / actions/cache 版本 / 存储策略 | 🟡 中 |
| 并行 Job 有 race condition,或串行太慢 | job 间数据依赖 / needs 依赖链设计 / matrix 设计 | 🟡 中 |
| 日志里有乱码、中文显示异常 | locale 设置 / 文件编码 / log 层级配置 | 🟢 低 |
二、诊断三板斧:logs → 环境变量 → 权限
不管什么报错,先跑这三步,80% 的问题在这里就能定位。
1. 先看 Logs,别猜
Actions 日志是金矿。很多人一看红了就慌,其实日志里写得清清楚楚。关键是看三点:
- 失败那行的上下文:往上滚动 10-20 行,找到第一条 error 而不是最后一行 panic
- Exit code:非零退出码背后藏着真相,`echo $?` 或者日志里的
Exit code: 1 - warnings:特别是 Node/Python 版本警告,很多行为是因为 Node 版本差异导致的隐性 bug
💡 技巧:在 Job 失败时点「Re-run failed jobs」之前,先把完整日志另存为。重新跑会覆盖日志,有时候第一次的报错才是根因。
2. 环境变量是否到位
很多"玄学"问题其实是环境变量没配或者配错了地方。最常见的情况:
# ❌ 错误:环境变量写在 job 外面但在 step 里用了
env:
NODE_ENV: production
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ✅ 正确:环境变量写在 job 内部
jobs:
build:
runs-on: ubuntu-latest
env:
NODE_ENV: production
steps:
- uses: actions/checkout@v4
检查清单:
- 变量是在
env:还是在 step 里的env:?作用域不同 - secrets 在 workflow 里要用
${{ secrets.XXX }}注入,不能直接写值 - 矩阵(matrix)展开的变量在 job 内可见,job 外不可见
3. 权限对了没有
GITHUB_TOKEN 默认权限是受限的,很多操作需要显式授权。这是新手最常踩的坑。
# 最常见的权限问题场景
jobs:
deploy:
permissions:
contents: write # 推送代码 / 创建 tag / Pages 部署
packages: write # 推送 Docker 镜像到 GHCR
pull-requests: write # 评论 PR / 创建 PR
id-token: write # OIDC 云认证(AWS/GCP/Azure)
⚠️ 坑:Organization 仓库默认会覆盖仓库级别的权限设置。如果你的 workflow 在 org 仓库里跑,即使加了
permissions: 也可能不生效,要去 org 设置里放开。
三、5 种常见错误 + 修复方案
错误 1:runner 一直 pending 超时
报错表现
Job 状态是黄色 "In progress",但没有任何日志输出,等待几分钟后显示 "The runner has not received a heartbeat in 600 seconds"。
原因主要有三种:
- 标签写错:比如写
ubuntu-22.04但仓库没有自托管 runner,或者self-hosted标签没有匹配的机器 - 自托管 runner 离线:服务器关机、agent 服务没启动、网络不通
- macOS runner 队列爆炸:GitHub 托管的 macOS runner 僧多粥少,高峰期排队严重
修复方案
# 检查 runner 标签是否正确
jobs:
build:
runs-on: ubuntu-latest # GitHub 托管,直接用这个
# runs-on: [self-hosted] # 自托管,注意确保机器在线
timeout-minutes: 30 # 加超时限制,别让 Job 无限挂起
# 自托管 runner 排查顺序:
# 1. 服务器上: ./run.sh 是否在跑(ps aux | grep run)
# 2. 网络: curl https://api.github.com 是否通
# 3. 标签: 仓库 Settings → Actions → Runners,确认标签匹配
错误 2:secrets 没配或引用方式错误
报错表现
Error: Input required and not supplied: token 或 Error: secrets.xxx is not defined,或者 push 到仓库时显示 "Authentication failed"。
secrets 配置和引用是两件事,很多人搞混。
第一步:仓库/Organization 里配置 secrets
- 仓库 Settings → Secrets and variables → Actions → New repository secret
- Organization secrets 可以共享给多个仓库,但要确保该仓库有权限
第二步:workflow 里正确引用
# ✅ 正确引用方式
jobs:
deploy:
runs-on: ubuntu-latest
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
steps:
- name: Deploy
run: ./deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} # step 级也行
# ❌ 常见错误:把 secrets 当普通变量写
env:
DB_PASSWORD: "your_real_password" # 不要这样做!会提交到 git
💡 环境变量 vs step env:job 级的
env: 所有 step 共享;step 级的 env: 只有当前 step 可用。如果某个 step 需要单独的 secrets,用 step 级。
错误 3:action 版本问题 / 找不到 action
报错表现
Error: Cannot find module '@actions/artifact'」或「The workflow is not valid. Unexpected value 'v4'"`,以及 "The version 'v3' is deprecated for this action"。
action 版本有三个坑:
- 不写版本,用 latest:
actions/checkout@v4写死的版本不会突然爆炸 - 大版本 breaking change:
actions/setup-node@v4有时候会更新导致不兼容 - 私有 action 路径写错:
uses: ./my-action路径没找到
# ✅ 推荐:锁定到具体版本(SHA 安全且稳定)
jobs:
build:
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/setup-node@v4.2.3
with:
node-version: '20'
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# ❌ 不推荐:latest 或 major 版本随时可能变
# - uses: actions/checkout@latest ← 不稳定
# - uses: actions/checkout@v4 ← major 可能 breaking
🔒 安全建议:用 SHA 而非版本号更安全,防止供应链攻击。GitHub 官方 action 的 SHA 在 release 页面有记录,每次 update 后记得换 SHA。
错误 4:Docker build 失败
报错表现
Error response from daemon: docker build failed with exit code 1,或 Dockerfile 里 RUN npm ci 时报错 "npm not found",或者 multi-stage build 里某 stage 找不到依赖。
Docker build 失败的根因五花八门,按这个顺序查:
- 构建上下文正确吗?
docker build默认在 git root,如果Dockerfile不在 root,要用context指定 - docker/login-action 用了吗?推送到 GHCR 需要先登录
- .dockerignore 漏了 node_modules 吗?本地 node_modules 被 COPY 进去导致覆盖镜像层
- 多阶段构建 target 写对了吗?
# 完整 Docker 构建 + 推送 workflow
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- 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.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: ./backend # ← 指定构建上下文
push: true
tags: ghcr.io/${{ github.repository }}/myapp:latest
cache-from: type=gha # ← 用 GitHub Actions cache 加速
cache-to: type=gha,mode=max
# .dockerignore 示例(避免 node_modules 被 COPY)
node_modules
.git
*.log
.env
如果 build 缓存失效太频繁,用 cache-from: type=gha + cache-to: type=gha 把构建层缓存到 GitHub Actions Cache,第二次构建快很多。
错误 5:权限不足(GITHUB_TOKEN 限制)
报错表现
GraphQL: Resource not accessible by integration (HTTP 403),或者 push 代码时 "remote: Permission denied",或者 "Unable to push to remote repository"。GITHUB_TOKEN 的默认权限极其保守。常见需要额外权限的场景:
| 操作 | 所需权限 |
|---|---|
| Push 代码到另一个仓库 | contents: write(目标仓库要有写入权) |
| 创建/更新 GitHub Release | contents: write |
| 推送 Docker 镜像到 GHCR | packages: write |
| 创建 PR / 评论 PR | pull-requests: write |
| 写入 GitHub Pages | pages: write |
| OIDC 云认证(AWS/GCP/Azure) | id-token: write |
| 更新 GitHub Projects | projects: write |
# 完整权限示例:部署到 GitHub Pages
jobs:
deploy-pages:
runs-on: ubuntu-latest
permissions:
contents: read # 检出代码
pages: write # 写入 GitHub Pages
id-token: write # OIDC 认证
environment: github_pages # 指定环境,环境级权限更细
steps:
- uses: actions/checkout@v4
- uses: actions/upload-pages-artifact@v3
with:
path: ./dist
- uses: actions/deploy-pages@v4
四、优化 CI 速度:并行 vs 串行
CI 跑 20 分钟和跑 5 分钟,对开发体验影响巨大。这里说几个实打实的优化手段。
1. 矩阵并行:让多个 Job 同时跑
# 矩阵并行:同时测试多个 Node 版本
jobs:
test:
strategy:
matrix:
node-version: ['18', '20', '22']
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm' # 自动缓存 node_modules
- run: npm ci
- run: npm test
# 结论:3 个 Node × 2 个 OS = 6 个 Job 并行跑,总时间不变,效率 6 倍
2. Job 依赖链优化:减少不必要的串行
# ❌ 低效:所有 Job 串行等前一个完成
jobs:
install:
runs-on: ubuntu-latest
steps: ...
build:
needs: install # 等 install 完才能跑
runs-on: ubuntu-latest
steps: ...
test:
needs: build # 等 build 完才能跑
runs-on: ubuntu-latest
steps: ...
# ✅ 高效:install → build|test 并行
jobs:
install:
runs-on: ubuntu-latest
steps:
- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
build:
needs: install
runs-on: ubuntu-latest
steps: ...
test:
needs: install # ← 只依赖 install,不依赖 build
runs-on: ubuntu-latest
steps: ...
needs 依赖链的设计原则:只依赖真正需要的前置结果,不要为了"保险"串一堆。
3. 依赖缓存:让每次构建不是从零开始
# Node.js 缓存(最常见)
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
# Python 缓存
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ runner.os }}-${{ hashFiles('**/requirements.txt') }}
# Docker layer 缓存(用 buildx)
- uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
4. 快、省、准:条件执行
# 只在特定分支/文件变化时才跑 CI
jobs:
test:
if: github.event_name == 'push' || github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 需要 shallow false 来做 diff
- name: Run tests
run: |
if git diff --name-only origin/main...HEAD | grep -qE '\.(js|ts)
常见问题
Q: 如何使用 githubactions部署失败排查指南 相关工具?
A: 这类工具一般有明确的输入框和输出框,按提示输入内容,点击对应按钮即可得到结果。建议先用简单示例测试功能是否正常,再处理实际数据。
Q: githubactions部署失败排查指南 适合在什么场景使用?
A: 根据具体工具类型决定。格式转换工具适合处理第三方数据,编码工具适合加密传输,压缩工具适合文件上传前处理。多积累工具使用经验,遇到问题时能快速判断用哪个工具解决。
Q: 有没有更好的替代工具?
A: 不同工具有不同侧重,重点是理解原理。可以同时安装多个类似工具,实际使用中对比效果,选择最顺手的一个。随着使用经验增加,你也能判断工具的好坏。