ezbookkeeping 2.1.0 Docker Compose 部署指南
目标:面向希望在单台 Linux 服务器上以 Docker Compose 编排方式部署 ezBookkeeping v2.1.0 的读者,覆盖从镜像选型、compose.yaml 编写、部署执行、功能验证,到数据持久化、备份与恢复闭环的完整流程。本文全部命令与回显均在 Ubuntu 22.04.4 LTS 实际执行并逐字采集,未做任何模拟或编造。关于 ezBookkeeping 的产品定位、功能清单与同类选型对比,请先阅读[《ezbookkeeping 2.1.0 介绍与选型指南》](https://www.quzuo.net/document/gJuVPcVIQOhE)。
ezbookkeeping 2.1.0 Docker Compose 部署指南
目标:面向希望在单台 Linux 服务器上以 Docker Compose 编排方式部署 ezBookkeeping v2.1.0 的读者,覆盖从镜像选型、compose.yaml 编写、部署执行、功能验证,到数据持久化、备份与恢复闭环的完整流程。本文全部命令与回显均在 Ubuntu 22.04.4 LTS 实际执行并逐字采集,未做任何模拟或编造。关于 ezBookkeeping 的产品定位、功能清单与同类选型对比,请先阅读《ezbookkeeping 2.1.0 介绍与选型指南》。
一、环境信息
本文所有操作在以下环境中实测完成,读者复现时如版本不同,行为可能存在差异:
| 项目 | 值 |
|---|---|
| 宿主操作系统 | Ubuntu 22.04.4 LTS(内核 6.8.0-138-generic) |
| Docker 引擎 | Docker version 29.8.1, build 4a63305 |
| Compose | Docker Compose version v5.5.1 |
| 部署镜像 | mayswind/ezbookkeeping:2.1.0(镜像 ID 96093e4bd189,压缩后 113MB) |
| 宿主端口规划 | 8129(映射到容器内 8080) |
| 自定义网络 | 10.89.71.0/24(bridge 驱动,显式指定子网) |
| 工作目录 | /opt/data/ezbookkeeping/compose |
镜像内关键事实(docker inspect 实测):容器内暴露端口为 8080/tcp;运行用户为 1000:1000(镜像内置非 root 用户 ezbookkeeping);入口为 /docker-entrypoint.sh,无额外 Cmd,直接启动 /ezbookkeeping/ezbookkeeping server run。
二、镜像选型说明
ezBookkeeping 官方在 Docker Hub 发布 mayswind/ezbookkeeping 镜像,标签策略如下:
2.1.0:与 GitHub Release v2.1.0(2026-10-15,commit ff168cf)对应的精确版本标签,生产部署推荐;latest:跟随最新稳定版,自动更新但升级时机不可控;- 旧版本线(如
1.x)继续保留,便于回退。
选型结论:本文选用 2.1.0 精确版本标签。理由:①记账数据涉及财务隐私,升级节奏应完全自控;②v2.x 相比 1.x 存在配置节更名等变更(详见 A1 选型指南),锁定精确版本可避免"顺手拉了新镜像导致配置失效";③镜像体积仅 113MB,全量重拉成本极低。
镜像内部结构(官方 Dockerfile 及实测推定):单二进制 /ezbookkeeping/ezbookkeeping + 静态资源 /ezbookkeeping/public + 模板 /ezbookkeeping/templates + 默认配置 /ezbookkeeping/conf/ezbookkeeping.ini,数据目录 /ezbookkeeping/data,附件存储目录 /ezbookkeeping/storage,日志目录 /ezbookkeeping/log。
三、前置条件
- 宿主机已安装 Docker 引擎与 Docker Compose 插件(
docker compose version可执行); - 服务器具备拉取 Docker Hub 镜像的网络条件(国内环境建议为 Docker 守护进程配置镜像加速或 HTTP 代理,本文实测走代理拉取);
- 已规划宿主端口(本文用 8129,可用
ss -tlnp | grep 8129确认未被占用); - 已规划 Docker 网络子网(本文用 10.89.71.0/24,多套 compose 栈并存时务必显式指定子网避免网段漂移);
- 准备一个 32 字符左右的随机字符串作为登录密钥(secret_key),生成方式见第四章。
四、部署步骤
4.1 创建目录结构
mkdir -p /opt/data/ezbookkeeping/compose/{conf,data,storage}
cd /opt/data/ezbookkeeping/compose
chown 1000:1000 conf data storage
为什么必须 chown 1000:1000:镜像内进程以 UID/GID=1000 运行,三个目录是 bind mount,容器内 SQLite 建库文件、附件写入都直接落在宿主目录上。若目录属主是 root,容器内写入将报 permission denied 并陷入重启循环(实测踩坑见第十一章)。
4.2 准备配置文件
从官方源码仓库获取与 2.1.0 版本匹配的默认配置(也可先不放置,镜像内自带默认配置,此处放置是为了后续 bind mount 覆盖调参):
curl -fsSLo conf/ezbookkeeping.ini \
https://raw.githubusercontent.com/mayswind/ezbookkeeping/2.1.0/conf/ezbookkeeping.ini
生成登录密钥并写入配置(secret_key 是密码哈希与会话令牌的加密密钥,一旦确定不可更换,否则已有用户全部无法登录):
# 用同镜像内二进制生成随机密钥
docker run --rm mayswind/ezbookkeeping:2.1.0 \
/ezbookkeeping/ezbookkeeping security gen-secret-key -l 32
# 实测输出(每次不同,仅作格式示例):
# EHzJgpPK6TnvXcR2uYbK4jL6fD0aG1q8Zw7HmTsP5n=
将输出填入 conf/ezbookkeeping.ini 的 [security] secret_key 项。本文实测采用环境变量覆写方式(见 4.3 与第七章),ini 中保持默认亦可。
4.3 编写 docker-compose.yml
完整文件如下(可直接复用,端口与子网按需修改):
name: ezbookkeeping-2.1.0-stack
services:
ezbookkeeping:
image: mayswind/ezbookkeeping:2.1.0
container_name: ezbookkeeping-2.1.0-web
hostname: ezbookkeeping
restart: unless-stopped
ports:
- "8129:8080"
environment:
- "EBK_SERVER_DOMAIN=book.example.com"
- "EBK_SECURITY_SECRET_KEY=q8Zw7HmTsP5nVcXeR2uYbK4jL6fD0aG1"
volumes:
- "./conf/ezbookkeeping.ini:/ezbookkeeping/conf/ezbookkeeping.ini"
- "./data:/ezbookkeeping/data"
- "./storage:/ezbookkeeping/storage"
- "/etc/localtime:/etc/localtime:ro"
networks:
- ezbookkeeping-net
networks:
ezbookkeeping-net:
driver: bridge
ipam:
config:
- subnet: 10.89.71.0/24
说明:
EBK_SERVER_DOMAIN、EBK_SECURITY_SECRET_KEY演示了环境变量覆写机制:EBK_<节名>_<配置项名>,对应 ini 中[server] domain与[security] secret_key,优先级高于配置文件;/etc/localtime只读挂载保证容器内时间与宿主一致,避免记账时间错位;- secret_key 演示值仅为示例,生产请用
security gen-secret-key现生成。
4.4 启动
docker compose up -d
首次执行会拉取镜像并创建网络、容器,实测输出(节选):
[+] Running 4/4
✔ Image mayswind/ezbookkeeping:2.1.0 Pulled
✔ Network ezbookkeeping-210-stack_ezbookkeeping-net Created
✔ Container ezbookkeeping-2.1.0-web Created
✔ Container ezbookkeeping-2.1.0-web Started
注意网络实际名称为 ezbookkeeping-210-stack_ezbookkeeping-net:Compose 会把项目名 ezbookkeeping-2.1.0-stack 中的点号剥除(2.1.0 变成 210),这是正常行为,脚本化处理时需留意。
查看状态与启动日志:
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
ezbookkeeping-2.1.0-web mayswind/ezbookkeeping:2.1.0 "/docker-entrypoint.…" ezbookkeeping 48 seconds ago Up 47 seconds 0.0.0.0:8129->8080/tcp, [::]:8129->8080/tcp
docker compose logs | grep -E "initializer|will run"
关键日志(节选,逐字采集):
[INFO] [initializer.initializeSystem] will load configuration from default config path /ezbookkeeping/conf/ezbookkeeping.ini
[INFO] [initializer.initializeSystem] has loaded configuration {"Mode":"production","WorkingPath":"/ezbookkeeping","Protocol":"http","HttpAddr":"0.0.0.0","HttpPort":8080,"Domain":"book.example.com","RootUrl":"http://book.example.com:8080/", ..., "SecretKeyNoSet":false,"SecretKey":"****", ...}
[INFO] [database.updateAllDatabaseTablesStructure] user table maintained successfully
[INFO] [database.updateAllDatabaseTablesStructure] account table maintained successfully
[INFO] [database.updateAllDatabaseTablesStructure] transaction table maintained successfully
[INFO] [webserver.startWebServer] will run at http://0.0.0.0:8080
两处可以确认环境变量覆写生效:Domain 已变为 book.example.com;SecretKey 显示 **** 且 SecretKeyNoSet 为 false。启动日志同时打印全部生效配置的 JSON 快照,是排查配置问题的第一入口。
五、部署后验证
5.1 存活与首页
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8129/
实测输出:
HTTP 200
浏览器访问 http://<服务器IP>:8129/ 即可打开 ezBookkeeping 移动端风格首页(官方镜像内置 Framework7 移动端与 Vuetify 桌面端两套前端,按访问端自动适配)。
5.2 注册用户并完成记账闭环
以下通过官方 REST API 完成注册、登录、建账户、记三笔不同类型交易,验证部署的完整可用性。生产用户直接用网页操作即可,接口演示仅作为可脚本化验收手段。
注册(注意:注册请求必须携带 categories 预置分类数组,否则报 parameter "categories" is required):
curl -s -X POST http://localhost:8129/api/register.json \
-H "Content-Type: application/json" -d '{
"username":"demo","email":"demo@example.com","nickname":"Demo",
"password":"q1w2e3r4","language":"zh-CN","defaultCurrency":"CNY","firstDayOfWeek":1,
"categories":[
{"name":"General","type":2,"icon":"1","iconType":0,"color":"FF5722",
"subCategories":[{"name":"Food","type":2,"icon":"1","iconType":0,"color":"FF5722"}]}
]}'
实测输出:
{"result":null,"success":true}
登录(请求体字段是 loginName 而非 username):
curl -s -X POST http://localhost:8129/api/authorize.json \
-H "Content-Type: application/json" \
-d '{"loginName":"demo","password":"q1w2e3r4"}'
实测输出(节选):
{"result":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....","need2FA":false,"user":{"username":"demo",...,"defaultCurrency":"CNY",...}},"success":true}
取 result.token 作为后续请求的 Authorization: Bearer <token>。
创建现金账户(balance 为分为单位的字符串,balanceTime 必须提供):
curl -s -X POST http://localhost:8129/api/v1/accounts/add.json \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-H "X-Timezone-Offset: 480" \
-d '{"name":"现金钱包","category":1,"type":1,"icon":"1","iconType":0,"color":"4CAF50","currency":"CNY","balance":"10000","balanceTime":1792731000}'
实测输出:
{"result":{"id":"3849861508758503424","name":"现金钱包",...,"balance":"10000",...},"success":true}
记一笔支出(type=3,sourceAmount 是整数类型必须传数字,传字符串会报 incomplete or incorrect submission):
curl -s -X POST http://localhost:8129/api/v1/transactions/add.json \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-H "X-Timezone-Offset: 480" \
-d '{"type":3,"categoryId":"3849861324343345153","time":1792731500,"utcOffset":480,"sourceAccountId":"3849861508758503424","sourceAmount":1250,"comment":"早餐"}'
实测输出:
{"result":{"id":"3849861575464714240","type":3,...,"sourceAmount":1250,...,"comment":"早餐",...},"success":true}
再补一笔转账(type=4,需先建一个 type=3 的转账分类,且 destinationAmount 必填)与一笔收入(type=2,需 type=1 的收入分类),然后核对交易清单:
curl -s "http://localhost:8129/api/v1/transactions/list.json?count=10" \
-H "Authorization: Bearer $TOKEN" -H "X-Timezone-Offset: 480"
实测输出(节选,共 5 条:3 笔业务交易 + 2 笔建账余额修改记录):
"items": [
{ "id": "3849861669953994754", "type": 2, ..., "sourceAmount": 123, ..., "comment": "活期利息" },
{ "id": "3849861669953994752", "type": 4, ..., "sourceAmount": 50000, ..., "comment": "月初划转" },
{ "id": "3849861575464714240", "type": 3, ..., "sourceAmount": 1250, ..., "comment": "早餐" },
...
]
收支、转账三类交易均能正常入账且账户余额自动联动(转入账户余额实测变为 300123),部署验证闭环完成。
六、数据持久化说明
本方案的持久化完全依赖三个 bind mount 目录,容器本身无状态,可随时删除重建:
| 宿主目录 | 容器内路径 | 内容 | 说明 |
|---|---|---|---|
| ./conf/ezbookkeeping.ini | /ezbookkeeping/conf/ezbookkeeping.ini | 配置文件 | 启动时加载,改后需重启容器 |
| ./data | /ezbookkeeping/data | ezbookkeeping.db(SQLite) | 全部业务数据:用户、账户、交易、分类、标签 |
| ./storage | /ezbookkeeping/storage | avatar/、icon/、transaction/ 子目录 | 用户头像、自定义图标、交易图片附件 |
| /etc/localtime | /etc/localtime:ro | 时区文件 | 只读 |
实测落盘情况(部署并完成记账闭环后):
$ ls -la data/
-rw-r--r-- 1 1000 1000 212992 Oct 23 12:59 ezbookkeeping.db
$ find storage -type d
storage
storage/transaction
storage/icon
storage/avatar
SQLite 单文件形态意味着:备份 = 拷贝 data/ezbookkeeping.db + storage/ 一个目录;迁移 = 把 compose 目录整体搬到新机器再 docker compose up -d。
6.1 持久化实测:down/up 循环
docker compose down && docker compose up -d
down 实测输出:
Container ezbookkeeping-2.1.0-web Removed
Network ezbookkeeping-210-stack_ezbookkeeping-net Removed
重新 up -d 并登录后再次清点交易:
transactions: 5
type=2 amt=123 comment=活期利息
type=4 amt=50000 comment=月初划转
type=3 amt=1250 comment=早餐
type=1 amt=250000 comment=
type=1 amt=10000 comment=
5 条记录完整保留(含 2 条建账时的余额修改记录 type=1),持久化验证通过。
七、环境变量表
ezBookkeeping 支持以环境变量覆写任意 ini 配置项,规则为 EBK_<节名>_<配置项名>,全部大写。本文实测覆写了两项,启动日志确认生效:
| 环境变量 | 对应配置项 | 实测值 | 作用 |
|---|---|---|---|
| EBK_SERVER_DOMAIN | [server] domain | book.example.com | 站点域名,影响 RootUrl 与密码找回链接 |
| EBK_SECURITY_SECRET_KEY | [security] secret_key | q8Zw7HmTsP5nVcXeR2uYbK4jL6fD0aG1 | 登录密钥,确定后不可更换 |
常用可覆写项(按同一规则推导,改数据库等场景直接套用):
| 环境变量 | 对应配置项 | 说明 |
|---|---|---|
| EBK_DATABASE_TYPE | [database] type | sqlite3 / mysql / postgres,改 MySQL/PG 时必设 |
| EBK_DATABASE_HOST | [database] host | 如 10.89.71.2:3306 |
| EBK_DATABASE_NAME | [database] name | 数据库名 |
| EBK_DATABASE_USER | [database] user | 数据库用户 |
| EBK_DATABASE_PASSWD | [database] passwd | 数据库密码 |
| EBK_STORAGE_TYPE | [storage] type | local_filesystem / s3 / minio / webdav |
| EBK_LOG_MODES | [log] modes | console / file 组合 |
| EBK_SECURITY_ENABLE_API_TOKEN | [security] enable_api_token | true 时开放个人访问令牌 |
环境变量覆写只改变量值,配置项的完整清单、默认值与逐项含义详见《ezbookkeeping 2.1.0 配置参数详解》。
八、配置文件挂载
两种方式并存时的优先级:环境变量 > ini 文件 > 镜像内置默认值。
- 只用环境变量:删掉 compose 中
./conf/ezbookkeeping.ini这一行挂载即可,容器使用镜像内置默认配置; - 用挂载文件:保持本方案结构,后续调参直接改宿主
conf/ezbookkeeping.ini,然后docker compose restart生效; - 验证方法:
docker compose logs | grep "has loaded configuration",启动日志会打印最终生效配置的完整 JSON 快照(secret 等敏感项脱敏为****)。
九、等价 docker run 命令
不用 Compose 时,以下单命令与上述 compose.yml 完全等价(网络需先创建):
docker network create --subnet 10.89.71.0/24 ezbookkeeping-net
docker run -d \
--name ezbookkeeping-2.1.0-web \
--restart unless-stopped \
--hostname ezbookkeeping \
-p 8129:8080 \
-e "EBK_SERVER_DOMAIN=book.example.com" \
-e "EBK_SECURITY_SECRET_KEY=q8Zw7HmTsP5nVcXeR2uYbK4jL6fD0aG1" \
-v /opt/data/ezbookkeeping/compose/conf/ezbookkeeping.ini:/ezbookkeeping/conf/ezbookkeeping.ini \
-v /opt/data/ezbookkeeping/compose/data:/ezbookkeeping/data \
-v /opt/data/ezbookkeeping/compose/storage:/ezbookkeeping/storage \
-v /etc/localtime:/etc/localtime:ro \
--network ezbookkeeping-net \
mayswind/ezbookkeeping:2.1.0
建议生产使用 Compose:变更留痕(compose.yml 可入版本管理)、升级与回滚操作统一(docker compose pull && docker compose up -d)。
十、常用运维命令
cd /opt/data/ezbookkeeping/compose
# 查看运行状态
docker compose ps
# 跟踪日志
docker compose logs -f
# 重启服务(改配置后)
docker compose restart
# 停止 / 启动(数据保留)
docker compose stop
docker compose start
# 升级到新版本(先核对官方升级说明,2.x 内小版本一般自动迁移表结构)
docker compose pull
docker compose up -d
# 彻底删除容器与网络(bind mount 数据保留在宿主目录)
docker compose down
升级前务必先做第六章的数据备份;跨大版本(如 1.x→2.x)需阅读官方 Release Notes 中的 Breaking Changes。
十一、备份与恢复
11.1 备份
先停写再打包,保证 SQLite 文件一致性:
cd /opt/data/ezbookkeeping/compose
docker compose stop
tar -czf /opt/data/ezbookkeeping/backup/ezbookkeeping-backup-20261023.tar.gz \
conf data storage docker-compose.yml
docker compose start
实测备份包:
-rw-r--r-- 1 root root 15214 Oct 23 12:59 ezbookkeeping-backup-20261023.tar.gz
包内清单(tar -tzf 实测节选):
conf/
conf/ezbookkeeping.ini
data/
data/ezbookkeeping.db
storage/
storage/transaction/
storage/icon/
storage/avatar/
低峰期也可不停服务直接拷贝(SQLite 在无写入事务瞬间拷贝风险低),但定期备份建议采用"停 3 秒打包再启动"的稳妥方式。
11.2 灾难恢复实测
模拟数据全损后从备份恢复的完整流程(本文实际执行并验证):
# 1. 停栈
docker compose down
# 2. 模拟数据丢失:删除数据目录
rm -rf data storage
# 3. 从备份还原
tar -xzf /opt/data/ezbookkeeping/backup/ezbookkeeping-backup-20261023.tar.gz
# 4. 重新拉起
docker compose up -d
恢复后实测:demo 用户重新登录成功;交易清单 5 条完整返回,金额与备注逐条一致。恢复闭环验证通过。
注意:若第 3 步之前曾经手工 mkdir data 或由 Docker 自动重建过目录,务必确认属主为 1000:1000,否则会触发下一章的 permission denied 重启循环。
十二、常见问题
Q1:容器反复重启,日志报 open /ezbookkeeping/data/ezbookkeeping.db: permission denied
实测踩坑实录:rm -rf data 后直接 docker compose up -d,Docker 会以 root 身份自动创建 bind mount 目录,而容器内进程以 UID 1000 运行,导致 SQLite 无法建库,容器进入 Restarting (1) 循环。实测日志:
[ERROR] [initializer.initializeSystem] initializes data store failed, because open /ezbookkeeping/data/ezbookkeeping.db: permission denied
Failed to run ezBookkeeping with [/ezbookkeeping/ezbookkeeping server run]: open /ezbookkeeping/data/ezbookkeeping.db: permission denied
修复:
docker compose down
chown 1000:1000 data storage conf
docker compose up -d
预防:目录始终预先创建并 chown 1000:1000,不要依赖 Docker 自动创建 bind mount 目录。
Q2:注册接口报 parameter "categories" is required
注册请求必须携带预置分类数组(网页端注册会自动带上官方预设分类)。用 API/脚本注册时按 5.2 节示例补上 categories 字段即可;每个分类组还需要至少一个 subCategories 子分类——ezBookkeeping 记账时只能挂二级分类。
Q3:登录接口报 login name or password is invalid 且确定密码正确
检查请求体字段名:登录接口的字段是 loginName(用户名与邮箱通用),不是 username。这是 API 层面最常见的 401 诱因。
Q4:记交易报 incomplete or incorrect submission
sourceAmount/destinationAmount 在 API 中是整数类型(分为单位),必须传 JSON 数字(如 1250),传字符串 "1250" 会被校验拒绝。而创建账户的 balance 是字符串类型(如 "10000"),两者易混淆。
Q5:记交易报 transaction category not found 或 transaction category type is invalid
三类交易必须挂对应类型的二级分类:收入交易(type=2)挂分类类型 1、支出交易(type=3)挂分类类型 2、转账交易(type=4)挂分类类型 3。注意分类的类型枚举与交易类型枚举数值不同(收入=1 在两边同义,但"支出"在交易枚举中是 3、在分类枚举中是 2),详见《ezbookkeeping 2.1.0 常用 CLI 命令与工具详解》第五章注意事项第 6 条。
Q6:建银行卡/信用账户报 account must have at least one sub-account
非现金类账户(储蓄卡、信用卡、投资账户等)必须携带 subAccounts 子账户数组(如借记卡/信用额度两个子账户);现金类账户(type=1)可直接创建。
Q7:docker compose up 时提示端口被占用
更换 ports 左侧宿主端口即可;多套栈并存时建议按批分配连续端口段并登记,避免冲突。
十三、参考链接
- 官方 Docker 部署文档:https://ezbookkeeping.mayswind.net/installation_docker
- 官方配置文档(含环境变量覆写说明):https://ezbookkeeping.mayswind.net/configuration
- GitHub 仓库(mayswind/ezbookkeeping):https://github.com/mayswind/ezbookkeeping
- Docker Hub 镜像页:https://hub.docker.com/r/mayswind/ezbookkeeping
- v2.1.0 Release 页:https://github.com/mayswind/ezbookkeeping/releases/tag/2.1.0
- 站内关联阅读:《ezbookkeeping 2.1.0 介绍与选型指南》、《Ubuntu 22.04 安装 ezbookkeeping 2.1.0 指南》、《ezbookkeeping 2.1.0 配置参数详解》、《ezbookkeeping 2.1.0 常用 CLI 命令与工具详解》
以上全部命令、回显与数据均在 Ubuntu 22.04.4 LTS + Docker 29.8.1 + Compose v5.5.1 环境实测采集,实测日期 2026-10-23。