GitHub Actions 实战:给个人项目接上免费的自动部署流水线

GitHub Actions 实战:给个人项目接上免费的自动部署流水线

别再手动 scp 了,让每次 git push 自动把项目部署上去。

我早期更新个人网站都是本地构建完,手动 scp 到服务器、再 ssh 进去重启,经常忘了哪一步就部署了个半成品。后来接上 GitHub Actions,现在只要推代码,构建、测试、部署全自动跑。这篇给初学者一份能直接抄的流水线模板。

不管你是做课程设计、接外包还是维护个人主页,只要代码放在 GitHub 上,这套思路都能用:把"部署"这件重复又容易出错的事交给机器。你只需要关心代码本身,剩下的交给流水线。下面所有片段都经过我实际跑通,复制后改改密钥和路径就能用。

一、免费额度与适用场景

GitHub Actions 对个人开发者非常友好:

项目 公开仓库 私有仓库
每月免费分钟数 无限 2000 分钟
存储 无限 500 MB
自带 runner 2 核 / 7 GB 同左
自托管 runner 免费、无限制 免费、无限制

适用场景:前端站自动构建部署、Node 服务推到服务器、跑单测做提交门禁、自动发版打 tag。个人项目基本够用,真不够可以挂一台自己的机器当自托管 runner。


二、workflow 文件长什么样

所有流水线都放在仓库的 .github/workflows/ 目录下,文件名随意、后缀 .yml。一个最基础的骨架:

yaml 复制代码
name: CI              # 流水线名字,显示在 Actions 页
on:                  # 什么时候触发
  push:
    branches: [main] # 只有推到 main 才跑
  pull_request:
    branches: [main]

jobs:                # 一个 workflow 由多个 job 组成
  build:
    runs-on: ubuntu-latest   # 用官方提供的 Linux  runner
    steps:                   # 顺序执行的步骤
      - uses: actions/checkout@v4   # 拉取代码
      - run: echo "在这里写命令"

三个核心概念:on 决定触发时机,jobs 是并行任务单元,steps 是具体动作(uses 引用别人写好的 action,run 跑 shell 命令)。

关于触发时机还有几个常用写法:on.push.tags 可以在打 tag 时触发发版;on.workflow_dispatch 能让你在网页上手动点按钮跑一次,调试流水线特别方便;on.pull_request 适合只在提 PR 时跑测试、不部署。多个 job 之间默认并行,如果一个要等另一个(比如先测试通过再部署),用 needs: build 声明依赖即可。另外加 concurrency 能防止多次快速推送时部署任务叠罗汉:

yaml 复制代码
concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: true   # 新推送进来就取消还在跑的旧部署

三、跑构建与测试(checkout + setup-node)

下面是一个 Node 项目的标准 CI:拉代码 → 装 Node → 装依赖 → 跑测试。

yaml 复制代码
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: 拉取代码
        uses: actions/checkout@v4

      - name: 安装 Node 20
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: 安装依赖
        run: npm ci          # ci 比 install 更严格,锁定 lockfile

      - name: 构建
        run: npm run build

      - name: 跑测试
        run: npm test

npm ci 要求必须有 package-lock.json,且版本不符会直接报错------这正好帮你在 CI 里卡住"依赖对不上"的问题。测试挂了,整个 job 标红,push 就不会被误判成功。


四、把产物部署到服务器(ssh + secrets)

构建完要部署到自己的云服务器,用 appleboy/ssh-action 通过 SSH 执行远程命令。密钥绝对不能写进仓库,统一放仓库 Settings → Secrets and variables → Actions 里:

yaml 复制代码
      - name: 部署到服务器
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.HOST }}          # 服务器 IP
          username: ${{ secrets.USERNAME }}  # 如 root
          key: ${{ secrets.SSH_KEY }}         # 私钥内容,非密码
          script: |
            cd /home/app/my-project
            git pull
            docker compose pull
            docker compose up -d
            docker image prune -f

secrets.SSH_KEY 放的是你本地 ~/.ssh/id_rsa私钥内容 (不是路径)。生成密钥对:ssh-keygen -t ed25519,把公钥 id_rsa.pub 追加到服务器的 ~/.ssh/authorized_keys,私钥整段粘进 secret。


五、部署到 Pages(GitHub Pages / Cloudflare Pages)

纯静态站(Vite、Vue、React 构建产物)没必要上服务器,直接丢 Pages 最省事。

GitHub Pages 需要额外加权限声明,否则会部署失败:

yaml 复制代码
permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci && npm run build
      - name: 上传产物
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./dist          # 构建输出目录
      - name: 部署
        uses: actions/deploy-pages@v4

Cloudflare Pages 用 wrangler 推上去,连服务器都不用买:

yaml 复制代码
      - name: 部署到 Cloudflare Pages
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          accountId: ${{ secrets.CF_ACCOUNT_ID }}
          command: pages deploy dist --project-name=my-site

六、缓存依赖、矩阵构建与分支触发

缓存依赖能显著加速,避免每次都重新下载:

yaml 复制代码
      - name: 缓存 npm
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

矩阵构建一次性验证多版本 Node,证明兼容性:

yaml 复制代码
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci && npm test

只让 main 触发部署 (避免 feature 分支也去动服务器):把部署 job 的触发单独限制,或者用 if: github.ref == 'refs/heads/main' 做条件判断。我习惯把 CI 和 CD 拆成两个文件:测试任何分支都跑,部署只在 main 上跑。


七、常见坑逐个排

报错 1:workflow 完全不触发

先确认文件在 .github/workflows/ 下且是合法 YAML;再确认 on.push.branches 写的就是你推送的分支名(很多人默认写了 main,实际仓库叫 master)。本地可用 yaml 校验语法。

报错 2:权限不足 / 403

Pages 部署忘记加 permissions 块是最常见的。自托管 runner 跑 docker 也要把用户加进 docker 组。

报错 3:secrets 读不到

secrets.XXX 只能在 with / run 里用,不能直接在 if 等部分上下文裸用;另外确认 secret 名字拼写和仓库设置里完全一致(大小写敏感)。

报错 4:部署成功但页面还是旧的

八成是 CD 没清缓存,或者部署的是 dist 但构建输出其实是 build。本地先 npm run build 看真实输出目录;Pages 注意开"每次部署前清除旧文件"。

报错 5:超时失败

单 job 默认超时 360 分钟、整个 runner 有 6 小时上限。装依赖卡住时优先加缓存;海外源慢就换国内镜像:npm config set registry https://registry.npmmirror.com

收个尾:流水线不是越复杂越好,先把"push main → 自动部署"这条最短路跑通,再慢慢加测试和缓存。今晚就给你的个人项目建一个 .github/workflows/deploy.yml,把 HOSTUSERNAMESSH_KEY 三个 secret 配好,推一次代码验证它真的自动上线了。

相关推荐
あ-2 小时前
企业 DevOps + 协同办公 + 可观测性 + 网络基础设施平台-Part 15.10 Kubernetes Role
devops
あ-2 小时前
企业 DevOps + 协同办公 + 可观测性 + 网络基础设施平台-Part 15.15 Backup & Disaster Recovery Role
devops
troy1282 小时前
Python 进阶提升(十二):自动化测试与 DevOps 实战
python·devops
m4Rk_2 小时前
【论文阅读】Agent 记忆机制(67):MemPO——用记忆级信用分配训练 Agent 主动管理长程上下文
论文阅读·人工智能·学习·开源·github
あ-3 小时前
企业 DevOps + 协同办公 + 可观测性 + 网络基础设施平台-Part 15.18 Storage & Data Platform Role
devops
A心有千千结4 小时前
Nginx网关可观测建设:打通流量入口,加速线上故障诊断
nginx·prometheus·devops
parksben4 小时前
OpenSider:让浏览器驱动 Agent
开源·github·agent
Lyy4 小时前
DevOps平台 — 第十一篇:工作项的设计与实现
后端·devops
ShineWinsu4 小时前
对于Git:远程操作的超详细保姆级解析
linux·git·gitee·github·远程仓库·分布式版本控制系统·远程操作