gonic 常用命令与运维实战(核心篇)

gonic v0.23.0 运维手册:Compose 服务管理命令、Subsonic API 双认证端点实测(ping/getLicense/getArtists/search3/stream/startScan/getScanStatus)、SQLite 热备冷备与收藏回滚恢复演练、日志排障与错误码速查、版本升级五步法实测与回滚预案。

gonicgonic音乐流媒体音频流媒体2026/10/28

gonic 常用命令与运维实战(核心篇)

目标:把 gonic v0.23.0 日常运维最高频的操作做成一份可照抄的实战手册——服务管理命令、Subsonic API 运维端点(明文与 token 双认证)、SQLite 热备/冷备与恢复演练、日志排障手法、版本升级全流程。全部命令与输出为 2026-10-28 在 Ubuntu 24.04 服务器上的逐行实测,演示账号 admin/q1w2e3r4,服务端口 8137,数据目录 /opt/data/quzuo/tmp/gonic/。部署基线见本专栏《gonic Docker Compose 部署实战》,参数含义见《gonic 配置参数详解》。

一、服务管理常用命令

本章汇总以 Docker Compose 方式托管时的日常管理命令(在编排文件所在目录 /opt/data/quzuo/tmp/gonic/ 下执行):

$ docker compose ps            # 查看运行状态
NAME               IMAGE                   COMMAND                 SERVICE   CREATED         STATUS         PORTS
gonic-0.23.0-app   sentriz/gonic:v0.23.0   "/sbin/tini -- gonic"   gonic     4 seconds ago   Up 3 seconds   0.0.0.0:8137->80/tcp, [::]:8137->80/tcp
$ docker compose stop gonic    # 停止(数据保留)
 Container gonic-0.23.0-app Stopped
$ docker compose start gonic   # 启动
 Container gonic-0.23.0-app Started
$ docker compose up -d --force-recreate   # 改了编排文件后重建生效
 Container gonic-0.23.0-app Recreated
 Container gonic-0.23.0-app Started
$ docker compose down          # 停止并删除实例(数据目录不受影响)
 Container gonic-0.23.0-app Stopping
 Container gonic-0.23.0-app Removed
$ docker logs -f gonic-0.23.0-app   # 实时日志
$ docker exec gonic-0.23.0-app gonic -version   # 实例内查看版本
v0.23.0

记忆要点:stop/start 与 down/up 的区别在于是否删除运行实例本体;无论哪种,只要 data/、music/ 等挂载目录在宿主机上,数据就不会丢——这是挂载卷托管形态的天然安全性。

二、Subsonic API 运维实战

本章把运维最常用的 API 端点逐一打通。gonic 的 API 挂在 /rest/*.view 路径下,每个请求都要带认证参数与 v(API 版本)、c(客户端标识)两个约定参数。

2.1 两种认证方式

方式一:明文密码(u+p),适合本机调试:

$ curl -s 'http://127.0.0.1:8137/rest/ping.view?u=admin&p=q1w2e3r4&v=1.16.1&c=curltest&f=json'
{"subsonic-response":{"status":"ok","version":"1.16.1","type":"gonic","serverVersion":"0.23.0","openSubsonic":true}}

方式二:token+salt(u+t+s),适合写进脚本与客户端:

$ SALT=7a7f39ca
$ TOKEN=$(printf '%s' "q1w2e3r4${SALT}" | md5sum | awk '{print $1}')
$ echo "salt=$SALT token=$TOKEN"
salt=7a7f39ca token=db4d1a45d03f4d115a034684fd5f929b
$ curl -s "http://127.0.0.1:8137/rest/ping.view?u=admin&t=${TOKEN}&s=${SALT}&v=1.16.1&c=curltest&f=json"
{"subsonic-response":{"status":"ok",...}}

💡 技术拓展:token = md5(password + salt) 是 Subsonic API 的现代认证形态——salt 是客户端每次随机生成的一次性随机串,URL 里只出现 token 与 salt、不出现密码本体,即使访问日志被收集也无法反推密码。明文 u+p 模式的密码会完整留在 URL 里(gonic 的 http-log、反代访问日志都会记录),生产环境一律用 token 模式。下文统一用变量 $AT 代表 token 认证串。

认证失败时返回错误码 40,注意 HTTP 状态码仍是 200,错误在响应体的 status:"failed" 里:

$ curl -s 'http://127.0.0.1:8137/rest/ping.view?u=admin&p=wrongpass&v=1.16.1&c=curltest&f=json'
{"subsonic-response":{"status":"failed",...,"error":{"code":40,"message":"invalid password"}}}

2.2 健康检查与许可:ping / getLicense

$ AT="u=admin&t=db4d1a45d03f4d115a034684fd5f929b&s=7a7f39ca&v=1.16.1&c=curltest&f=json"
$ curl -s "http://127.0.0.1:8137/rest/getLicense.view?$AT"
{"subsonic-response":{"status":"ok",...,"license":{"valid":true}}}

ping 是最小健康探针;getLicense 返回 valid:true(Subsonic 兼容服务端按约定回 true)。监控平台可定期调 ping?view 判活,记得带认证参数——裸调会返回错误码 10 而非 200 ok。

2.3 曲库巡检:getMusicFolders / getArtists / search3

$ curl -s "http://127.0.0.1:8137/rest/getMusicFolders.view?$AT"
{"subsonic-response":{...,"musicFolders":{"musicFolder":[{"id":0,"name":"music"}]}}}
$ curl -s "http://127.0.0.1:8137/rest/getArtists.view?$AT"
{"subsonic-response":{...,"artists":{...,"artist":[{"id":"ar-2","name":"Test Artist One","albumCount":2,...},{"id":"ar-1","name":"Test Artist Two","albumCount":1,...}]}}}
$ curl -s "http://127.0.0.1:8137/rest/search3.view?$AT&query=Test&songCount=10"
{"subsonic-response":{...,"searchResult3":{"artist":[...2 位...],"song":[...6 首...]}}}

这三个端点构成「曲库规模巡检」的最小集:音乐库数量、艺术家数量、关键词命中量。资源 ID 前缀语义:ar- 艺术家、al- 专辑、tr- 音轨。

2.4 播放链路验证:stream

$ curl -s "http://127.0.0.1:8137/rest/stream.view?$AT&id=tr-3" -o tr3.stream -w 'HTTP %{http_code} | %{content_type} | %{size_download} bytes\n'
HTTP 200 | audio/flac | 368150 bytes
$ md5sum tr3.stream 'music/Rock/Test Artist One/(2024) First Album/01 Sunrise Test.flac'
a743d0e6fccfbfe87c5be41303a85b6a  tr3.stream
a743d0e6fccfbfe87c5be41303a85b6a  music/Rock/Test Artist One/(2024) First Album/01 Sunrise Test.flac

md5 与源文件一致即播放链路无损。运维上这是「客户端报无声/卡顿」时的第一层验证:服务端能完整吐出源文件,问题就在客户端或网络。

2.5 扫描控制:startScan / getScanStatus

$ curl -s "http://127.0.0.1:8137/rest/startScan.view?$AT"
{"subsonic-response":{...,"scanStatus":{"scanning":false,"count":6}}}
$ curl -s "http://127.0.0.1:8137/rest/getScanStatus.view?$AT"
{"subsonic-response":{...,"scanStatus":{"scanning":false,"count":6}}}

对应日志(实测):

2026/10/28 21:14:44 starting scan
2026/10/28 21:14:44 finished scan in 7.89ms, +0/6 tracks (0 err)

startScan 触发增量扫描(返回里的 scanning 是触发瞬间状态,小曲库经常瞬完);getScanStatus 轮询进度,count 为当前库内音轨总数。曲库入库异常的排查动线:看日志 finished scan ... +N/M tracks (X err) → 错配 0 err 但数量不对就查 exclude-pattern 与目录约束(同专辑同目录)。

三、SQLite 数据库备份与恢复

本章实测 gonic 唯一状态文件 data/gonic.db 的两种备份手法与一次完整恢复演练。

3.1 热备份:sqlite3 .backup(服务不停机)

$ env -i /usr/bin/sqlite3 /opt/data/quzuo/tmp/gonic/data/gonic.db ".backup '/opt/data/quzuo/tmp/gonic/backup_demo/gonic_hot.db'"
$ env -i /usr/bin/sqlite3 /opt/data/quzuo/tmp/gonic/backup_demo/gonic_hot.db 'PRAGMA integrity_check;'
ok
$ env -i /usr/bin/sqlite3 /opt/data/quzuo/tmp/gonic/backup_demo/gonic_hot.db "SELECT id,name,is_admin FROM users;"
1|admin|1
$ env -i /usr/bin/sqlite3 /opt/data/quzuo/tmp/gonic/backup_demo/gonic_hot.db "SELECT COUNT(*) FROM tracks;"
6

.backup 是 SQLite 官方的在线备份命令,基于备份 API 拷贝出一致性快照,不需要停服。备完必做两件事:PRAGMA integrity_check 验证完整性,抽查关键表(users、tracks)确认内容。gonic 库共 27 张表(实测 .tables 输出含 albums/artists/tracks/users/sessions/migrations 等)。

💡 说明:env -i 是用干净环境执行 sqlite3——本实测机的 shell 环境变量被污染导致 sqlite3 报 symbol lookup error,env -i 绕开污染。你的机器若 sqlite3 正常,去掉 env -i 即可。不建议直接 cp 运行中的数据库文件:WAL 模式下主库文件可能不完整,要么用 .backup,要么走 3.2 的冷备。

3.2 冷备份:停机拷贝

$ docker compose stop gonic
 Container gonic-0.23.0-app Stopped
$ cp -a data/gonic.db backup_demo/gonic_cold.db
$ docker compose start gonic
 Container gonic-0.23.0-app Started

停机后主库文件处于一致状态,直接 cp -a 即可。停机窗口实测只有秒级(小曲库),适合有维护窗口的场景。

3.3 恢复演练:以「收藏回滚」为证据

光备不练等于没备。本次演练:先制造一个状态变更(收藏曲目 tr-3),再用 3.1 的热备份回灌,验证状态被精确回滚。

# 第一步:制造变更——star 曲目并确认
$ curl -s "http://127.0.0.1:8137/rest/star.view?$AT&id=tr-3"
{"subsonic-response":{"status":"ok",...}}
$ curl -s "http://127.0.0.1:8137/rest/getStarred2.view?$AT"
{...,"starred2":{"song":[{"id":"tr-3","title":"Sunrise Test",...,"starred":"2026-10-28T21:19:42.58516372+08:00",...}]}}
# 第二步:停服 → 热备份回灌 → 清 WAL 残件 → 启动
$ docker compose stop gonic
$ cp backup_demo/gonic_hot.db data/gonic.db && rm -f data/gonic.db-shm data/gonic.db-wal
$ docker compose start gonic
# 第三步:验证——收藏列表应为空(回滚成功),登录照常
$ curl -s "http://127.0.0.1:8137/rest/getStarred2.view?$AT"
{"subsonic-response":{...,"starred2":{}}}
$ curl -s 'http://127.0.0.1:8137/rest/ping.view?u=admin&p=q1w2e3r4&v=1.16.1&c=curltest&f=json'
{"subsonic-response":{"status":"ok",...}}

starred2 从有到空、账号可用,证明备份文件是可用的一致快照。注意回灌时务必删掉 gonic.db-shm/gonic.db-wal 两个 WAL 残件,否则 SQLite 会把旧 WAL 里的新事务重放到备份库上,恢复就失效了。

四、日志与排障

本章汇总 gonic 的日志形态与高频故障处置。

4.1 日志的三种形态

$ docker logs gonic-0.23.0-app
  • 启动段:72 条 migration(仅首次/升级后)→ provided config 全量配置回显 → starting job "..." 后台任务清单;
  • 访问段(http-log=true 默认开):每请求一行,如 2026/10/28 21:14:44 response 200 GET /startScan?u=admin&t=...;
  • 业务段:starting scan / finished scan in 7.89ms, +0/6 tracks (0 err) 等扫描与后台任务记录。

4.2 SQL 级排障:log-db

配置项 GONIC_LOG_DB=true 重建后,每条 SQL 带耗时输出(实测):

2026/10/28 21:18:38 query 262.435µs "SELECT * FROM \"users\"  WHERE (name=?) ORDER BY \"users\".\"id\" ASC LIMIT 1"
2026/10/28 21:18:38 query 850.596µs "SELECT artists.*, count(album_credits.album_id) album_count, ... ORDER BY artists.name COLLATE NOCASE"

定位「某 API 慢」「某操作没生效」类问题时临时开启,排完关回(日志量大)。

4.3 高频错误码速查

错误码实测触发方式含义与处置
10ping.view 不带任何参数 / getAlbum 不带 id缺少必需参数,检查调用方参数拼接
40ping.view 用错误密码凭证无效;改密后旧凭证立即失效
70getAlbum?id=al-9999资源不存在,多为客户端缓存了已删除资源的旧 ID,让客户端刷新

注意所有业务错误 HTTP 层都是 200,错误信息在响应体 error.code——写监控判活时要看 body 的 status 字段,不能只看 HTTP 码。

4.4 两个实测故障样本

  • 路径不存在拒绝启动:播客目录挂载失效时启动即退出,日志 checking podcast directory: path does not exist, please provide one。处置:检查挂载点,恢复目录或暂时摘掉对应配置项;
  • 非 API 路径返回 303 而非 404:未登录访问 /nonexistent 实测返回 HTTP 303 跳登录页。处置:健康检查脚本对 Web 路径要接受 303,对 API 路径带认证认 200。

五、版本升级流程实测

本章固化 gonic 升级五步法:备份 → 改 tag → 重建 → 验迁移 → 验数据。gonic 升级本质是「换制品 tag + 重建运行实例」,数据库 schema 迁移由程序启动时自动完成(机制证据:首次部署空库时启动日志连续执行了 72 条 migration,见《gonic Docker Compose 部署实战》第四章)。本次以同版本重建做完整流程演练,每步均为实测。

5.1 升级前备份与数据标记

铁律:先备份再升级。为让「数据兼容」可验证,先制造一个数据标记(收藏曲目 tr-3),再做热备份:

$ curl -s "http://127.0.0.1:8137/rest/star.view?$AT&id=tr-3" -o /dev/null -w 'star HTTP %{http_code}\n'
star HTTP 200
$ curl -s "http://127.0.0.1:8137/rest/getStarred2.view?$AT" | python3 -c 'import json,sys; d=json.load(sys.stdin)["subsonic-response"]["starred2"]; print("starred:", [s["id"] for s in d.get("song",[])])'
starred: ['tr-3']
$ env -i /usr/bin/sqlite3 data/gonic.db ".backup '/opt/data/quzuo/tmp/gonic/backup_demo/gonic_pre_upgrade.db'"
$ ls -la backup_demo/gonic_pre_upgrade.db
-rw-r--r-- 1 root root 323584 Oct 28 21:47 backup_demo/gonic_pre_upgrade.db

5.2 改 tag 并重建

编辑 docker-compose.yml,把 image: sentriz/gonic:v0.23.0 改成目标新版本号(生产升级时换成官方 Release 页的最新 tag),然后重建:

$ grep 'image:' docker-compose.yml
    image: sentriz/gonic:v0.23.0      # 生产升级时改为新版本 tag
$ docker compose up -d --force-recreate
 Container gonic-0.23.0-app Starting
 Container gonic-0.23.0-app Started

实测重建前后实例创建时间从 2026-10-28T13:18:59Z 变为 2026-10-28T13:47:21Z,运行实例确已换新。

5.3 验证迁移与数据兼容

$ docker logs gonic-0.23.0-app 2>&1 | head -2
2026/10/28 21:47:22 starting gonic v0.23.0
2026/10/28 21:47:22 provided config
$ docker logs gonic-0.23.0-app 2>&1 | grep -c "migration '"
0
$ curl -s 'http://127.0.0.1:8137/rest/ping.view?u=admin&p=q1w2e3r4&v=1.16.1&c=curltest&f=json'
{"subsonic-response":{"status":"ok","version":"1.16.1","type":"gonic","serverVersion":"0.23.0","openSubsonic":true}}
$ curl -s "http://127.0.0.1:8137/rest/getScanStatus.view?$AT" | python3 -c 'import json,sys; print("scanStatus:", json.load(sys.stdin)["subsonic-response"]["scanStatus"])'
scanStatus: {'scanning': False, 'count': 6}
$ curl -s "http://127.0.0.1:8137/rest/getStarred2.view?$AT" | python3 -c 'import json,sys; d=json.load(sys.stdin)["subsonic-response"]["starred2"]; print("starred:", [s["id"] for s in d.get("song",[])])'
starred: ['tr-3']

三项验证全部通过:账号可登录(密码散列随库迁移)、曲库计数 6 不变、升级前制造的收藏标记 tr-3 完好保留。本次为同版本演练故新迁移 0 条;跨版本升级时此处会出现新版引入的 migration 行,逐条 finished 即迁移成功——若某条迁移报错,不要进业务验证,直接走回滚。

5.4 回滚预案

若升级后异常:停服 → 用 5.1 的备份回灌 data/gonic.db(删掉 gonic.db-shm/gonic.db-wal 两个 WAL 残件)→ 把 tag 改回旧版本号 → up -d --force-recreate 重建。SQLite 单文件形态让「回滚」与 3.3 节的「恢复」是同一套动作,演练一次两处受益。

六、日常运维清单与小结

日常巡检建议(均可脚本化):

  1. ping.view(token 认证)判活,看 body status:"ok";
  2. getScanStatus 看 count 是否符合预期、scanning 是否卡住;
  3. docker logs 扫 err 关键字(扫描错误、转码失败都会留痕);
  4. 每日一次 .backup 热备份 + integrity_check,异机留存;
  5. 升级走「备份 → 改 tag → 重建 → 验迁移 → 验数据」五步法,回滚预案常备。

至此 gonic 专栏三篇实战篇齐备:部署见《gonic Docker Compose 部署实战》,配置见《gonic 配置参数详解》,选型背景见《gonic 介绍与选型指南》。