〇、前言

很多个人项目,一开始的部署方式都比较简单:本地开发完了直接打包,上传到服务器直接运行。

后面项目变大后,打包时间变长了、包体积大了、传输也更费时了,就想着直接把代码上传服务器,在服务器打包运行不就完了!

所以部署方式又改为:本地开发提交推送,登录服务器更新代码然后部署运行。

时间久了,就感觉后面那步全是在重复劳动呀!作为一名程序员,怎么能够被重复劳动限制住手脚呢?

所以我决定,必须要实现自动化部署,而我,只需要push一下代码接即可。

一、优化思路

这里以自部署 Gitea 为例,使用:

Gitea Actions
act_runner
Docker Compose

实现 push 后自动部署。

目标是把部署流程改成:

本地开发
→ git push 到 Gitea
→ Gitea Actions 自动触发
→ 服务器自动执行 docker compose 部署

最终日常只需要 git push ,剩下的交给 Gitea Actions。

二、实现方案

这里选择一种最适合个人项目和单服务器项目的方式:

把 act_runner 直接安装在应用服务器上

也就是:

Gitea 仓库收到 push
→ Gitea Actions 触发任务
→ 应用服务器上的 act_runner 接收任务
→ 在服务器本机执行 docker compose

这样就不需要 GitHub Actions,也不需要额外的 CI 服务器,也不需要 SSH 回应用服务器。

(一)开启 Gitea Actions

确认 Gitea 已经启用 Actions。

如果 Gitea 版本较老,需要在配置文件中开启:

[actions]
ENABLED=true

然后进入仓库设置:

仓库 Settings
→ Actions
→ Enable Repository Actions

(二)安装 act_runner

在应用服务器上创建目录:

mkdir -p /opt/act_runner
cd /opt/act_runner

下载对应系统版本的 act_runnr,地址:https://gitea.com/gitea/act_runner/releases

赋予执行权限:

chmod +x act_runner
./act_runner --version

生成配置文件:

./act_runner generate-config > config.yaml

(三)注册 runner

在 Gitea 仓库页面获取 runner 注册 token:

仓库 Settings
→ Actions
→ Runners
→ Create new runner

然后在服务器执行:

./act_runner register --no-interactive \
  --instance https://你的-gitea-地址 \
  --token 你的-registration-token \
  --name prod-server \
  --labels spring:host

这里需要注意两个概念。

--name 是 runner 的名字,它只是显示用的。比如: prod-server 。

--labels 才是 workflow 里匹配 runner 用的标签,比如:spring:host 。

其中spring 是标签名,host 表示直接在宿主机执行(当然也有写 docker 的,那就是在 docker内运行)。

对应在 workflow 里应该写:

runs-on: spring

(四)编写部署 workflow

在项目中创建文件:

.gitea/workflows/deploy.yml

如果生产环境配置在服务器固定目录,比如 /srv/diary-dashboard,可以写成:

name: deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: spring

    steps:
      - uses: actions/checkout@v4

      - name: Deploy
        run: |
          cd /srv/diary-dashboard
          git pull
          docker compose up -d --build

不过更推荐让 workflow 使用当前 checkout 出来的代码进行构建,这样部署的 commit 会更明确。

(五)把 runner 做成系统服务

手动运行测试:

cd /opt/act_runner
./act_runner daemon --config config.yaml

确认 Gitea 页面中 runner 在线后,再配置 systemd。

创建服务文件:

sudo nano /etc/systemd/system/act_runner.service

写入:

[Unit]
Description=Gitea Actions runner
After=network.target docker.service
Requires=docker.service

[Service]
WorkingDirectory=/opt/act_runner
ExecStart=/opt/act_runner/act_runner daemon --config /opt/act_runner/config.yaml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

启动服务:

sudo systemctl daemon-reload
sudo systemctl enable --now act_runner
sudo systemctl status act_runner

三、可能遇到的问题

1. 提示没有匹配的 runner

如果页面提示:

没有匹配标签的在线 runner: spring

说明注册 runner 时没有给其添加上我们想要的标签,可以手动给 act_runner 添加上标签。

在你的 config.yaml 里找 runner:,加上:

runner:
  labels:
    - "spring:host"

然后重启服务使其生效:

sudo systemctl restart act_runner

2. runner 权限问题

使用 host 类型 runner 时,要注意 runner 是由哪个用户运行的。

如果用 root 运行,虽然执行 Docker 和部署命令会比较方便,但权限过高。因为 host runner 会直接在宿主机执行 workflow 命令,一旦脚本有问题,影响范围会很大。另外,root 用户和你平时部署用的普通用户不是同一个环境,可能会丢失原来的 Git 凭据、SSH 配置、known_hosts 等,导致 git pull 或访问私有仓库失败。

如果用普通用户运行,则需要确保这个用户有足够的执行权限。例如:

1. 能执行 act_runner
2. 能读写 runner 工作目录
3. 能访问项目部署目录
4. 有 docker 执行权限

其中 Docker 权限通常需要把该用户加入 docker 组:

sudo usermod -aG docker $USER

所以更推荐使用专门的普通用户运行 runner,然后按需补齐目录权限和 Docker 权限。

总结

改造前的部署流程是:

本地 push
→ 登录服务器
→ git pull
→ docker compose up -d --build

改造后变成:

本地 push
→ Gitea Actions 自动触发
→ 服务器上的 act_runner 自动部署

对于个人项目项目来说,这种方式非常实用。

它不需要额外 CI 服务器,不需要复杂的镜像仓库流程,也不需要每次手动登录服务器。

只要 push 代码,Gitea Actions 就会自动把部署流程跑完。

后续如果项目变多,或者部署环境更复杂,还可以继续升级为:

Gitea Actions 构建 Docker 镜像
→ 推送到 Gitea Container Registry
→ 服务器 docker compose pull
→ docker compose up -d

但对于起步阶段来说,Gitea Actions + act_runner + Docker Compose 已经足够把部署体验提升一大截。

做自己,而不是解释自己!