1.引言:为什么要进行架构升级?

在传统的个人博客或轻量级 CMS 部署中,我们通常采用“本地构建 + 手动上传”的模式。旧架构往往包含多个独立的服务:博客托管的 Nginx+headless-cms-hexo 包括(CMS 的前端(cms-frontend)与后端(cms-backend)),以及自定义的本地博客 Nginx 容器。每次发布新文章或更新代码,都需要基于 Vue3 + FastAPI 的无头 CMS,用于通过 Web 界面管理 Hexo 博客的 Markdown 内容,并通过 Git 同步与映射hexo实现自动化发布。

这种模式不仅繁琐,且不安全,不具备分布式的优势。为了彻底解放双手,实现代码的版本控制与持续交付,需要将这套架构升级为基于 Gitea镜像gitee仓库 + Woodpecker CI + Hexo 的现代化 DevOps 架构。

2.新架构核心组件解析

本次架构升级的核心思想是“一切皆容器,一切皆自动化”。新架构由以下三大核心组件构成:

  1. Gitea(代码托管中心(镜像gitee项目)):作为轻量级的自建 Git 服务,通过镜像服务同步 Gitee的仓库项目。它负责集中管理 Hexo 博客的源码(Markdown 文件、主题、配置文件等)。
  2. Woodpecker CI(自动化引擎):作为 Drone CI 的开源分支,Woodpecker 负责接收 Gitea 的触发信号,调度构建任务。它会在隔离的 Docker 容器中执行代码拉取、依赖安装和静态文件生成。
    1)Server-Agent 架构
    Woodpecker 采用经典的架构设计,主要分为三个关键组件协同工作:
    • Server(服务端):系统的核心枢纽,负责提供 Web 界面、管理构建队列和调度任务。
    • Forge(代码仓库):与外部代码平台集成,负责监听代码变更、触发构建并反馈状态。
    • Agent(代理):运行在构建节点上的代理程序,负责从 Server 获取任务并在容器中执行具体的构建和部署操作。
      2)使用它的目的是,在服务器资源不足的情况下代替jenkins实现ci/cd流程,
      3)Woodpecker CI 使用 Go 语言编写,性能优越且资源占用极低。整个服务器组件只有几 MB 大小,这意味着你可以在资源非常有限的环境(如 1GB RAM 的小型 VPS)中顺畅运行它,非常适合中小型团队或个人开发者。
  3. local-hexo-blog(部署载体):这是一个自定义的轻量级 Nginx 镜像。它不再需要复杂的后端服务,仅作为纯粹的静态文件托管容器,接收 Woodpecker 构建产出的 public 目录并对外提供 Web 访问。

3.gitea配置

3.1gitea部署方案

1
2
mkdir -p /var/gitea
cd /var/gitea
1
2
3
4
5
6
7
8
9
10
11
12
docker run -d --name gitea \  
-p 8096:3000 \
-p 8097:22 \
-v /var/gitea:/data \
-v /etc/timezone:/etc/timezone:ro \
-v /etc/localtime:/etc/localtime:ro \
-e USER_UID=1000 \
-e USER_GID=1000 \
-e GITEA__database__DB_TYPE=sqlite3 \
-e GITEA__webhook__ALLOWED_HOST_LIST=* \
--restart always \
gitea/gitea:latest

3.2gitee 同步到gitea的同步方案(镜像仓库方案)

创建镜像仓库的完整步骤

  1. 登录 Gitea 并进入组织或个人主页
    • 建议先在“组织”下创建镜像仓库,便于团队协作与权限管理。若为个人使用,可直接在个人主页操作。
  2. 点击“+”号 → 选择“迁移外部仓库”
    • 在右上角导航栏找到“+”按钮,下拉菜单中选择“迁移外部仓库”。
  3. 选择镜像源类型
    • 从列表中选择“从任意 Git 服务迁移仓库”,这是最通用的选项,支持 Gitee、GitHub、GitLab 等所有标准 Git 服务。
  4. 填写远程仓库地址与认证信息

3.3gitea的oauth应用

3.3.1第一步:在 Gitea 中配置 OAuth2 应用

Woodpecker 需要通过 Gitea 的 OAuth2 进行用户授权和 Webhook 管理。

  1. 登录 Gitea,进入 站点管理 (Site Administration) > 应用 (Applications) 或 个人设置 > 应用
  2. 创建一个新的 OAuth2 应用:
    • 应用名称Woodpecker CI
    • **重定向 URI (Redirect URI)**:https://ci.your-domain.com/authorize (需与后续 Woodpecker 的访问地址严格一致)
  3. 创建后,妥善保存生成的 Client ID 和 Client Secret

3.3.2第二步:填写应用信息

在创建应用的表单中,填写以下关键信息:
应用名称:自定义填写,例如 Woodpecker-CI。
应用主页:填写你的 Woodpecker 访问地址(公网地址)。
应用描述:简要说明用途,例如“用于 Woodpecker CI 自动化构建”。
应用回调地址 (Redirect URI):这是最关键的一步,必须填写 Woodpecker 的授权回调地址。格式通常为:(额外添加/authorize)

1
http://<你的Woodpecker公网IP或域名>:8000/authorize

权限:根据需要勾选(通常用于 CI 拉取代码,勾选 user_info、projects 等读取权限即可)。

3.3.3第三步:获取凭证

确认信息无误后,点击 “创建” 按钮。
应用创建成功后,系统会跳转到应用详情页面。
在该页面中,可以直接看到生成的 Client ID 和 Client Secret。

4.woodpecker 部署

4.1woodpecker 配置

第一步:准备 Docker Compose 配置文件
在你的服务器上创建一个 docker-compose.yml 文件,并填入以下基础配置:

1
2
3
mkdir -p /var/woodpecker  

cd /var/woodpecker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
version: '3'  
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:v3.15.0
container_name: woodpecker-server
environment:
- WOODPECKER_OPEN=true
- WOODPECKER_OPEN=true
- WOODPECKER_ADMIN=<自定义gitea登录用户> #必须,不然没有最高管理权限
- WOODPECKER_HOST=http://woodpecker.brightchen.top
- WOODPECKER_GITEA=true
- WOODPECKER_GITEA_URL=<自定义gitea地址>
- WOODPECKER_GITEA_CLIENT=<Gitea OAuth2 Client ID>
- WOODPECKER_GITEA_SECRET=<Gitea OAuth2 Client Secret>
- WOODPECKER_AGENT_SECRET=<自定义Secret>
- WOODPECKER_PLUGINS_PRIVILEGED=plugins/docker
- WOODPECKER_ENABLE_PRIVILEGED=true # 必须开启
ports:
- "8000:8000"
volumes:
- /var/woodpecker:/var/lib/woodpecker
restart: always

woodpecker-agent:
image: woodpeckerci/woodpecker-agent:v3.15.0
container_name: woodpecker-agent
command: agent
depends_on:
- woodpecker-server
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=<和上面的自定义Secret一致>
- WOODPECKER_MAX_PROCS=2
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: always

WOODPECKER_MAX_PROCS :限制 Woodpecker Agent 节点能够同时并行执行的构建任务(流水线/工作流)的最大数量 默认为1

4.2woodpecker docker-compose命令

启动命令

1
docker-compose up -d

优雅地重启所有服务(不重新创建容器)

1
docker-compose restart

如果只想重启某个特定服务(例如 woodpecker-server),可以加上服务名:

1
docker-compose restart woodpecker-server

停止所有容器,但不删除它们

1
docker-compose stop

停止并删除所有容器、网络

1
docker-compose down

5.Woodpecker流水线配置

5.1Woodpecker 流水线ssh版

代码推送 -> Hexo 编译 -> Docker 镜像打包 -> 自动部署上线 流程

.woodpecker.yml 文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
steps:
# 1. Hexo 编译阶段:生成静态文件到 public 目录
build-hexo:
image: node:20-alpine
commands:
- npm install
- npx hexo clean
- npx hexo generate
when:
event: [push, manual] # 支持推送事件和手动触发
branch: master

# 2. Docker 镜像打包阶段:将 public 目录打包为 Nginx 镜像
build-docker:
image: plugins/docker
settings:
repo: <你的Docker镜像仓库地址>/hexo-blog
tags: latest
username: <镜像仓库用户名>
password:
from_secret: docker_password
when:
event: [push, manual] # 支持推送事件和手动触发
branch: master

# 3. 自动部署上线阶段:拉取并运行 Nginx 镜像
deploy:
image: appleboy/drone-ssh
settings:
host: <目标部署服务器IP>
username: <SSH用户名>
password:
from_secret: ssh_password
script:
- docker pull <你的Docker镜像仓库地址>/hexo-blog:latest
- docker stop hexo-blog || true
- docker rm hexo-blog || true
# 注意:这里映射的端口改为 80,因为 Nginx 默认监听 80 - docker run -d --name hexo-blog -p 80:80 --restart always <你的Docker镜像仓库地址>/hexo-blog
when:
event: [push, manual] # 支持推送事件和手动触发
branch: master

5.2woodpecker 流水线local版本(当前使用版本)

和服务器在同一环境情况下的简化处理流程
主要流程:代码推送 -> 编译 Hexo -> 构建本地镜像 -> 重启本地容器

hexo 的配置文件Dockerfile

1
2
3
4
5
6
7
8
9
10
# 使用轻量级的 Nginx Alpine 镜像作为基础
FROM nginx:alpine

# 将 Hexo 编译生成的 public 目录下的静态文件复制到 Nginx 的默认网页目录
COPY public/ /usr/share/nginx/html/

# 暴露 80 端口
EXPOSE 80

# Nginx 镜像默认会自动启动,无需额外指定 CMD

流水线配置.woodpecker.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
steps:  
# 1. 编译 Hexo 生成静态文件
- name: build-hexo
image: node:20-alpine
commands:
- npm install
- npx hexo clean
- npx hexo generate
when:
event: [push, manual] # 支持推送事件和手动触发
branch: master

# 2. 构建本地 Docker 镜像
- name: build-local-image
image: docker:24-cli
commands:
# 直接运行 docker build 命令
- docker build -t local-hexo-blog:latest -f Dockerfile .
volumes:
- /var/run/docker.sock:/var/run/docker.sock
when:
event: [push, manual]
branch: master

# 3. 部署本地容器
- name: deploy-local
image: docker:24-cli
commands:
- docker stop hexo-blog || true
- docker rm hexo-blog || true
- |
docker run -d \
--name hexo-blog \
-p 80:80 \
--restart always \
local-hexo-blog:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
when:
event: [push, manual] # 支持推送事件和手动触发
branch: master

6.全新的日常开发工作流

架构升级完成后,你的博客发布流程将变得极其优雅且安全:
创作:在本地执行 hexo new “我的新文章”,在 Markdown 编辑器中完成创作。
自动交付:代码推送到gitee,触发 Gitea镜像仓库同步,Woodpecker 自动接管。它会在后台完成拉取、构建、清理旧容器、启动新容器等一系列动作。
验证:刷新浏览器,博客已无缝更新到最新版本。

总结

通过将原有的 Gitee + 手动 Nginx 部署模式迁移至 Gitea镜像 + Woodpecker + Hexo,我们不仅消除了繁琐的 SSH 上传步骤,还将博客源码、构建环境和部署配置全部纳入了 Git 版本控制。这套基于 Docker 的自动化流水线配置统一、易于维护,未来甚至可以一键迁移至任何云服务器,是个人开发者践行 DevOps 理念的最佳实践。