OpnForm v2.8.1 常用 CLI 命令与工具详解

OpnForm v2.8.1 自托管实例的 CLI 工具链实战:docker compose 编排、artisan 诊断/缓存/队列、psql 与 redis-cli 直连、pg_dump 备份与 curl 健康探测,全部命令与回显取自真实部署实例实测。

OpnFormOpnForm表单构建DockerDocker ComposePostgreSQLRedis2026/11/02

OpnForm v2.8.1 常用 CLI 命令与工具详解

目标:把 OpnForm v2.8.1 自托管实例日常运维要用的 CLI 工具链——Docker Compose 编排命令、Laravel artisan 管理命令、psql/redis-cli 直连工具、pg_dump 备份与 curl 健康探测——逐条讲清用法、参数与真实回显。所有命令均在 2026-11-01/02 部署完成的真实实例上实测执行。

一、环境信息

  • 宿主:Linux x86_64(内网 IP 192.168.1.172),Docker 29.9.2(Docker version 29.9.2, build a82e528),Docker Compose v5.6.1
  • OpnForm:v2.8.1,Laravel Framework 12.70.1(artisan --version 实测),PHP 8.3.36,PostgreSQL 16.15,Redis 7
  • 部署目录:/opt/data/quzuo/tmp/opnform/OpnForm,对外端口 8161
  • 7 服务:api / api-worker / api-scheduler(同一镜像 jhumanj/opnform-api:latest)、ui(jhumanj/opnform-client:latest)、db(postgres:16)、redis(redis:7)、ingress(nginx:1)
  • artisan 在容器内的路径:/usr/share/nginx/html/artisan(healthcheck 即写全路径)
  • 演示账号:g25admin@example.com / G25test@12345
  • 实例状态基线:forms=1(slug g25-spqlvr)、form_submissions=2、users=1(psql 实测)

本文所有 compose 命令统一使用双文件前缀(override 文件把入口端口钉在 8161):

cd /opt/data/quzuo/tmp/opnform/OpnForm
docker compose -f docker-compose.yml -f docker-compose.override.yml <子命令>

二、工具概览

工具入口职责
docker compose宿主,部署目录内起停/重建/日志/exec 七服务
php artisanexec -T api php artisan <cmd>运行时诊断、迁移、缓存、队列、调度器状态
psql / pg_isreadyexec -T db psql / exec -T db pg_isready数据核对、连接检查、绕过 artisan 的库级查询
redis-cliexec -T redis redis-cli <cmd>缓存/队列/会话侧排查
pg_dumpexec -T db pg_dump <db>逻辑备份
curl宿主/api/healthcheck 与 API 冒烟

表中入口列省略了公共前缀 docker compose -f docker-compose.yml -f docker-compose.override.yml(见第一章);正文所有命令均给出完整形式,可直接照抄执行。

💡 技术拓展:OpnForm 备份不止 pg_dump 一条路。对比——

渠道覆盖特点
pg_dump 逻辑备份数据库 44 张表跨版本可移植、可单表恢复;不含上传附件
数据卷快照/cppostgres-data + opnform_storage全量但绑定存储驱动与同版本恢复
PostgreSQL 流复制数据库实时副本高可用级,单实例自托管一般不需要

本方案采用 pg_dump + 单独打包 opnform_storage 卷的组合(见 4.6),附件目录不可漏。

三、前置条件

  1. 实例已按 《OpnForm v2.8.1 Docker Compose 部署指南》 部署且 setup 完成。
  2. 七服务 healthy(实测基线,见 4.1 的 ps 回显)。
  3. exec 建议带 -T(禁用 TTY 分配):本文所有实测回显均以 -T 采集,管道/脚本环境下不加 -T 可能报 the input device is not a TTY。

四、各工具详解

4.1 docker compose 编排命令

ps——状态总览:

docker compose -f docker-compose.yml -f docker-compose.override.yml ps

实测回显(7 服务全 healthy,仅 ingress 有宿主端口):

NAME                    IMAGE                           COMMAND                  SERVICE         CREATED          STATUS                    PORTS
opnform-api             jhumanj/opnform-api:latest      "/usr/local/bin/opnf…"   api             9 minutes ago    Up 9 minutes (healthy)    9000/tcp
opnform-api-scheduler   jhumanj/opnform-api:latest      "/usr/local/bin/opnf…"   api-scheduler   9 minutes ago    Up 9 minutes (healthy)    9000/tcp
opnform-api-worker      jhumanj/opnform-api:latest      "/usr/local/bin/opnf…"   api-worker      9 minutes ago    Up 9 minutes (healthy)    9000/tcp
opnform-client          jhumanj/opnform-client:latest   "docker-entrypoint.s…"   ui              9 minutes ago    Up 9 minutes (healthy)
opnform-db              postgres:16                     "docker-entrypoint.s…"   db              20 minutes ago   Up 20 minutes (healthy)   5432/tcp
opnform-ingress         nginx:1                         "/docker-entrypoint.…"   ingress         18 minutes ago   Up 8 minutes (healthy)    0.0.0.0:8161->80/tcp, [::]:8161->80/tcp
opnform-redis           redis:7                         "docker-entrypoint.s…"   redis           20 minutes ago   Up 20 minutes (healthy)   6379/tcp

解读:STATUS 列的 (healthy) 来自 compose 各服务 healthcheck——api 用 php artisan about、worker 用 pgrep -f 'php artisan queue:work'、scheduler 用 artisan app:scheduler-status --mode=check --max-minutes=3、ui 用 wget --spider -q http://localhost:3000/login、db 用 pg_isready、redis 用 redis-cli ping、ingress 用 nginx -t && curl -f http://localhost/。排障时先定位哪个服务 unhealthy,再按对应 healthcheck 命令手工复现。

logs——日志跟踪:

docker compose -f docker-compose.yml -f docker-compose.override.yml logs --tail=5 api

实测回显:

opnform-api  | 172.21.0.8 -  01/Nov/2026:20:25:36 +0000 "POST /index.php" 422
opnform-api  | 172.21.0.8 -  01/Nov/2026:20:26:06 +0000 "POST /index.php" 422
opnform-api  | 172.21.0.8 -  01/Nov/2026:20:26:06 +0000 "POST /index.php" 422
opnform-api  | 172.21.0.8 -  01/Nov/2026:20:26:12 +0000 "POST /index.php" 400
opnform-api  | 172.21.0.8 -  01/Nov/2026:20:26:12 +0000 "POST /index.php" 422

解读:LOG_CHANNEL=errorlog 使 Laravel 请求日志走 PHP error_log → 容器 stdout;来源 IP 172.21.0.8 是 ingress 容器、请求路径记为 /index.php 是 fastcgi 转发的结果(原始 URI 由 REQUEST_URI 参数传入)。422 行对应本文写作期间的参数纠偏实验请求,属预期。logs -f <svc> 实时跟踪。

down/up——单服务重建(改 env 唯一生效路径):

docker compose -f docker-compose.yml -f docker-compose.override.yml down api
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d

实测:Compose v5.6.1 接受 down 带服务名,仅停止并移除该服务容器;伴随输出 Network opnform_default Resource is still in use 为无害警告(网络被其余服务占用,删不掉属正常)。改 api/.env 后 restart api 实测不加载新值(容器内 printenv 仍 rc=1),必须走本对命令;api-worker/api-scheduler 共享同一 env_file,应一并重建。重建 api/ui 后补一条 docker compose -f docker-compose.yml -f docker-compose.override.yml restart ingress,规避 nginx 缓存旧上游 IP 导致的 502(实测闭环)。

pull + up -d——官方更新路径:

docker compose -f docker-compose.yml -f docker-compose.override.yml pull
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d

官方维护文档(docker.mdx)给出的升级两步:先 pull 新镜像,再 up -d 只重建镜像有变化的服务。用 latest 标签时建议更新前先在容器内记录 printenv APP_VERSION_DOCKER(本环境实测 2.8.1),更新后复查确认版本推进。

4.2 artisan 运行时诊断

artisan 命令统一通过 exec 进入 api 容器执行(完整前缀如下,本文所有 artisan 命令均可照抄):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan <命令>

about——全景体检(api healthcheck 同款):

  Application Name ................................................... OpnForm
  Laravel Version .................................................... 12.70.1
  PHP Version ......................................................... 8.3.36
  Environment ..................................................... production
  Debug Mode ............................................................. OFF
  URL ..................................................... 192.168.1.172:8161
  Maintenance Mode ....................................................... OFF
  Config / Events / Routes / Views ................................. CACHED
  Cache / Queue / Session .............................................. redis
  Database ............................................................. pgsql
  Logs .............................................................. errorlog
  Mail ................................................................... log
  public/storage ...................................................... LINKED

输出节选(实测首尾,完整回显含 Composer/Sentry 段)。要点:Debug Mode=OFF 是生产硬指标;Mail=log 表示邮件不外发(见 《配置参数详解》 5.10 与 FAQ 7.4);Sentry 段 Data Collection=NOT SET / Enabled=MISSING DSN 说明未配置错误上报属正常默认。

--version:

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan --version
# Laravel Framework 12.70.1

migrate:status——迁移核对:

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan migrate:status

实测输出节选(实测首尾):

  Migration name .............................................. Batch / Status
  2014_10_12_000000_create_users_table ............................... [1] Ran
  2014_10_12_100000_create_password_resets_table ..................... [1] Ran
  2016_06_01_000001_create_oauth_auth_codes_table .................... [1] Ran
  …
  2026_10_22_000000_add_agent_form_draft_version_history ............. [1] Ran

全部 [1] Ran:setup 期一次性跑完全部迁移、批次号=1、无 Pending。升级镜像后若出现 Pending,由 api 容器入口脚本自动补跑;人工核对用本命令。

db:show / db:table——库级概览(含镜像缺陷实测):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan db:show

实测回显(输出节选(实测首尾)——摘要段完整,尾部为崩溃报错原文):

  PostgreSQL ................................. 16.15 (Debian 16.15-1.pgdg13+2)
  Connection ........................................................... pgsql
  Database ............................................................. forge
  Host .................................................................... db
  Port .................................................................. 5432
  Username ............................................................. forge
  Open Connections ......................................................... 6
  Tables .................................................................. 44

In Number.php line 453:
  The "intl" PHP extension is required to use the [format] method.

⚠️ 实测发现:官方 api 镜像未装 PHP intl 扩展,db:show/db:table 在格式化表体积时必崩(db:table forms 同样先输出 Columns ... 67 后同错)。摘要段仍可用;需要逐表数据时改用 psql(4.5)。

4.3 artisan 缓存与配置管理

四条命令实测回显(前后成套执行,最后重新 config:cache 恢复基线):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan config:cache
#    INFO  Configuration cached successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan config:clear
#    INFO  Configuration cache cleared successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan route:clear
#    INFO  Route cache cleared successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan cache:clear
#    INFO  Application cache cleared successfully.
docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan config:cache   # 恢复:about 的 Config=CACHED 基线
#    INFO  Configuration cached successfully.

用途区分:config:cache 把 .env+config 编译为缓存(about 里 Config=CACHED 即此态),改 .env 后必须重建容器再跑才有意义;cache:clear 清的是应用数据缓存(redis db),官方维护文档把它列为前端异常/设置不刷新时的第一动作;route:clear 清路由缓存。storage:link 幂等验证:

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan storage:link
#    ERROR  The [public/storage] link already exists.

报错原文即"已链接",与 about 的 public/storage=LINKED 互证,无需处理。

4.4 artisan 队列与调度器

queue:work:常驻进程由 api-worker 服务承担(compose command: ["php","artisan","queue:work"]),不要在 api 里手工再起第二个(会抢任务)。验证 worker 活着用 healthcheck 同款命令:

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api-worker pgrep -f 'php artisan queue:work'
# 1

回显 1 为进程 PID(容器内主进程)。提交落库依赖它:匿名 answer 返回 submission_id:null 属正常异步,约 5-8 秒(实测)后可见;持续不可见先查这里,再看 logs api-worker。

schedule:work 与 app:scheduler-status:api-scheduler 常驻 php artisan schedule:work。OpnForm 自定义命令 app:scheduler-status 记录/检查调度器心跳(artisan list 实测描述:"Records or checks the scheduler last run timestamp, conditional on self-hosted mode."):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T api php artisan app:scheduler-status --mode=check --max-minutes=3
# Scheduler is healthy. Last ran: 32 seconds ago

rc=0。这正是 api-scheduler healthcheck 的判据:调度器超过 3 分钟没跑即 unhealthy。

4.5 psql 与 redis-cli 直连

pg_isready(db healthcheck 同款):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db pg_isready
# /var/run/postgresql:5432 - accepting connections

psql 数据核对(口令 forge 由 compose ①层注入,见《配置参数详解》5.3):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db \
  psql -U forge -d forge -tc "select (select count(*) from forms), (select count(*) from form_submissions), (select count(*) from users);"
#      1 |     2 |     1

与 API 侧闭环结果一致(1 表单 / 2 提交 / 1 用户)。db:table 崩溃时的表结构替代查询——psql 的 \d forms 实测:67 列(与 db:table forms 崩溃前打印的 Columns ... 67 互证),关键列 properties json not null、visibility 默认 public、presentation_style 默认 classic、size 默认 md、width 默认 centered(与建表单 API 的枚举校验一一对应);索引 forms_pkey / forms_slug_index / forms_workspace_id_index,外键 creator_id → users.id(CASCADE)。

redis-cli(redis healthcheck 同款):

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T redis redis-cli ping
# PONG

队列积压排查:redis-cli llen queues:default(Laravel redis 队列的默认列表键)实测回显 0;redis-cli --scan --pattern 'queues*' 实测返回空——当前没有任何 queues:* 键(llen 对不存在的键同样返回 0,两者互证无积压)。有积压时 llen 给出等待任务数,配合 logs api-worker 定位消费端。

4.6 pg_dump 逻辑备份

docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db \
  pg_dump -U forge forge | gzip > /opt/data/quzuo/tmp/opnform/backup-$(date +%F).sql.gz

实测产物:backup-test.sql.gz 14001 字节(空库+2 提交规模)。恢复:gunzip -c 文件 | docker compose -f docker-compose.yml -f docker-compose.override.yml exec -T db psql -U forge -d forge。附件卷单独打包:

docker run --rm -v opnform_opnform_storage:/data -v /opt/data/quzuo/tmp/opnform:/backup alpine \
  tar czf /backup/storage-$(date +%F).tar.gz -C /data .

⚠️ 注意:卷名带项目前缀 opnform_(setup.log 实测 Volume opnform_opnform_storage Creating),换目录部署会新建空卷,备份前先 docker volume ls | grep opnform 核对。

4.7 curl 健康探测与 API 冒烟

自托管专用健康端点(仅 self_hosted 注册,api/routes.php L54-56):

curl -s http://192.168.1.172:8161/api/healthcheck
# {"status":"ok","dependencies":{"database":true,"redis":true}}

适合拨测:一次请求同时验证 ingress→api→pgsql→redis 全链路。冒烟三连(实测):

curl -s http://192.168.1.172:8161/forms/g25-spqlvr | grep -o '<title>[^<]*</title>'
# <title>G25 反馈表单 - OpnForm</title>
curl -s http://192.168.1.172:8161/api/forms/g25-spqlvr/view
# {"type":"success","message":"Form viewed."}
curl -s -X POST http://192.168.1.172:8161/api/login -H 'Content-Type: application/json' \
  -d '{"email":"g25admin@example.com","password":"G25test@12345","remember":false}' | head -c 60
# {"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJod

要点:登录路径 /api/login(/api/auth/login 实测 404);响应字段名 token 而非 access_token;expires_in:86400 对应 JWT_TTL=1440 分钟。

4.8 artisan 命令清单速查

artisan list 实测节选(本文档涉及项):

Laravel Framework 12.70.1
  about                                                     Display basic information about your application
  app:scheduler-status                                      Records or checks the scheduler last run timestamp, conditional on self-hosted mode.
  cache:clear                                               Flush the application cache
  config:cache                                              Create a cache file for faster configuration loading
  db:monitor                                                Monitor the number of connections on the specified database
  db:seed                                                   Seed the database with records
  db:show                                                   Display information about the given database
  db:table                                                  Display information about the given database table
  db:wipe                                                   Drop all tables, views, and types
  migrate                                                   Run the database migrations
  migrate:fresh / migrate:install / migrate:refresh / migrate:reset / migrate:rollback

⚠️ 注意:db:wipe、migrate:fresh、migrate:reset 会清空/重建全部数据,生产环境禁用;db:monitor 可循环观察连接数(db:show 实测 Open Connections=6)。

五、注意事项

  1. exec 一律 -T:非交互环境(脚本、管道)不加 -T 可能因 TTY 分配失败;-T 下回显可直接入文档入日志。
  2. 三个 api 服务共享镜像与 env_file:artisan 命令在哪个容器执行结果等价,但长驻进程(queue:work/schedule:work)只在 worker/scheduler 里跑;改 api/.env 后三个服务一起 down/up,避免配置漂移(实测三容器 printenv 同步生效)。
  3. 重建 api/ui 后 restart ingress:nginx 缓存上游 IP,不重启会 502(实测闭环,见 4.1)。
  4. db:show/db:table 崩溃是镜像缺 intl 扩展:摘要段可用,明细走 psql;不要误判为数据库故障。
  5. Windows 检出源码注意 LF:api/artisan 变 CRLF 会让容器卡 "Waiting for DB to be ready",修复 sed -i 's/\r$//' api/artisan(官方排障)。
  6. down 单服务的网络警告无害:Network opnform_default Resource is still in use 不影响该服务重建。

六、常见问题

6.1 db:show 报 "The intl PHP extension is required"

官方 api 镜像已知限制(实测),命令已输出库版本/表数摘要后在体积格式化处崩溃。替代:exec -T db psql -U forge -d forge -c "\dt" 或 -c "select count(*) from <表>"。

6.2 提交一直不落库

顺序排查:exec -T api-worker pgrep -f 'php artisan queue:work'(实测回显 PID)→ logs api-worker → 在 api 容器执行 php artisan about(完整前缀见 4.2)确认 Queue=redis → exec -T redis redis-cli ping(PONG)。队列驱动 redis 时 worker 挂了提交永远不可见。

6.3 api-scheduler 显示 unhealthy

healthcheck 判据是 app:scheduler-status --mode=check --max-minutes=3(超 3 分钟未跑即失败)。手工执行实测 Scheduler is healthy. Last ran: 32 seconds ago;若报 stale,logs api-scheduler 看 schedule:work 是否异常,必要时按 4.1 重建该服务。

6.4 改完 .env 用 restart 无效

restart 不加载 env_file 新值(实测 printenv rc=1),必须 down <svc> && up -d,随后 restart ingress。详见《配置参数详解》3.2 的闭环实验。

6.5 前端页面异常/设置不刷新

官方维护路径:exec -T api php artisan cache:clear(实测 INFO Application cache cleared successfully.),必要时 ui 服务 down ui && up -d ui。

七、参考链接

OpnForm v2.8.1 常用 CLI 命令与工具详解 - Quzuo