道鲤鱼音乐 Docker 部署教程(群晖 NAS + Windows Docker)
本文记录在群晖 NAS 和 Windows 10 Docker 上部署道鲤鱼音乐的完整流程,含踩坑记录与解决方案。
一、项目简介
道鲤鱼音乐(daoliyu-music)是一个自托管的音乐/视频流媒体服务,支持:
- 音乐库管理、在线播放
- 视频库管理
- 局域网自动发现
- MySQL / SQLite 数据库支持
镜像地址:msmkls/daoliyu-music:latest
二、群晖 NAS 部署
1. 前置准备
- 群晖已安装 Container Manager(DSM 7)或 Docker(DSM 6)
- 已有一个可用的 MySQL 容器(推荐 MySQL 8.x)
- 准备音乐、视频存放目录,例如:
/volume1/music/volume1/video
2. 创建数据库
进入 MySQL 容器:
bash
docker exec -it mysql mysql -u root -p
执行:
sql
CREATE DATABASE IF NOT EXISTS daoliyu CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
FLUSH PRIVILEGES;
如果 MySQL 只允许 root 从 localhost 登录,需要创建
root@%用户:sql
CREATE USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码'; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;
3. 创建项目文件夹
在 File Station 中创建:
text
/volume1/docker/daoliyumusic/
并在其中创建子文件夹:
text
runtime-prod/
├── data
├── library
└── cache/transcoding
或者用 SSH:
bash
mkdir -p /volume1/docker/daoliyumusic/runtime-prod/{data,library,cache/transcoding}
4. 编写 docker-compose.yml
在 /volume1/docker/daoliyumusic/ 下创建 compose.yaml:
yaml
services:
daoliyu-music:
image: docker.xuanyuan.run/msmkls/daoliyu-music:latest
container_name: daoliyu-music
restart: unless-stopped
ports:
- "4000:4000"
- "42123:42123/udp"
environment:
DLY_DB_DRIVER: "mysql"
# ⚠️ 用群晖的实际 IP,不要写 localhost 或 mysql 主机名
DLY_DB_DSN: "root:你的密码@tcp(192.168.31.82:3306)/daoliyu?charset=utf8mb4&parseTime=true&loc=Local"
DLY_DISCOVERY_ENABLED: "true"
DLY_DISCOVERY_UDP_ADDR: ":42123"
DLY_LOG_MIRROR_CONSOLE: "true"
TZ: "Asia/Shanghai"
volumes:
- ./runtime-prod/data:/app/runtime/data
- ./runtime-prod/library:/app/runtime/library
- ./runtime-prod/cache/transcoding:/app/runtime/cache/transcoding
- /etc/machine-id:/host/etc/machine-id:ro
- /proc/1/net/if_inet6:/host/proc/net/if_inet6:ro
# 媒体路径映射(改成自己的实际路径)
- /volume1/music:/volume1/music
- /volume1/video:/volume1/video
devices:
- /dev/snd:/dev/snd
group_add:
- audio
5. 部署
方式 A:图形界面(推荐)
- 打开 Container Manager → 项目 → 新增
- 来源选择 创建 docker-compose.yml
- 粘贴上面的内容
- 项目名称填
daoliyu,点击下一步 → 完成
方式 B:SSH 命令行
bash
cd /volume1/docker/daoliyumusic
docker-compose up -d
6. 访问
浏览器打开:
text
http://群晖IP:4000
三、Windows 10 Docker 部署
1. 前置准备
- Windows 10 已安装 Docker Desktop(WSL2 后端)
- 已安装 MySQL 8.x(本地安装,非 Docker 版)
- 在 Docker Desktop → Settings → Resources → File Sharing 中共享
I:盘
2. 创建数据库
打开 CMD:
cmd
mysql -u root -p
执行:
sql
CREATE DATABASE IF NOT EXISTS daoliyu CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
3. 修改 MySQL 配置
编辑 C:\ProgramData\MySQL\MySQL Server 8.0\my.ini,在 [mysqld] 段添加:
ini
bind-address = 0.0.0.0
重启 MySQL 服务:
cmd
net stop mysql
net start mysql
同时确保 Windows 防火墙放行 3306 端口。
4. 编写 compose.yaml
在 I:\docker\daoliyu\ 下创建 compose.yaml:
yaml
services:
daoliyu-music:
image: docker.xuanyuan.run/msmkls/daoliyu-music:latest
container_name: daoliyu-music
restart: unless-stopped
ports:
- "4000:4000"
- "42123:42123/udp"
environment:
DLY_DB_DRIVER: "mysql"
# ⚠️ 初始化页面里也填 host.docker.internal:3306
DLY_DB_DSN: "root:123456@tcp(host.docker.internal:3306)/daoliyu?charset=utf8mb4&parseTime=true&loc=Local"
DLY_DISCOVERY_ENABLED: "true"
DLY_DISCOVERY_UDP_ADDR: ":42123"
DLY_LOG_MIRROR_CONSOLE: "true"
TZ: "Asia/Shanghai"
volumes:
- ./runtime-prod/data:/app/runtime/data
- ./runtime-prod/library:/app/runtime/library
- ./runtime-prod/cache/transcoding:/app/runtime/cache/transcoding
# Windows 路径直接用 I:/ 格式
- I:/media/music:/volume1/music
- I:/media/video:/volume1/video
5. 启动
在 I:\docker\daoliyu\ 下打开 CMD:
cmd
docker-compose up -d
6. 初始化页面配置
浏览器访问 http://localhost:4000,进入初始化页面:
| 字段 | 填写内容 |
|---|---|
| 主机地址 | host.docker.internal:3306 |
| 数据库名 | daoliyu |
| 用户名 | root |
| 密码 | 123456 |
⚠️ 千万不要填
127.0.0.1:3306,容器内部的127.0.0.1指向容器自身,不是 Windows 宿主机。
四、常见问题与踩坑记录
❌ 坑 1:报错 dial tcp: lookup mysql ... no such host
原因:compose.yaml 里 DSN 写的是 tcp(mysql:3306),把 mysql 当主机名解析,但容器网络里找不到。
解决:改成实际 IP(群晖用局域网 IP,Windows 用 host.docker.internal)。
❌ 坑 2:报错 Unknown database 'daoliyu'
原因:容器连接的 MySQL 和你 CMD 里操作的 MySQL 不是同一个。
解决:确认 DSN 里的 IP/主机名指向的就是你创建了 daoliyu 库的那个 MySQL。
❌ 坑 3:报错 dial tcp 127.0.0.1:3306: connect: connection refused
原因:在 Web 初始化页面填了 127.0.0.1,容器里指向自己。
解决:改成 host.docker.internal:3306 或宿主机实际 IP。
❌ 坑 4:报错 Bind mount failed
原因:runtime-prod/data、runtime-prod/library 等本地文件夹不存在。
解决:手动创建这些目录后再启动:
bash
mkdir -p runtime-prod/{data,library,cache/transcoding}
❌ 坑 5:卡在“资料库升级需要处理”
原因:本地残留了旧的升级标记或数据库结构不兼容。
解决:
- 进 MySQL 执行
DROP DATABASE daoliyu;后重建 - 清空
runtime-prod/data/*和runtime-prod/library/* - 重启容器
❌ 坑 6:报错 Error 1396: Operation ALTER USER failed for 'root'@'%'
原因:root@% 用户不存在,不能直接 ALTER。
解决:改用 CREATE USER:
sql
CREATE USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
⚠️ 坑 7:MySQL 8.0 默认加密方式不兼容
原因:MySQL 8.0 默认用 caching_sha2_password,部分客户端/容器不兼容。
解决:创建用户时显式指定 mysql_native_password。
⚠️ 坑 8:只有 root@localhost,没有 root@%
原因:MySQL 默认只允许本机连接。
解决:创建 root@% 或专用账号(更安全):
sql
CREATE USER 'daoliyu_app'@'%' IDENTIFIED BY '强密码';
GRANT ALL PRIVILEGES ON daoliyu.* TO 'daoliyu_app'@'%';
五、关于客户端
- 安卓端:暂无官方 App,可用手机浏览器访问
http://IP:4000 - TV 端:暂无 TV 版,可在电视浏览器或支持 WebView 的应用中打开网页版
后续如有官方客户端,关注项目仓库更新。
六、总结
| 场景 | 数据库地址 | 备注 |
|---|---|---|
| 群晖 NAS | 群晖IP:3306 | 不要用 localhost 或容器名 |
| Windows Docker | host.docker.internal:3306 | 不要用 127.0.0.1 |
| 容器内部访问 | 容器名或 IP | 依赖 Docker 网络 |
核心就一句话:容器里的 localhost 不是宿主机,数据库地址必须写宿主机可访问的 IP 或域名。
部署顺利后,把音乐和视频路径映射好,扫描媒体库就能用了。
七、一键启动 MySQL + 道鲤鱼
@echo off
chcp 936 >nul
title 道鲤鱼音乐 一键启动
echo ================================
echo 1. 启动 MySQL 服务
echo ================================
net start MySQL80 >nul 2>&1
if %errorlevel% equ 0 (
echo MySQL80 已启动
) else (
echo MySQL80 可能已在运行,跳过。
)
echo.
echo ================================
echo 2. 检查 Docker 状态
echo ================================
docker ps >nul 2>&1
if errorlevel 1 (
echo Docker 未运行,正在启动 Docker Desktop...
start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe"
echo 等待 Docker 启动完成...
:check_docker
timeout /t 5 /nobreak >nul
docker ps >nul 2>&1
if errorlevel 1 (
echo 等待 Docker 就绪...
goto check_docker
)
echo Docker 已就绪!
) else (
echo Docker 已在运行中
)
echo.
echo ================================
echo 3. 启动 道鲤鱼音乐
echo ================================
cd /d "I:\docker\daoliyu"
if errorlevel 1 (
echo 错误:找不到目录 I:\docker\daoliyu
pause >nul
exit /b
)
docker-compose up -d
if %errorlevel% equ 0 (
echo.
echo ================================
echo 道鲤鱼音乐 启动成功!
echo ================================
echo.
echo 访问地址:http://localhost:4000
echo 音乐目录:I:\media\music
echo 视频目录:I:\media\video
echo ================================
timeout /t 3 /nobreak >nul
start http://localhost:4000
) else (
echo.
echo 启动失败,请检查配置或端口是否被占用。
)
echo.
echo 按任意键退出...
pause >nul
八、一键关闭脚本
@echo off
chcp 936 >nul
title 一键关闭 Docker 服务
echo ================================
echo 1. 停止 道鲤鱼音乐 容器
echo ================================
cd /d "I:\docker\daoliyu"
if errorlevel 1 (
echo 警告:找不到目录 I:\docker\daoliyu
echo 跳过 道鲤鱼 停止步骤。
) else (
docker-compose down
if %errorlevel% equ 0 (
echo 道鲤鱼 已停止。
) else (
echo 道鲤鱼 停止失败,可能容器未运行。
)
)
echo.
echo ================================
echo 2. 停止 songloft 容器
echo ================================
cd /d "I:\docker\songloft"
if errorlevel 1 (
echo 警告:找不到目录 I:\docker\songloft
echo 跳过 songloft 停止步骤。
) else (
docker-compose down
if %errorlevel% equ 0 (
echo songloft 已停止。
) else (
echo songloft 停止失败,可能容器未运行。
)
)
echo.
echo ================================
echo 3. 停止所有运行中的容器
echo ================================
for /f "tokens=*" %%i in ('docker ps -q') do (
echo 正在停止容器: %%i
docker stop %%i >nul
)
echo.
echo 所有容器已停止!
echo.
echo ================================
echo 4. 停止 MySQL 服务
echo ================================
net stop MySQL80 >nul 2>&1
if %errorlevel% equ 0 (
echo MySQL80 已停止。
) else (
echo MySQL80 可能未运行,跳过。
)
echo.
echo ================================
echo 5. 是否关闭 Docker Desktop
echo ================================
set /p close_docker=关闭 Docker Desktop? (y/n):
if /i "%close_docker%"=="y" (
echo 正在关闭 Docker Desktop...
taskkill /f /im "Docker Desktop.exe" >nul 2>&1
echo Docker Desktop 已关闭。
) else (
echo 保留 Docker Desktop 运行。
)
echo.
echo 按任意键退出...
pause >nul
