使用github action自动部署,别光dev,也ops一下

dev&ops

作为一个程序员,我们的工作本质上可以拆解为两个动作:Develop(开发软件)Operation(操作,部署,维护把开发的东西用起来)

在 Dev 时,我们追求工程化,设计模式、可读性、最佳实践。在 Ops 时,我们却成了懒狗。代码一丢,nohup 一挂,能跑就行。

既然我们总是以工程师的角色在dev,那ops也理应工程

无论是自动部署还是容器,在配置上都挺让人感到繁琐的,但其实这也是我们应该做的,把运维工作描述出来并且规范化,这也是开发的一部分

从最典中典的流程开始:代码推送到 GitHub → 自动测试构建 → 服务器同步代码 → 自动重启 Node 服务。

写一个github action

文档: https://docs.github.com/zh/actions

action实际上是一个yaml配置文件,位于你的项目/.github/workflows/[名称].yml

虽然可能有种脚本的感觉,但他不是脚本

下面是一个基础的action

name: 名称
on: [push] #在推送时触发,支持多种条件
jobs:
    build: #build是job id,这里可以自定义
        runs-on: ubuntu-latest #跑在最新的ubuntu中
        steps:
            - name: Trigger webhook # 步骤们

可以看出来,github会给我们提供一个虚拟环境,然后开始我们的步骤

很显然,最重要的就是steps

steps能干什么?

1.run – 执行shell命令

你可以随心所欲的在github给你的环境中做任何事,甚至临时开一个mc服务器

- name: 单行
  run: npm install
- name: 检查环境
  run: |
    node -v
    npm -v 
    ls -la
    df -h # 查看磁盘空间

tip : | vs > (小知识)

虽然不常用,但 YAML 还有一个 > 符号:

> (Folded):折叠换行。它会把多行文本变成一个很长的单行字符串(中间用空格隔开)。

| (Literal):保留换行。你写几行,执行时就是几行。

2. 调用”积木“ (uses)

它是别人封装好的功能,你直接拿来用。

你可以在这里找你需要的操作: https://github.com/marketplace?type=actions

  • 官方积木:如设置环境 (setup-node)、上传产物 (upload-artifact)。
  • 社区积木:如发送钉钉消息、部署到阿里云、扫描代码漏洞。
- name: 压缩图片
  uses: calibreapp/image-actions@main # 直接引用别人的插件
  with:
    githubToken: ${{ secrets.GITHUB_TOKEN }}

3. 逻辑与条件控制 (if)

这是体现“工程化严谨性”的地方。你可以让某个步骤只在特定条件下运行。

  • 场景:只有测试通过了才执行部署,或者只有在 main 分支才发送生产环境通知。
- name: 告警通知
  if: failure() # 只有前面的步骤失败时,才执行这个步骤
  run: curl -X POST https://your-webhook-url -d '{"msg": "构建挂了!"}'

4. 变量管理与数据传递 (env & outputs)

- name: 获取当前版本号
  id: get_version
  run: echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT

- name: 使用上一步的版本号
  run: echo "当前版本是 ${{ steps.get_version.outputs.VERSION }}"
ID 与输出:给 Step 起个 ID,它的结果就能被引用。

最常用的用法就是把一些敏感数据,比如token放在secrets中肯定比写在yaml中要好

这里区分一下 Repository secrets 和 Environment secrets

特性Repository Secrets (仓库级)Environment Secrets (环境级)
作用范围整个仓库。只要是这个仓库的 Action 都能用。特定环境。只有声明了使用该环境的任务(Job)才能用。

编译并部署到服务器

服务器同步代码有两种实现方式,一是在action打包并且传送到服务器,一个是在服务器中git pull后自行处理

一般来说应该这么写,在action中实现打包与部署

不过我要在宝塔中使用,编译后发送到服务器,速度较慢,也会有一些权限问题,所以只使用了webhook功能,并使用shell脚本实现剩下的流程

webhook功能可在应用市场中安装插件

我的项目是node项目,添加项目时选择pm2项目,可以通过命令行管理项目

# 实现一个webhook机器人的发消息函数

send_to_feishu() {
    local text_content=$1
    local json_data="{\"msg_type\":\"text\",\"content\":{\"text\":\"$text_content\"}}"
    curl -s -X POST -H "Content-Type: application/json" -d "$json_data" "你的_WEBHOOK_URL" > /dev/null
}

logger(){ # 输出的同时可以发消息到飞书
    if [ $# -gt 0 ]; then
        send_to_feishu "$1"
        echo "$1"
    else
        while IFS= read -r line; do
            send_to_feishu "$line"
            echo "$line"
        done
    fi
}
set -eo pipefail # 遇到错误便停止
logger "--- 任务开始: $(date) ---"
TARGET_DIR="项目路径"
REPO_URL="git地址"
# 进入目录
cd "$TARGET_DIR" || { logger "错误: 无法进入目录 $TARGET_DIR"; exit 1; }

# 经典信任文件夹
export HOME=/root # 保存设置,webhook是以root身份执行的
git config --global --add safe.directory "$TARGET_DIR" 2>&1 | logger

if [ -d ".git" ]; then
    logger "Git仓库已存在,执行更新..."
    git clean -fd 2>&1 | logger
    git reset --hard HEAD 2>&1 | logger
    # 强制拉取,防止分支名不一致(有些是 main,有些是 master)
    git pull origin $(git branch --show-current) 2>&1 | logger
else
    logger "Git仓库不存在,执行克隆..."
    # 如果目录非空,git clone . 会报错,这里先确保清理
    git clone "$REPO_URL" . 2>&1 | logger
fi

logger "最新的提交:"
git log -1 --pretty=format:"%h - %an, %ar : %s" | logger

logger "\n--- 开始构建 (npm) ---"

cd mailSilver
npm i
npm run build 
logger "构建完成"
pm2 reload mailSilver 
logger "重启完成"

评论