雷灵模板

我给自己项目配了一套 GitHub Actions 自动部署,踩了几个坑以后终于顺手了

author
·
7
0
🤖AI摘要
文章分享了作者将 GitHub Actions 集成到项目部署中,提高了效率的过程。介绍了 GitHub Actions 部署的具体步骤,包括拉代码、构建项目、使用 SSH 同步文件到服务器及重启服务,节省了时间和简化了部署流程。还讲解了触发条件和设置注意事项,并针对 npm 的 `npm ci` 使用、缓存机制及 SSH 部署的要点做了说明。

以前我部署项目的方式说出来挺丢人的:本地 npm run build,然后用 FileZilla 把 dist 拖到服务器上。每次改个错别字都得走一遍这个流程。

后来项目多了,部署频率也高了,终于受不了了。配了一套 GitHub Actions,现在 push 完代码去喝杯水回来就部署好了。写一下我怎么配的,以及踩过的几个坑。


我想要的部署效果

其实就是几步:

  1. 代码 push 到 GitHub 的 main 分支
  2. GitHub Actions 自动触发
  3. 跑测试、构建项目
  4. SSH 到我的 VPS,把构建产物同步过去
  5. 重启一下服务(或者 nginx reload)

整套流程大概一两分钟跑完。跟以前手拖文件比,省了多少时间就不说了。


一个能直接用的 workflow 文件

先看完整的 .github/workflows/deploy.yml,我再拆开讲每段的作用:

name: Deploy to Server

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: 拉代码
        uses: actions/checkout@v4

      - name: 装 Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: 装依赖 & 构建
        run: |
          npm ci
          npm run build

      - name: 同步文件到服务器
        uses: easingthemes/ssh-deploy@v5
        with:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          REMOTE_HOST: ${{ secrets.SERVER_HOST }}
          REMOTE_USER: ${{ secrets.SERVER_USER }}
          SOURCE: "dist/"
          TARGET: "/var/www/my-site/"
          SCRIPT_AFTER: |
            sudo systemctl reload nginx

如果你用的不是 npm,比如 pnpm 或者 yarn,改一下 npm ci 那行就行,逻辑完全一样。


关键步骤拆解

1. 什么时候触发

on:
  push:
    branches:
      - main

意思是只要 push 到 main 分支就触发。如果你用的是 master,就改成 master。也可以加 develop 分支的触发,但我个人习惯只在合到 main 时部署。

如果你只想在特定文件改动时触发(比如只改 README 不触发),可以加个 paths

on:
  push:
    branches:
      - main
    paths:
      - 'src/**'
      - 'package.json'

2. Node 版本和缓存

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: 'npm'

cache: 'npm' 这一行别看短,省了不少时间。GitHub Actions 会把 node_modules 缓存起来,第二次构建的时候 npm ci 基本秒过。我试过不加缓存,构建时间从 20 秒变成两分钟。

如果你用 pnpm,这里写 cache: 'pnpm',用 yarn 就写 cache: 'yarn'

3. npm ci 不是 npm install

这个区别新手很容易忽略:

  • npm install — 根据 package.json 安装,可能改 package-lock.json
  • npm ci — 严格按照 package-lock.json 安装,适合 CI 环境

CI 里请用 npm ci。不然哪天 lock 文件跟 package.json 不一致,本地正常、CI 炸了,排查起来想死。

4. SSH 部署

我用的是 easingthemes/ssh-deploy 这个 Action,用 rsync 把 dist/ 同步到服务器。核心是三个 secret:

  • SSH_PRIVATE_KEY — 服务器 SSH 私钥
  • SERVER_HOST — 服务器 IP
  • SERVER_USER — 登录用户名

用 rsync 而不是 scp 的好处是:它只传有变化的文件。项目大了以后这个差别很明显——几百个文件只改了几个,rsync 只传改过的,scp 会全量覆盖。


Secrets 怎么配(这个最容易搞错)

在 GitHub 仓库页面,Settings → Secrets and variables → Actions → New repository secret

配 SSH 私钥的步骤:

  1. 先在服务器上生成一个专用的 SSH key:
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions
  1. 把公钥加到服务器:
cat ~/.ssh/github_actions.pub >> ~/.ssh/authorized_keys
  1. 把私钥内容复制出来,贴到 GitHub Actions secrets 里,名字叫 SSH_PRIVATE_KEY
cat ~/.ssh/github_actions

注意:复制的时候从 -----BEGIN OPENSSH PRIVATE KEY----------END OPENSSH PRIVATE KEY-----,整段都要。

另外两个 secret:

  • SERVER_HOST — 你的服务器 IP
  • SERVER_USER — 登录用户名,一般是 root 或者你创建的用户

我踩过的三个坑

坑一:私钥格式不对导致 SSH 连接失败

GitHub Actions 的 SSH 要求私钥末尾有空行。很多编辑器复制的时候会自动吞掉最后的空行。结果就是 Action 日志里报 Load key failed: invalid format

解决办法:手动在 secret 内容的最后加一个空行(敲一下回车)。

坑二:rsync 权限错误

部署的目标目录 /var/www/my-site/,rsync 往里写的时候报了权限错误。因为默认的 GitHub Actions SSH 用户没有该目录的写权限。

两种解法:

  • 把目标目录的 owner 改成 SERVER_USER
  • 或者在 SCRIPT_AFTER 里用 sudo 操作

我用的第二种,因为有时候目录权限不想改太宽:

SCRIPT_AFTER: |
  sudo rsync -a /tmp/deploy-temp/ /var/www/my-site/
  sudo systemctl reload nginx

坑三:node_modules 不装 devDependencies

默认 npm ci 会安装所有依赖,包括 devDependencies。如果你的构建脚本用了 devDependencies 里的工具(大概率是用了的),就不用管。

但如果你的 NODE_ENV=production 被设上了,npm ci 会跳过 devDependencies。检查一下 workflow 里有没有意外设置环境变量。


加一个通知步骤(可选)

部署完了不知道成功没有,每次都去打开 Actions 页面看也挺烦的。我加了一个 Slack 通知步骤:

- name: 通知
  if: always()
  uses: slackapi/slack-github-action@v2
  with:
    webhook: ${{ secrets.SLACK_WEBHOOK }}
    webhook-type: incoming-webhook
    payload: |
      {
        "text": "部署${{ job.status == 'success' && '成功 ✅' || '失败 ❌' }}\n项目: ${{ github.repository }}\n提交: ${{ github.event.head_commit.message }}"
      }

也可以换成 Telegram、飞书、企业微信,逻辑一样。


花了多长时间、省了多少事

我算过一次,以前手拖部署要花大概 3 分钟:打开 FTP → 连服务器 → 拖文件 → 检查有无遗漏 → SSH 进去手动重启。每次上线都紧张,就怕漏文件。

现在改完代码 git push,一两分钟后通知来了,部署完成。中间该干嘛干嘛。

多项目的时候差别更大。我有五个个人项目,以前每个部署一遍十几分钟没了。现在 push 完挨个自动跑,我在群里等通知就行。


小结

GitHub Actions 免费额度对个人项目完全够用(每月 2000 分钟)。这套配置跑一个 workflow 就一两分钟,你一个月 push 一两百次都绰绰有余。

如果你用的是 GitLab、Gitee,也有对应的 CI 工具(GitLab CI、Gitee Go),配置思路是一样的:触发 → 构建 → 同步 → 重启服务。把这四个环节想清楚,换哪个平台都差不多。

把部署从"手动操作"变成"自动发生",这事做完以后你就不想回去了。那种"push 完代码就不用管"的爽感,体会过的人都知道。


easingthemes/ssh-deploy Action 文档:https://github.com/easingthemes/ssh-deploy

评论 (0)