Penpot 常用命令与运维实战

Penpot 2.18.5 常用命令与运维实战:8 服务栈运维命令矩阵、单服务重启与开机自愈案例(admin-console 抢启实录)、pg_dump+双数据卷备份实测(181KB dump 与资产分片目录)、升级路径与版本核对、数据库删除保护/导出接口 transit 编码/内存水位等真实排障沉淀(2026-10-28 实测)。

PenpotPenpot设计工具GUI2026/10/28

Penpot 常用命令与运维实战

目标:给 Penpot 2.18.5 自托管管理员一套拿来即用的运维手册——栈级命令矩阵、单服务处置、备份恢复实测、升级路径,以及本次真实运维中沉淀的排障实录(开机抢启、数据库删除保护、导出接口编码、内存水位)。部署与配置背景分别见 《Penpot Docker Compose 部署实战》 与 《Penpot 配置参数详解》。以下全部命令与回显为 2026-10-28 真实服务器实测。

一、环境信息

  • 栈:Penpot 2.18.5 官方 Compose 编排,项目名 penpot-2.18.5-stack(compose 归一化前缀 penpot-218-stack),部署目录 /opt/penpot/deploy/,入口 :8140。
  • 8 服务:frontend / backend / exporter / admin-console / mcp / postgres:15 / valkey:8.1 / mailpit:v1。
  • 数据落点:penpot-218-stack_penpot_postgres_v15(数据库卷)与 penpot-218-stack_penpot_assets(资产卷)两个 Docker 卷。

二、栈运维命令矩阵

统一在部署目录执行(cd /opt/penpot/deploy):

场景命令说明
全栈状态docker compose ps8 服务逐一显示 Up/healthy;postgres 与 valkey 自带健康检查
全栈日志docker compose logs -f --tail=100排障第一入口
单服务日志docker compose logs -f penpot-backendbackend/exporter 日志信息量最大
资源水位docker stats --no-stream内存/CPU 快照
重启单服务docker compose restart penpot-backend不重建、不重读编排文件
重建单服务docker compose up -d penpot-backend编排/.env 变更后使用(可重读配置)
停栈docker compose stop保留数据卷
起栈docker compose start配合 stop 做计划内停机
销毁栈docker compose down保留卷;down -v 连卷一起删(数据全失,见第七章)
数据库直连docker compose exec penpot-postgres psql -U penpot penpot只读排查用

版本核对的两个实测入口:

docker compose logs penpot-backend | grep "welcome to penpot"   # → version="2.18.5-RC1"
docker compose ps                                               # → penpotapp/backend:2.18.5

💡 技术拓展:version="2.18.5-RC1" 不是拿错版本——GitHub tags 实查(2026-10-28)显示 2.18.5 与 2.18.5-RC1 指向同一提交 f4456696,正式版与 RC1 是同一构建,日志串与镜像 tag 的写法差异而已。

三、单服务处置实录:开机抢启与自愈

3.1 真实案例

2026-10-28 00:34 宿主机重启,全栈依赖 restart: always 自动拉起。admin-console(Node 服务)抢在 PostgreSQL 完成启动前发起连接,当场报错退出(真实日志节选):

penpot-admin-console-1  | 2026-10-28T00:34:21.596498161Z         throw new DrizzleQueryError(queryString, params, e);
penpot-admin-console-1  | DrizzleQueryError: Failed query: CREATE SCHEMA IF NOT EXISTS "drizzle"
penpot-admin-console-1  |   cause: error: the database system is starting up

几秒后自动重试成功(它自己在数据库侧建 drizzle 迁移 schema),服务恢复,无需人工干预。结论:抢启失败是自愈型瞬时错误,看到 the database system is starting up 不必动手;只有持续 1 分钟以上不恢复才需要 docker compose restart penpot-admin-console。backend/exporter 因有 service_healthy 依赖门控不会抢启,这是官方编排的健康检查设计(2 秒间隔×5 次)。

3.2 重启后必看的三行日志

每次整栈重启后按序确认:

penpot-postgres-1  | LOG:  database system is ready to accept connections
penpot-backend-1   | I app.migrations - hint="running migrations", module=:app.migrations/migrations
penpot-backend-1   | I app.main - hint="welcome to penpot", flags="...", version="2.18.5-RC1"

backend 每次启动都会重跑一遍迁移检查(幂等),welcome to penpot 出现即代表 API(内部 6060 端口)就绪。

四、备份与恢复实测

4.1 备份对象盘点

docker volume ls --format '{{.Name}}' | grep penpot
penpot-218-stack_penpot_assets
penpot-218-stack_penpot_postgres_v15

两个数据卷分别承载:PostgreSQL 15 数据目录(用户/团队/文件元数据)与资产目录(用户上传图片、导出产物,按资产 id 前两位分片存放,实测目录形态为 99/、ee/)。测试邮箱 mailpit 的消息仅存内存,官方注释明确不落盘、重建即丢——不需要也无处备份,生产接真实 SMTP 后此服务可弃用。

4.2 数据库备份(pg_dump 实测)

cd /opt/penpot/deploy
docker compose exec penpot-postgres pg_dump -U penpot penpot > /opt/backup/penpot-$(date +%F).sql

实测产物:181082 字节(空库+测试数据状态),包含全部建表与数据。建议每日 cron 执行并轮转保留 7~30 天。

4.3 资产卷备份

docker run --rm -v penpot-218-stack_penpot_assets:/data -v /opt/backup:/backup alpine \
  tar czf /backup/penpot-assets-$(date +%F).tar.gz -C /data .

初始实测仅 36KB(两个分片目录),随上传量增长;若已把对象存储切到 S3/MinIO(配置见 《Penpot 配置参数详解》),此卷备份改为对应桶的同步策略。

4.4 恢复顺序

  1. 起一个全新栈(同版本 PENPOT_VERSION,先不对外开放);
  2. 停 backend/admin-console(docker compose stop penpot-backend penpot-admin-console),避免恢复期间写入;
  3. docker compose exec -T penpot-postgres psql -U penpot penpot < penpot-YYYY-MM-DD.sql 回灌数据库;
  4. 资产卷解包回 penpot_assets 卷对应位置;
  5. 起回停掉的服务,登录验证文件可打开、图片资产可加载。

五、升级路径

官方建议小步快跑(small increments),实测标准动作:

cd /opt/penpot/deploy
vi .env                 # PENPOT_VERSION=2.19.0(示例)
docker compose pull     # 拉取新版本
docker compose up -d    # 滚动重建
docker compose logs penpot-backend | grep "welcome to penpot"   # 核对新 version

升级前强制项:先做第四章备份(数据库卷 + 资产卷);迁移在启动时自动执行且只进不退,跨大版本(如 2.18→2.20)无法用同一份数据降级回滚——回滚等于恢复备份。

六、排障实录沉淀

6.1 数据库删除保护(最意外的发现)

直接用 SQL 删除业务行会被拒绝(实测回显):

ERROR:  unable to proceed to delete row on "team"
HINT:  disable deletion protection with "SET rules.deletion_protection TO off"
CONTEXT:  PL/pgSQL function raise_deletion_protection() line 3 at RAISE

Penpot 在 PostgreSQL 内装了触发器级的数据删除保护(覆盖 team/project/file 等核心表),防止误删。确需手工清理时(如删除测试账号残留),必须在事务内显式关闭保护:

BEGIN;
SET LOCAL rules.deletion_protection TO off;
DELETE FROM public.team WHERE id = '<team-id>';
COMMIT;

两个细节:SET LOCAL 作用域仅当前事务,提交后自动恢复保护;表名是单数(profile/team/file/project),与直觉的复数命名不同。

6.2 导出接口必须用 transit 编码

对 /api/export(frontend 统一入口转发 exporter)做脚本化导出时,普通 JSON 体看似合法却报内部错误:

HTTP 500
{"~:type":"~:server-error","~:hint":"conj on a map takes map entries or seqables of map entries"}

原因是服务端按 transit 协议解析参数:键名与枚举值需带 ~: 前缀、UUID 需 ~u 前缀、Content-Type 用 application/transit+json。改对后即 200 并返回资产下载地址(完整可用的导出脚本见 《Penpot Docker Compose 部署实战》第五章)。参数校验失败时服务端会返回带 spec 说明的 400,把缺失/错误的键名原文列出,是调试导出参数最有效的反馈。

6.3 导出 503 与临时文件

  • 导出服务首启或重启后,内置无头浏览器需要数秒就绪;此窗口内的导出请求会得到 503(服务端错误码 browser-not-ready),等待重试即可,无需重启。
  • 渲染产物先落在 /tmp/penpot/penpot.tmp.bitmap.*.png,带定时删除(实测日志 hint="schedule tempfile deletion")。若 /tmp 被按会话清空不影响正确性——临时文件本就一次性。
  • exporter 空闲即占 461MiB(无头浏览器常驻),并发导出会继续上涨;内存紧张时优先调低 PENPOT_EXPORTER_MAX_CONCURRENT_JOBS(默认 4)。

6.4 内存水位基线(实测)

服务空闲常驻建议规划值
penpot-backend2.1 GiB2.5 GiB(已加 -Xmx512m 仍需此量,堆外占大头)
penpot-exporter461.7 MiB1 GiB(含并发余量)
penpot-mcp190.6 MiB256 MiB
penpot-frontend172.9 MiB256 MiB
penpot-postgres167.7 MiB512 MiB
penpot-admin-console93.1 MiB128 MiB
penpot-mailpit32.5 MiB64 MiB
penpot-valkey4.2 MiB128 MiB 上限(VALKEY_EXTRA_FLAGS 限定)

全栈合计约 3.2GiB 空闲水位;2GB 服务器跑不动,4GB 起步,6GB 从容。

6.5 其他实测备忘

  • GET /api/healthz 返回 404——Penpot 没有这个习惯路径的探活端点;服务健康判断用 docker compose ps 的 healthy 状态 + 入口 HTTP 200。
  • admin-console 日志里的 appVersion 显示 2.18.0-RC4-1-gd8dd1b8,与其余服务的 2.18.5-RC1 不一致——管理控制台组件有自己的构建版本线,同栈混显属正常。
  • 数据库直查用户清单:docker compose exec penpot-postgres psql -U penpot -c "select email, fullname from public.profile;"(注册/登录异常时核对账号是否存在)。
  • 弱密码直接被服务端策略拒绝(400 weak-password,要求大小写+数字+特殊字符全齐),不是可配置项,见 《Penpot Docker Compose 部署实战》4.1 实测。

七、管理后台与辅助工具

工具入口用途与注意
Admin Consolehttp://<服务器IP>:8140/admin-console/实例级用户/团队/项目管理(2.18 新增),依赖 enable-admin-console 旗标
Mailpithttp://127.0.0.1:8148(默认编排为 :8025,本例改绑回环)测试邮箱收件箱,查看注册/邀请邮件内容;消息仅存内存
MCP/mcp/ws、/mcp/stream(同端口)AI 智能体接入通道,依赖 enable-mcp 旗标
PREPLbackend 旗标 enable-prepl-server(默认开)运维诊断 REPL,官方默认保留

八、停栈与数据安全

docker compose down      # 停栈并移除编排网络,两个数据卷保留
docker compose down -v   # ⚠️ 连卷一起删除:数据库与资产全部清空,不可恢复

down -v 只应用于测试栈重置或确认备份完整后的下线。生产栈日常停机一律 stop/start 或不带 -v 的 down。

九、参考链接