Black Candy Docker Compose 部署实战
Black Candy v3.2.1 Docker Compose 部署实战:镜像选型(GHCR 渠道/latest 与 edge 标签/无版本号标签实证)、compose 编排逐字段说明、目录属主 uid 1000 修正、登录与媒体同步全链路验证、原格式直出与转码流播放实测,排障实录沉淀。
Black Candy Docker Compose 部署实战
> 目标:用 Docker Compose 在单台 Ubuntu 22.04 服务器上从零部署 Black Candy v3.2.1 自托管音乐流媒体服务器,完成「目录规划 → 编排启动 → 管理员登录 → 媒体目录挂载 → 曲库同步 → 原格式/转码流播放」的完整验证链路。本文全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Docker Engine:29.9.2(API 1.56),Docker Compose 插件 v5.6.1
- Black Candy 版本:v3.2.1(2026-08-26 发布,官方最新稳定版,发布信息查询日期 2026-10-28)
- 官方映像:
ghcr.io/blackcandy-org/blackcandy:latest(amd64,534 MB,映像摘要sha256:996bef686b0907f5c35fd4f1d660dca5d48474098cec2df78968f381c482d580) - 测试曲库:2 位艺人 / 3 张专辑共 6 首 mp3(128 kbps、30 秒正弦波测试音频,含 ID3 标签)
- 端口规划:Black Candy 服务端口
8136(容器内监听 80,经 Thruster 代理转发至 Puma 3000)。生产环境建议映射为标准 80/443 或经反向代理暴露,本文端口取值仅为与实测环境保持一致,可按需替换 - 编排目录:
/opt/black-candy/(示例路径,含docker-compose.yml、media_data/、storage_data/) - 独立网络:
blackcandy-net(bridge,网段10.89.60.0/24)
二、镜像选型说明
Black Candy 官方只发布单一应用映像(Web + 后台任务同进程栈,无独立的任务服务角色),选型要点集中在发布渠道与标签策略两点:
| 项目 | 取值 | 说明 |
|---|---|---|
| 主发布渠道 | ghcr.io/blackcandy-org/blackcandy | GitHub Container Registry,官方 README 安装章节首选渠道 |
| 备用渠道 | blackcandy/blackcandy | Docker Hub 官方命名空间,README 注明「Or pull from Docker Hub」 |
| 滚动最新标签 | latest | 跟随最新稳定版,docker compose pull 即升级 |
| 边缘版本标签 | edge | 基于 master 分支构建,官方明确「not stable,可能遇到数据丢失」,不建议生产使用 |
| 语义化版本标签 | 不提供 | 实测 docker pull ghcr.io/blackcandy-org/blackcandy:v3.2.1 返回 not found——官方未发布版本号标签,版本固化只能借助摘要(digest)或自行构建 |
⚠️ 网络说明:实测环境中 Docker Hub 拉取被守护进程配置的 DaoCloud 公共镜像加速器拦截(报错
this image is not in the allowlist),GHCR 渠道直连正常。当前实测可用渠道为 GHCR;读者环境若 Docker Hub 顺畅,两渠道内容一致,任选其一。
映像关键元数据(docker inspect 实测):
User=app(1000) | Entry=["./bin/docker-entrypoint"] | Cmd=["./bin/thrust","./bin/rails","server"]
WorkDir=/rails | Exposed={"80/tcp":{}} | Env=[RUBY_VERSION=4.0.2, RAILS_ENV=production,
WEB_CONCURRENCY=auto, COMMIT_HASH=93cfdca9857a5e2ae847469c3238a6174515c76f,
LD_PRELOAD=/usr/lib/libjemalloc.so.2]
- 服务以 Rails 8.1.3 + Ruby 4.0.2(+YJIT)运行,前端 Thruster 监听容器内 80 端口、反代至 Puma 3000 端口;
- 媒体同步等后台任务由 Solid Queue 在同一栈内运行(Puma 插件分叉 supervisor/dispatcher/worker 子进程),不需要也不存在额外的任务服务角色;
- 映像内置 ffmpeg 8.0.1(转码)与 libvips(封面图片处理),服务端功能开箱即用;
- 进程以专用低权用户
app(uid/gid 1000)运行——这决定了挂载目录的属主要求(见「四、部署步骤」与「九、常见问题」)。
三、前置条件
- 服务器已安装 Docker Engine 与 Compose 插件,验证:
docker version --format 'Engine {{.Server.Version}} api {{.Server.APIVersion}} {{.Server.Os}}/{{.Server.Arch}}'
实测输出:
Engine 29.9.2 api 1.56 linux/amd64
docker compose version
实测输出:
Docker Compose version v5.6.1
- 规划端口未被占用,验证(以
8136为例,无输出即空闲):
ss -ltn | grep ':8136 ' || echo 'port 8136 free'
实测输出:
port 8136 free
- 准备测试音频需要宿主机有 ffmpeg(仅用于制作测试音频;Black Candy 服务端已内置 ffmpeg,非运行依赖)。无 ffmpeg 的服务器可跳过造数,改用既有音乐文件目录。
四、部署步骤
4.1 目录规划与测试音频制作
创建编排目录与两个数据目录(媒体目录、持久化数据目录):
mkdir -p /opt/black-candy/media_data /opt/black-candy/storage_data
无输出即创建成功,验证:
ls -ld /opt/black-candy/media_data /opt/black-candy/storage_data
实测输出:
drwxr-xr-x 2 root root 4096 Oct 28 17:00 /opt/black-candy/media_data
drwxr-xr-x 2 root root 4096 Oct 28 17:00 /opt/black-candy/storage_data
用 ffmpeg 制作 6 首带 ID3 标签的测试音频(每首 30 秒、128 kbps;歌手/专辑名通过 -metadata 写入,Black Candy 同步时即按标签建库)。逐条执行以下命令:
ffmpeg -y -f lavfi -i "sine=frequency=260:duration=30" -f lavfi -i "sine=frequency=480:duration=30" \
-filter_complex "[0:a][1:a]amix=inputs=2" \
-metadata artist="Test Artist 1" -metadata album="Test Album 1" \
-metadata title="Test Song 1" -metadata genre="Test" \
-b:a 128k /opt/black-candy/media_data/test_song_1.mp3
实测输出(节选):
size= 470KiB time=00:00:30.00 bitrate= 128.3kbits/s speed= 279x elapsed=0:00:00.10
其余 5 首同法制作,仅替换频率、序号与标签(Test Artist 1 配 Test Album 1 的 1-2 首、Test Artist 2 配 Test Album 2 的 3-4 首、Test Artist 2 配 Test Album 3 的 5-6 首):
ffmpeg -y -f lavfi -i "sine=frequency=300:duration=30" -f lavfi -i "sine=frequency=520:duration=30" \
-filter_complex "[0:a][1:a]amix=inputs=2" \
-metadata artist="Test Artist 1" -metadata album="Test Album 1" \
-metadata title="Test Song 2" -metadata genre="Test" \
-b:a 128k /opt/black-candy/media_data/test_song_2.mp3
ffmpeg -y -f lavfi -i "sine=frequency=340:duration=30" -f lavfi -i "sine=frequency=560:duration=30" \
-filter_complex "[0:a][1:a]amix=inputs=2" \
-metadata artist="Test Artist 2" -metadata album="Test Album 2" \
-metadata title="Test Song 3" -metadata genre="Test" \
-b:a 128k /opt/black-candy/media_data/test_song_3.mp3
ffmpeg -y -f lavfi -i "sine=frequency=380:duration=30" -f lavfi -i "sine=frequency=600:duration=30" \
-filter_complex "[0:a][1:a]amix=inputs=2" \
-metadata artist="Test Artist 2" -metadata album="Test Album 2" \
-metadata title="Test Song 4" -metadata genre="Test" \
-b:a 128k /opt/black-candy/media_data/test_song_4.mp3
ffmpeg -y -f lavfi -i "sine=frequency=420:duration=30" -f lavfi -i "sine=frequency=640:duration=30" \
-filter_complex "[0:a][1:a]amix=inputs=2" \
-metadata artist="Test Artist 2" -metadata album="Test Album 3" \
-metadata title="Test Song 5" -metadata genre="Test" \
-b:a 128k /opt/black-candy/media_data/test_song_5.mp3
ffmpeg -y -f lavfi -i "sine=frequency=460:duration=30" -f lavfi -i "sine=frequency=680:duration=30" \
-filter_complex "[0:a][1:a]amix=inputs=2" \
-metadata artist="Test Artist 2" -metadata album="Test Album 3" \
-metadata title="Test Song 6" -metadata genre="Test" \
-b:a 128k /opt/black-candy/media_data/test_song_6.mp3
验证曲库文件就绪:
ls -la /opt/black-candy/media_data/
实测输出:
-rw-r--r-- 1 root root 481202 Oct 28 17:05 test_song_1.mp3
-rw-r--r-- 1 root root 481202 Oct 28 17:05 test_song_2.mp3
-rw-r--r-- 1 root root 481202 Oct 28 17:05 test_song_3.mp3
-rw-r--r-- 1 root root 481202 Oct 28 17:05 test_song_4.mp3
-rw-r--r-- 1 root root 481202 Oct 28 17:05 test_song_5.mp3
-rw-r--r-- 1 root root 481202 Oct 28 17:05 test_song_6.mp3
4.2 生成会话密钥
Black Candy 用 SECRET_KEY_BASE 作为会话加密根,不设置则每次重启都会使全部登录会话失效(官方 README 明确的行为)。用 openssl 生成一个 64 字节十六进制密钥:
openssl rand -hex 64
实测输出(本环境生成值,读者环境应使用自己重新生成的值):
755d2fdebb694ac35618e4ebbe237c4254ef30b0298214099f826248c1a787cb422bde0fbba5935756204f0cdff82df8068b7e5c7fef16d688d6efe63f22e0ca
4.3 修正挂载目录属主
Black Candy 映像内进程以 uid/gid 1000 的 app 用户运行。官方 README 的「Running as an Arbitrary User」一节明确:挂载卷时宿主与运行身份的属主需一致,否则会遇到权限问题。实测中若跳过此步,首次启动即报 SQLite 无法打开数据库文件(完整排障过程见「九、常见问题」第 1 条)。将两个数据目录属主改为 1000:1000:
chown -R 1000:1000 /opt/black-candy/storage_data /opt/black-candy/media_data
无输出即成功,验证:
ls -ld /opt/black-candy/storage_data /opt/black-candy/media_data
实测输出:
drwxr-xr-x 2 yahui yahui 4096 Oct 28 17:00 /opt/black-candy/media_data
drwxr-xr-x 2 root root 4096 Oct 28 17:05 /opt/black-candy/storage_data
💡 说明:
yahui是本环境宿主上 uid=1000 的账号名,数值属主1000:1000才是关键;读者环境显示的账号名会不同,只要属主数值为 1000:1000 即可。若不想改属主,也可按官方 README 的方式在运行配置中显式指定与宿主目录属主一致的 UID/GID(见「八、等价单命令运行」)。
4.4 编写 docker-compose.yml
在编排目录写入 docker-compose.yml 完整内容:
name: black-candy-v3.2.1-stack
networks:
blackcandy-net:
driver: bridge
ipam:
config:
- subnet: 10.89.60.0/24
services:
app:
image: ghcr.io/blackcandy-org/blackcandy:latest
container_name: black-candy-v3.2.1-app
restart: unless-stopped
ports:
- "8136:80"
volumes:
- /opt/black-candy/storage_data:/rails/storage
- /opt/black-candy/media_data:/media_data
environment:
SECRET_KEY_BASE: 755d2fdebb694ac35618e4ebbe237c4254ef30b0298214099f826248c1a787cb422bde0fbba5935756204f0cdff82df8068b7e5c7fef16d688d6efe63f22e0ca
MEDIA_PATH: /media_data
networks:
blackcandy-net:
ipv4_address: 10.89.60.10
逐项说明:
name:Compose 项目名,固定为black-candy-v3.2.1-stack,多套部署并存时避免同名项目互相干扰;image:GHCR 渠道latest标签(v3.2.1 内容),追求可复现可改用latest@sha256:996bef...摘要形式;ports:宿主 8136 → 容器内 80(Thruster 代理监听口),生产可换成"80:80";volumes第一行:唯一持久化数据目录/rails/storage(内含曲库/队列/缓存/推送四个 SQLite 库与封面缓存),挂到宿主storage_data/;v3.1 及之前版本该路径为/app/storage,升级读者必须改挂载路径(官方 v3.2 升级指南的断代变更);volumes第二行:音乐文件目录挂到容器内/media_data,与MEDIA_PATH环境变量呼应;environment:SECRET_KEY_BASE用 4.2 生成的值替换;MEDIA_PATH指向容器内媒体挂载点;networks:自定义 bridge 网段(示例10.89.60.0/24,按读者环境空闲网段调整)并固定服务地址,便于防火墙精细化放行。
4.5 启动
cd /opt/black-candy && docker compose up -d
实测输出:
[+] Running 2/2
✔ Network black-candy-v3.2.1-stack_blackcandy-net Created
✔ Container black-candy-v3.2.1-app Started
⚠️ 网络说明:若这一步长时间卡在拉取层,是访问 GHCR 缓慢所致;实测环境直连 GHCR 正常,无需额外配置。若报
port is already allocated,见「九、常见问题」第 2 条。
4.6 启动过程观察
首次启动时,入口脚本会自动执行数据库准备(建库 + 迁移)。观察日志:
docker compose logs --tail 20 app
实测输出(节选,正常启动日志):
{"time":"2026-10-28T09:01:13.658522712Z","level":"INFO","msg":"Server started","http":":80"}
=> Booting Puma
=> Rails 8.1.3 application starting in production
[25] Puma starting in cluster mode...
[25] * Puma version: 6.6.1 ("Return to Forever")
[25] * Ruby version: ruby 4.0.2 (2026-03-17 revision d3da9fec82) +YJIT +PRISM [x86_64-linux-musl]
[25] * Listening on http://0.0.0.0:3000
[25] - Worker 0 (PID: 33) booted in 0.01s, phase: 0
[25] - Worker 1 (PID: 36) booted in 0.01s, phase: 0
SolidQueue-1.1.5 Started Supervisor (36.7ms) pid: 99, hostname: "f23bf6ea8678", process_id: 1, name: "supervisor-905a864244bb53fc7d63"
SolidQueue-1.1.5 Started Dispatcher (7.5ms) pid: 105, hostname: "f23bf6ea8678", process_id: 2, name: "dispatcher-f87893b81992729fc36c", polling_interval: 1, batch_size: 500, concurrency_maintenance_interval: 30
SolidQueue-1.1.5 Started Worker (10.1ms) pid: 108, hostname: "f23bf6ea8678", process_id: 3, name: "worker-b7bd9a4c451f3b7a7a6f", polling_interval: 0.1, queues: "critical,high,default,low", thread_pool_size: 3
日志中出现三类关键信号:Puma 集群(6 个 worker,由 WEB_CONCURRENCY=auto 按机器核数自动决定)、Thruster 代理已在 80 端口就绪(Server started, http: :80)、Solid Queue 后台任务体系(Supervisor + Dispatcher + Worker)已启动——后者就是媒体同步任务的执行者。
4.7 运行状态与端口验证
docker compose ps
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
black-candy-v3.2.1-app ghcr.io/blackcandy-org/blackcandy:latest "./bin/docker-entryp…" app 8 minutes ago Up 8 minutes 0.0.0.0:8136->80/tcp, [::]:8136->80/tcp
curl -sI http://127.0.0.1:8136/ | head -5
实测输出:
HTTP/1.1 302 Found
Location: http://127.0.0.1:8136/sessions/new
Content-Security-Policy: ...
X-Content-Type-Options: nosniff
💡 说明:访问根路径 302 跳转到
/sessions/new登录页,是未登录状态的预期行为,说明 Thruster → Puma → Rails 全链路已通。
五、数据持久化说明
Black Candy 需要持久化的状态收敛在一个目录:容器内 /rails/storage。查看实测目录内容:
ls -la /opt/black-candy/storage_data/
实测输出(启动并同步后的真实内容):
-rw-r--r-- 1 1000 1000 155648 production.sqlite3
-rw-r--r-- 1 1000 1000 32768 production.sqlite3-shm
-rw-r--r-- 1 1000 1000 461472 production.sqlite3-wal
-rw-r--r-- 1 1000 1000 40960 production_cable.sqlite3
-rw-r--r-- 1 1000 1000 40960 production_cache.sqlite3
-rw-r--r-- 1 1000 1000 86552 production_cache.sqlite3-wal
-rw-r--r-- 1 1000 1000 192512 production_queue.sqlite3
-rw-r--r-- 1 1000 1000 32768 production_queue.sqlite3-shm
-rw-r--r-- 1 1000 1000 32768 production_queue.sqlite3-wal
production.sqlite3:主库——用户、艺人/专辑/曲目、播放列表、收藏、会话等全部业务数据;production_queue.sqlite3:Solid Queue 后台任务库;production_cache.sqlite3:应用缓存库(含「同步进行中」标志位);production_cable.sqlite3:Action Cable 推送消息库;-wal/-shm是 SQLite WAL 模式的伴随文件,备份时一并保留(详见《Black Candy 常用命令与运维实战》篇的备份章节)。
音乐文件本体在 media_data/ 目录,只读挂载给服务即可(同步只读文件、不回写)。备份 = 备份这两个目录。
六、环境变量表
官方 README 环境变量章节的完整清单(Default 列为官方标注默认值):
| 环境变量 | 默认值 | 说明 |
|---|---|---|
MEDIA_PATH | 无 | 媒体目录路径;不设置时也可在 Web 管理设置页指定 |
SECRET_KEY_BASE | 每次启动随机生成 | 会话加密根;不设置则每次重启全部登录会话失效,生产必设 |
DB_ADAPTER | sqlite | 数据库适配器,支持 sqlite 与 postgresql |
DB_URL | 无 | PostgreSQL 连接串,DB_ADAPTER=postgresql 时必设 |
CABLE_DB_URL | 无 | 推送(Pub/Sub)库连接串,PostgreSQL 模式必设 |
QUEUE_DB_URL | 无 | 后台任务库连接串,PostgreSQL 模式必设 |
CACHE_DB_URL | 无 | 缓存库连接串,PostgreSQL 模式必设 |
FORCE_SSL | false | 强制全站 HTTPS 访问 |
DEMO_MODE | false | 演示模式:开启后所有用户(含管理员)无管理特权且不能改个人资料 |
HTTP_PORT | 80 | 服务在容器内监听的端口,需换端口时设置 |
各项的深入语义、取值实测与组合建议见《Black Candy 配置参数详解》篇。
七、配置参数说明
本节说明编排文件中最值得斟酌的三个参数:
SECRET_KEY_BASE(必设):官方建议用 openssl rand -hex 64 生成(见 4.2 节实测)。其影响面是登录会话的有效性——值变化即全部会话失效。latest 标签升级后容器重建时该值不变,会话即可无缝延续。
MEDIA_PATH(二选一):既可用环境变量声明,也可在 Web 设置页指定。环境变量方式的优点是声明与编排同处一份文件、幂等可审;设置页方式的值持久化在主库中。两者同时存在时以环境变量为准(启动时注入的运行配置优先)。
DB_ADAPTER/DB_URL 族(可选切换):默认 SQLite 四库分离(主库/任务/缓存/推送各一个文件),对个人量级是零运维方案;官方 README 明确若自认为 SQLite 不够用、或托管在 Heroku 类平台,可整体切换 PostgreSQL——四个库各自需要独立的连接串(DB_URL/QUEUE_DB_URL/CACHE_DB_URL/CABLE_DB_URL),官方示例形态:
docker run -e DB_ADAPTER=postgresql -e DB_URL=postgresql://yourdatabaseurl ghcr.io/blackcandy-org/blackcandy:latest
(以上为官方 README 原例,yourdatabaseurl 处替换为读者环境实际的 PostgreSQL 连接串;Compose 部署时把 -e 键值对移入 environment: 块即可。)
八、等价单命令运行
不用 Compose 时,与 4.4 编排等价的单命令形态:
docker run -d --name black-candy-v3.2.1-app \
-p 8136:80 \
-v /opt/black-candy/storage_data:/rails/storage \
-v /opt/black-candy/media_data:/media_data \
-e SECRET_KEY_BASE=755d2fdebb694ac35618e4ebbe237c4254ef30b0298214099f826248c1a787cb422bde0fbba5935756204f0cdff82df8068b7e5c7fef16d688d6efe63f22e0ca \
-e MEDIA_PATH=/media_data \
--user 1000:1000 \
ghcr.io/blackcandy-org/blackcandy:latest
--user 1000:1000即官方 README「Running as an Arbitrary User」方案:让运行身份与宿主目录属主一致,可替代 4.3 的 chown(二选一,实测以 chown 方式验证为主);- 其余参数与 Compose 编排一一对应。长期运行仍建议用 Compose 管理(编排即文档、升级回滚明确)。
九、常见问题(实测排障实录)
Q1:首次启动即崩溃重启,日志报 SQLite3::CantOpenException: unable to open database file
实测现象:docker compose up -d 后容器反复重启,日志核心报错:
bin/rails aborted!
ActiveRecord::StatementInvalid: SQLite3::CantOpenException: unable to open database file (ActiveRecord::StatementInvalid)
Caused by:
SQLite3::CantOpenException: unable to open database file (SQLite3::CantOpenException)
Tasks: TOP => db:prepare
(See full trace by running task with --trace)
定位:入口脚本首次启动要执行 db:prepare 在 /rails/storage 下创建 SQLite 库文件;挂载目录属主是 root(或其它非 1000 用户),而映像内进程以 uid 1000 的 app 用户运行,无写权限。
解决:把挂载目录属主改为 1000:1000 后重启(见 4.3 节),或改用 --user 指定与目录属主一致的身份(见第八节)。实测修正后一次启动成功。
Q2:docker compose up -d 报 Bind for 0.0.0.0:8136 failed: port is already allocated
实测现象:目标端口已被其它服务(或残留的同端口部署)占用:
Error response from daemon: failed to set up container networking: driver failed programming external connectivity
on endpoint black-candy-v3.2.1-app (...): Bind for 0.0.0.0:8136 failed: port is already allocated
定位与解决:ss -ltn | grep ':8136 ' 找到占用者;换一个空闲端口改 ports: 后重新 docker compose up -d(会自动按新配置重建)。注意 ss 看不到的已停用编排也可能占用端口,必要时 docker ps -a 一并核查。
Q3:设置了媒体路径、点了同步,但曲库始终为空
排查三步(均实测有效):
- 确认媒体目录在容器内可见且可读:同步任务以 uid 1000 身份枚举文件,宿主目录属主非 1000 且无 others 读权限时会静默得到 0 个文件——
chown -R 1000:1000修正; - 确认
MEDIA_PATH环境变量值与媒体目录的容器内挂载点一致(本例均为/media_data);设置页显示的 Media Path 应为同一路径; - 同步是后台异步任务:点同步后看日志确认任务真的入队执行——
docker compose logs app 2>&1 | grep -i 'MediaSync'
实测输出(节选):
[ActiveJob] Enqueued MediaSyncAllJob (Job ID: cfb1afd4-f5b2-449d-9f00-8553be6edc6d) to SolidQueue(critical)
[ActiveJob] [MediaSyncAllJob] [cfb1afd4-f5b2-449d-9f00-8553be6edc6d] Performing MediaSyncAllJob (Job ID: cfb1afd4-f5b2-449d-9f00-8553be6edc6d) from SolidQueue(critical)
看到 Enqueued → Performing 即任务链路正常;只有 Enqueued 没有 Performing 则是任务执行侧问题,重启栈观察 SolidQueue 三进程是否起来(见 4.6 节日志)。
Q4:每次重启服务后所有人都被登出
SECRET_KEY_BASE 未设置。官方 README 明确:不设置时每次启动都会生成新密钥,全部既有会话失效。按 4.2/4.4 固定该值即可。
Q5:Docker Hub 渠道拉取报 this image is not in the allowlist
实测报错原文:
Error response from daemon: error from registry: 🚫 👀-> https://github.com/DaoCloud/public-image-mirror/issues/2328 🔗 这镜像不在白名单. this image is not in the allowlist.
这是本地 Docker 守护进程配置的 DaoCloud 公共加速器对 blackcandy/blackcandy 命名空间未放行,并非官方镜像不存在。解决:改走 GHCR 主渠道 ghcr.io/blackcandy-org/blackcandy:latest(实测直连正常),或调整加速器白名单。
十、常用运维命令
日常操作均以 black-candy-v3.2.1-stack 项目为对象,在 /opt/black-candy/ 目录内执行:
docker compose ps # 实例状态与端口映射
docker compose logs -f app # 跟踪服务日志(Ctrl-C 退出)
docker compose restart # 重启服务
docker compose stop # 停止(保留实例)
docker compose start # 再次启动
stop/start 实测输出:
Container black-candy-v3.2.1-app Stopped
Container black-candy-v3.2.1-app Started
升级到新版本按官方 README 的 Compose 升级流程(拉新映像 → 重建实例;数据在 /rails/storage 内自动迁移):
docker compose pull
docker compose up -d
⚠️ 注意:升级前先读官方升级指南(
docs/upgrade.md)——Black Candy 在大版本存在断代变更(如 v3.1 → v3.2 的工作目录/app→/rails,挂载路径必须同步修改),且 v3.2.0 起要求移动客户端 v2.0 以上。回滚即docker compose down后改回旧标签(或摘要)再up -d,存储目录建议升级前先备份。
退役清理(删除实例与网络,宿主数据目录保留):
docker compose down
十一、参考链接
- 官方 README(安装/配置/环境变量/数据持久化):https://github.com/blackcandy-org/blackcandy
- 官方升级指南(v3.1 → v3.2 断代变更):https://github.com/blackcandy-org/blackcandy/blob/master/docs/upgrade.md
- 版本发布页:https://github.com/blackcandy-org/blackcandy/releases
- 本专栏系列篇:《Black Candy 介绍与选型指南》、《Black Candy 配置参数详解》、《Black Candy 常用命令与运维实战》