Family Accounting Tool v4.29 Docker Compose 部署指南
用 Docker Compose 部署 Family Accounting Tool v4.29:镜像选型、初始化建库建号、数据持久化实测、环境变量与配置挂载、等价 docker run 与运维命令。
Family Accounting Tool v4.29 Docker Compose 部署指南
目标:用 Docker Compose 一键部署开源家庭记账系统 Family Accounting Tool(facto)v4.29(应用 + MariaDB 双服务),覆盖镜像选型、初始化建库建号、数据持久化验证、环境变量与配置挂载、等价 docker run 形态与常用运维命令。本文全部命令与回显均在 Docker 29.x + Compose v2 环境实测通过(镜像
nymanjens/facto:v4.29、mariadb:10.3)。
一、环境信息
本文实测环境与产物:
- 宿主操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Docker:29.x(含 Compose v2 插件,
docker compose version可用) - 应用镜像:
nymanjens/facto:v4.29(601 MB,内含 Eclipse Temurin JRE 11.0.31 + 发行包) - 数据库镜像:
mariadb:10.3(503 MB,与官方 compose 示例一致) - 部署形态:1 个 compose 项目、2 个服务(
db+web)、1 个命名卷(db_data) - 应用端口:容器内 9000(Play Framework 默认 HTTP 端口)
- 初始管理员:
admin/changeme(镜像内置配置默认值,登录后应立即修改) - 演示密码约定:凡需自定义口令处均以
q1w2e3r4演示 - 官方仓库:
https://github.com/nymanjens/facto(compose 示例来自仓库根目录docker-compose.yml,v4.29)
⚠️ 定位说明:官方 README 将 Docker 形态标注为「Installation with Docker (discouraged)」——作者认为其适合快速体验/演示,若长期保存真实数据与自定义配置,推荐走发行包安装。但 compose 形态本身完整可用(本文实测含数据持久化验证),配合第八节的配置挂载即可长期运行;作者给出理由的讨论见仓库 issue #4。
二、镜像选型说明
官方镜像 nymanjens/facto 由作者发布到 Docker Hub,其构建方式极简(镜像内 /app/Dockerfile 实测内容):
FROM eclipse-temurin:11-jre
COPY ./ /app
WORKDIR /app
即:把发行包原样装进 Temurin JRE 11 基础镜像。版本选择上有两个实测事实需要知道:
| 镜像标签 | 构建时间(Docker Hub API 实查) | 说明 |
|---|---|---|
v4.29 / latest | 2026-08-01 | v4.29 为查询日 2026-10-23 时 GitHub Releases 的 Latest 稳定版,latest 即指向它 |
v4.28 及更早 | 2026-07-30 起 | 历史版本,可用于回退 |
| v4.30 | 无镜像 | 该标签只有源码、无 CI 编译产物,不要尝试拉取 nymanjens/facto:v4.30 |
选型结论:固定使用 nymanjens/facto:v4.29。不建议 latest——作者发布节奏快(2026 年 7-8 月每周至双周一个标签),latest 随时可能漂移,家庭记账数据应当锁定明确版本。镜像内部对配置的支持机制:/app/conf/application.conf 中数据库 URL 与会话密钥两处使用 HOCON 可选替换语法(镜像内实测原文):
http.secret.key="changeme"
http.secret.key=${?APPLICATION_SECRET}
url = "jdbc:mysql://localhost/facto?user=mysqluser&password=mysqlpassword"
url = ${?DATABASE_URL}
即向容器注入 APPLICATION_SECRET、DATABASE_URL 两个环境变量即可覆盖默认配置,这正是官方 compose 文件的对接方式(详见第六节环境变量表)。
三、前置条件
- 一台装有 Docker Engine 与 Compose v2 插件的 Linux 服务器(本文实测 Ubuntu 22.04);
- 磁盘剩余 ≥ 2 GB(两镜像共约 1.1 GB,另加数据库与附件增长);
- 宿主端口 9000 未被占用:
ss -ltn | grep 9000无输出; - 服务器可访问 Docker Hub(拉取镜像;国内环境可自行配置镜像加速器);
- 建工作目录:
mkdir -p /opt/facto-compose && cd /opt/facto-compose。
四、部署步骤
4.1 编写 docker-compose.yml
在 /opt/facto-compose/docker-compose.yml 写入以下内容(基于官方示例,固定版本号并补充 JVM 堆限制与命名):
name: family-accounting-v4.29-stack
services:
db:
image: mariadb:10.3
container_name: facto-db
volumes:
- db_data:/var/lib/mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: q1w2e3r4
MYSQL_DATABASE: facto
web:
depends_on:
- db
command: bin/server
image: nymanjens/facto:v4.29
container_name: facto-web
ports:
- "9000:9000"
restart: unless-stopped
environment:
APPLICATION_SECRET: q1w2e3r4-application-secret-2026
DATABASE_URL: jdbc:mysql://db:3306/facto?user=root&password=q1w2e3r4&disableMariaDbDriver
JAVA_OPTS: "-Xms256m -Xmx256m"
volumes:
db_data: {}
逐项说明:
name:固定 compose 项目名,避免与宿主上其他 compose 项目互相干扰;db服务用官方示例同款mariadb:10.3,MYSQL_DATABASE: facto让容器首次启动自动创建空库facto;数据卷db_data挂到/var/lib/mysql,这是数据持久化的关键(第五节实测验证);web服务command: bin/server覆盖镜像默认命令(镜像本身不带启动命令);depends_on保证 db 先创建;ports: 9000:9000把 Web 界面暴露到宿主 9000;restart: unless-stopped保证开机后自动拉起;JAVA_OPTS限制 JVM 堆在 256MB(家庭规模足够,见第七节)。
4.2 启动数据库
docker compose up -d db
实测输出:
[+] Running 2/2
✔ Network opt_facto-compose_default Created
✔ Container facto-db Started
等待约 10 秒让 MariaDB 完成首次初始化,确认状态:
docker compose ps
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
facto-db mariadb:10.3 "docker-entrypoint.s…" db 11 seconds ago Up 10 seconds 3306/tcp
4.3 初始化:建表与创建管理员
官方 README 规定的初始化方式是用 docker compose run 起一次性容器执行 bin/server 的两个初始化参数。先等数据库就绪(官方做法:sleep 5):
docker compose run --rm web sleep 5
实测输出:
[+] Creating 1/0
✔ Container facto-db Running
创建数据库表:
docker compose run --rm web bin/server -DdropAndCreateNewDb
实测输出(首部 Guice 反射警告略,见收尾关键行):
[info] p.a.d.DefaultDBApi - Database [default] initialized
[info] p.a.d.HikariCPConnectionPool - Creating Pool for datasource 'default'
Dropping the database tables (if present) and creating new ones...
Done. Exiting.
进程输出 Done. Exiting. 后自动退出(--rm 顺带清掉一次性容器)。创建初始管理员:
docker compose run --rm web bin/server -DcreateAdminUser
实测输出:
Creating admin user...
loginName: admin
password: changeme
Done. Exiting.
⚠️ 注意两点:其一,-DdropAndCreateNewDb 会清空重建全部表,仅限首次部署;其二,Docker 形态下初始密码是镜像内置配置的默认值 changeme(发行包方式可通过改 app.setup.defaultPassword 定制,Docker 方式见第八节挂载自定义配置),首次登录后应立即在界面改密。
4.4 启动应用并验证
docker compose up -d
实测输出:
✔ Container facto-db Running
✔ Container facto-web Started
等待约 20 秒(Play 应用启动),确认两个服务均为 Up:
docker compose ps --format '{{.Name}} {{.Status}}'
实测输出:
facto-4.29-compose-db Up 22 seconds
facto-4.29-compose-web Up 22 seconds
查看应用日志确认启动完成:
docker compose logs web | tail -3
实测输出:
facto-4.29-compose-web | [info] p.a.d.HikariCPConnectionPool - Creating Pool for datasource 'default'
facto-4.29-compose-web | [info] play.api.Play - Application started (Prod) (no global state)
facto-4.29-compose-web | [info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
HTTP 层逐项验证:
curl -sI http://localhost:9000/ | head -2
实测输出(未登录首页重定向到登录页):
HTTP/1.1 303 See Other
Location: /login/
curl -s -o /dev/null -w "login page: HTTP %{http_code}\n" http://localhost:9000/login/
curl -s http://localhost:9000/externalapi/healthcheck/ -w " [%{http_code}]\n"
实测输出:
login page: HTTP 200
OK [200]
浏览器访问 http://<服务器IP>:9000/,用 admin / changeme 登录(⚠️ 登录后第一时间进入 /app/useradministration 修改密码)。
4.5 验证 JVM 堆限制生效
镜像内是 JRE(无 jps),用 ps 直接查看进程参数:
docker exec facto-web ps -ef | grep [j]ava | cut -c1-100
实测输出:
root 1 0 24 03:39 ? 00:00:04 /opt/java/openjdk/bin/java -Xms256m -Xmx256m -Du
-Xms256m -Xmx256m 出现在实际命令行即证明 compose 的 JAVA_OPTS 环境变量已生效。
五、数据持久化说明
家庭记账数据全部存放在 db 服务的命名卷 db_data(对应 MariaDB 数据目录 /var/lib/mysql),附件类文件经外部 API 上传后存入数据库。持久化实测过程如下:先经外部 API 写入一笔真实交易(接口用法见 《Family Accounting Tool v4.29 API 使用详解》;命令如下可直接复现):
curl -s -X POST "http://localhost:9000/externalapi/acc/trans/add/q1w2e3r4-application-secret-2026/" -H "Content-Type: text/plain" --data-binary $'transactions:\n - beneficiaryCode: Alice\n moneyReservoirCode: CASH_ALICE\n categoryCode: LIFE\n description: Bakery test\n flowAsFloat: -2.5\n' -w " [%{http_code}]\n"
实测输出:
OK [200]
然后彻底销毁容器与网络再重建(卷会被保留):
docker compose down
实测输出(节选):
Container facto-4.29-compose-web Removed
Container facto-4.29-compose-db Removed
Network family-accounting-v429-stack_facto_net Removed
docker compose up -d
等待约 20 秒后查询刚才那笔交易是否还在:
curl -s "http://localhost:9000/externalapi/acc/trans/search/Bakery/q1w2e3r4-application-secret-2026/" | grep -E '"description"|"flowInCents"'
实测输出(数据完好):
"description":"Bakery test",
"flowInCents":-250,
结论:down(移除容器与网络)后 up,记账数据原样保留,持久化可靠。⚠️ 只有 docker compose down -v 才会连卷一起删除——这是不可逆清库操作,请勿在生产数据上执行。
六、环境变量表
web 服务(facto 应用)支持的环境变量(机制:镜像内 conf/application.conf 以 ${?VAR} 语法读取,均实测生效):
| 环境变量 | 必填 | 示例值 | 作用与默认值 |
|---|---|---|---|
APPLICATION_SECRET | 是 | q1w2e3r4-application-secret-2026 | 覆盖 play.http.secret.key:Play 会话签名密钥,同时是外部 API 鉴权用的 appSecret。不注入时为 changeme(危险,必须改) |
DATABASE_URL | 是 | jdbc:mysql://db:3306/facto?user=root&password=q1w2e3r4&disableMariaDbDriver | 覆盖 db.default.url 完整 JDBC 串。不注入时指向 localhost(容器内无库,必错) |
JAVA_OPTS | 否 | -Xms256m -Xmx256m | JVM 参数,经 bin/server 启动脚本透传给 java 进程(4.5 节实测验证)。不注入时用 JVM 默认堆 |
db 服务(MariaDB)的环境变量:
| 环境变量 | 必填 | 示例值 | 作用 |
|---|---|---|---|
MYSQL_ROOT_PASSWORD | 是 | q1w2e3r4 | MariaDB root 密码(DATABASE_URL 中的密码须与其一致) |
MYSQL_DATABASE | 是 | facto | 首次启动自动创建的库名 |
💡 说明:
DATABASE_URL末尾的disableMariaDbDriver参数来自官方 compose 示例,作用是禁用 MySQL Connector/J 对 MariaDB 服务端版本串的自动探测(该驱动对 MariaDB 10.x 的版本握手有兼容性问题,加此参数强制按 MySQL 协议直连),照抄即可。
七、配置参数说明
容器化形态下 facto 的配置分三层,修改优先级从高到低:
- 环境变量(
APPLICATION_SECRET/DATABASE_URL):只覆盖会话密钥与数据库两项,适合 compose 场景的最小定制; - 挂载自定义
conf/application.conf:覆盖全部 Play 与应用参数(见第八节); - 镜像内置默认值:
/app/conf/application.conf的原始内容(会话密钥changeme、数据库指向 localhost、语言en、会话有效期http.session.maxAge = 60d、WebSocket 帧上限 100M、初始管理员密码app.setup.defaultPassword = "changeme")。
家庭化记账科目/账户/模板则由 conf/accounting-config.yml 声明,默认使用发行包自带的演示配置(Alice/Bob/Common 三账户体系),深度定制方式同样见第八节。
7.1 JVM 内存
facto 为单 JVM 进程,家庭规模(2-6 名成员、日均几十笔流水)堆内存 256–512MB 足够:compose 中通过 environment: JAVA_OPTS: "-Xms256m -Xmx256m" 设置,改后执行 docker compose up -d web 重建生效,并用 4.5 节的 ps -ef | grep [j]ava 命令验证实际参数(实测输出已示)。
八、配置文件挂载
需要自定义 application.conf(例如把初始管理员密码改为 q1w2e3r4、扩大附件目录)或 accounting-config.yml(家庭化科目与成员)时,把文件挂进容器覆盖 /app/conf/ 下的同名文件。步骤:
- 在宿主准备配置目录并放入定制文件(application.conf 完整写法与逐项含义见 《Ubuntu 22.04 安装 Family Accounting Tool v4.29 指南》 4.6 节与 《Family Accounting Tool v4.29 配置参数详解》,此处演示最小两处改动):
mkdir -p /opt/facto-compose/conf
# 复制镜像内默认配置为起点
docker run --rm nymanjens/facto:v4.29 cat /app/conf/application.conf > /opt/facto-compose/conf/application.conf
# 修改初始管理员密码
sed -i 's|setup.defaultPassword = "changeme"|setup.defaultPassword = "q1w2e3r4"|' /opt/facto-compose/conf/application.conf
- 在
docker-compose.yml的web服务下追加挂载:
volumes:
- ./conf/application.conf:/app/conf/application.conf:ro
- 重建 web 服务(⚠️ 首次部署流程中此步应放在 4.3 节初始化之前,
-DcreateAdminUser才会使用新密码):
docker compose up -d web
实测输出:
✔ Container facto-web Started
验证挂载内容进容器:
docker exec facto-web grep defaultPassword /app/conf/application.conf
实测输出:
setup.defaultPassword = "q1w2e3r4"
accounting-config.yml 同理挂载到 /app/conf/accounting-config.yml;修改后 docker compose restart web 生效。
九、等价 docker run 部署
不用 compose 时,以下三条 docker run 序列与第四节完全等价(实测通过,部署后健康检查返回 OK [200]、登录页返回 HTTP 200)。先建网络与数据库:
docker network create facto-net
docker run -d --name facto-db --network facto-net \
-e MYSQL_ROOT_PASSWORD=q1w2e3r4 -e MYSQL_DATABASE=facto \
-v facto-dbdata:/var/lib/mysql \
mariadb:10.3
等 10 秒后执行两个一次性初始化容器(与 4.3 节同参数,实测输出同为 Done. Exiting.):
docker run --rm --network facto-net \
-e APPLICATION_SECRET=q1w2e3r4-application-secret-2026 \
-e DATABASE_URL="jdbc:mysql://facto-db:3306/facto?user=root&password=q1w2e3r4&disableMariaDbDriver" \
nymanjens/facto:v4.29 bin/server -DdropAndCreateNewDb
docker run --rm --network facto-net \
-e APPLICATION_SECRET=q1w2e3r4-application-secret-2026 \
-e DATABASE_URL="jdbc:mysql://facto-db:3306/facto?user=root&password=q1w2e3r4&disableMariaDbDriver" \
nymanjens/facto:v4.29 bin/server -DcreateAdminUser
启动常驻应用:
docker run -d --name facto-web --network facto-net -p 9000:9000 \
-e APPLICATION_SECRET=q1w2e3r4-application-secret-2026 \
-e DATABASE_URL="jdbc:mysql://facto-db:3306/facto?user=root&password=q1w2e3r4&disableMariaDbDriver" \
nymanjens/facto:v4.29 bin/server
💡 技术拓展:容器编排形态除了本文的 Compose,常见还有——
形态 特点 适用场景 docker run 序列 零依赖、直观,但多条命令难维护 单机临时验证 Docker Compose 单文件声明、 up/down一键、重启策略内建单机生产/家庭服务器(本文采用) Kubernetes/ Helm 自愈、扩缩容、滚动升级 多节点集群与大规模部署 家庭记账是单机单实例场景,无高可用诉求,Compose 是复杂度与可靠性的最佳平衡点。
验证与清理:
curl -s http://localhost:9000/externalapi/healthcheck/ -w " [%{http_code}]\n" # OK [200]
docker rm -f facto-web facto-db && docker network rm facto-net && docker volume rm facto-dbdata
十、常用运维命令
以下命令均在 compose 项目目录内执行(实测可用):
docker compose ps # 查看服务状态(4.2/4.4 节实测输出)
docker compose logs -f web # 跟踪应用日志(Ctrl+C 退出)
docker compose logs web | tail -3 # 查看启动日志尾部(4.4 节实测输出)
docker compose restart web # 重启应用(改配置/挂载后用)
docker compose up -d web # 重建 web 服务(改 compose 文件后用)
docker compose down # 停止并移除容器与网络(数据卷保留,第五节实测)
docker compose up -d # 从停止状态恢复全套服务
docker compose down -v # ⚠️ 彻底清库(含数据卷),不可逆
docker exec facto-web ps -ef | grep [j]ava # 查看 JVM 实际参数(4.5 节实测输出)
升级到新版本(以 v4.30 之后的某个带镜像标签的版本为例):改 docker-compose.yml 中 image: 标签 → docker compose up -d → 浏览器验证;升级前建议 docker compose exec db sh -c 'mariadb-dump -uroot -p$MYSQL_ROOT_PASSWORD facto' > facto-backup.sql 做数据库备份。
十一、常见问题(FAQ)
Q1:为什么官方说 Docker 形态 discouraged?还能用吗
作者的顾虑集中在两点:默认镜像配置不可改(初始密码固定 changeme、附件目录等),以及早期版本对数据卷处理不够体贴(来源:仓库 issue #4)。本文已用两个手段补齐:挂载自定义 application.conf(第八节,实测挂载生效)与命名卷持久化验证(第五节,销毁重建后数据完好)。补齐后长期运行没有问题;若仍希望完全按作者推荐路线,请使用发行包方式安装。
Q2:首次登录密码是什么?改密码在哪改
admin / changeme(镜像内置默认值,4.3 节 -DcreateAdminUser 实测输出可证)。登录后进入 http://<服务器IP>:9000/app/useradministration 界面修改;或在部署前按第八节挂载自定义 application.conf 并设置 app.setup.defaultPassword,则 -DcreateAdminUser 一步到位生成指定密码。
Q3:web 起不来,日志报连接数据库失败
按顺序排查:docker compose ps 看 db 是否 Up;docker compose logs db 看首次初始化是否完成(MariaDB 首启约需 10 秒,期间 web 连不上是正常现象,restart: unless-stopped 会自动重试);核对 DATABASE_URL 中主机名 db 与服务名一致、密码与 MYSQL_ROOT_PASSWORD 一致、disableMariaDbDriver 参数未漏(见第六节说明)。
Q4:-DdropAndCreateNewDb 可以随时跑吗
不可以。实测日志明确显示其行为是「Dropping the database tables (if present) and creating new ones...」——存在表也照样删。仅限首次部署,或明确要清空全部记账数据时使用。
Q5:想升级到新版本,镜像怎么选
先到 Docker Hub Tags 页确认新版本有无对应镜像标签(本文写作时 v4.30 标签无镜像、Docker Hub 最新为 v4.29,实查时间 2026-10-23);有则改 image: 标签 up -d 升级,无则等作者推镜像,或走发行包方式安装新版本。升级前务必备份数据库(第十节命令)。
十二、参考链接
- 官方仓库 compose 示例:
https://github.com/nymanjens/facto/blob/v4.29/docker-compose.yml - 官方 README「Installation with Docker (discouraged)」节:
https://github.com/nymanjens/facto - Docker 形态讨论(issue #4):
https://github.com/nymanjens/facto/issues/4 - Docker Hub 镜像页(标签与更新时间):
https://hub.docker.com/r/nymanjens/facto/tags - MariaDB 10.3 官方镜像:
https://hub.docker.com/_/mariadb - Compose 文件参考(
name:/depends_on/volumes语义):https://docs.docker.com/compose/compose-file/