VoucherVault 1.30.3 Docker Compose 部署指南

用 Docker Compose 部署 VoucherVault v1.30.3 的完整实录:compose 文件解析、数据卷权限、启动日志取证(含自动生成的管理员密码)、HTTP 验证、Nginx 反代接入与排障。

VoucherVaultVoucherVaultDocker优惠券管理2026/10/25

VoucherVault 1.30.3 Docker Compose 部署指南

目标:用 Docker Compose 快速拉起 VoucherVault v1.30.3 的全功能栈(应用 + Redis),涵盖最小可用 SQLite 版 Compose 文件、目录权限修正、启动日志取证、功能验证与排障。已具备 Docker 环境的读者,优先使用本方案;裸机安装请见《Ubuntu 22.04 安装 VoucherVault 指南》。VoucherVault 介绍与选型请读《VoucherVault 介绍与选型指南》。

一、环境信息

项目值
软件版本VoucherVault v1.30.3
Docker Engine27.x+(测试环境 v27.3.1)
Docker Composev5.6.1
应用镜像l4rm4nd/vouchervault:1.30.x(约 1.26GB,内置 Python 3.12.13 + Django 5.2.18)
Redis 镜像redis:7-alpine(约 57.8MB)
端口宿主机 8130:8000(按需修改)
自定义网络10.89.61.0/24,隔离 Redis 与 App 通信
数据持久化./volume-data/database → 容器内 /opt/app/database
运行时用户www-data(UID 33,镜像内已预置)
首次管理员密码自动生成并打印到容器日志(实测见后文)

二、目录结构与前置准备

创建工作目录并建立数据卷文件夹:

mkdir -p /opt/data/quzuo/tmp/vouchervault/compose/volume-data/database

⚠️ 关键:数据卷需要把属主设为容器内运行用户 UID 33,否则容器启动时会报权限不足并退出:

chown -R 33:33 /opt/data/quzuo/tmp/vouchervault/compose/volume-data/database

验证 UID 33 存在(Ubuntu/Debian 默认已有 www-data):

id -nu 33
www-data

三、Compose 文件

基于官方 docker-compose-sqlite.yml 改写:显式自定义网络、指定宿主机端口 8130,并把 DOMAIN 指向测试地址(按需改为生产域名)。文件存为 docker-compose.yml:

name: vouchervault-1.30.3-stack

services:

  app:
    image: l4rm4nd/vouchervault:1.30.x
    container_name: vouchervault-app
    restart: unless-stopped
    environment:
      - DOMAIN=127.0.0.1
      - PORT=8130
      - SECURE_COOKIES=False
      - EXPIRY_THRESHOLD_DAYS=30
      - TZ=Asia/Shanghai
    ports:
      - 8130:8000
    volumes:
      - ./volume-data/database:/opt/app/database
    networks:
      - vouchervault-net

  redis:
    image: redis:7-alpine
    container_name: vouchervault-redis
    restart: unless-stopped
    expose:
      - 6379
    networks:
      - vouchervault-net

networks:
  vouchervault-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.61.0/24

要点说明:

  • name: vouchervault-1.30.3-stack:显式项目名,避免默认取目录名导致不同组件互相冲突;
  • DOMAIN 与 PORT 共同决定 ALLOWED_HOSTS 和 CSRF_TRUSTED_ORIGINS,如果最终通过反向代理访问,需改成实际域名和 443;
  • expose 只暴露给内部网络,不会映射到宿主机,减少攻击面;
  • Redis 无持久化卷要求(仅作 Celery 消息队列中间件),状态由 App 落 SQLite/PostgreSQL。

四、启动栈

拉取镜像并启动:

docker compose pull
docker compose up -d
Container vouchervault-redis Creating
Container vouchervault-app Creating
Container vouchervault-app Created
Container vouchervault-redis Created
Container vouchervault-app Starting
Container vouchervault-redis Starting
Container vouchervault-app Started
Container vouchervault-redis Started

检查容器状态:

docker compose ps
NAME                 IMAGE                         COMMAND                  SERVICE   CREATED          STATUS         PORTS
vouchervault-app     l4rm4nd/vouchervault:1.30.x   "/opt/app/docker/ent…"   app       10 seconds ago   Up 8 seconds   0.0.0.0:8130->8000/tcp, [::]:8130->8000/tcp
vouchervault-redis   redis:7-alpine                "docker-entrypoint.s…"   redis     10 seconds ago   Up 8 seconds   6379/tcp

五、查看启动日志并获取管理员密码

首次启动(数据库不存在时),容器会自动执行数据库迁移、创建默认周期任务和 admin 超级用户,并把随机密码打印到日志。务必第一时间记录密码:

docker compose logs app
vouchervault-app  | [TASK] Validating volume permissions
vouchervault-app  | [DONE] Permissions ok. Container can read and write database.
vouchervault-app  | [TASK] Migrating changes to the database
vouchervault-app  |   Applying contenttypes.0001_initial... OK
vouchervault-app  |   Applying auth.0001_initial... OK
vouchervault-app  |   Applying contenttypes.0002_remove_content_type_name... OK
vouchervault-app  |   Applying auth.0002_alter_permission_name_max_length... OK
vouchervault-app  |   Applying auth.0003_alter_user_email_max_length... OK
vouchervault-app  |   Applying auth.0004_alter_user_username_opts... OK
vouchervault-app  |   Applying auth.0005_alter_user_last_login_null... OK
vouchervault-app  |   Applying auth.0006_require_contenttypes_0002... OK
vouchervault-app  |   Applying auth.0007_alter_validators_add_error_messages... OK
vouchervault-app  |   Applying auth.0008_alter_user_username_max_length... OK
vouchervault-app  |   Applying auth.0009_alter_user_last_name_max_length... OK
...
vouchervault-app  | [TASK] Creating superuser account
vouchervault-app  | 18 objects imported automatically (use -v 2 for details).
vouchervault-app  |
vouchervault-app  | [>] username: admin
vouchervault-app  | [>] password: yi1RaS95a3Lt581Ogr9E
vouchervault-app  | -------------------------------------------------
vouchervault-app  | [TASK] Starting Celery worker and beat
vouchervault-app  | [TASK] Spawning the application server
vouchervault-app  | [uWSGI] getting INI configuration from docker/docker_uwsgi.ini
vouchervault-app  | [uwsgi-static] added mapping for /static => /opt/app/myapp/static/
vouchervault-app  | *** Operational MODE: preforking+threaded ***
vouchervault-app  | WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x7b2030a15390 pid: 1 (default app)
vouchervault-app  | *** uWSGI is running in multiple interpreter mode ***
vouchervault-app  | spawned uWSGI master process (pid: 1)
vouchervault-app  | spawned uWSGI worker 1 (pid: 26, cores: 2)
vouchervault-app  | spawned uWSGI worker 2 (pid: 27, cores: 2)
  • 默认超级用户名固定为 admin,密码是 20 位随机串(每栈初始化一次)。如需重置,进入容器用 Django shell 改;
  • uWSGI 进程 PID 为 1,说明在主容器进程位上,直接受 Docker 重启策略管理;
  • 若第二次启动时数据库已存在,日志会打印 [INFO] SQLite3 database found. Skipping initialization.,跳过初始化,不影响已有数据。

六、功能验证

从宿主机访问栈暴露的 8130 端口:

curl -s -o /dev/null -w 'GET / -> %{http_code} redirect=%{redirect_url}\n' http://127.0.0.1:8130/
GET / -> 302 redirect=http://127.0.0.1:8130/en/

登录页返回 200:

curl -s -o /dev/null -w 'GET /en/accounts/login/ -> %{http_code}\n' http://127.0.0.1:8130/en/accounts/login/
GET /en/accounts/login/ -> 200

使用日志中的密码模拟登录:

curl -s -c /tmp/cj http://127.0.0.1:8130/en/accounts/login/ \
  | grep -o 'csrfmiddlewaretoken" value="[^"]*' \
  | head -1 | cut -d'"' -f3 > /tmp/token
curl -s -b /tmp/cj -c /tmp/cj -o /dev/null -w 'POST login -> %{http_code} redirect=%{redirect_url}\n' \
  --data-urlencode "csrfmiddlewaretoken=$(cat /tmp/token)" \
  --data-urlencode "username=admin" \
  --data-urlencode "password=yi1RaS95a3Lt581Ogr9E" \
  http://127.0.0.1:8130/en/accounts/login/
POST login -> 302 redirect=http://127.0.0.1:8130/

302 到首页即登录成功,栈已可用。

七、网络与容器内通信

自定义桥接网络避免了容器间通过宿主机 IP 通信的问题:

docker network ls | grep vouchervault
docker network inspect vouchervault-1303-stack_vouchervault-net --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
10.89.61.0/24

注:项目名中的点号 . 在 Compose 生成网络名时会被移除,因此实际网络名称为 vouchervault-1303-stack_vouchervault-net,不影响功能。

容器内 App 通过服务名 redis 即可解析到 Redis:

docker compose exec app sh -c "nc -z redis 6379 && echo 'redis reachable'"
redis reachable

八、Nginx 反向代理(生产接入)

仅暴露容器端口到宿主机并不安全,生产环境建议用宿主机 Nginx 做 TLS 终止,再透传至容器。最小配置示例:

server {
    listen 443 ssl http2;
    server_name vouchervault.example.com;

    ssl_certificate     /etc/nginx/ssl/vouchervault.crt;
    ssl_certificate_key /etc/nginx/ssl/vouchervault.key;

    client_max_body_size 20M;

    location / {
        proxy_pass http://127.0.0.1:8130;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

同步修改 Compose 中的环境变量:

      - DOMAIN=vouchervault.example.com
      - SECURE_COOKIES=True

然后重刷栈:

docker compose down
docker compose up -d

九、常用运维操作

# 查看日志(实时)
docker compose logs -f app

# 进入容器执行 Django 命令
docker compose exec app python manage.py shell

# 停止栈(保留数据卷)
docker compose down

# 彻底清理(含数据卷,慎用)
docker compose down -v

# 重启应用
docker compose restart app

十、排障实录

1. 容器启动即退出,日志报 [FAIL] Insufficient permissions on bind mount volume

原因:宿主机数据目录属主不是 UID 33。解法:执行 chown -R 33:33 volume-data/database 后重新 up -d。

2. 首次启动后忘记管理员密码

进入容器重置:

docker compose exec app python manage.py shell -c \
  "from django.contrib.auth.models import User; u=User.objects.get(username='admin'); u.set_password('q1w2e3r4'); u.save()"

3. 修改 DOMAIN 或环境变量后未生效

VoucherVault 在容器启动时把 .env 读入 Python 进程,修改 Compose 环境变量后需要 docker compose up -d --force-recreate app。

4. 周期任务不触发

Compose 内 Celery Beat 已在官方 entrypoint.sh 中自动启动,无需手动干预;如果 beat 未启动,检查 vouchervault-redis 是否已就绪,然后 docker compose restart app。

十一、参考链接