Yearning:把 MySQL 变更放进可追踪的审核流程
生产库的一条 ALTER TABLE,真正困难的部分通常不在语法:谁能提交、规则是否允许、由谁审批、何时执行、失败后怎样追溯,都需要落到一个稳定流程里。Yearning 面向 DBA 与开发团队,把 SQL 检测、工单审批、执行和记录放进同一个自托管 Web 平台;查询也可以按数据源授权、审批并保留审计记录。
这套平台的重点是建立数据库操作边界,不是替开发者补一个在线 SQL 编辑器。管理员需要先配置用户、权限组、审批流程和数据源,提交者才能在允许的范围内创建工单。这个前置成本,正是 Yearning 能把“发一段 SQL 给 DBA”变成可检查流程的原因。
GitHub 仓库信息
| 信息 | 内容 |
|---|---|
| 项目标题 | Yearning |
| 项目描述 | 面向 DBA 与开发人员的本地部署 MySQL SQL 检测、工单审批和查询审计平台。 |
| GitHub 仓库 | cookieY/Yearning |
| 官网地址 | Yearning Guide |
| 主要开发语言 | Go 99.5%、Dockerfile 0.5% |
| 开源许可证 | AGPL-3.0 |
| 最近代码更新 | 2026-08-24(GitHub pushed_at,核对日期:2026-09-18) |
Yearning 控制的是变更路径
Yearning 自带 SQL 检测逻辑,不要求另行部署第三方审核引擎。提交者在编辑器中触发检测后,页面会展示规则结果;只有错误等级都为 0,提交按钮才会激活。管理员可以为不同环境配置规则,例如表名约束、必须字段、最大影响行数,以及是否允许删除表、分区或视图。
检测通过不等于直接获得生产库权限。管理员把数据源、权限组和审批流程组合起来:权限组决定某个用户能向哪些数据源提交结构变更(DDL)、数据写入(DML)或查询,流程决定工单经过哪些审核人,最后一个节点必须是“执行”类型。最终节点通过后,Yearning 才连接目标 MySQL 执行 SQL,并把工单状态和结果留在平台数据库中。
查询走另一条受控路径。数据源可以标记为读、写或读写,查询还能限制数据库、排除库名并按字段名脱敏。查询负责人、记录审计和 RBAC 适合约束日常查数,但字段名匹配的脱敏不能替代数据库本身的最小权限、视图隔离或专业数据防泄漏能力。
如果执行环境开启了 binlog,提交者还可以请求生成回滚语句。执行成功后的回滚不是一个跳过审核的紧急按钮:Yearning 会用回滚 SQL 创建新工单,再走一遍审批流程。这个设计保留了追踪链,但生成的回滚语句仍需 DBA 结合数据变化和时间窗口判断,不能当作数据库备份。
正在准备渲染...
查看源码
flowchart LR
User[提交者浏览器] --> Web[Yearning Web 与 API]
Web --> Auth[JWT、用户与权限组]
Auth --> Engine[SQL 检测规则]
Engine --> Flow[审批流程]
Flow -->|最终执行节点通过| Target[(目标 MySQL)]
Web --> Meta[(Yearning 平台库)]
Flow --> Meta
Target --> Result[执行结果与可选回滚 SQL]
Result --> Meta
Auditor[审核者与审计人员] --> Web采用前先看边界
Yearning 当前只面向 MySQL。平台自身还需要一个独立 MySQL 库保存账号、数据源、加密后的密码、流程、工单和审计记录;这个平台库不要与被审核的业务库混为一谈。官方文档要求 MySQL 5.7 及以上,MySQL 8.0 及以上需要把 sql_mode 设为空,并建议使用最新 Chrome 与 1080p 或更高分辨率。
SecretKey 是 token 以及数据库密码加解密所依赖的 16 位密钥。这个密钥必须在首次初始化前生成并长期保留;初始化后随意更换,会导致已保存的数据源密码无法解密。默认管理员为 admin / Yearning_admin,首次登录后必须立即修改密码。
适合 Yearning 的团队通常有明确 DBA 或数据库负责人,需要统一 DDL/DML 提交、多人审批、查询授权与留痕。若数据库变更全部随应用代码进入 CI/CD,团队更关心版本化迁移而不是人工工单,可优先评估 Flyway、Liquibase 或框架自带 migration。需要多种数据库和更广运维编排时,应再比较 Archery 或商业数据库变更平台,而不是假定 MySQL 专用规则能够直接迁移。
Docker Compose 部署
本文选择 Release v3.1.9.1。这个版本修复了查询审核模式的权限提升、SSL 数据源查询和 bigint(20) 精度问题。2026-09-18 查询 Shields 的 Docker tag 聚合端点时,v3.1.9 返回存在,v3.1.9.1 返回 tag not found;Docker Hub API 与 Registry manifest 因当前网络超时,未能直接确认完整标签清单。下面不假定存在 v3.1.9.1 官方镜像,而是沿用官方 Dockerfile 的构建方式,从同版本 Release 二进制构建本地镜像。
这条路径支持 Release 提供的 linux/amd64 与 linux/arm64 包。官方没有发布校验和,当前网络也未能完成二进制下载和 Docker Registry manifest 核验;高保证环境应先把 Release 文件纳入自己的制品审批、计算并固定校验和,再允许 Docker 构建访问受控镜像源。
准备目录和密钥
主机需要 Docker Engine、Compose 插件、BuildKit,以及可以访问 GitHub Releases 的构建网络。CPU 和内存没有可靠的官方最低值,应按用户数、工单量和目标库延迟在测试环境测量。以下命令在准备长期保留的部署目录中执行:
mkdir yearning
cd yearning
umask 077
{
printf 'YEARNING_SECRET_KEY=%s\n' "$(openssl rand -hex 8)"
printf 'YEARNING_DB_PASSWORD=%s\n' "$(openssl rand -base64 24)"
printf 'YEARNING_DB_ROOT_PASSWORD=%s\n' "$(openssl rand -base64 24)"
} > .env
chmod 600 .env2
3
4
5
6
7
8
9
YEARNING_SECRET_KEY 由 8 字节随机数编码成 16 个十六进制字符,符合 Yearning 的长度要求。.env 同时包含平台库密码,不要提交到 Git、复制到工单或把展开后的 docker compose config 输出保存到普通日志。
在同一目录创建 Dockerfile:
# syntax=docker/dockerfile:1
ARG ALPINE_VERSION=3.20.2
FROM alpine:${ALPINE_VERSION} AS unpack
ARG YEARNING_VERSION=v3.1.9.1
ARG TARGETARCH
RUN apk add --no-cache ca-certificates unzip wget \
&& case "${TARGETARCH}" in amd64|arm64) ;; *) exit 1 ;; esac \
&& wget -O /tmp/yearning.zip \
"https://github.com/cookieY/Yearning/releases/download/${YEARNING_VERSION}/Yearning-${YEARNING_VERSION}-linux-${TARGETARCH}.zip" \
&& unzip /tmp/yearning.zip -d /tmp/release \
&& install -D -m 0755 /tmp/release/Yearning/Yearning /out/Yearning \
&& install -D -m 0600 /tmp/release/Yearning/conf.toml /out/conf.toml
FROM alpine:${ALPINE_VERSION}
RUN apk add --no-cache bash ca-certificates dumb-init libc6-compat tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& printf 'Asia/Shanghai\n' > /etc/timezone
COPY --from=unpack /out/Yearning /opt/Yearning
COPY --from=unpack /out/conf.toml /opt/conf.toml
WORKDIR /opt
EXPOSE 8000
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["./Yearning", "run"]2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
再创建 compose.yaml:
x-yearning-build: &yearning-build
image: local/yearning:v3.1.9.1
build:
context: .
args:
YEARNING_VERSION: v3.1.9.1
x-yearning-environment: &yearning-environment
MYSQL_USER: yearning
MYSQL_PASSWORD: ${YEARNING_DB_PASSWORD:?set in .env}
MYSQL_ADDR: mysql:3306
MYSQL_DB: yearning
SECRET_KEY: ${YEARNING_SECRET_KEY:?set in .env}
IS_DOCKER: is_docker
Y_LANG: zh_CN
services:
mysql:
image: mysql:8.0
restart: unless-stopped
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --sql-mode=
environment:
MYSQL_ROOT_PASSWORD: ${YEARNING_DB_ROOT_PASSWORD:?set in .env}
MYSQL_DATABASE: yearning
MYSQL_USER: yearning
MYSQL_PASSWORD: ${YEARNING_DB_PASSWORD:?set in .env}
volumes:
- yearning-mysql:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 20
start_period: 30s
yearning-init:
<<: *yearning-build
profiles: ["tools"]
environment: *yearning-environment
depends_on:
mysql:
condition: service_healthy
command: ["./Yearning", "install"]
yearning:
<<: *yearning-build
restart: unless-stopped
environment: *yearning-environment
depends_on:
mysql:
condition: service_healthy
ports:
- "127.0.0.1:8000:8000"
healthcheck:
test: ["CMD", "wget", "-q", "-T", "3", "-O", "/dev/null", "http://127.0.0.1:8000/"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
volumes:
yearning-mysql: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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
mysql:8.0 是版本系列 tag,仍可能随补丁更新而变化。正式环境应在目标主机核验平台后改成组织批准的精确 tag 或 digest;若改用外部或托管 MySQL,应删除 mysql 服务与卷,把 MYSQL_ADDR 指向受控地址,并先创建 utf8mb4 字符集的 yearning 库。
初始化、启动与验收
首次部署依次构建镜像、启动平台库、执行一次初始化,再启动 Web 服务:
docker compose config --quiet
docker compose build yearning yearning-init
docker compose up -d mysql
docker compose ps
docker compose run --rm yearning-init
docker compose up -d yearning
docker compose ps
docker compose logs --tail=100 yearning
curl --fail --output /dev/null http://127.0.0.1:8000/2
3
4
5
6
7
8
9
初始化命令应报告成功并给出默认账号信息;docker compose ps 应显示 mysql 与 yearning 正常运行且最终进入健康状态,日志不应持续出现 MySQL 连接错误,HTTP 请求应以零状态退出。初始化服务只在首次建库时运行;已有表时再次执行不会重建数据。
浏览器与 Docker 在同一台机器时打开 http://127.0.0.1:8000。远程服务器可先用 SSH 隧道访问:
ssh -N -L 8000:127.0.0.1:8000 user@server随后在客户端打开同一地址。需要多人访问时,应在 TLS 反向代理后开放,并保留 8000 端口的回环绑定。Yearning 个别功能使用 WebSocket,代理必须支持 HTTP/1.1 Upgrade;通用配置可参考 Docker 服务反向代理与 HTTPS。
登录 admin / Yearning_admin 后立即修改管理员密码。再执行一次持久化检查:创建一个临时普通用户,运行 docker compose restart yearning,确认管理员和临时用户仍能登录。只看到登录页并不能证明平台库、密钥和认证状态可恢复。
完成第一张 SQL 工单
不要把生产库作为第一次体验。准备一个可丢弃的 MySQL 测试实例和专用账号,只授予测试库所需权限;Yearning 平台库账号与目标业务库账号也应分开。然后用管理员账号依次完成以下配置:
- 在“管理 -> 用户”创建提交者与审核者,不让日常操作共用
admin。 - 在“管理 -> 权限组”建立测试组,只开放测试数据源的 DDL、DML 或查询权限,再把提交者加入该组。
- 在“管理 -> 流程”创建审批链。中间节点可以是开发负责人或 DBA,末端节点必须选择“执行”。
- 在“管理 -> 数据源”添加测试 MySQL,选择读、写或读写类型,把刚才的审批流程绑定到该数据源。
- 在“管理 -> 审核规则”检查测试环境规则;若新增环境,还要为环境创建流程模板。
切换到提交者,在“工单申请”选择 DDL 和测试数据源。下面的建表语句使用短表名、主键、字段注释和表注释,可以作为新安装默认规则的测试起点;组织已经调整规则时,应按页面给出的检测结果修正,而不是关闭规则:
CREATE TABLE yr_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
name VARCHAR(10) NOT NULL DEFAULT '' COMMENT 'Name',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Yearning test';2
3
4
5
在编辑器中用右键菜单或 Ctrl/Cmd + E 触发 SQL 检测。可观察的第一层成功信号是所有错误等级为 0,提交按钮从禁用变为可用;执行完成后,目标测试库中应出现 yr_demo 表。
工单进入审批链后,由审核者在“审核 -> 工单”打开详情并再次检查 SQL。最终执行节点通过后,成功结果应同时满足:工单显示执行成功,目标测试库出现预期表,工单详情保留流程与执行结果,审计记录可以关联到提交人与数据源。若任一信号缺失,不要在生产数据源继续测试。
定时执行依赖 Yearning 所在服务器的本地时间,服务在触发前崩溃或重启可能丢失定时信息;Yearning 的定时功能不适合作为需要持久化调度保证的数据库发布队列。DML 自动执行任务会绕过人工审核,也只应在条件清晰、影响范围可测并有独立回退手段时启用。
一张工单背后的模块
单个 Go 服务同时提供前端静态资源、登录和 /api/v2 业务接口。路由层把数据源、用户、权限、流程、SQL 工单、查询工单和记录审计分开,受保护接口使用 JWT 中间件;服务启动时加载全局规则,并启动查询脱敏和工单统计的后台任务。
平台库是整条链路的控制面:权限、流程、加密后的数据源凭据、工单和结果都依赖平台库。目标 MySQL 才是实际 SQL 的执行面。把两者分开理解后,备份范围也很清楚:只备份业务库无法恢复 Yearning 的审批上下文,只备份平台库也不能恢复业务数据。
备份、升级与回滚
恢复 Yearning 至少需要三部分:平台 MySQL 数据、保存 SecretKey 和数据库密码的 .env、实际使用的 Dockerfile 与 compose.yaml。SecretKey 丢失后,即使平台库恢复成功,已有数据源密码也可能无法解密。备份应加密保存到另一故障域,并限制只有运维人员可读。
备份前暂停新工单与自动任务,等待正在执行的工单结束,再停止 Yearning,避免控制面状态继续变化。平台库使用标准 MySQL 时,可以采用一致性逻辑备份或存储快照;恢复后必须使用原 SecretKey,并验收管理员登录、普通用户权限、数据源连通性、审批流程、历史工单和一条低风险测试工单。通用卷与数据库方法见 Docker 备份与恢复数据。
docker compose stop yearning
docker compose exec -T mysql sh -c \
'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction --routines --triggers yearning' \
> yearning.sql
docker compose start yearning2
3
4
5
yearning.sql 与 .env 都包含敏感信息,应设置最小权限并加密。外部 MySQL 或托管数据库应使用对应平台的一致性备份,不要机械套用容器内命令。
Yearning 正常启动会自动同步表结构;只有目标 Release 明确说明存在破坏性变化时,才在启动新版本前执行 ./Yearning migrate。源码把这个命令直接描述为“破坏性版本升级修复”,不能把 migrate 加入每次启动。升级顺序应是:阅读目标 Release、停止提交、完成并验证备份、构建目标版本、按版本说明决定是否迁移、启动后重新登录,并验收权限、数据源、流程和测试工单。
如果新版本已经改写平台库,回滚必须同时恢复旧镜像配置、升级前数据库和原 SecretKey。只把镜像版本改回去无法撤销数据库变化。Compose 的通用更新和停止边界见 Docker Compose 服务生命周期。docker compose down 默认保留平台数据卷;docker compose down -v 会删除 yearning-mysql,不能作为普通卸载命令。
常见问题
| 症状 | 定位 | 修复与再验证 |
|---|---|---|
| 初始化提示无法连接 MySQL | 检查 docker compose ps、MySQL 健康状态、.env 与 MYSQL_ADDR | 先让平台库健康,再重新运行一次 yearning-init,确认出现初始化成功信息 |
| 新建数据源失败 | 检查目标库网络、账号权限、密码中的特殊字符与 16 位 SecretKey | 使用专用最小权限账号;修复后在数据源编辑页确认连接警告消失 |
| 环境无法提交 DDL/DML | 检查权限组的数据源范围,以及数据源是否绑定审批流程 | 补齐权限和流程后重新登录,再确认数据源卡片出现 |
| 工单不能提交或同意 | 查看 SQL 检测错误等级与当前审核规则 | 按团队规则修正 SQL;不要为了放行测试临时关闭生产规则 |
| 最终审批后没有执行 | 检查流程末端节点是否为“执行”类型,并查看服务日志和目标库权限 | 修正流程,在测试库重新提交新工单;不要改动正在流转的生产流程 |
| 代理后部分操作失效 | 检查 WebSocket Upgrade、超时和 8000 源站是否可达 | 补齐代理长连接配置,同时保持源站不被公网绕过 |
| 升级后数据源密码全部失效 | 比对升级前后的 SecretKey | 停止继续修改,恢复原密钥与匹配的数据库备份,再验收数据源连接 |
安全与下一步
Yearning 保存能够连接业务数据库的凭据,也可以执行 DDL/DML,管理面应按高权限系统保护。不要直接公开 8000 端口;通过受控 HTTPS 入口访问,限制管理页面来源,分离管理员、提交者、审核者与审计角色,并为每个目标库创建最小权限账号。容器与镜像供应链的通用要求可参考 Docker Compose 生产安全加固。
AI 助手默认配置指向 OpenAI 兼容接口,但 API key 初始为空。不开启 AI 不影响 SQL 审核主链路;开启前应确认 SQL、表结构和提示词会发送到哪个服务、是否允许出网、怎样脱敏,以及供应商的数据保留政策。自托管 Yearning 不等于所有可选功能都只在本地处理数据。
完成测试工单后,下一步最有价值的动作是做一次恢复演练:把平台库和配置恢复到隔离环境,确认原用户、权限、数据源、流程与历史工单都存在,再连接一个新的测试库完成同样的提交和审批。只有恢复链路成立,审批记录才真正具备运维价值。
版本与验证说明
本文依据 Yearning 默认分支提交 6e56e68、Release v3.1.9.1 与 2026-09-18 可访问的官方中文文档。仓库源码、Release、Dockerfile、Compose、配置读取、初始化和升级命令均做了静态核对;目标仓库代码没有被执行。
Docker Compose 配置已使用示例校验变量通过 docker compose config --quiet 语法展开,但没有构建镜像、启动容器、登录页面、连接真实 MySQL、执行 SQL、演练备份恢复或升级。Docker Hub manifest 与 Release 文件下载因当前网络超时未完成,部署前仍需在目标主机检查镜像平台、Release 制品和构建网络。