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 部署

本文选择 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/amd64linux/arm64 包。官方没有发布校验和,当前网络也未能完成二进制下载和 Docker Registry manifest 核验;高保证环境应先把 Release 文件纳入自己的制品审批、计算并固定校验和,再允许 Docker 构建访问受控镜像源。

准备目录和密钥

主机需要 Docker Engine、Compose 插件、BuildKit,以及可以访问 GitHub Releases 的构建网络。CPU 和内存没有可靠的官方最低值,应按用户数、工单量和目标库延迟在测试环境测量。以下命令在准备长期保留的部署目录中执行:

bash
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 .env

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

在同一目录创建 Dockerfile

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"]

再创建 compose.yaml

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:

mysql:8.0 是版本系列 tag,仍可能随补丁更新而变化。正式环境应在目标主机核验平台后改成组织批准的精确 tag 或 digest;若改用外部或托管 MySQL,应删除 mysql 服务与卷,把 MYSQL_ADDR 指向受控地址,并先创建 utf8mb4 字符集的 yearning 库。

初始化、启动与验收

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

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

初始化命令应报告成功并给出默认账号信息;docker compose ps 应显示 mysqlyearning 正常运行且最终进入健康状态,日志不应持续出现 MySQL 连接错误,HTTP 请求应以零状态退出。初始化服务只在首次建库时运行;已有表时再次执行不会重建数据。

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

完成第一张 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。最终执行节点通过后,成功结果应同时满足:工单显示执行成功,目标测试库出现预期表,工单详情保留流程与执行结果,审计记录可以关联到提交人与数据源。若任一信号缺失,不要在生产数据源继续测试。

定时执行依赖 Yearning 所在服务器的本地时间,服务在触发前崩溃或重启可能丢失定时信息;Yearning 的定时功能不适合作为需要持久化调度保证的数据库发布队列。DML 自动执行任务会绕过人工审核,也只应在条件清晰、影响范围可测并有独立回退手段时启用。

一张工单背后的模块

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

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

备份、升级与回滚

恢复 Yearning 至少需要三部分:平台 MySQL 数据、保存 SecretKey 和数据库密码的 .env、实际使用的 Dockerfilecompose.yamlSecretKey 丢失后,即使平台库恢复成功,已有数据源密码也可能无法解密。备份应加密保存到另一故障域,并限制只有运维人员可读。

备份前暂停新工单与自动任务,等待正在执行的工单结束,再停止 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、停止提交、完成并验证备份、构建目标版本、按版本说明决定是否迁移、启动后重新登录,并验收权限、数据源、流程和测试工单。

如果新版本已经改写平台库,回滚必须同时恢复旧镜像配置、升级前数据库和原 SecretKey。只把镜像版本改回去无法撤销数据库变化。Compose 的通用更新和停止边界见 Docker Compose 服务生命周期docker compose down 默认保留平台数据卷;docker compose down -v 会删除 yearning-mysql,不能作为普通卸载命令。

常见问题

症状定位修复与再验证
初始化提示无法连接 MySQL检查 docker compose ps、MySQL 健康状态、.envMYSQL_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 制品和构建网络。

参考资料

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