首页
/ 使用 Docker Compose 自托管 Maybe:从安装、安全配置到镜像更新的完整部署指南

使用 Docker Compose 自托管 Maybe:从安装、安全配置到镜像更新的完整部署指南

2026-09-05 13:31:34作者:裘晴惠Vivianne

本篇技术指南基于 Maybe 仓库的官方自托管文档 docs/hosting/docker.md 展开,覆盖用 Docker Compose 部署 Maybe 的完整流程:安装 Docker、获取并理解 Compose 配置、生成 SECRET_KEY_BASE 等安全环境变量、以前台/后台模式运行应用,以及基于 GHCR 镜像的日常更新与版本固定。读完后你可以独立搭建、维护一台自托管的 Maybe 实例,并能看懂仓库中 compose.example.ymlDockerfile 的关键实现细节。

一、前置准备:安装并验证 Docker

自托管 Maybe 最推荐的方式是 Docker Compose,它负责一次性拉起应用、数据库和缓存三个服务。准备工作分三步:

  1. 按 Docker 官方安装指南安装 Docker Engine(支持 Linux、macOS 等平台);
  2. 启动本机的 Docker 服务;
  3. 在终端运行验证命令,确认 Docker 已正确安装并处于运行状态:
# 如果 Docker 配置正确,该命令会成功执行
docker run hello-world

该命令会从镜像仓库拉取一个最小镜像并运行;只要能看到成功输出,说明后续步骤所需的环境已就绪。

二、创建部署目录并获取 Compose 配置文件

首先为应用创建一个专属运行目录(目录名可自定,下例采用推荐命名):

# 在电脑上创建存放 Docker 文件的目录(名称可任意)
mkdir -p ~/docker-apps/maybe

# 将当前工作目录切换到新文件夹
cd ~/docker-apps/maybe

然后在当前目录下下载仓库提供的示例 Compose 文件并另存为 compose.yml

# 从 Maybe 的 GitHub 仓库下载示例 compose 文件
curl -o compose.yml https://raw.githubusercontent.com/maybe-finance/maybe/main/compose.example.yml

这条命令做了两件事:

  1. 从 Maybe 的公开仓库拉取示例 Docker Compose 文件(即仓库中的 compose.example.yml);
  2. 在当前目录生成一个名为 compose.yml 的文件,内容即该示例文件。

执行完毕后,当前目录下应该只有 compose.yml 一个文件。你也可以跳过下载,直接从仓库中阅读 compose.example.yml 的内容并自行保存为 compose.yml

三、读懂 compose.example.yml:四个服务与关键环境变量

compose.example.yml 是一个开箱即用的标准配置,但如果你想了解它实际做了什么,可以对照仓库源文件逐段阅读。该文件由四个服务、三个卷(volume)和一个网络组成:

服务 镜像 作用
web ghcr.io/maybe-finance/maybe:latest Rails 主应用,对外暴露 3000 端口
worker 同上,command: bundle exec sidekiq Sidekiq 后台任务进程
db postgres:16 PostgreSQL 数据库,数据挂载到 postgres-data
redis redis:latest Redis 缓存/队列,数据挂载到 redis-data

几个值得注意的设计(均来自 compose.example.yml 原文):

  • 环境变量复用:文件顶部用 YAML anchor 定义了 x-db-envPOSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB)和 x-rails-env(在 db 变量基础上追加应用变量),四个服务通过锚点引用,保证配置一致。
  • 带默认值的变量:所有变量都提供了默认值,例如 POSTGRES_USER 默认 maybe_userPOSTGRES_PASSWORD 默认 maybe_passwordPOSTGRES_DB 默认 maybe_production——这正是文档说"默认零配置即可运行"的原因。这也解释了为什么应用侧 config/database.yml 中 production 环境通过 ENV.fetch("POSTGRES_DB") { "maybe_production" } 读取库名,并通过 DB_HOST/DB_PORT 定位数据库(Compose 中固定为 DB_HOST: dbDB_PORT: 5432)。
  • 健康检查与依赖顺序dbpg_isready 做 healthcheck,redisredis-cli ping 做 healthcheck;web 服务声明 depends_oncondition: service_healthy,确保数据库就绪后才启动应用。
  • SELF_HOSTED: "true":应用通过该变量识别自身处于自托管模式。从源码结构看,config/application.rbapp_mode 正是在 SELF_HOSTED == "true" 时取值为 self_hosted,否则为 managed,该模式会影响应用内展示的行为(例如托管模式下的升级提示)。
  • REDIS_URL: redis://redis:6379/1:Sidekiq 队列连接 Redis 的 1 号库。后台任务的队列配置见 config/sidekiq.yml,包含 scheduledhigh_prioritymedium_prioritylow_prioritydefault 五条队列,并发数由 RAILS_MAX_THREADS(默认 3)决定——worker 服务正是承载这些任务的进程。
  • 数据卷app-storage 挂载到容器内 /rails/storage(对应 Dockerfile 中预置的 storage 目录),postgres-dataredis-data 分别保存数据库与缓存数据。三个卷都是持久化更新的关键:更新镜像时数据不会丢失。
  • 可选的 OPENAI_ACCESS_TOKEN:文件中以注释明确提醒,启用后使用 AI 相关功能(聊天、规则)会产生费用,建议先在账户中设置好消费上限再配置。

四、(可选)创建 .env 文件加强安全性

compose.example.yml 默认无需任何配置即可运行。但如果你要把实例暴露在局域网之外的公网环境,建议按文档补充环境变量以增强安全性;仅本机使用且不在意安全性的话可以跳过本节。

1. 创建 .env 文件

Docker 从名为 .env 的文件读取环境变量,用以下命令创建空文件:

touch .env

2. 生成 SECRET_KEY_BASE

应用运行依赖环境变量 SECRET_KEY_BASE。安装 openssl 的话可以直接生成:

openssl rand -hex 64

如果没有 openssl,也可以用这条零依赖的 bash 命令生成同样长度的十六进制密钥:

head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n' && echo

生成后妥善保存该密钥,进入下一步。

3. 填写 .env 文件

用任意文本编辑器打开刚才创建的 .env,填入以下变量:

SECRET_KEY_BASE="replacemewiththegeneratedstringfromthepriorstep"
POSTGRES_PASSWORD="replacemewithyourdesireddatabasepassword"

其中 SECRET_KEY_BASE 替换为上一步生成的字符串,POSTGRES_PASSWORD 替换为你想要的数据库密码。这两个变量会分别覆盖 compose.example.ymlx-rails-envx-db-env 里对应的默认值。

五、启动应用并创建账号

一切就绪,先用前台模式启动,便于观察日志、确认无误:

docker compose up

该命令会拉取官方 Docker 镜像并启动全部服务,终端中会滚动输出日志。随后打开浏览器访问 http://localhost:3000,如果一切正常,你会看到 Maybe 的登录页。

这里的"首次启动即自动建库"并非魔法。镜像的入口脚本是 bin/docker-entrypoint,其逻辑只有两行核心判断:当被执行的命令是 ./bin/rails server 时,先执行 ./bin/rails db:prepare(创建或迁移数据库),再 exec 启动原始命令。而 Dockerfile 正是将 ENTRYPOINT 指向该脚本、CMD 默认为 ./bin/rails serverEXPOSE 3000,与 Compose 文件中 3000:3000 的端口映射对应。

首次运行时需要注册账号:在登录页点击 "create your account",填入邮箱和密码即可。

六、后台运行与状态检查

自托管用户通常希望 Maybe 常驻后台。按 Ctrl+C 停止前台进程后执行:

docker compose up -d

-d 参数让 Docker Compose 以 detached(分离)模式运行。可用以下命令验证其处于运行状态:

docker compose ls

此后实例即可持续通过 http://localhost:3000 访问。由于三个卷(app-storagepostgres-dataredis-data)都是具名卷,容器重启不会丢失账号、账户数据与交易记录。

七、更新自托管应用:GHCR 镜像与更新流程

更新自托管 Maybe 的核心机制是 compose.yml 中引用的 GHCR(GitHub Container Registry)镜像:

image: ghcr.io/maybe-finance/maybe:latest

官方推荐两种镜像 tag,也可以自行固定到任意版本:

  • ghcr.io/maybe-finance/maybe:latest——对应 main 分支最新提交;
  • ghcr.io/maybe-finance/maybe:stable——对应最新发布版本。

从发布流水线的源码可以印证这两个 tag 的生成规则:.github/workflows/publish.yml 中,推送 main 分支时打 latest 标签,推送 v* 开头的版本 tag 时打 stable 标签;且镜像为 linux/amd64,linux/arm64 双架构构建(第 79 行),因此 x86 与 ARM(如 Apple Silicon、树莓派类设备)宿主机均可直接拉取。

需要强调的是:默认情况下你的应用不会自动更新。手动更新时,在部署目录中依次执行:

cd ~/docker-apps/maybe            # 进入当初配置应用的目录
docker compose pull                # 从 GHCR 拉取最新发布的镜像
docker compose build               # 基于更新后的镜像重建应用
docker compose up --no-deps -d web worker   # 用最新版本重启应用服务

其中 --no-deps 表示不连带重启 dbredis 等依赖服务,只重启 webworker 两个应用服务,避免无谓地触碰数据库容器。

八、固定版本(版本回退/锁定)

如果希望把应用锁定在特定版本或 tag 上,只需编辑 compose.yml

image: ghcr.io/maybe-finance/maybe:stable

修改后务必重启应用使新镜像生效:

docker compose pull    # 从 GHCR 拉取镜像
docker compose build   # 重建应用
docker compose up --no-deps -d web worker   # 用最新版本重启

注意:compose.example.ymlwebworker 两个服务需要分别设置 image 字段,锁定版本时两处保持一致即可。

九、故障排查:ActiveRecord::DatabaseConnectionError

如果第一次启动 Maybe 时遇到数据库连接问题(ActiveRecord::DatabaseConnectionError),很可能是 Docker 之前已经用一个不同的默认角色初始化过 Postgres 数据库(通常源于先前某次启动尝试的残留数据)。

此时可以选择重置数据库

注意:该操作会删除 Maybe 数据库中已有的所有数据,请谨慎执行。 对只是想把应用跑起来的初次使用者,一般可以安全地执行以下命令:

docker compose down
docker volume rm maybe_postgres-data   # 数据库挂载的卷名
docker compose up
docker exec -it maybe-postgres-1 psql -U maybe -d maybe_production -c "SELECT 1;"   # 验证问题已修复

执行上述命令后,原有的 Maybe 数据库会被删除并重新初始化。补充一点细节:验证命令中的用户名需与实际初始化角色一致——示例 Compose 中 POSTGRES_USER 的默认值是 maybe_user(见 compose.example.ymlx-db-env 锚点),如果你在 .env 中未改过它,验证时应使用 psql -U maybe_user -d maybe_production,数据库容器名也可能因 compose 项目名不同而有所变化,可先用 docker compose ps 查看实际容器名。

十、延伸阅读:镜像构建与部署相关文件

本文以部署文档为主线,以下仓库文件是理解其背后的关键依据,建议进一步阅读:

按照本文流程,你可以完成 Maybe 自托管实例的完整生命周期管理:安装依赖、生成密钥、启动与验证、后台常驻、拉取更新以及故障时的数据库重置。

登录后查看全文
热门项目推荐
相关项目推荐