InvenTree 1.6.1 Docker Compose 部署指南
InvenTree 1.6.1 官方五服务栈(PostgreSQL 17 + Redis 7 + Caddy)Compose 生产部署实测:镜像选型、数据持久化、初始化、销毁重建恢复闭环与排障实录。
InvenTree 1.6.1 Docker Compose 部署指南
目标:使用官方生产形态(
inventree/inventree:1.6.1+ PostgreSQL 17 + Redis 7 + Caddy 反代 + django-q2 工作进程,五服务栈)以 Docker Compose 从零部署 InvenTree,覆盖镜像选型、数据持久化、初始化、销毁重建恢复闭环、升级与排障。全部命令与回显在 Ubuntu 22.04(x86_64,内核 6.8.0-138-generic)实测通过,实测时点 2026-10-23;官方 compose 基线取自仓库 1.6.1 tag 的contrib/container/docker-compose.yml。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64)
- 内核:6.8.0-138-generic
- Docker Engine:29.8.1;Docker Compose:v5.5.1(
docker composev2 子命令形态) - InvenTree 版本:1.6.1(2026-10-21 发布,官方最新稳定版,版本核实见 《InvenTree 1.6.1 介绍与选型指南》)
- 部署目录:
/opt/inventree(compose 项目文件与.env所在目录) - 数据目录:
/opt/inventree/data(PostgreSQL 数据、静态/媒体文件、备份、Redis、Caddy 状态全部在内) - Web 端口:宿主机 8146(Caddy HTTP 发布端口)
- compose 项目名:
inventree-161-stack(显式声明,避免与其他 compose 项目同名冲突) - 栈内网络:
inventree-161-stack_net,显式网段10.89.68.0/24
二、镜像选型说明
2.1 官方五服务栈
InvenTree 官方生产 compose(1.6.1 tag 的 contrib/container/docker-compose.yml)定义了五个服务,本指南完全沿用该形态:
| 服务 | 镜像 | 角色 | 实测镜像 ID / 体积(docker compose images) |
|---|---|---|---|
| inventree-db | postgres:17 | PostgreSQL 数据库 | b8faeff77126 / 640MB |
| inventree-cache | redis:7-alpine | 缓存(官方显式关闭磁盘持久化,仅作缓存) | 57e4255cc971 / 57.3MB |
| inventree-server | inventree/inventree:1.6.1 | gunicorn Web 服务(API + 前端页面) | 7c1e251a6c52 / 2.07GB |
| inventree-worker | inventree/inventree:1.6.1 | django-q2 后台任务工作进程(invoke worker) | 7c1e251a6c52 / 2.07GB |
| inventree-proxy | caddy:alpine | 反向代理 + 静态/媒体文件分发 + TLS | eb4d35b7452d / 92.8MB |
选型解读:
- inventree/inventree 是官方镜像(Docker Hub 官方账号 inventree),标签策略为
stable(最新稳定版)/latest(开发版)/具体版本号;生产锁定具体版本号1.6.1,避免stable浮动升级。 - server 与 worker 共用同一镜像:worker 只是启动命令不同(
command: invoke worker),保证两个进程版本严格一致。 - Redis 在官方 1.6.1 栈中定位是「缓存管理器」,compose 注释明确说明其缓存数据属临时性(
--save "" --appendonly no),不承担持久化职责——真正的状态全在 PostgreSQL 与数据卷里。 - Caddy 承担静态文件(
/static/)与媒体文件(/media/)的直接分发(媒体文件默认强制Content-Disposition: attachment下载并经 Django 鉴权),这是官方栈把「应用进程」与「文件服务」分离的设计。
2.2 版本锁定方式
版本号由 .env 的 INVENTREE_TAG 控制,compose 中引用为 image: inventree/inventree:${INVENTREE_TAG:-stable}。本指南锁定 INVENTREE_TAG=1.6.1;升级时只改这个值(见第十章)。
三、前置条件
- 服务器已安装 Docker Engine 与 Docker Compose v2:
docker --version && docker compose version
Docker version 29.8.1, build 4a63305
Docker Compose version v5.5.1
- 端口未占用(本指南用 8146;如用默认 80/443 则跳过):
ss -ltn | grep 8146 || echo "port 8146 free"
port 8146 free
- 磁盘余量:四个镜像压缩拉取约 1.4GB、解压后约 2.9GB,加上数据库初始化与媒体文件,预留 8GB 以上。
- 可访问 Docker Hub(离线环境可先在联网机器
docker pull+docker save迁入)。
四、部署步骤
4.1 创建部署与数据目录
sudo mkdir -p /opt/inventree/data
sudo chmod 777 /opt/inventree/data # 首次启动由栈内进程写入,先放开权限
cd /opt/inventree
⚠️ 注意:
INVENTREE_EXT_VOLUME指向的目录会被 PostgreSQL(容器内 UID 999)、InvenTree、Caddy 多方写入。首次启动前放开权限是最省事的做法,初始化完成后可按ls -l结果收敛属主。
4.2 编写 .env
在 /opt/inventree 下创建 .env(变量集与官方 contrib/container/.env 模板一致,按本机实际调整):
sudo tee /opt/inventree/.env > /dev/null <<'EOF'
# compose 项目名(compose 文件内已显式 name,此处同步声明)
COMPOSE_PROJECT_NAME=inventree-161-stack
# InvenTree 版本标签(生产锁定具体版本号)
INVENTREE_TAG=1.6.1
# 站点对外访问地址(含端口,与用户实际访问 URL 一致)
INVENTREE_SITE_URL="http://192.168.146.128:8146"
# InvenTree 服务在栈内监听端口(官方默认 8000,不建议修改)
INVENTREE_WEB_PORT=8000
# Caddy 反代发布端口(宿主机与栈内一致,见第十一章排障说明)
INVENTREE_HTTP_PORT=8146
# 反代转发头
INVENTREE_USE_X_FORWARDED_HOST=True
INVENTREE_USE_X_FORWARDED_PORT=True
INVENTREE_USE_X_FORWARDED_PROTO=True
# 外部数据卷路径
INVENTREE_EXT_VOLUME=/opt/inventree/data
# 日志级别
INVENTREE_LOG_LEVEL=WARNING
# 启用插件
INVENTREE_PLUGINS_ENABLED=True
# 自动执行数据库迁移(不取代手动 invoke update)
INVENTREE_AUTO_UPDATE=True
# 首次启动自动创建管理员账号
INVENTREE_ADMIN_USER=admin
INVENTREE_ADMIN_EMAIL=admin@localhost
INVENTREE_ADMIN_PASSWORD=q1w2e3r4
# PostgreSQL 连接(指向栈内服务名 inventree-db)
INVENTREE_DB_ENGINE=postgresql
INVENTREE_DB_NAME=inventree
INVENTREE_DB_HOST=inventree-db
INVENTREE_DB_PORT=5432
INVENTREE_DB_USER=pguser
INVENTREE_DB_PASSWORD=q1w2e3r4
# Redis 缓存(指向栈内服务名 inventree-cache)
INVENTREE_CACHE_ENABLED=True
INVENTREE_CACHE_HOST=inventree-cache
INVENTREE_CACHE_PORT=6379
# gunicorn
INVENTREE_GUNICORN_TIMEOUT=90
EOF
关键项说明:
INVENTREE_SITE_URL:写用户实际访问的完整 URL(含端口)。它同时决定 Django 的CSRF_TRUSTED_ORIGINS(源码settings.py:if SITE_URL and SITE_URL not in CSRF_TRUSTED_ORIGINS: CSRF_TRUSTED_ORIGINS.append(SITE_URL),1.6.1 tag 实读)与 Caddy 的站点监听地址。INVENTREE_DB_*:数据库凭据不是 InvenTree 登录账号,它们是 PostgreSQL 的连接凭据(官方 .env 注释原文)。演示环境用pguser/q1w2e3r4,生产请换成强口令。INVENTREE_ADMIN_*:三项齐全时首次启动自动创建超级管理员;缺任一项则不创建(源码apps.py校验INVENTREE_ADMIN_USER/INVENTREE_ADMIN_EMAIL/INVENTREE_ADMIN_PASSWORD三项齐备,1.6.1 tag 实读)。INVENTREE_AUTO_UPDATE=True:启动时自动跑数据库迁移;官方注释说明它不取代手动invoke update(静态文件收集、包安装等仍由 update 流程覆盖)。
4.3 编写 docker-compose.yml
以官方 contrib/container/docker-compose.yml(1.6.1 tag)为基线,做两处显式化调整:顶部声明项目名、末尾声明网络与网段。完整文件如下(官方文件本身注释丰富,此处保留服务定义主体):
sudo tee /opt/inventree/docker-compose.yml > /dev/null <<'EOF'
name: inventree-161-stack
services:
inventree-db:
image: postgres:17
container_name: inventree-db
expose:
- ${INVENTREE_DB_PORT:-5432}/tcp
environment:
- PGDATA=/var/lib/postgresql/data/pgdb
- POSTGRES_USER=${INVENTREE_DB_USER:?You must provide the 'INVENTREE_DB_USER' variable in the .env file}
- POSTGRES_PASSWORD=${INVENTREE_DB_PASSWORD:?You must provide the 'INVENTREE_DB_PASSWORD' variable in the .env file}
- POSTGRES_DB=${INVENTREE_DB_NAME:?You must provide the 'INVENTREE_DB_NAME' variable in the .env file}
volumes:
- ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/var/lib/postgresql/data/:z
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U "$${POSTGRES_USER}" -d "$${POSTGRES_DB}"']
interval: 15s
timeout: 5s
retries: 10
start_period: 20s
restart: unless-stopped
inventree-cache:
image: redis:7-alpine
container_name: inventree-cache
command: redis-server --save "" --appendonly no
env_file:
- .env
expose:
- ${INVENTREE_CACHE_PORT:-6379}
volumes:
- ${INVENTREE_EXT_VOLUME}/redis:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 15s
timeout: 5s
retries: 10
start_period: 10s
restart: always
inventree-server:
image: inventree/inventree:${INVENTREE_TAG:-stable}
container_name: inventree-server
expose:
- ${INVENTREE_WEB_PORT:-8000}
depends_on:
inventree-db:
condition: service_healthy
inventree-cache:
condition: service_healthy
env_file:
- .env
environment:
INVENTREE_SERVER: http://inventree-server:${INVENTREE_WEB_PORT}
volumes:
- ${INVENTREE_EXT_VOLUME}:/home/inventree/data:z
healthcheck:
test:
[
'CMD-SHELL',
'invoke server-health --address "http://localhost:$${INVENTREE_WEB_PORT:-8000}"',
]
interval: 20s
timeout: 5s
retries: 10
start_period: 60s
restart: unless-stopped
inventree-worker:
image: inventree/inventree:${INVENTREE_TAG:-stable}
container_name: inventree-worker
command: invoke worker
depends_on:
inventree-server:
condition: service_healthy
env_file:
- .env
volumes:
- ${INVENTREE_EXT_VOLUME}:/home/inventree/data:z
healthcheck:
test: ['CMD-SHELL', 'invoke worker-health']
interval: 60s
timeout: 10s
retries: 3
start_period: 180s
restart: unless-stopped
inventree-proxy:
container_name: inventree-proxy
image: caddy:alpine
restart: always
depends_on:
inventree-server:
condition: service_healthy
inventree-worker:
condition: service_healthy
ports:
- ${INVENTREE_HTTP_PORT:-80}:${INVENTREE_HTTP_PORT:-80}
env_file:
- .env
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://127.0.0.1:9090/api/system/health/']
interval: 20s
timeout: 5s
retries: 10
start_period: 20s
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro,z
- ${INVENTREE_EXT_VOLUME}/static:/var/www/static:z
- ${INVENTREE_EXT_VOLUME}/media:/var/www/media:z
- ${INVENTREE_EXT_VOLUME}:/var/log:z
- ${INVENTREE_EXT_VOLUME}:/data:z
- ${INVENTREE_EXT_VOLUME}:/config:z
networks:
default:
name: inventree-161-stack_net
ipam:
config:
- subnet: 10.89.68.0/24
EOF
与官方原文件的差异(仅两处,其余逐行一致):
| 调整点 | 官方原样 | 本指南 | 原因 |
|---|---|---|---|
| 项目名 | 未声明(默认取目录名) | 顶部 name: inventree-161-stack | 多套栈共存时防止同名项目互删(down 只作用于本项目) |
| 端口映射 | ${INVENTREE_HTTP_PORT:-80}:80 与 ${INVENTREE_HTTPS_PORT:-443}:443 | ${INVENTREE_HTTP_PORT:-80}:${INVENTREE_HTTP_PORT:-80}(单端口) | INVENTREE_SITE_URL 含端口时 Caddy 在栈内监听同号端口而非 80(官方 Caddyfile 站点地址直接取 INVENTREE_SITE_URL),发布映射必须对齐,详见第十一章排障实录 |
| 网段 | 未显式声明 | 10.89.68.0/24 | 与服务器上其他 compose 网络显式隔离,避免网段冲突 |
4.4 获取 Caddyfile
官方栈用 ./Caddyfile 相对挂载,需把它与 compose 文件放在一起。两种方式任选:
# 方式一:从官方仓库 1.6.1 tag 下载(联网服务器)
sudo wget -O /opt/inventree/Caddyfile https://raw.githubusercontent.com/inventree/InvenTree/1.6.1/contrib/container/Caddyfile
# 方式二:从本机已克隆的源码复制
sudo cp contrib/container/Caddyfile /opt/inventree/Caddyfile
Caddyfile 的职责(官方文件实读):/static/、/media/ 由 Caddy 直接分发(媒体强制 attachment 下载 + 经 Django /auth/ 鉴权),其余请求反代到 inventree-server:8000;另有内部 :9090 健康检查口。
4.5 首次启动
cd /opt/inventree && docker compose up -d
首次启动会依次拉取四个镜像、按依赖顺序拉起服务(输出节选,实测):
Image postgres:17 Pulling
Image redis:7-alpine Pulling
Image inventree/inventree:1.6.1 Pulling
Image caddy:alpine Pulling
Image redis:7-alpine Pulled
Image postgres:17 Pulled
Image inventree/inventree:1.6.1 Pulled
Image caddy:alpine Pulled
Network inventree-161-stack_net Creating
Network inventree-161-stack_net Created
Container inventree-db Created
Container inventree-cache Created
Container inventree-server Created
Container inventree-worker Created
Container inventree-proxy Created
Container inventree-cache Starting
Container inventree-db Starting
Container inventree-cache Started
Container inventree-db Started
Container inventree-db Waiting
Container inventree-cache Waiting
Container inventree-cache Healthy
Container inventree-db Healthy
Container inventree-server Starting
Container inventree-server Started
Container inventree-server Waiting
Container inventree-server Healthy
Container inventree-worker Starting
Container inventree-worker Started
Container inventree-worker Waiting
Container inventree-server Waiting
Container inventree-server Healthy
Container inventree-worker Healthy
Container inventree-proxy Starting
Container inventree-proxy Started
启动顺序由 healthcheck 强约束:db/cache 健康 → server 启动(执行首次初始化)→ server 健康 → worker 启动 → proxy 启动。首次初始化包含 281 条数据库迁移(docker compose logs inventree-server | grep -c Applying 实测 281)、config.yaml 模板复制、静态文件目录创建,约 1~2 分钟。
server 首启日志开头(实测节选):
inventree-server | Creating directory /home/inventree/data/static
inventree-server | Creating directory /home/inventree/data/media
inventree-server | Creating directory /home/inventree/data/backup
inventree-server | Copying config file from /home/inventree/src/backend/InvenTree/config_template.yml to /home/inventree/data/config.yaml
inventree-server | INVE-W3: Could not detect git information.
inventree-server | 2026-10-23 09:24:34,985 WARNING Plugin configuration file does not exist - creating default file
4.6 状态确认与访问验证
cd /opt/inventree && docker compose ps
NAME SERVICE STATUS
inventree-cache inventree-cache Up 2 minutes (healthy)
inventree-db inventree-db Up 2 minutes (healthy)
inventree-proxy inventree-proxy Up About a minute (healthy)
inventree-server inventree-server Up 2 minutes (healthy)
inventree-worker inventree-worker Up About a minute (healthy)
五个服务全部 healthy 后,逐层验证:
curl -s http://192.168.146.128:8146/api/system/health/
{"status": "ok"}
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.146.128:8146/
302
- 健康接口返回
{"status": "ok"};首页 302 跳转到前端入口。 - 浏览器打开
http://192.168.146.128:8146即进入 InvenTree 界面,用.env里配置的admin/q1w2e3r4登录。
验证管理员账号确实已自动创建(Basic 认证实测):
curl -s -u admin:q1w2e3r4 http://192.168.146.128:8146/api/user/me/ | head -c 120
{"pk":1,"username":"admin","first_name":"","last_name":"","email":"admin@localhost","groups":[],"is_staff":true,"is_supe
五、数据持久化说明
5.1 持久化设计
全部状态都落在 INVENTREE_EXT_VOLUME 指向的宿主机目录 /opt/inventree/data,五个服务的数据卷映射:
| 服务 | 栈内路径 | 宿主机路径 | 内容 |
|---|---|---|---|
| inventree-db | /var/lib/postgresql/data/ | /opt/inventree/data/pgdb/ | PostgreSQL 全部数据(PGDATA 指向 pgdb/ 子目录) |
| inventree-server / worker | /home/inventree/data | /opt/inventree/data | 配置、静态/媒体文件、备份、插件清单 |
| inventree-proxy | /var/www/static、/var/www/media、/var/log、/data、/config | 同上各子目录 | 静态文件分发、媒体分发、Caddy 日志与状态 |
5.2 数据目录清单(部署并初始化后实测)
ls -la /opt/inventree/data
total 60
drwxrwxrwx 9 root root 4096 Oct 23 22:25 .
drwxr-xr-x 5 root root 4096 Oct 23 22:36 ..
drwxr-xr-x 2 root root 4096 Oct 23 22:24 backup
drwx------ 3 root root 4096 Oct 23 22:25 caddy
-rw-r--r-- 1 root root 10201 Oct 23 22:24 config.yaml
drwxr-xr-x 3 root root 4096 Oct 23 22:25 media
-rw-r--r-- 1 root root 3243 Oct 23 22:24 oidc.pem
drwx------ 19 999 root 4096 Oct 23 22:30 pgdb
drwxr-xr-x 3 root root 4096 Oct 23 22:24 plugins
-rw-r--r-- 1 root root 53 Oct 23 22:24 plugins.txt
drwxr-xr-x 2 999 root 4096 Oct 23 22:24 redis
-rw-r--r-- 1 root root 50 Oct 23 22:24 secret_key.txt
drwxr-xr-x 2 root root 4096 Oct 23 22:24 static
du -sh /opt/inventree/data/* 2>/dev/null
4.0K backup
32K caddy
12K config.yaml
88K media
4.0K oidc.pem
71M pgdb
16K plugins
4.0K plugins.txt
4.0K redis
4.0K secret_key.txt
4.0K static
关键文件/目录解读:
pgdb/:PostgreSQL 数据目录(属主 UID 999),整个系统最核心的数据。config.yaml:首次启动由镜像内模板自动复制生成(见 4.5 节日志),是 InvenTree 的主配置文件,改它 + 重启即生效;逐节详解见本专栏配置篇。secret_key.txt:Django SECRET_KEY,首次启动自动生成——丢失它会导致会话/令牌全部失效,务必纳入备份。backup/:invoke backup的默认备份落点(官方 config 模板backup_dir指向/home/inventree/data/backup)。media/、static/:上传附件与前端静态资源;plugins/、plugins.txt:插件目录与清单;caddy/、redis/:两个附属服务的状态。
5.3 备份要点
- 数据库:
docker compose exec inventree-db pg_dump -U pguser inventree > inventree-$(date +%F).sql,或用 InvenTree 自带invoke backup(落backup/目录,用法见本专栏命令篇)。 - 配置与凭据:
config.yaml、secret_key.txt、.env三个文本文件单独留份。
六、环境变量表
.env 全量变量(含官方默认值)速查(来源:官方 contrib/container/.env 模板 + compose 文件默认值,1.6.1 tag 实读;实测部署值见 4.2 节):
| 变量 | 默认值 | 说明 |
|---|---|---|
INVENTREE_TAG | stable | 镜像版本标签;生产建议锁具体版本(如 1.6.1) |
INVENTREE_SITE_URL | http://localhost | 对外访问 URL;决定 CSRF 白名单与 Caddy 监听地址 |
INVENTREE_WEB_PORT | 8000 | server 栈内监听端口,勿改 |
INVENTREE_HTTP_PORT | 80 | Caddy HTTP 发布端口 |
INVENTREE_HTTPS_PORT | 443 | Caddy HTTPS 发布端口(SITE_URL 用 https:// 时 Caddy 自动启用 Automatic HTTPS) |
INVENTREE_USE_X_FORWARDED_HOST/PORT/PROTO | True | 反代转发头开关 |
INVENTREE_EXT_VOLUME | ./inventree-data | 外部数据卷路径 |
INVENTREE_LOG_LEVEL | WARNING | 日志级别 |
INVENTREE_PLUGINS_ENABLED | False | 是否启用插件(官方 .env 模板示例置 True) |
INVENTREE_AUTO_UPDATE | False | 启动时自动迁移 |
INVENTREE_ADMIN_USER/EMAIL/PASSWORD | 注释态 | 首启自动建管理员,三项须齐备 |
INVENTREE_DB_ENGINE | postgresql | 数据库引擎(栈内固定 postgresql) |
INVENTREE_DB_NAME | inventree | 数据库名 |
INVENTREE_DB_HOST | inventree-db | 数据库地址(栈内服务名) |
INVENTREE_DB_PORT | 5432 | 数据库端口 |
INVENTREE_DB_USER/PASSWORD | pguser/pgpassword | 数据库凭据(非登录账号) |
INVENTREE_CACHE_ENABLED | True | 启用 Redis 缓存 |
INVENTREE_CACHE_HOST/PORT | inventree-cache/6379 | 缓存地址端口 |
INVENTREE_GUNICORN_TIMEOUT | 90 | gunicorn 请求超时(秒) |
INVENTREE_GUNICORN_WORKERS | CPU 核数×2+1 | gunicorn 进程数(gunicorn.conf.py 实读:未设置时按 CPU 自动计算) |
COMPOSE_PROJECT_NAME | inventree | compose 项目名 |
💡 说明:除上表外,InvenTree 全部
INVENTREE_*配置项(数据库、邮件、SSO、后台线程数等)同样可通过.env注入并优先于config.yaml,完整覆盖机制见本专栏配置篇。
七、配置参数说明
栈内三个关键配置面的分工:
.env(本指南 4.2 节):compose 栈自身的编排参数(端口、路径、凭据)+ InvenTree 应用配置的环境变量形态。改动后需要docker compose up -d重建对应服务生效。config.yaml(/opt/inventree/data/config.yaml):InvenTree 应用主配置,首启自动生成。改文件后重启 server/worker 生效;优先级低于INVENTREE_*环境变量。Caddyfile(/opt/inventree/Caddyfile):反代与文件服务行为,改动后docker compose restart inventree-proxy生效。
八、配置文件挂载
8.1 config.yaml 挂载
config.yaml 无需在 compose 里显式挂载:它位于数据卷内(/home/inventree/data/config.yaml),server 与 worker 共享同一数据卷,天然同步。直接编辑宿主机 /opt/inventree/data/config.yaml 后:
cd /opt/inventree && docker compose restart inventree-server inventree-worker
Restarting inventree-server ... done
Restarting inventree-worker ... done
8.2 Caddyfile 挂载
compose 已声明 ./Caddyfile:/etc/caddy/Caddyfile:ro,z。需要自定义反代规则(如外接 TLS、加访问控制)时编辑宿主机文件后:
cd /opt/inventree && docker compose restart inventree-proxy
九、等价 docker run(单进程理解用)
compose 栈的等效单进程形态(仅帮助理解各服务角色,生产请用 compose——依赖健康检查与共享数据卷,手工 docker run 难以复现启动顺序):
# 数据库
docker run -d --name inventree-db \
-v /opt/inventree/data:/var/lib/postgresql/data/ \
-e PGDATA=/var/lib/postgresql/data/pgdb \
-e POSTGRES_USER=pguser -e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_DB=inventree \
postgres:17
# InvenTree Web 服务(环境变量取自 .env,此处节选核心项)
docker run -d --name inventree-server \
-v /opt/inventree/data:/home/inventree/data \
-e INVENTREE_DB_ENGINE=postgresql -e INVENTREE_DB_HOST=inventree-db \
-e INVENTREE_DB_USER=pguser -e INVENTREE_DB_PASSWORD=q1w2e3r4 \
-e INVENTREE_SITE_URL="http://192.168.146.128:8146" \
inventree/inventree:1.6.1
# 后台工作进程(同一镜像,换启动命令)
docker run -d --name inventree-worker \
-v /opt/inventree/data:/home/inventree/data \
inventree/inventree:1.6.1 invoke worker
⚠️ 注意:
INVENTREE_EXT_VOLUME挂载到 server 的/home/inventree/data是官方镜像的硬约定(compose 注释原文「Data volume must map to /home/inventree/data」),换路径会导致配置与媒体文件丢失。
十、常用运维命令
以下命令均在部署目录内执行(cd /opt/inventree):
docker compose ps # 栈状态(五服务 healthy 为正常态)
docker compose logs -f inventree-server # 跟随 Web 服务日志(-n 200 只看最近 200 行)
docker compose stop # 停栈(保留容器)
docker compose start # 起栈
docker compose restart inventree-server # 单独重启某服务
docker compose down # 销毁容器与网络(数据卷不受影响)
docker compose up -d # 拉起/重建
docker compose exec inventree-server invoke version # 查看运行版本
版本与镜像信息实测:
docker compose exec inventree-server invoke version
InvenTree Version Info
InvenTree Version: 1.6.1
...
(完整输出与逐项解读见本专栏命令篇。)
升级流程(以升级到未来版本为例):
cd /opt/inventree
sed -i 's/^INVENTREE_TAG=.*/INVENTREE_TAG=<新版本号>/' .env # 改版本标签
docker compose pull # 拉新镜像
docker compose up -d # 重建;server 启动时自动跑新增迁移(INVENTREE_AUTO_UPDATE=True)
回滚:把 INVENTREE_TAG 改回旧版本号,docker compose up -d 即回退;注意 1.6.0 起数据库迁移有压缩合并(官方 CHANGELOG #12830:1.0.0 之前版本必须先升到 1.0.0),跨大版本回滚前先核对官方升级说明,数据库层面回滚需恢复备份。
十一、销毁重建与恢复闭环(实测)
本节为完整实测闭环:造一条数据 → 销毁栈 → 重建 → 验证数据完好。
第一步,经 API 创建一条测试零件(Basic 认证):
curl -s -u admin:q1w2e3r4 -X POST -H 'Content-Type: application/json' \
-d '{"name":"R-10K-0603","description":"10kOhm 0605 resistor","active":true}' \
http://192.168.146.128:8146/api/part/ | head -c 200
{"active":true,"assembly":false,"barcode_hash":"","category":null,"category_detail":null,"category_path":null,"component":true,"creation_date":"2026-10-23","creation_user":1,"default_expiry":0,"default_location":null,"default_location_detail":null,"description":"10kOhm 0605 resistor","full_name":"R-10K-0603","image":null,"IPN":"","is_template":false,"keywords":null,"link":null,"locked":false,"minimum_stock":0.0,"maxi
第二步,销毁栈:
docker compose down
Container inventree-proxy Stopping
Container inventree-proxy Stopped
Container inventree-proxy Removing
Container inventree-proxy Removed
Container inventree-worker Stopping
Container inventree-worker Stopped
Container inventree-worker Removing
Container inventree-worker Removed
Container inventree-server Stopping
Container inventree-server Stopped
Container inventree-server Removing
Container inventree-server Removed
Container inventree-cache Stopping
Container inventree-db Stopping
Container inventree-db Stopped
Container inventree-db Removing
Container inventree-cache Removed
Container inventree-cache Removed
Network inventree-161-stack_net Removing
Network inventree-161-stack_net Removed
docker compose ps -a
NAME STATUS
容器与网络已全部清除,ps -a 无残留;/opt/inventree/data 不受 down 影响(bind mount 设计目的正是如此)。
第三步,重建栈:
docker compose up -d && sleep 75 && docker compose ps
NAME SERVICE STATUS
inventree-cache inventree-cache Up About a minute (healthy)
inventree-db inventree-db Up About a minute (healthy)
inventree-proxy inventree-proxy Up About a minute (healthy)
inventree-server inventree-server Up About a minute (healthy)
inventree-worker inventree-worker Up About a minute (healthy)
第四步,恢复验证——账号与业务数据完好:
curl -s -u admin:q1w2e3r4 http://192.168.146.128:8146/api/user/me/ | head -c 120
{"pk":1,"username":"admin","first_name":"","last_name":"","email":"admin@localhost","groups":[],"is_staff":true,"is_supe
curl -s -u admin:q1w2e3r4 'http://192.168.146.128:8146/api/part/?search=R-10K' \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps([{k: p[k] for k in ('pk','full_name','description')} for p in d], ensure_ascii=False))"
[{"pk": 1, "full_name": "R-10K-0603", "description": "10kOhm 0605 resistor"}]
结论:down + up -d 后管理员账号与零件数据完好,恢复闭环成立。数据库迁移不重跑(库结构已在 pgdb/ 中),重建耗时约 1 分钟。
十二、常见问题(排障实录)
12.1 访问 8146 端口返回 200 但内容为空(或直接拒连)
现象:栈五服务全部 healthy,但 curl http://localhost:8146/api/system/health/ 返回 HTTP/1.1 200 OK 且 Content-Length: 0(改用官方原版 compose 时甚至直接连接拒绝)。
定位:Caddy 日志显示其站点监听地址直接取自 INVENTREE_SITE_URL:
{"level":"warn",...,"msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":8146"}
{"level":"info","logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
官方 Caddyfile 的站点地址是 {$INVENTREE_SITE_URL:...}:当 INVENTREE_SITE_URL="http://192.168.146.128:8146"(含端口)时,Caddy 在栈内监听 8146 端口;而官方 compose 的发布映射是 ${INVENTREE_HTTP_PORT:-80}:80(宿主机 8146 → 栈内 80),两端口号错位,请求落空。
解决:把发布映射两端对齐——compose 的 ports 改为 ${INVENTREE_HTTP_PORT:-80}:${INVENTREE_HTTP_PORT:-80}(即 4.3 节文件),docker compose up -d 重建后验证:
curl -s http://192.168.146.128:8146/api/system/health/
{"status": "ok"}
同理注意 Host 匹配:Caddy 按站点地址匹配请求 Host。用 http://localhost:8146 访问时 Host 为 localhost,与站点地址 192.168.146.128 不匹配,Caddy 返回空的 200——请始终用 INVENTREE_SITE_URL 配置的地址访问,或在 Caddyfile 中追加匹配地址。
12.2 创建网络报 Pool overlaps
现象:docker compose up -d 报 Error response from daemon: invalid pool request: Pool overlaps with other one on this address space。
定位:显式声明的网段(10.89.68.0/24)与服务器上现存 Docker 网络重叠。
解决:docker network ls + docker network inspect 排查已占网段,换一个空闲网段写入 compose 的 networks.default.ipam.config.subnet 后重建。多套 compose 栈共存的服务器建议统一做网段分配规划。
12.3 管理员账号未自动创建
现象:首启后用 admin 登录被拒。
定位:INVENTREE_ADMIN_USER/INVENTREE_ADMIN_EMAIL/INVENTREE_ADMIN_PASSWORD 三项必须同时存在才会自动建号(源码 apps.py 缺一即跳过创建并告警)。
解决:补齐三项后重建 server;或手动建号:docker compose exec inventree-server invoke superuser(交互式,用法见本专栏命令篇)。
12.4 数据目录权限问题导致首启失败
现象:server 日志报写入 /home/inventree/data/... 失败。
定位:INVENTREE_EXT_VOLUME 指向的宿主机目录对栈内进程(PostgreSQL UID 999、InvenTree)不可写。
解决:按 4.1 节放开目录权限(chmod 777)或提前 chown 999:999 数据目录。
十三、参考链接
- 官方 Docker 部署文档:https://docs.inventree.org/en/latest/start/docker/
- 官方生产 compose(1.6.1 tag):https://github.com/inventree/InvenTree/blob/1.6.1/contrib/container/docker-compose.yml
- 官方 .env 模板(1.6.1 tag):https://github.com/inventree/InvenTree/blob/1.6.1/contrib/container/.env
- 官方镜像仓库:https://hub.docker.com/r/inventree/inventree
- 配置总文档:https://docs.inventree.org/en/latest/start/config/
- 站内同类部署参考:《grocy 4.7.1 Docker Compose 部署指南》