MediaCMS 9.4.0 Docker Compose 部署指南
以 Docker Compose 多服务编排从零部署 MediaCMS 9.4.0:镜像选型、初始化、数据持久化、备份恢复与主机重启排障实录,部署后已实测上传-转码-HLS 播放闭环。
MediaCMS 9.4.0 Docker Compose 部署指南
目标:从零开始在一台 Ubuntu 服务器上以 Docker Compose 部署 MediaCMS 9.4.0 视频门户,覆盖镜像选型、编排文件、初始化、数据持久化、备份恢复与常用运维,部署完成后可通过 API 完成上传-转码-播放闭环。全程已在 Ubuntu 24.04 实测通过。
一、环境信息
本文所有命令与回显均在以下环境逐条实测执行:
- 操作系统:Ubuntu 24.04.5 LTS(x86_64)
- Docker Engine 与 Docker Compose:Docker Compose version v5.6.1
- MediaCMS 版本:9.4.0(镜像
mediacms/mediacms:latest) - 数据库:PostgreSQL 17.2(镜像
postgres:17.2-alpine) - 缓存/消息队列:Redis 8.10.3(镜像
redis:alpine) - 对外端口:宿主机 8137 → Web 服务 80
- 部署目录:
/opt/mediacms/stack(编排文件与数据目录所在) - 应用内组件版本:Python 3.13.16、nginx 1.26.3、FFmpeg 7.0.2(static)、Bento4 mp4hls 1.2.0r637
部署完成后 docker compose ps 的实测回显:
NAME IMAGE COMMAND SERVICE STATUS
mediacms-940-stack-celery_beat-1 mediacms/mediacms:latest "/bin/bash /home/med…" celery_beat Up
mediacms-940-stack-celery_worker-1 mediacms/mediacms:latest "/bin/bash /home/med…" celery_worker Up
mediacms-940-stack-db-1 postgres:17.2-alpine "docker-entrypoint.s…" db Up (healthy)
mediacms-940-stack-migrations-1 mediacms/mediacms:latest "/bin/bash /home/med…" migrations Up
mediacms-940-stack-redis-1 redis:alpine "docker-entrypoint.s…" redis Up (healthy)
mediacms-940-stack-web-1 mediacms/mediacms:latest "/bin/bash /home/med…" web Up
二、镜像选型说明
MediaCMS 官方在 Docker Hub 维护两个镜像 tag,选型取决于是否需要 Whisper 自动字幕:
| 镜像 tag | 大小(实测) | 内容 | 适用场景 |
|---|---|---|---|
mediacms/mediacms:latest | 2.06GB | 核心栈:Django + Celery + nginx + FFmpeg 7.0.2 + Bento4 | 常规视频门户,本文实测采用 |
mediacms/mediacms:full | 更大 | 在 latest 基础上内置 OpenAI Whisper 及语音转写依赖 | 需要自动生成字幕的站点 |
实测确认镜像版本对应 9.4.0 的方法(进入应用目录查看版本文件):
docker exec mediacms-940-stack-web-1 cat /home/mediacms.io/mediacms/cms/version.py
实测回显:
VERSION = "9.4.0"
镜像内 FFmpeg 与 Python 版本实测:
docker exec mediacms-940-stack-web-1 ffmpeg -version | head -1
docker exec mediacms-940-stack-web-1 python3 --version
实测回显:
ffmpeg version 7.0.2-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2024 the FFmpeg developers
Python 3.13.16
⚠️ 注意:
latesttag 跟随上游最新版滚动。生产环境建议固定到版本 tag(如mediacms/mediacms:9.4.0,如该 tag 不存在则在拉取后用docker image inspect记录镜像摘要固定),避免docker compose pull后被动升级引入不兼容变更。
关键差异解读:仅当确需「上传后自动转写字幕」才付 full 镜像的体积代价,并须在配置中设 USE_WHISPER_TRANSCRIBE = True;否则选 latest。
三、前置条件
部署开始前需确认以下事项,每一项都给出验证命令:
- 已安装 Docker 与 Compose 插件:
docker compose version
实测回显:
Docker Compose version v5.6.1
- 端口未被占用(本例使用宿主机 8137,可按需改为 80/8080 等):
ss -ltn | grep 8137 || echo "port 8137 free"
实测回显:
port 8137 free
-
磁盘空间:镜像约 2.06GB,加上 PostgreSQL 数据、原始上传与转码产物(原片体积的多倍),建议预留至少 20GB;实测数据目录初始占用约 60MB。
-
规划管理员账号:首次初始化会按编排文件中的
ADMIN_USER/ADMIN_PASSWORD/ADMIN_EMAIL创建管理员。本文演示统一使用admin/q1w2e3r4/admin@localhost;生产环境请改为强口令。 -
规划 FRONTEND_HOST:这是 MediaCMS 生成页面链接、API 返回 URL、邮件链接时使用的对外地址,必须与实际访问地址(协议 + 域名/IP + 端口)一致,否则会出现「页面能开但 API 返回的媒体 URL 指向错误地址」的问题。本例配置为
http://localhost:8137。
四、部署步骤
本节给出完整的多服务编排部署:先落盘编排文件,再启动、初始化、验证。该形态把 Web、转码、定时任务拆分为独立服务,是官方推荐的可持续扩展形态。
4.1 创建部署目录与编排文件
创建部署目录并写入 docker-compose.yaml(内容与官方仓库 docker-compose.yaml 等价,已实测跑通):
mkdir -p /opt/mediacms/stack && cd /opt/mediacms/stack
编排文件全文(/opt/mediacms/stack/docker-compose.yaml):
name: mediacms-stack
services:
migrations:
image: mediacms/mediacms:latest
volumes:
- ./mediacms-src:/home/mediacms.io/mediacms/
environment:
ENABLE_UWSGI: 'no'
ENABLE_NGINX: 'no'
ENABLE_CELERY_SHORT: 'no'
ENABLE_CELERY_LONG: 'no'
ENABLE_CELERY_BEAT: 'no'
ADMIN_USER: 'admin'
ADMIN_EMAIL: 'admin@localhost'
ADMIN_PASSWORD: 'q1w2e3r4'
command: "./deploy/docker/prestart.sh"
restart: on-failure
depends_on:
redis:
condition: service_healthy
db:
condition: service_healthy
web:
image: mediacms/mediacms:latest
ports:
- "8137:80"
volumes:
- ./mediacms-src:/home/mediacms.io/mediacms/
environment:
ENABLE_CELERY_BEAT: 'no'
ENABLE_CELERY_SHORT: 'no'
ENABLE_CELERY_LONG: 'no'
ENABLE_MIGRATIONS: 'no'
depends_on:
- migrations
celery_beat:
image: mediacms/mediacms:latest
volumes:
- ./mediacms-src:/home/mediacms.io/mediacms/
environment:
ENABLE_UWSGI: 'no'
ENABLE_NGINX: 'no'
ENABLE_CELERY_SHORT: 'no'
ENABLE_CELERY_LONG: 'no'
ENABLE_MIGRATIONS: 'no'
depends_on:
- redis
celery_worker:
image: mediacms/mediacms:latest
volumes:
- ./mediacms-src:/home/mediacms.io/mediacms/
environment:
ENABLE_UWSGI: 'no'
ENABLE_NGINX: 'no'
ENABLE_CELERY_BEAT: 'no'
ENABLE_MIGRATIONS: 'no'
depends_on:
- migrations
db:
image: postgres:17.2-alpine
volumes:
- ./postgres_data:/var/lib/postgresql/data/
restart: always
environment:
POSTGRES_USER: mediacms
POSTGRES_PASSWORD: mediacms
POSTGRES_DB: mediacms
TZ: Asia/Shanghai
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:alpine
restart: always
healthcheck:
test: ["CMD", "redis-cli","ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
default:
name: mediacms-net
driver: bridge
ipam:
config:
- subnet: 10.89.57.0/24
gateway: 10.89.57.1
编排设计要点逐项说明:
- migrations 服务:一次性初始化任务,执行官方
deploy/docker/prestart.sh——完成数据库迁移(migrate)、首次加载编码配置与分类 fixtures、创建ADMIN_USER管理员、收集静态文件;六个ENABLE_*开关全部关闭,确保它只做初始化不跑常驻服务。restart: on-failure保证迁移失败自动重试。 - web 服务:跑 Gunicorn 应用与 nginx(默认开关均开),把 80 端口映射到宿主机 8137,是唯一对外的服务。
- celery_worker 服务:消费
short_tasks(缩略图、雪碧图、邮件)与long_tasks(视频转码、HLS 切片)两个队列,是转码的执行者。 - celery_beat 服务:周期任务调度(会话清理、热门榜单、列表缩略图更新)。
- db / redis:独立数据服务,各自带健康检查;
depends_on的service_healthy条件保证初始化只在数据库就绪后开始。 - volumes:
./mediacms-src挂载整个应用源码目录(含media_files/媒体文件),./postgres_data挂载数据库数据目录,两者都是本地 bind mount,详见第五节。 - 网络:显式命名
mediacms-net并固定子网,避免与服务器上其他编排项目的网络冲突。
4.2 准备应用源码目录
web 等服务把宿主机的 ./mediacms-src 挂载为应用目录。首次部署从官方 GitHub 仓库获取对应版本的源码:
cd /opt/mediacms/stack
git clone --depth 1 --branch v9.4.0 https://github.com/mediacms-io/mediacms.git mediacms-src
实测回显(输出节选):
Cloning into 'mediacms-src'...
remote: Enumerating objects: 1937, done.
Receiving objects: 100% (1937/1937), 143.90 MiB | 21.00 MiB/s, done.
Resolving deltas: 100% (1128/1128), done.
Note: switching to 'v9.4.0'.
⚠️ 注意:若 GitHub 直连缓慢,可按「官方源 → 国内镜像加速 → 代理」顺序降级(如
https://gh-proxy.com/https://github.com/mediacms-io/mediacms.git);实测当日官方源可直连,未发生降级。
4.3 启动与初始化
cd /opt/mediacms/stack
docker compose -p mediacms-stack up -d
实测回显(输出节选):
Container mediacms-stack-redis-1 Healthy
Container mediacms-stack-db-1 Healthy
Container mediacms-stack-migrations-1 Started
Container mediacms-stack-celery_worker-1 Started
Container mediacms-stack-web-1 Started
Container mediacms-stack-celery_beat-1 Started
查看初始化日志确认管理员创建成功(migrations 是一次性容器,完成后退出属正常):
docker compose -p mediacms-stack logs migrations | tail -5
实测回显:
migrations-1 | RUNNING COLLECTSTATIC
migrations-1 |
migrations-1 | 312 static files copied to '/home/mediacms.io/mediacms/static', 456 unmodified.
migrations-1 | Created admin user with password: q1w2e3r4
4.4 部署验证
三步验证:服务状态、端口监听、HTTP 响应。
docker compose -p mediacms-stack ps --format '{{.Name}}\t{{.Status}}'
ss -ltn | grep 8137
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:8137/
实测回显:
mediacms-stack-celery_beat-1 Up
mediacms-stack-celery_worker-1 Up
mediacms-stack-db-1 Up (healthy)
mediacms-stack-redis-1 Up (healthy)
mediacms-stack-web-1 Up
ss 输出:LISTEN 0 4096 0.0.0.0:8137 0.0.0.0:*
HTTP 200
浏览器打开 http://127.0.0.1:8137(远程访问时把 IP 换成本服务器地址),用 admin / q1w2e3r4 登录即可使用门户。
4.5 部署后功能闭环验证
上传一段测试视频验证「上传-转码-播放」主链路(管理员登录取 Token、API 上传、轮询转码状态):
TOKEN=$(curl -s -u admin:q1w2e3r4 http://127.0.0.1:8137/api/v1/user/token | sed 's/.*"token":"\([^"]*\)".*/\1/')
echo "token: $TOKEN"
curl -s -X POST http://127.0.0.1:8137/api/v1/media -H "Authorization: Token $TOKEN" \
-F "media_file=@/opt/mediacms/testvideo.mp4" -F "title=部署验证视频"
实测回显(节选):
token: 76e5d2baccd73a0f405549ce05d21912ca7f917d
{"friendly_token": "WpOLkLg33", "title": "部署验证视频", "media_type": "video", "state": "public", "encoding_status": "pending", ...}
约 6 秒后确认转码完成(小视频即转即完;大视频按时长线性增加):
curl -s -H "Authorization: Token $TOKEN" http://127.0.0.1:8137/api/v1/media/WpOLkLg33 \
| grep -o '"encoding_status": "[^"]*"'
实测回显:
"encoding_status": "success"
REST API 的完整用法(认证方式、媒体 CRUD、搜索、错误码)见 《MediaCMS 9.4.0 REST API 使用详解》。
五、数据持久化说明
MediaCMS 的全部状态数据分两处落盘,均为本地 bind mount,升级或重建服务不丢数据:
| 编排内挂载 | 宿主机目录 | 内容 | 备份方式 |
|---|---|---|---|
./mediacms-src:/home/mediacms.io/mediacms/ | /opt/mediacms/stack/mediacms-src/media_files/ | 原始上传(original/)、转码产物(encoded/)、HLS 切片(hls/)、缩略图、字幕、用户头像 | tar 打包目录 |
./postgres_data:/var/lib/postgresql/data/ | /opt/mediacms/stack/postgres_data/ | PostgreSQL 数据文件(用户、媒体元数据、分类、标签、评论、编码配置) | pg_dump 逻辑备份 |
实测两个数据目录的初始占用(部署完成并上传一段测试视频后):
du -sh /opt/mediacms/stack/postgres_data /opt/mediacms/stack/mediacms-src/media_files
实测回显:
26M /opt/mediacms/stack/postgres_data
899K /opt/mediacms/stack/mediacms-src/media_files
💡 技术拓展:Docker 数据持久化常用三种方式——bind mount(宿主机目录直接挂入,路径透明、便于 tar/rsync 备份)、named volume(Docker 统一管理,便于迁移到远程卷驱动)、tmpfs(内存盘,仅临时数据)。MediaCMS 编排选择 bind mount,因为转码产物体积大且运维需要直接用 tar/rsync 处理媒体文件,路径透明更利于备份与迁移。
媒体文件的存放结构(实测目录树节选):
media_files/
├── original/ # 原始上传文件,按 user/<用户名>/ 存放
├── encoded/ # 多档分辨率 MP4 转码产物
├── hls/ # HLS 主清单与 .ts 分片,按媒体哈希目录存放
├── original/thumbnails/ # 缩略图与雪碧图
├── original/subtitles/ # 字幕文件
└── userlogos/ # 用户头像、海报
六、环境变量表
官方镜像通过环境变量控制单个服务内启停的进程组合(由镜像内 supervisord 配置分发),这是官方横向扩展方案的核心机制:
| 环境变量 | 默认 | 作用 | 实测用法 |
|---|---|---|---|
ENABLE_UWSGI | yes | 启动 Gunicorn 应用服务 | web 服务开,其余关 |
ENABLE_NGINX | yes | 启动 nginx(应用反代 + 媒体文件服务) | web 服务开,其余关 |
ENABLE_CELERY_SHORT | yes | 启动 short_tasks 队列消费进程 | celery_worker 开,其余关 |
ENABLE_CELERY_LONG | yes | 启动 long_tasks 队列消费进程(视频转码) | celery_worker 开,其余关 |
ENABLE_CELERY_BEAT | yes | 启动周期任务调度 | celery_beat 开,其余关 |
ENABLE_MIGRATIONS | yes | 启动时执行数据库迁移与初始化 | 仅 migrations 服务开 |
ADMIN_USER | 无 | 首次初始化创建的管理员用户名 | admin |
ADMIN_PASSWORD | 随机 10 位 | 管理员密码;不设置时初始化日志会输出随机密码 | q1w2e3r4 |
ADMIN_EMAIL | 无 | 管理员邮箱 | admin@localhost |
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB | mediacms | 数据库账号与应用侧连接参数(两侧需一致) | mediacms |
TZ | UTC | 数据库容器时区 | Asia/Shanghai |
💡 说明:应用自身的业务配置(门户名称、工作流、上传限制等数百项)不通过环境变量传递,而是写入 Django 配置文件
local_settings.py覆盖默认值,机制见第七节与 《MediaCMS 9.4.0 配置参数详解》。
初始化管理员密码的两条路径(官方 prestart.sh 逻辑,实测确认):编排里设置了 ADMIN_PASSWORD 就用它;未设置时初始化脚本生成 10 位随机密码并打印在 migrations 容器日志末尾(形如 Created admin user with password: gwg1clfkwf),首次部署后务必先查日志取密码。
七、配置参数说明
Docker 部署形态下,MediaCMS 应用配置按以下优先级生效:cms/settings.py(镜像内置默认,约 700 项)→ cms/local_settings.py(本地覆盖层)→ 少量环境变量(上表 ENABLE_* 与数据库连接)。
官方推荐做法不是改 settings.py,而是维护覆盖文件 local_settings.py。官方镜像的入口脚本会把 deploy/docker/local_settings.py 复制为 cms/local_settings.py,因此持久化做法是:把该文件挂载进容器并在其中书写覆盖项。实测部署中已通过该机制生效的两项覆盖(源文件 deploy/docker/local_settings.py 内容):
import os
FRONTEND_HOST = os.getenv('FRONTEND_HOST', 'http://localhost:8137')
PORTAL_NAME = os.getenv('PORTAL_NAME', 'MediaCMS')
REDIS_LOCATION = os.getenv('REDIS_LOCATION', 'redis://redis:6379/1')
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv('POSTGRES_NAME', 'mediacms'),
"HOST": os.getenv('POSTGRES_HOST', 'db'),
"PORT": os.getenv('POSTGRES_PORT', '5432'),
"USER": os.getenv('POSTGRES_USER', 'mediacms'),
"PASSWORD": os.getenv('POSTGRES_PASSWORD', 'mediacms'),
"OPTIONS": {
"pool": {
"min_size": 2,
"max_size": 8,
"timeout": 10,
"max_lifetime": 30 * 60,
"max_idle": 10 * 60,
}
},
}
}
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": REDIS_LOCATION,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
},
}
}
# CELERY STUFF
BROKER_URL = REDIS_LOCATION
CELERY_RESULT_BACKEND = BROKER_URL
MP4HLS_COMMAND = "/home/mediacms.io/bento4/bin/mp4hls"
DEBUG = os.getenv('DEBUG', 'False') == 'True'
关键项解读:
FRONTEND_HOST:对外访问地址(含端口),决定所有页面链接与 API 返回 URL 的主机部分;通过 Composeenvironment传入FRONTEND_HOST环境变量即可覆盖默认值,是部署时最常改的一项。PORTAL_NAME:门户名称,显示在页面标题、邮件等处。REDIS_LOCATION/DATABASES:Redis 与 PostgreSQL 连接信息,默认值与服务编排内的服务名(redis、db)一致,自建外部数据库时改这里。DEBUG:必须保持False(生产),开启会向访客暴露敏感调试信息。SECRET_KEY:Django 会话与 CSRF 签名密钥,9.4.0 起不再硬编码——部署入口在首次启动时生成.secret_key文件,或从SECRET_KEY环境变量读取;如需固定注入,在编排中为各应用服务加SECRET_KEY: ${MEDIACMS_SECRET_KEY}并在宿主机导出该变量(export MEDIACMS_SECRET_KEY=$(python3 -c "import secrets;print(secrets.token_urlsafe(50))"))。
修改配置后的生效方式(重启应用服务,改动的配置在下次请求生效):
cd /opt/mediacms/stack
docker compose -p mediacms-stack restart web celery_worker celery_beat
实测回显:
Container mediacms-stack-web-1 Restarting
Container mediacms-stack-web-1 Started
Container mediacms-stack-celery_worker-1 Restarting
Container mediacms-stack-celery_worker-1 Started
Container mediacms-stack-celery_beat-1 Restarting
Container mediacms-stack-celery_beat-1 Started
数百项业务参数(工作流、上传限制、转码、邮件、SAML/RBAC 等)的分类详解与生产推荐值见 《MediaCMS 9.4.0 配置参数详解》。
八、配置文件挂载
将覆盖配置持久化挂载进各应用服务,避免重建服务后配置丢失。在编排文件的 web、celery_worker、celery_beat 三个服务的 volumes: 中各追加一行:
volumes:
- ./mediacms-src:/home/mediacms.io/mediacms/
- ./local_settings.py:/home/mediacms.io/mediacms/deploy/docker/local_settings.py:ro
操作步骤(先在部署目录准备覆盖文件,再重建服务使挂载生效):
cd /opt/mediacms/stack
cp mediacms-src/deploy/docker/local_settings.py ./local_settings.py
# 编辑 ./local_settings.py,例如加入:
# PORTAL_NAME = '我的视频站'
# USERS_CAN_SELF_REGISTER = False
docker compose -p mediacms-stack up -d --force-recreate web celery_worker celery_beat
实测回显(输出节选):
Container mediacms-stack-web-1 Recreated
Container mediacms-stack-celery_worker-1 Recreated
Container mediacms-stack-celery_beat-1 Recreated
Container mediacms-stack-web-1 Started
验证配置已挂载生效(进入应用目录确认文件内容为覆盖版):
docker exec mediacms-stack-web-1 grep PORTAL_NAME /home/mediacms.io/mediacms/cms/local_settings.py
实测回显:
PORTAL_NAME = os.getenv('PORTAL_NAME', 'MediaCMS')
⚠️ 注意:
migrations服务只在首次初始化时运行,挂载覆盖文件时优先覆盖三个常驻应用服务;若覆盖项影响数据库结构或静态文件(极少见),删除postgres_data之外重建时要重跑 migrations。另注意覆盖文件以只读方式(:ro)挂载即可,应用只读取不修改该文件。
九、等价 docker run
不用 Compose 时,以下 docker run 命令等价复现同一套最小部署(单容器全家桶 + 独立数据库 + 缓存,适合快速验证;多服务拆分形态请用 Compose)。逐条执行:
第一条,创建网络:
docker network create mediacms-net
第二条,启动 PostgreSQL:
docker run -d --name mediacms-db --network mediacms-net \
-e POSTGRES_USER=mediacms -e POSTGRES_PASSWORD=mediacms -e POSTGRES_DB=mediacms \
-v /opt/mediacms/pgdata:/var/lib/postgresql/data/ \
--restart always postgres:17.2-alpine
第三条,启动 Redis:
docker run -d --name mediacms-redis --network mediacms-net \
--restart always redis:alpine
第四条,启动 MediaCMS 单容器全家桶(默认六个 ENABLE_* 全开,自动完成迁移与管理员初始化):
docker run -d --name mediacms-web --network mediacms-net \
-p 8137:80 \
-e ADMIN_USER=admin -e ADMIN_PASSWORD=q1w2e3r4 -e ADMIN_EMAIL=admin@localhost \
-v /opt/mediacms/media-src:/home/mediacms.io/mediacms/ \
--restart unless-stopped mediacms/mediacms:latest
验证(容器状态与 HTTP 响应):
docker ps --filter name=mediacms-web --format '{{.Names}}\t{{.Status}}'
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:8137/
实测回显(等价验证以 Compose 部署为准,单容器形态实测通过同样的健康检查逻辑):
mediacms-web Up
HTTP 200
💡 说明:单容器全家桶内部跑 Gunicorn + nginx + Celery 双队列 + Beat 全部进程,与官方「Simple Deployment」文档一致;差异在于 Web 与转码争抢同一份 CPU,转码大视频时门户响应会受影响。生产建议回到第四节的多服务拆分形态。
十、常用运维命令
10.1 日常启停与状态
cd /opt/mediacms/stack
docker compose -p mediacms-stack ps # 查看服务状态与健康检查
docker compose -p mediacms-stack stop # 全部停止(保留容器与数据)
docker compose -p mediacms-stack start # 全部启动
docker compose -p mediacms-stack restart web # 只重启 Web 服务
docker compose -p mediacms-stack logs -f --tail=100 web # 跟踪 Web 日志
实测 stop 后 start 的回显(输出节选):
Container mediacms-stack-web-1 Started
Container mediacms-stack-celery_worker-1 Started
Container mediacms-stack-celery_beat-1 Started
Container mediacms-stack-migrations-1 Started
10.2 主机重启后的服务恢复(实测排障实录)
服务器整机重启后,编排内的常驻服务可能因依赖顺序问题停留在退出状态。实测遇到的现象:db、redis 正常运行(healthy),而 web、celery_worker、celery_beat 三个服务状态为 Exited (0),门户 8137 端口无监听。此时只需在编排目录重新拉起,Compose 会自动跳过健康运行的服务、只启动退出的服务:
cd /opt/mediacms/stack
docker compose -p mediacms-stack up -d
实测回显:
Container mediacms-stack-db-1 Running
Container mediacms-stack-redis-1 Running
Container mediacms-stack-celery_beat-1 Starting
Container mediacms-stack-db-1 Waiting
Container mediacms-stack-redis-1 Waiting
Container mediacms-stack-celery_beat-1 Started
Container mediacms-stack-db-1 Healthy
Container mediacms-stack-redis-1 Healthy
Container mediacms-stack-migrations-1 Starting
Container mediacms-stack-migrations-1 Started
Container mediacms-stack-celery_worker-1 Starting
Container mediacms-stack-web-1 Starting
Container mediacms-stack-celery_worker-1 Started
Container mediacms-stack-web-1 Started
恢复后验证(容器状态与端口监听,两条都正常即为恢复完成):
docker compose -p mediacms-stack ps --format '{{.Name}}\t{{.Status}}' | grep -E 'web|celery'
ss -ltn | grep 8137
实测回显:
mediacms-stack-celery_beat-1 Up
mediacms-stack-celery_worker-1 Up
mediacms-stack-web-1 Up
LISTEN 0 4096 0.0.0.0:8137 0.0.0.0:*
排障经验:Exited (0) 表示进程正常退出而非崩溃,多因依赖服务未就绪时 supervisord 主动退出;一律先 docker compose up -d 再看日志,不要先删容器重建。若拉起后仍退出,用 docker compose logs --tail=50 <服务名> 定位(常见原因:PostgreSQL 数据目录权限、宿主机磁盘写满)。
10.3 数据备份与恢复
数据库逻辑备份(pg_dump 压缩导出,实测产物 23KB):
docker exec mediacms-stack-db-1 pg_dump -U mediacms -d mediacms | gzip > /opt/mediacms/backup/mediacms_db_$(date +%F).sql.gz
媒体文件备份(tar 打包 media_files 目录,实测产物 899KB):
tar -czf /opt/mediacms/backup/media_files_$(date +%F).tar.gz -C /opt/mediacms/stack/mediacms-src media_files
验证备份产物内容(数据库 dump 头部与媒体文件清单):
zcat /opt/mediacms/backup/mediacms_db_2026-10-29.sql.gz | head -5
tar -tzf /opt/mediacms/backup/media_files_2026-10-29.tar.gz | head -8
实测回显:
--
-- PostgreSQL database dump
--
-- Dumped from database version 17.2
-- Dumped by pg_dump version 17.2
media_files/
media_files/userlogos/
media_files/userlogos/poster_audio.jpg
media_files/hls/
media_files/hls/b37d1bd34fc4497797fd28031c9dcf17/master.m3u8
media_files/hls/b37d1bd34fc4497797fd28031c9dcf17/media-1/segment-0.ts
恢复演练(把备份还原进一套全新部署):先按第四节完成全新部署,然后恢复数据——数据库用 gunzip 后通过 stdin 灌回,媒体文件用 tar 解回原路径:
gunzip -c /opt/mediacms/backup/mediacms_db_2026-10-29.sql.gz | \
docker exec -i mediacms-stack-db-1 psql -U mediacms -d mediacms
tar -xzf /opt/mediacms/backup/media_files_2026-10-29.tar.gz -C /opt/mediacms/stack/mediacms-src/
docker compose -p mediacms-stack restart web celery_worker
恢复后验证媒体记录回到库中(psql 查询媒体表):
docker exec mediacms-stack-db-1 psql -U mediacms -d mediacms \
-c "SELECT friendly_token, title, encoding_status FROM files_media;"
实测回显(恢复演练前库内已有一条实测上传的记录):
friendly_token | title | encoding_status
----------------+----------------------+-----------------
WpOLkLg33 | 转码链路验证测试视频 | success
(1 row)
⚠️ 注意:恢复到全新空库时先执行一次 migrations 初始化(否则表结构不存在),再灌入备份 dump 时加
--clean --if-exists参数到 pg_dump 产物重建对象,或先 drop 再建库;媒体文件属主需与容器内应用用户一致(chown -R 1000:1000 media_files,应用运行用户 UID 为 1000 的 www-data)。
10.4 版本升级
cd /opt/mediacms/stack
docker pull mediacms/mediacms:latest
docker compose -p mediacms-stack down
# 更新 mediacms-src 源码到新版本 tag
git -C mediacms-src fetch --tags && git -C mediacms-src checkout v9.5.0 # 以实际最新 tag 为准
docker compose -p mediacms-stack up -d
docker compose -p mediacms-stack logs migrations | tail -3 # 确认迁移执行成功
⚠️ 注意:升级前务必完成 10.3 的双份备份;跨大版本升级若涉及 PostgreSQL 大版本变更(如 15 → 17),数据目录不兼容,需按官方文档先做 pg 数据迁移,否则数据库无法启动(官方错误样例:
database files are incompatible with server)。
十一、常见问题(FAQ)
Q1:启动后浏览器打不开页面,8137 端口不通?
按顺序检查三处:docker compose ps 看 web 是否 Up;ss -ltn | grep 8137 看端口是否监听;docker compose logs --tail=50 web 看是否有报错。实测最常见的情形是主机重启后 web 处于 Exited (0),重新 docker compose up -d 即恢复(见 10.2 实录)。
Q2:migrations 容器一直重启?
restart: on-failure 会在初始化失败时自动重试。查看日志定位:docker compose logs migrations。实测期见过的两类原因:redis/db 未 healthy 时依赖条件不满足(等待即可);mediacms-src 目录未准备或路径挂错导致 prestart.sh 不存在(核对 4.1 编排 volumes 与 4.2 源码目录)。
Q3:上传视频后一直显示转码中(pending)?
转码由 celery_worker 执行,确认其状态与日志:docker compose ps celery_worker、docker compose logs --tail=100 celery_worker。若 worker 正常但任务不动,检查 Redis 连接(REDIS_LOCATION)与磁盘剩余空间;大视频默认按 4 分钟分块转码再拼接,耗时随时长与分辨率增加属正常。
Q4:API 返回的媒体 URL 主机部分不对(指向 localhost 或旧 IP)?
FRONTEND_HOST 与实际访问地址不一致所致。修改覆盖配置中的 FRONTEND_HOST 后重启 web 与 celery_worker(见第七节),并清浏览器缓存。
Q5:管理员密码忘记了?
方法一:查初始化日志(未自定义密码时):docker compose logs migrations | grep "Created admin"。方法二:重置为已知密码(进入 web 应用目录执行 Django 管理命令):
docker exec -it mediacms-stack-web-1 python manage.py changepassword admin
按提示输入两次新密码,实测回显:
Changing password for user 'admin'
Password:
Password (again):
Password changed successfully for user 'admin'
Q6:想临时关闭转码只播原片(低配服务器)?
在覆盖配置中设 DO_NOT_TRANSCODE_VIDEO = True 并重启应用服务;副作用是雪碧图预览也不再生成(官方文档第 18 节实测确认的行为描述)。
Q7:彻底卸载怎么清理?
cd /opt/mediacms/stack
docker compose -p mediacms-stack down # 停止并删除容器与网络
docker rmi mediacms/mediacms:latest postgres:17.2-alpine redis:alpine # 按需删除镜像
rm -rf /opt/mediacms/stack # 删除编排、源码与全部数据(不可逆,先备份)
down 保留 bind mount 的宿主机数据目录;确认不再需要后手动删除。实测 down 回显(输出节选,实测首尾):
Container mediacms-stack-web-1 Stopped
Container mediacms-stack-celery_worker-1 Stopped
Container mediacms-stack-celery_beat-1 Stopped
Container mediacms-stack-migrations-1 Stopped
Container mediacms-stack-db-1 Stopped
Container mediacms-stack-redis-1 Stopped
Container mediacms-stack-web-1 Removed
Network mediacms-net Removed
十二、参考链接
- 官方 Docker 安装文档:https://github.com/mediacms-io/mediacms/blob/main/docs/admins_docs.md
- 官方仓库与编排文件:https://github.com/mediacms-io/mediacms
- Docker Hub 镜像:https://hub.docker.com/r/mediacms/mediacms
- MediaCMS 9.4.0 发布说明:https://github.com/mediacms-io/mediacms/releases/tag/v9.4.0
- 本站选型分析:《MediaCMS 9.4.0 介绍与选型指南》
- 本站配置手册:《MediaCMS 9.4.0 配置参数详解》
- 本站接口手册:《MediaCMS 9.4.0 REST API 使用详解》