OpenStock自建指南:Docker+PostgreSQL搭建开源库存管理系统
1. OpenStock 到底是什么为什么值得动手搭一套OpenStock 这个词最近在技术圈里被反复提起很多人第一次听到会以为是某个股票行情软件或者量化交易平台。实际上它更像是一类开源的库存与物资管理系统的统称——你可以把它理解成一个“自己说了算”的进销存中枢用来管理商品、物料、设备、耗材等一切需要记录“有多少、在哪里、谁在用”的东西。它解决的问题非常具体中小团队用不起昂贵的商业 ERP用 Excel 又管不住多人协作和实时同步于是需要一个轻量、可自建、可二次开发的方案。我最早接触这类系统是因为帮一个做硬件的小团队整理物料。他们有几百种元器件采购、领用、归还全靠一张共享表格结果经常出现“账上有、柜子里没有”的情况。后来我们决定自己搭一套 OpenStock 类的系统核心诉求就三个数据存在自己手里、多人能同时操作、能按自己的业务改字段。这套东西适合谁呢适合有一定 Linux 基础、懂点 Docker、愿意折腾的开发者或运维也适合小团队里负责内部工具的那个人。如果你完全没碰过命令行跟着做也能跑起来但遇到问题排查会吃力一些。需要先说明的是OpenStock 并不是一个官方唯一指定的软件名市面上叫这个名字或类似名字的开源项目有好几个方向。我下面讲的这套搭建思路是基于“自建库存管理服务”这个最常见、最实用的场景来展开的选型上会偏向成熟、社区活跃、文档齐全的方案。你完全可以根据自己团队的技术栈替换其中的组件核心逻辑是相通的。2. 搭建前的整体设计与选型思路2.1 为什么优先选“自建”而不是买 SaaS很多人第一反应是找个在线的库存管理工具注册就能用为什么还要自己搭我踩过的坑是这样的早期用某在线表格管物料免费版有行数限制团队超过五个人就要升级更麻烦的是有些物料的供应商信息、成本价属于敏感数据放在别人的服务器上总归不踏实。自建 OpenStock 的最大好处是数据主权——数据库在你自己的机器上备份策略你说了算想导出什么格式就导出什么格式。另一个关键点是可定制。标准 SaaS 的字段是固定的比如“商品名称、数量、价格”但实际业务里你可能需要“封装形式、耐压值、存放货架号”这些字段。自建系统可以直接改数据库表结构或者通过配置扩展不用等产品经理排期。当然代价是你得自己负责运维服务器挂了要自己修这也是为什么我建议用 Docker 来降低维护成本。2.2 技术栈选型为什么是 Docker PostgreSQL 轻量后端整套方案我推荐的技术组合是Docker Compose 编排、PostgreSQL 做数据库、后端用 Python FastAPI 或 Node.js、前端用现成的管理面板。逐个说下理由。Docker 的价值在于环境隔离和一键迁移。库存系统通常不是天天改代码但依赖的数据库、缓存、Web 服务版本容易冲突。用 Docker 把每个组件打包成容器换服务器时只需要把docker-compose.yml和数据库卷拷过去几分钟就能恢复。我实测过从一台云主机迁移到另一台停机时间不到十分钟。数据库选 PostgreSQL 而不是 MySQL主要看中它对 JSON 字段和复杂查询的支持更好。库存场景里经常要存“扩展属性”比如某个物料的规格参数是变动的用 JSONB 字段存就很灵活查询时还能建索引。MySQL 也能做但 PostgreSQL 在这块更顺手。如果团队已经有 MySQL 运维经验换成 MySQL 也完全可行逻辑不变。后端语言看团队熟悉度。FastAPI 写起来快自带接口文档适合快速迭代Node.js 生态里库存管理的轮子更多有些现成的开源项目可以直接拿来改。我下面以 FastAPI 为例因为它的代码可读性强方便你后续自己加功能。2.3 部署架构单机还是多节点对于大多数中小团队单机 Docker 部署就够了。一台 2 核 4G 的云主机跑数据库、后端、前端三个容器支撑几十个人同时操作毫无压力。库存系统的并发量通常很低瓶颈不在 CPU 而在数据库的写入锁。如果团队规模上百人或者需要高可用再考虑把数据库单独拆出来加一个只读副本做报表查询。网络方面如果只在公司内网使用直接绑定内网 IP 即可如果需要外网访问建议加一层反向代理并配置 HTTPS。这里不展开具体工具原则是不要直接把数据库端口暴露到公网这是最基本的安全底线。3. 核心细节解析与实操要点3.1 数据库表结构怎么设计才不返工库存系统的表结构是地基设计不好后面改起来非常痛苦。我建议至少包含这几张核心表物料表、库存表、出入库记录表、用户表、操作日志表。物料表存静态信息名称、编码、规格、单位库存表存动态数量当前数量、锁定数量、货架位置出入库记录表存每一次变动的流水。这里有个关键设计点库存数量不要直接存在物料表里。我见过有人图省事在物料表加一个quantity字段每次出入库直接加减。这样做的问题是一旦出现并发操作或者程序 bug数量对不上时你根本查不出是哪一笔出的错。正确做法是库存表只存“当前快照”所有变动都写流水需要核对时用流水累加来验证快照。这多写一张表的成本换来的是可追溯性。另一个细节是物料编码的唯一性。建议用“类别前缀 自增序号”的方式生成比如ELEC-0001表示电子类第一个物料。不要用随机字符串人工核对时太痛苦。编码一旦生成就不要改因为很多地方会引用它。3.2 出入库逻辑的并发处理库存系统最怕的就是两个人同时领用同一个物料导致超卖。比如仓库里只剩 1 个A 和 B 同时提交领用申请如果程序先查再改两个请求都查到“有 1 个”然后都扣减结果变成 -1。解决办法是在数据库层面加行锁用SELECT ... FOR UPDATE把那一行锁住等第一个事务提交后再让第二个事务读取。具体到代码里出入库操作必须放在一个数据库事务里先锁库存行检查数量是否足够足够则更新快照并插入流水不足则回滚并返回错误。这个逻辑听起来简单但很多开源项目为了性能会省略锁导致数据不准。你自己搭的时候一定要确认这一点或者干脆在应用层加一个队列把同一物料的出入库请求串行化。注意行锁会带来等待如果某个物料的出入库非常频繁可能成为瓶颈。实际业务里这种极端情况很少真遇到了再考虑用消息队列削峰。3.3 权限与操作日志不能省小团队容易觉得“都是自己人不用搞权限”但库存数据一旦被误删或误改恢复起来很麻烦。建议至少分三种角色管理员可增删改所有数据、操作员只能出入库和查询、只读用户只能看报表。权限控制可以在后端接口层做每个请求校验用户角色。操作日志要记录“谁、什么时间、对哪个物料、做了什么操作、改前改后的值”。这张表只增不改定期归档。我遇到过有人误把某个物料的数量从 100 改成 1因为有日志五分钟就定位并恢复了。没有日志的话只能全量回滚数据库损失更大。4. 手把手实操从零跑起一套 OpenStock4.1 环境准备与依赖安装先准备一台 Linux 服务器Ubuntu 22.04 或 Debian 12 都可以。最低配置 2 核 4G硬盘 40G 起步因为日志和备份会占空间。用 root 或 sudo 权限执行以下步骤。第一步安装 Docker 和 Docker Compose。官方脚本最省事curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo apt-get install docker-compose-plugin -y装完后验证版本docker --version docker compose version如果显示版本号就说明成功了。这里有个坑有些云主机的默认源里 Docker 版本很老用官方脚本能避免这个问题。另外如果服务器在国内拉取镜像可能较慢可以配置镜像加速具体方法各云厂商文档里都有这里不展开。4.2 编写 docker-compose 编排文件新建一个目录openstock在里面创建docker-compose.yml。下面是我实际用的一份配置你可以直接抄version: 3.9 services: db: image: postgres:15 restart: always environment: POSTGRES_USER: openstock POSTGRES_PASSWORD: 换成你的强密码 POSTGRES_DB: openstock volumes: - ./pgdata:/var/lib/postgresql/data ports: - 127.0.0.1:5432:5432 api: build: ./api restart: always depends_on: - db environment: DATABASE_URL: postgresql://openstock:换成你的强密码db:5432/openstock ports: - 127.0.0.1:8000:8000 web: image: nginx:alpine restart: always volumes: - ./web:/usr/share/nginx/html ports: - 80:80几个关键点解释下。数据库端口绑定127.0.0.1而不是0.0.0.0意思是只允许本机访问外网连不上这是安全底线。pgdata目录挂载到宿主机容器删了数据还在。api服务用build而不是现成镜像因为你要自己写业务代码。4.3 后端接口的最小实现在api目录下创建Dockerfile和main.py。Dockerfile内容FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]requirements.txt里写fastapi uvicorn psycopg2-binary sqlalchemymain.py先实现一个最核心的出入库接口。为了让你看清逻辑我写得直白一些from fastapi import FastAPI, HTTPException from sqlalchemy import create_engine, text import os app FastAPI() engine create_engine(os.environ[DATABASE_URL]) app.post(/stock/in) def stock_in(item_id: int, qty: int, user: str): with engine.begin() as conn: row conn.execute( text(SELECT quantity FROM stock WHERE item_id:id FOR UPDATE), {id: item_id} ).fetchone() if not row: raise HTTPException(404, 物料不存在) new_qty row[0] qty conn.execute( text(UPDATE stock SET quantity:q WHERE item_id:id), {q: new_qty, id: item_id} ) conn.execute( text(INSERT INTO stock_log(item_id, change, user) VALUES(:id, :c, :u)), {id: item_id, c: qty, u: user} ) return {item_id: item_id, quantity: new_qty}这段代码的关键是FOR UPDATE它会在事务期间锁住那一行防止并发扣减。engine.begin()自动管理事务出错会回滚。实际项目里还要加权限校验、参数验证、错误处理但核心逻辑就是这些。4.4 启动与验证在openstock目录下执行docker compose up -d第一次会拉取镜像并构建等几分钟。然后用docker compose ps看三个容器是否都是running状态。接着测试接口curl -X POST http://127.0.0.1:8000/stock/in?item_id1qty10usertest如果返回{item_id:1,quantity:10}说明链路通了。你可以再发一次同样的请求数量应该变成 20。这时候去数据库里查stock_log表应该有两行记录。到这一步最核心的出入库功能就跑起来了。提示生产环境一定要把user参数换成从登录态里取不能让前端随便传否则日志就失去意义了。5. 常见问题与排查技巧实录5.1 容器启动失败怎么快速定位最常见的报错是数据库连不上。先看docker compose logs db如果显示database system is ready to accept connections就说明数据库没问题。再看docker compose logs api如果报connection refused通常是DATABASE_URL里的主机名写错了。在 Compose 网络里服务名就是主机名所以应该写db而不是localhost。另一个高频问题是端口被占用。比如 80 端口已经被宿主机上的 Nginx 占了web容器就起不来。用ss -tlnp | grep 80查一下换个端口映射即可。我习惯把外部端口设成 8080 之类不常用的避免冲突。5.2 数据对不上时的排查顺序如果发现库存数量和实际不符按这个顺序查先看stock_log表里该物料的流水总和和stock表里的快照对比。如果流水总和等于快照说明数据没丢只是实物和账面对不上那是流程问题如果流水总和不等于快照说明有程序 bug 或者有人直接改了数据库。这时候用git log看最近有没有改过出入库代码重点检查事务是否完整。我遇到过一次快照比流水多 5 个的情况查了半天发现是有人手动执行了UPDATE stock SET quantityquantity5没写日志。所以再次强调所有库存变动必须走接口禁止直接操作数据库。5.3 性能问题的常见表现与对策库存系统一般不会遇到性能瓶颈但如果物料数量上万、流水上百万查询会变慢。对策是给stock_log表的item_id和created_at建联合索引报表查询走索引扫描。另外历史流水可以按月归档到单独的表主表只保留最近三个月的数据。这些优化等真正遇到慢查询再做也不迟过早优化反而增加复杂度。下面这张表整理了我踩过的坑和对应解法你可以存下来备用问题现象可能原因解决方向容器反复重启数据库密码不匹配检查环境变量和 pgdata 是否残留旧数据接口返回 500数据库连接池耗尽调大 SQLAlchemy 的 pool_size数量出现负数缺少行锁或事务不完整确认出入库用了 FOR UPDATE日志表暴涨没有归档策略按月分区或定期删除旧数据外网无法访问端口只绑定了 127.0.0.1加反向代理不要直接暴露后端5.4 备份与恢复的实操建议数据库备份用pg_dump最稳。在宿主机加一个定时任务每天凌晨执行docker compose exec -T db pg_dump -U openstock openstock backup_$(date %F).sql保留最近 30 天的备份旧的自动删除。恢复的时候先停掉api容器把 SQL 文件导入再启动。我实测过整个恢复过程不到两分钟。注意备份文件不要放在同一块硬盘上最好同步到另一台机器或对象存储防止硬盘故障导致数据全丢。6. 后续扩展与个人经验分享这套基础版跑通之后可以按需加功能。比如加一个低库存预警当某个物料数量低于阈值时发通知加一个扫码出入库用手机摄像头扫条码减少手工输入错误加一个报表导出按时间段统计领用最多的物料。这些都是在现有接口上扩展不用动核心架构。我自己在实际操作中的体会是库存系统的难点从来不在技术而在流程约束。工具再好如果团队成员图省事绕过系统直接改数据库数据迟早会乱。所以搭建的同时一定要定规矩所有变动走接口、所有操作留日志、定期对账。技术方案只是把规矩落地的载体。最后再分享一个小技巧初期可以把物料编码打印成二维码贴在货架上出入库时扫码操作比手工输入快得多也几乎不会出错。这个投入很小但效果立竿见影。

相关新闻

PCIe 4.0/5.0时钟选型与HCSL/LPHCSL设计实战指南

PCIe 4.0/5.0时钟选型与HCSL/LPHCSL设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 8:05:53 阅读更多 →
STM32烧录报错Contents mismatch?五大排查步骤详解

STM32烧录报错Contents mismatch?五大排查步骤详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 8:05:51 阅读更多 →
RL-赵-(七)-不基于模型2-时序差分/TD算法02:计算出给定π下的State Value【求解出State Value➜PE➜PI➜找最优π】

RL-赵-(七)-不基于模型2-时序差分/TD算法02:计算出给定π下的State Value【求解出State Value➜PE➜PI➜找最优π】

二、TD learning of state values TD learning既可以指一大类的强化学习算法,也可以指一个具体的estimating state values的算法。TD算法是基于数据,也就是不基于模型来实现强化学习。 1、TD算法描述 TD算法要求的data/experience如下: 给定 π π π 产生的 ( s 0 , r…

2026/9/25 8:05:53 阅读更多 →

最新新闻

制造经理的高效:从救火队长到系统管理员

制造经理的高效:从救火队长到系统管理员

做了十几年制造经理,我对“高效”这个词越来越警惕。面试的时候老板爱问“你怎么理解效率”,很多人脱口就是“结果导向、执行力强、按计划走”,听着都对,但放到现场基本没用。真正的高效不是你自己一天处理了多少件事,…

2026/9/25 8:52:12 阅读更多 →
树莓派5 GPIO 5V引脚供电实操:方案选型、压力测试与避坑指南

树莓派5 GPIO 5V引脚供电实操:方案选型、压力测试与避坑指南

这段时间身边好几个玩树莓派5的朋友都跑来问我同一个问题:能不能直接通过GPIO的5V引脚给板子供电?有的想把树莓派5塞进无人机或者小车里,不想带着原装Type-C电源线;有的是想省一个插座,从稳压模块直接拉电;…

2026/9/25 8:52:12 阅读更多 →
ESP32-S3桌面AI机器人实战:全双工语音与视觉多模态交互全解析

ESP32-S3桌面AI机器人实战:全双工语音与视觉多模态交互全解析

EchoEar喵伴这个项目,实际做下来我最大的感受是:它表面上看是个桌面小玩具,本质上却是一道特别扎手的嵌入式工程题。要在ESP32-S3这颗MCU上同时搞定全双工语音交互、摄像头视觉采集、云端大模型对话,还要保证用户能随时打断机器人…

2026/9/25 8:52:12 阅读更多 →
GD32高级定时器互补PWM输出与死区控制实战

GD32高级定时器互补PWM输出与死区控制实战

写GD32的高级定时器,绕不开三相电机控制、全桥逆变、UPS这类场景。做这类项目的人,百分之九十九都躲不过一个需求:要输出两路相位相反、中间还夹着一小段“空白”的PWM,而且这段空白还得精确可控。这段空白就是死区,控…

2026/9/25 8:52:12 阅读更多 →
外墙墙体渗水维修师傅 好工匠防水 高空作业 外墙裂缝修补专用材料

外墙墙体渗水维修师傅 好工匠防水 高空作业 外墙裂缝修补专用材料

随着国内建筑使用年限逐步增加,以及北方特殊气候对建筑外墙的持续侵蚀,外墙防水维修市场的需求正在持续增长。京津冀区域受北方冬季冻融循环、春季持续返潮、沿海区域盐蚀、雨季强降水的多重影响,外墙渗水问题成为民居、商用建筑、工业厂房都…

2026/9/25 8:52:11 阅读更多 →
httprequester实战:从接口调试到CI/CD健康检查的命令行HTTP工具

httprequester实战:从接口调试到CI/CD健康检查的命令行HTTP工具

简介:HttpRequester 是一款面向软件开发与测试人员的 HTTP 请求调试工具,主要用于构造 GET、POST 等各类请求并查看服务器响应,帮助快速验证接口正确性与排查网络问题。资源包内共包含 4 个文件,压缩后仅 224KB,体积非…

2026/9/25 8:51:11 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →