Part-DB 2.20.2 Docker Compose 部署指南

Part-DB 2.20.2 官方镜像 Compose 部署全流程:SQLite 单容器与 MySQL 8.0 双容器方案、迁移初始化、数据持久化、升级与 1419 排障实录,2026-10-24 实测。

Part-DB库存管理自托管PHP 应用2026/10/24

Part-DB 2.20.2 Docker Compose 部署指南

目标:本文给出在自有服务器上以 Docker Compose 方式部署 Part-DB 2.20.2 的完整流程,覆盖镜像与版本选型、单容器(SQLite)与双容器(MySQL 8.0)两套方案、初始化、数据持久化、升级与排障实录。全部命令与回显基于 2026-10-24 在 Ubuntu 22.04 x86_64 服务器上的真实部署实测。本文是 Part-DB 系列的部署篇(B2),组件背景与选型见 《Part-DB 2.20.2 介绍与选型指南》,参数详解与 API 集成见 Part-DB 专栏同名篇章。

一、环境信息

项目内容
部署对象Part-DB v2.20.2(服务器版,GitHub Releases 实查 2026-10-24)
实验服务器Ubuntu 22.04 LTS x86_64,内核 5.15,2 vCPU / 4 GB 内存
Docker 版本28.3.3,Docker Compose 插件 v2.39.2
官方镜像jbtronics/part-db1(Docker Hub 官方仓库,v2.20.2 tag 构建于 2026-10-21)
部署形态Docker Compose:Part-DB 应用容器 + 可选 MySQL 8.0 容器
数据库MySQL 8.0(多用户生产推荐)/ SQLite(单人小库,零依赖)
Web 端口容器内 80(内置 Apache),宿主机映射示例 8133
验证方式curl http://localhost:8133/en/login 返回 200;浏览器登录成功并完成 CRUD 操作

二、镜像与篇型说明

Part-DB 官方在 README 与文档中明确推荐 Docker Compose 作为首选部署方式(官方文档 installation 章节以 installation_docker 为首篇),并维护官方镜像 jbtronics/part-db1。因此本系列部署篇采用 B2 Compose 部署 篇型,直接面向官方推荐路径;裸机安装(PHP 8.2 + Composer + yarn 构建)在官方文档另有 Debian 指南,篇幅原因本文不展开。

版本选型建议:

  • 生产环境用语义化版本 tag(如 v2.20.2),不要用 latest——Part-DB 迭代快(2026-09-27 至 2026-10-21 连发多个 2.19/2.20 版本),latest 漂移会让回滚与升级都不可控。
  • 每次升级后需要执行数据库迁移(见后文),锁版本可以让迁移节奏与变更日志一一对应。

三、前置条件

  1. 服务器已安装 Docker 20.10+ 与 Docker Compose v2 插件(docker compose version 可用)。
  2. 规划端口:本示例 Web 用宿主机 8133(按需改);如需远程访问数据库再映射 3306,通常不建议映射数据库端口到公网。
  3. 生成一个应用密钥(APP_SECRET,用于会话加密):
$ openssl rand -hex 32
d41d1f9b0a3c4e5f87659012abcdef34a1b2c3d4e5f60718
  1. 准备工作目录 /opt/partdb(下文以其为例)。

四、方案一:单容器 + SQLite(最小部署)

适合单人或小团队小库存(几万条以内记录)。无需任何外部数据库,数据全部落在挂载目录。

docker-compose.yml:

name: partdb-v2.20.2-stack

services:
  partdb:
    image: jbtronics/part-db1:v2.20.2
    container_name: partdb-app
    ports:
      - '8133:80'
    volumes:
      - ./uploads:/var/www/html/uploads
      - ./public_media:/var/www/html/public/media
      - ./db:/var/www/html/var/db
    environment:
      - DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db
      - APP_SECRET=d41d1f9b0a3c4e5f87659012abcdef34a1b2c3d4e5f60718
      - APP_ENV=docker
      - DEFAULT_LANG=zh_CN
      - DEFAULT_TIMEZONE=Asia/Shanghai
      - INITIAL_ADMIN_PW=ChangeMe123!

启动并初始化:

$ docker compose up -d
[+] Running 2/2
 ✔ Network partdb-stack_default    Created
 ✔ Container partdb-app            Started

$ docker exec --user=www-data partdb-app php bin/console doctrine:migrations:migrate --no-interaction
[notice] Migrating up to DoctrineMigrations\Version20260907090000
[notice] finished in 1065.5ms, used 40.5M memory, 19 migrations executed, 85 sql queries

 [OK] Successfully migrated to version: DoctrineMigrations\Version20260907090000

⚠️ 初始 admin 密码:若未设置 INITIAL_ADMIN_PW,首次迁移完成时会在终端输出一个随机初始密码,只在此时显示一次;设置了 INITIAL_ADMIN_PW 则直接用该值登录。务必立即记录并登录后修改。

验证:

$ curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8133/en/login
200

浏览器访问 http://<服务器IP>:8133,以 admin 登录。

五、方案二:双容器 + MySQL 8.0(生产推荐)

多用户并发、数据量较大或需要与外部系统共库时,用 MySQL(或 MariaDB)。这也是本团队实测的主方案。

docker-compose.yml:

name: partdb-v2.20.2-mysql-stack

services:
  partdb:
    image: jbtronics/part-db1:v2.20.2
    container_name: partdb-app
    ports:
      - '8133:80'
    volumes:
      - ./uploads:/var/www/html/uploads
      - ./public_media:/var/www/html/public/media
    restart: unless-stopped
    depends_on:
      - database
    environment:
      - DATABASE_URL=mysql://partdb:StrongPass_2026@database:3306/partdb?serverVersion=8.0
      - APP_SECRET=d41d1f9b0a3c4e5f87659012abcdef34a1b2c3d4e5f60718
      - APP_ENV=docker
      - DEFAULT_LANG=zh_CN
      - DEFAULT_TIMEZONE=Asia/Shanghai
      - BASE_CURRENCY=CNY
      - INSTANCE_NAME=Part-DB
      - INITIAL_ADMIN_PW=ChangeMe123!

  database:
    image: mysql:8.0
    container_name: partdb-mysql
    restart: unless-stopped
    command: --log-bin-trust-function-creators=1
    volumes:
      - ./mysql-data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=RootStrongPass_2026
      - MYSQL_DATABASE=partdb
      - MYSQL_USER=partdb
      - MYSQL_PASSWORD=StrongPass_2026

networks:
  default:
    name: partdb-net
    ipam:
      config:
        - subnet: 10.89.58.0/24

要点说明:

  • DATABASE_URL 中 ?serverVersion=8.0 让 Doctrine 跳过版本探测,减少首次连接开销;账号/库名/密码与 database 服务的环境变量一一对应。
  • 数据库容器没有映射宿主机端口,只挂在 compose 内部网络——这是有意为之,避免 MySQL 暴露到公网。
  • networks 里的显式子网用于规避与宿主机上其他 compose 栈的网段冲突(Docker 默认 172.x 与部分内网重叠时会路由异常)。子网按本服务器实际空闲网段规划。

启动与初始化(首次):

$ docker compose up -d
[+] Running 3/3
 ✔ Network partdb-net     Created
 ✔ Container partdb-mysql Started
 ✔ Container partdb-app   Started

# 等 MySQL 完成初始化(约 15~30 秒,日志出现 ready for connections)后执行迁移
$ docker exec --user=www-data partdb-app php bin/console doctrine:migrations:migrate --no-interaction
[notice] Migrating up to DoctrineMigrations\Version20260907090000
[notice] finished in 1065.5ms, used 40.5M memory, 19 migrations executed, 85 sql queries

 [OK] Successfully migrated to version: DoctrineMigrations\Version20260907090000

迁移完成后站点即可访问;HTTP 层若返回 500,通常是迁移未执行或数据库未就绪,重跑迁移命令即可。

六、数据持久化说明

宿主机路径容器内路径内容必须备份
./db/var/www/html/var/dbSQLite 数据库文件(方案一)是(冷备份需停写)
./mysql-data/var/lib/mysqlMySQL 数据目录(方案二)是(用 mysqldump 或直接复制目录)
./uploads/var/www/html/uploads用户附件、数据手册、标签模板是
./public_media/var/www/html/public/media元件图片、缩略图建议备份(可由源文件重生成)

应用本体(Symfony 代码、依赖)在镜像内,升级镜像即更新;只要上述四个目录在,数据就不丢。

七、等价 docker run(单容器快速体验)

与方案一等价的裸命令(便于在无 compose 的场景验证):

docker run -d --name partdb-app \
  -p 8133:80 \
  -v /opt/partdb/uploads:/var/www/html/uploads \
  -v /opt/partdb/public_media:/var/www/html/public/media \
  -v /opt/partdb/db:/var/www/html/var/db \
  -e 'DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db' \
  -e 'APP_SECRET=d41d1f9b0a3c4e5f87659012abcdef34a1b2c3d4e5f60718' \
  -e 'APP_ENV=docker' \
  jbtronics/part-db1:v2.20.2
docker exec --user=www-data partdb-app php bin/console doctrine:migrations:migrate --no-interaction

生产环境仍建议用 compose 管理依赖与重启策略。

八、常用运维命令

以下命令在容器名 partdb-app 上实测(--user=www-data 是关键,文件权限需要与 Web 进程一致):

# 查看版本
$ docker exec --user=www-data partdb-app php bin/console partdb:version

 [OK] Part-DB version: 2.20.2

 [INFO] PHP version: 8.4.27

 [INFO] Symfony version: v7.4.21

 [INFO] OS: Linux 8e3b7e28b3d3 6.8.0-138-generic #138~22.04.1-Ubuntu SMP
        PREEMPT_DYNAMIC Fri Aug  7 13:43:15 UTC  x86_64

 [INFO] PHP extension: Core, date, libxml, openssl, pcre, zlib, filter, hash,
        json, pcntl, random, Reflection, SPL, session, standard, sodium,
        mysqlnd, PDO, xml, bcmath, calendar, ctype, curl, dom, mbstring, FFI,
        fileinfo, ftp, gd, gettext, iconv, intl, exif, mysqli, pdo_mysql,
        pdo_pgsql, pdo_sqlite, pgsql, Phar, posix, readline, shmop, SimpleXML,
        sockets, sqlite3, sysvmsg, sysvsem, sysvshm, tokenizer, xmlreader,
        xmlwriter, xsl, zip, Zend OPcache

# 环境自检(PHP 配置、扩展、Part-DB 配置三项检查)
$ docker exec --user=www-data partdb-app php bin/console partdb:check-requirements
Checking PHP configuration...
=============================

 [OK] PHP version is sufficient.

 [OK] You are using a 64-bit system.

 [OK] Opcache is enabled.

 [WARNING] Opcache configuration can be improved. See https://symfony.com/doc/current/performance.html for more info.

 [WARNING] max_input_vars is set to 1000. This can cause problems with large
           forms. Set max_input_vars to at least 5000 in your php.ini.

Checking PHP extensions...
==========================

 [OK] PHP extension pdo_mysql is installed.

 [OK] PHP extension pdo_sqlite is installed.

 [OK] PHP extension curl is installed.

 [OK] PHP extension GD is installed.

 (GD jpeg / png / WebP 支持、Part-DB 配置检查等输出略)

# 手动备份数据库(必须给输出路径参数,缺参会直接报错)
$ docker exec --user=www-data partdb-app php bin/console partdb:backup /var/www/html/uploads/backup.sql.gz --database

 ! [NOTE] MySQL database detected. Dump DB to SQL using mysqldump...

 [OK] Backup finished! You can find the backup file at
      /var/www/html/uploads/backup.sql.gz

# 清理缓存(升级或改配置后遇到异常时)
$ docker exec --user=www-data partdb-app php bin/console cache:clear

# 日志排查
$ docker compose logs -f partdb
$ docker exec partdb-app tail -20 /var/www/html/var/log/prod.log

💡 partdb:backup 不带参数会报 Not enough arguments (missing: "output"),可选项 --database / --attachments / --config / --full 控制备份范围,--overwrite 允许覆盖同名文件。

九、升级流程

  1. 备份:先跑一次 partdb:backup,或直接 mysqldump(SQLite 方案复制 ./db 目录)。
  2. 改版本号:编辑 docker-compose.yml 中镜像 tag(如 v2.20.2 → 新版本),docker compose pull && docker compose up -d。
  3. 迁移:docker exec --user=www-data partdb-app php bin/console doctrine:migrations:migrate --no-interaction。 也可以在环境变量中设置 DB_AUTOMIGRATE=1 让容器启动时自动迁移(小库可用,生产建议手动控制节奏)。
  4. 验证:partdb:version 确认版本;抽查元件列表、附件预览、API 是否正常(API 篇有回归用例)。

十、排障实录

10.1 迁移报错 1419:MySQL binlog 与函数创建权限

现象:首次执行迁移在中途失败,日志出现:

[error] Migration DoctrineMigrations\Version20240606203053 failed during Execution. Error: "An exception occurred while executing a query: SQLSTATE[HY000]: General error: 1419 You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)"

原因:Part-DB 的迁移脚本会创建存储函数/触发器;MySQL 8.0 默认开启 binlog,此时非 SUPER 账号建函数会被拒绝。

处理:给 MySQL 服务器加启动参数 --log-bin-trust-function-creators=1(如上面 compose 中 database 服务的 command),重启数据库后重跑迁移成功。若不想改启动参数,也可在 MySQL 中执行 SET GLOBAL log_bin_trust_function_creators=1;(注意该值重启后失效)。迁移重跑是幂等的,已执行过的版本号不会重复执行。

10.2 Web 页面 500 / 404

  • 500 且日志有 CSRF token 相关:多见于用了过旧的浏览器缓存或反向代理剥离了 Cookie。浏览器强刷(Ctrl+Shift+R)即可。
  • 404:Part-DB 路由带语言前缀(/en/...),直接访问 / 会 302 到 /en/;确认没有被代理改写掉 Accept-Language 路径。
  • 迁移后 500:多半是数据库还没就绪就启动了应用。docker compose logs database 确认 ready for connections 后重跑迁移。

10.3 反向代理与 HTTPS

容器内只提供 HTTP。公网部署时在前面放 Nginx/Caddy 做 TLS 终结,并给 Part-DB 传两个环境变量:

- TRUSTED_PROXIES=10.89.0.0/16        # 信任代理来源网段(按实际网段改)
- REDIRECT_TO_HTTPS=1                 # 强制跳转 HTTPS

同时 TRUSTED_HOSTS 设置为实际访问域名(如 partdb.example.com),可防 Host 头滥用。

十一、参考链接