Skip to content

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 结合数据变化和时间窗口判断,不能当作数据库备份。

Mermaid 流程图
查看源码
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 部署 ​

Yearning 官方文档把 Docker Compose 标为推荐安装方式,固定提交中的示例也直接使用公开镜像 yeelabs/yearning:latest 和独立 MySQL。对希望长期保留账号、流程与工单记录的读者,这条路径比下载源码再本地构建更短,也保留了数据库和配置的维护边界。

部署选择本文采用的方式
主路径官方镜像 + Docker Compose
官方镜像yeelabs/yearning:latest
版本关系项目参考 Release 为 v3.1.9.1;公开镜像 latest 未确认与该 Release 一一对应
依赖MySQL 8.0,数据保存在 ./data/mysql
备选路径固定 Release v3.1.9.1 后本地构建镜像

这里保留 latest,因为官方推荐的 Compose 没有给出与当前 Release 一一对应的镜像 tag。latest 会随镜像仓库更新,不能证明正在运行 v3.1.9.1;每次更新前都应先记录当前镜像 ID 或 digest,在测试环境完成登录、权限、数据源和工单验收。若组织要求构建输入必须固定,再使用后面的固定 tag + 官方 Dockerfile 备选路径。

准备目录和密钥 ​

主机需要 Docker Engine、Compose 插件,并能访问 Docker Hub。CPU 和内存没有可靠的官方最低值,应按用户数、工单量和目标库延迟在测试环境测量。以下命令创建长期保留的部署目录、平台库目录和随机密钥:

bash
mkdir yearning
cd yearning
mkdir -p data/mysql
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 .env

YEARNING_SECRET_KEY 由 8 字节随机数编码成 16 个十六进制字符,符合 Yearning 的长度要求。.env 同时包含平台库密码,不要提交到 Git、复制到工单或把展开后的 docker compose config 输出保存到普通日志。

创建 compose.yaml。配置沿用官方镜像和环境变量接口,把官方示例中的固定密码替换成 .env,并把 8000 端口限制在本机:

yaml
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:
      - ./data/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:
    image: ${YEARNING_IMAGE:-yeelabs/yearning:latest}
    profiles: ["tools"]
    environment: *yearning-environment
    depends_on:
      mysql:
        condition: service_healthy
    command: ["/bin/bash", "-c", "./Yearning install"]

  yearning:
    image: ${YEARNING_IMAGE:-yeelabs/yearning:latest}
    restart: unless-stopped
    environment: *yearning-environment
    depends_on:
      mysql:
        condition: service_healthy
    ports:
      - "127.0.0.1:8000:8000"

mysql:8.0 也是版本系列 tag,正式环境应在目标主机核验平台后改成组织批准的精确 tag 或 digest。切换外部或托管 MySQL 需要同时重写 MYSQL_ADDR、删除 mysql 服务、移除两个 Yearning 服务的 depends_on.mysql,并调整后续拉取与启动命令;不要只改数据库地址后继续使用这份 Compose。

初始化、启动与验收 ​

首次部署依次拉取镜像、启动平台库、执行一次初始化,再启动 Web 服务:

bash
docker compose config --quiet
docker compose pull mysql yearning
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/

初始化命令应报告成功并给出默认账号信息;docker compose ps 应显示 mysql 为 Healthy、yearning 为 Up,日志不应持续出现 MySQL 连接错误,HTTP 请求应以零状态退出。yearning-init 只在首次初始化平台库时执行,不要把初始化命令加入日常启动流程。

浏览器与 Docker 在同一台机器时打开 http://127.0.0.1:8000。远程服务器可先用 SSH 隧道访问:

bash
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,确认管理员和临时用户仍能登录。只看到登录页并不能证明平台库、密钥和认证状态可恢复。

需要固定版本时本地构建镜像 ​

公开镜像 tag 无法与 v3.1.9.1 建立一一对应关系时,可以检出固定 tag,使用仓库自带 Dockerfile 构建本地镜像,再复用上面的 Compose。这个备选方案适合必须固定应用版本的环境,不是官方推荐 Compose 的前置步骤。

官方 Dockerfile 不会编译 Go 源码,而是根据 YEARNING_VER 和目标架构下载对应 Release 压缩包再封装镜像。下面固定了仓库 tag 与 Dockerfile 构建参数;主路径结束时终端位于 yearning/,因此先返回父目录。主机还需要 Git。官方 Release 未提供校验和,因此组织仍应对下载制品做独立审批和校验。

bash
cd ..
git clone --branch v3.1.9.1 --depth 1 https://github.com/cookieY/Yearning.git Yearning-v3.1.9.1
docker build \
  --build-arg YEARNING_VER=v3.1.9.1 \
  -t local/yearning:v3.1.9.1 \
  Yearning-v3.1.9.1/docker
cd yearning
grep -v '^YEARNING_IMAGE=' .env > .env.next
printf 'YEARNING_IMAGE=local/yearning:v3.1.9.1\n' >> .env.next
chmod 600 .env.next
mv .env.next .env
docker compose config --quiet
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/

上面是已有 Yearning 平台库切换本地镜像的路径,不要再次运行 yearning-init。如果这是全新安装,并且 ./data/mysql 中还没有 Yearning 的平台表,才在首次启动 Web 服务前执行一次初始化:

bash
docker compose up -d mysql
docker compose run --rm yearning-init
docker compose up -d yearning

无论使用公开镜像还是本地镜像,yearning-init 都只属于全新平台库的首次安装。切换镜像、重启、升级或回滚已有平台库时重复初始化,可能破坏现有数据;不得将 yearning-init 作为常规启动步骤。

完成第一张 SQL 工单 ​

不要把生产库作为第一次体验。准备一个可丢弃的 MySQL 测试实例和专用账号,只授予测试库所需权限;Yearning 平台库账号与目标业务库账号也应分开。然后用管理员账号依次完成以下配置:

  1. 在“管理 -> 用户”创建提交者与审核者,不让日常操作共用 admin。
  2. 在“管理 -> 权限组”建立测试组,只开放测试数据源的 DDL、DML 或查询权限,再把提交者加入该组。
  3. 在“管理 -> 流程”创建审批链。中间节点可以是开发负责人或 DBA,末端节点必须选择“执行”。
  4. 在“管理 -> 数据源”添加测试 MySQL,选择读、写或读写类型,把刚才的审批流程绑定到该数据源。
  5. 在“管理 -> 审核规则”检查测试环境规则;若新增环境,还要为环境创建流程模板。

切换到提交者,在“工单申请”选择 DDL 和测试数据源。下面的建表语句使用短表名、主键、字段注释和表注释,可以作为新安装默认规则的测试起点;组织已经调整规则时,应按页面给出的检测结果修正,而不是关闭规则:

sql
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';

在编辑器中用右键菜单或 Ctrl/Cmd + E 触发 SQL 检测。可观察的第一层成功信号是所有错误等级为 0,提交按钮从禁用变为可用;执行完成后,目标测试库中应出现 yr_demo 表。

工单进入审批链后,由审核者在“审核 -> 工单”打开详情并再次检查 SQL。最终执行节点通过后,成功结果应同时满足:工单显示执行成功,目标测试库出现预期表,工单详情保留流程与执行结果,审计记录可以关联到提交人与数据源。若任一信号缺失,不要在生产数据源继续测试。

一张工单背后的模块 ​

单个 Go 服务同时提供前端静态资源、登录和 /api/v2 业务接口。路由层把数据源、用户、权限、流程、SQL 工单、查询工单和记录审计分开,受保护接口使用 JWT 中间件;服务启动时加载全局规则,并启动查询脱敏和工单统计的后台任务。

平台库是整条链路的控制面:权限、流程、加密后的数据源凭据、工单和结果都依赖平台库。目标 MySQL 才是实际 SQL 的执行面。把两者分开理解后,备份范围也很清楚:只备份业务库无法恢复 Yearning 的审批上下文,只备份平台库也不能恢复业务数据。

备份、升级与回滚 ​

恢复 Yearning 至少需要平台 MySQL 数据、保存 SecretKey 和数据库密码的 .env,以及实际使用的 compose.yaml;选择固定 tag + 官方 Dockerfile 备选路径时,还要保留检出的 Dockerfile 和已批准的 Release 制品信息。SecretKey 丢失后,即使平台库恢复成功,已有数据源密码也可能无法解密。备份应加密保存到另一故障域,并限制只有运维人员可读。

备份前暂停新工单与自动任务,等待正在执行的工单结束,再停止 Yearning,避免控制面状态继续变化。平台库使用标准 MySQL 时,可以采用一致性逻辑备份或存储快照;恢复后必须使用原 SecretKey,并验收管理员登录、普通用户权限、数据源连通性、审批流程、历史工单和一条低风险测试工单。通用卷与数据库方法见 Docker 备份与恢复数据。

bash
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 yearning

yearning.sql 与 .env 都包含敏感信息,应设置最小权限并加密。外部 MySQL 或托管数据库应使用对应平台的一致性备份,不要机械套用容器内命令。

Yearning 正常启动会自动同步表结构;只有目标 Release 明确说明存在破坏性变化时,才在启动新版本前执行 ./Yearning migrate。源码把这个命令直接描述为“破坏性版本升级修复”,不能把 migrate 加入每次启动。升级顺序应是:阅读目标 Release、停止提交、完成并验证备份、记录当前镜像 ID 或构建固定版本、按版本说明决定是否迁移、启动后重新登录,并验收权限、数据源、流程和测试工单。

如果新版本已经改写平台库,回滚必须同时恢复旧镜像配置、升级前数据库和原 SecretKey。只把镜像版本改回去无法撤销数据库变化。Compose 的通用更新和停止边界见 Docker Compose 服务生命周期。当前配置使用 ./data/mysql bind mount,docker compose down 和 docker compose down -v 都不会删除这个宿主机目录;只有在确认备份可恢复且明确要销毁平台数据时,才单独删除 ./data/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 不等于所有可选功能都只在本地处理数据。

完成测试工单后,下一步最有价值的动作是做一次恢复演练:把平台库和配置恢复到隔离环境,确认原用户、权限、数据源、流程与历史工单都存在,再连接一个新的测试库完成同样的提交和审批。只有恢复链路成立,审批记录才真正具备运维价值。

参考资料 ​

全部公开文章由同一个站点构建和发布。