Family Accounting Tool v4.29 Docker Compose 部署指南

用 Docker Compose 部署 Family Accounting Tool v4.29:镜像选型、初始化建库建号、数据持久化实测、环境变量与配置挂载、等价 docker run 与运维命令。

Family Accounting Tool财务记账自托管2026/10/23

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 / latest2026-08-01v4.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 -Xmx256mJVM 参数,经 bin/server 启动脚本透传给 java 进程(4.5 节实测验证)。不注入时用 JVM 默认堆

db 服务(MariaDB)的环境变量:

环境变量必填示例值作用
MYSQL_ROOT_PASSWORD是q1w2e3r4MariaDB root 密码(DATABASE_URL 中的密码须与其一致)
MYSQL_DATABASE是facto首次启动自动创建的库名

💡 说明:DATABASE_URL 末尾的 disableMariaDbDriver 参数来自官方 compose 示例,作用是禁用 MySQL Connector/J 对 MariaDB 服务端版本串的自动探测(该驱动对 MariaDB 10.x 的版本握手有兼容性问题,加此参数强制按 MySQL 协议直连),照抄即可。

七、配置参数说明

容器化形态下 facto 的配置分三层,修改优先级从高到低:

  1. 环境变量(APPLICATION_SECRET/DATABASE_URL):只覆盖会话密钥与数据库两项,适合 compose 场景的最小定制;
  2. 挂载自定义 conf/application.conf:覆盖全部 Play 与应用参数(见第八节);
  3. 镜像内置默认值:/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/ 下的同名文件。步骤:

  1. 在宿主准备配置目录并放入定制文件(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
  1. 在 docker-compose.yml 的 web 服务下追加挂载:
    volumes:
      - ./conf/application.conf:/app/conf/application.conf:ro
  1. 重建 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/