Dokku 0.29.0 迁移指南:run:detached 输出、sigil/Procfile 提取路径、hooks 重命名与属性化迁移全解析
导读:本文围绕 Dokku 0.29.0 版本引入的破坏性变更,梳理从旧版本升级时必须关注的行为调整——包括
run:detached的输出格式变化、cron任务 ID 的编码方式切换、nginx.conf.sigil与Procfile从"构建镜像内提取"改为"源码提取"、pre-restorehook 的重命名与职责细分,以及环境变量向插件属性(property)体系的迁移。读完本文,你将能对照新版行为逐项检查自己的应用配置,完成一次低风险的平滑升级。
概览:0.29.0 的变更主题
0.29.0 是 Dokku 在插件化与属性化道路上的一次重要演进。此次升级没有引入全新的部署调度器或构建器,而是集中修正了一批输出格式、文件提取时机、hook 生命周期与配置存储方式,其中多数变更属于破坏性变更,升级后需要同步调整脚本、监控逻辑与自定义 hook。
整体变更可以分为四类:
- 输出与标识变更:
run:detached输出容器名而非容器 ID;cron任务 ID 从 base64 改为 base36 编码。 - 构建期文件提取时机的变更:
nginx.conf.sigil与Procfile从"从已构建镜像中提取"改为"在源码提取阶段一并提取"。 - Hook 生命周期调整:原
pre-restorehook 更名为scheduler-pre-restore,并新增一个在ps:restore内触发的pre-restorehook。 - 配置项迁移与移除:
DOKKU_WAIT_TO_RETIRE环境变量迁移为checks插件的wait-to-retire属性;domains-setuptrigger 与URLS文件、get_app_urls公共函数被移除。
变更一:run:detached 输出改为容器名
在 0.29.0 之前,run:detached 返回的是新启动的 detached 容器的 容器 ID;从 0.29.0 起,输出改为容器名,例如 node-js-app.run.1。
这一变更直接影响到以下使用场景:
- 基于
run:detached输出编写自动化脚本,将返回值当作容器 ID 传给docker inspect、docker logs、docker exec等命令的场景; - 通过
run:list对 detached 容器进行后续管理的场景; - 将 detached 容器纳入监控或告警系统的场景。
从源码看,detached 运行流程位于 plugins/run/internal-functions 的 cmd-run-detached:它设置 DOKKU_DETACH_CONTAINER=1 与 DOKKU_RM_CONTAINER=1 后调用统一的 fn-run,最终通过 scheduler-run trigger 交给调度器执行。调度器在创建容器时会生成 app.run.N 格式的命名容器(进程名 run,序号 N 递增)。因此升级后:
- 若你的脚本需要容器 ID,可用
dokku run:detached输出的容器名再调用docker inspect -f '{{.Id}}' <container-name>获取; - 若只是需要区分多个 detached 容器,
run:list依旧可用,且容器名本身就是稳定的可读标识,这反而让日志筛选和故障排查更直观。
变更二:cron 任务 ID 由 base64 改为 base36
0.29.0 将 cron 任务 ID 的编码方式从 base64 切换为 base36(小写字母 + 数字),使 ID 更短、更易读,也避免了 base64 输出中可能出现的 +、/、= 等对 shell 与 URL 不友好的字符。
源码中的实现可以印证这一点:cron 插件的 ID 生成逻辑位于 plugins/cron/cron.go 与 plugins/cron/crontab.go,均通过 github.com/multiformats/go-base36 库的 base36.EncodeToStringLc 生成,例如对 appName + "===" + command + "===" + schedule 组合串编码。同一依赖也用于 plugins/builds/builds.go 中构建 ID 的生成(时间戳 + 随机数的 base36 ULID 风格 ID)。
迁移影响:
- 若你在脚本或外部系统中持久化了旧的 base64 任务 ID,升级后这些 ID 不再匹配,需要重新枚举任务并更新记录;
- 若你的 cron 配置是自动生成的(例如通过
cron:add),ID 会由 Dokku 自动按新格式生成,无需手工干预; - 建议以"任务命令 + 调度表达式"作为业务标识,而不是依赖 ID 的编码形态。
变更三:nginx.conf.sigil 与 Procfile 改为源码阶段提取
这是 0.29.0 中影响面最大的行为变更,涉及构建流程的两个关键文件。
3.1 变更前的行为与问题
在旧版本中:
nginx.conf.sigil(nginx 虚拟主机模板)从已构建的镜像中提取;Procfile(进程定义文件)同样从已构建的镜像中提取。
这意味着:即使源码仓库中修改了这两个文件,也必须重新构建并推送新镜像才能生效;并且在某些多阶段构建或非标准构建流程中,镜像内可能根本不包含这两个文件,导致部署阶段无法正确读取模板或进程定义。
3.2 变更后的行为
0.29.0 起,两者都改为在源码提取(source extraction)阶段从应用源码中读取:
nginx.conf.sigil随源码提取,用于生成 nginx 配置模板;Procfile随源码提取,用于解析进程类型与启动命令。
对于通过 git:from-image 部署的场景,两个文件会从源镜像中提取,并同样尊重对应的自定义路径属性。
3.3 自定义路径:nginx-conf-sigil-path
如果你希望使用非默认路径(例如 monorepo 中模板位于 .dokku/nginx.conf.sigil),可以通过 nginx 插件的 nginx-conf-sigil-path 属性设置:
# 为单个应用设置自定义 sigil 路径
dokku nginx:set node-js-app nginx-conf-sigil-path .dokku/nginx.conf.sigil
# 查看当前值
dokku nginx:set node-js-app nginx-conf-sigil-path
# 全局默认值(默认 nginx.conf.sigil),应用未设置时使用全局值
dokku nginx:set --global nginx-conf-sigil-path nginx.conf.sigil
该属性的默认值为 nginx.conf.sigil,支持 app 级与全局两级配置。源码层面,属性读取与计算位于 plugins/nginx-vhosts/internal-functions(fn-nginx-nginx-conf-sigil-path / fn-nginx-computed-nginx-conf-sigil-path / fn-nginx-global-nginx-conf-sigil-path),set 子命令在 plugins/nginx-vhosts/subcommands/set 中校验该键;构建后的 core-post-extract 阶段在 plugins/nginx-vhosts/core-post-extract 通过 fn-nginx-computed-nginx-conf-sigil-path "$APP" 计算实际路径并提取 sigil。完整的配置与 report 字段可参考 docs/networking/proxies/nginx.md 中的说明,nginx:report 也会输出 nginx-conf-sigil-path、nginx-global-nginx-conf-sigil-path、nginx-computed-nginx-conf-sigil-path 三个字段(见 plugins/nginx-vhosts/report.go)。
3.4 自定义路径:procfile-path
同理,ps 插件提供 procfile-path 属性,默认值为 Procfile,也支持 app 级与全局级配置:
# 为单个应用设置自定义 Procfile 路径
dokku ps:set node-js-app procfile-path .dokku/Procfile
# 查看当前值
dokku ps:set node-js-app procfile-path
# 设置全局默认值
dokku ps:set --global procfile-path global-Procfile
源码层面,ps 插件的默认属性表定义在 plugins/ps/ps.go,report 输出 procfile-path、global-procfile-path、computed-procfile-path 三个字段(见 plugins/ps/report.go),并在 core-post-extract trigger(plugins/ps/triggers.go)中确保实际使用的 Procfile 是指定路径对应的文件。更完整的用法说明见 docs/processes/process-management.md。
3.5 升级注意事项
- 如果此前依赖"从镜像中读取 sigil/Procfile"的行为(例如在构建阶段动态生成这两个文件),升级后请改为在源码阶段准备文件,或通过上述属性指向构建产物路径;
git:from-image部署的用户,请确认源镜像中确实包含这两个文件(或设置好对应路径),否则提取阶段可能找不到文件;- 使用
nginx:report/ps:report的--format json输出做自动化时,注意相关字段名的变化。
变更四:pre-restore hook 重命名与职责细分
0.29.0 对恢复流程的 hook 做了重构:
- 原有
pre-restorehook 更名为scheduler-pre-restore,语义更明确:它由调度器在恢复应用前触发; - 新增一个
pre-restorehook,在ps:restore命令内部、恢复任何应用之前触发一次。
源码层面的对应关系:
ps插件在 plugins/ps/ps.go 中注册scheduler-pre-restoretrigger,并通过ps:restore流程调用调度器执行;- docker-local 调度器的实现位于 plugins/scheduler-docker-local/scheduler-pre-restore;
- 各代理插件(nginx、caddy、haproxy、openresty)均提供了新的
pre-restorehook,用于在恢复前重建/准备代理配置,例如 plugins/nginx-vhosts/pre-restore、plugins/caddy-vhosts/pre-restore 等。
迁移建议:
- 如果你或第三方插件实现了自定义的
pre-restorehook,请将其重命名为scheduler-pre-restore,否则升级后将不再被触发; - 新逻辑若需要在"恢复任意应用之前"执行(例如恢复代理配置、预检环境),应实现新的
pre-restorehook; - 需要区分"每个应用恢复前"与"整体恢复开始前"两种时机时,正好分别对应
scheduler-pre-restore与pre-restore。
变更五:DOKKU_WAIT_TO_RETIRE 迁移为 checks 属性
DOKKU_WAIT_TO_RETIRE 环境变量被废弃,迁移为 checks 插件的 wait-to-retire 属性。若仍以环境变量方式设置,该值将被忽略。
新的设置方式:
# 为单个应用设置退役等待时间(秒)
dokku checks:set node-js-app wait-to-retire 30
# 全局设置
dokku checks:set --global wait-to-retire 30
该属性控制"新容器部署成功后、旧容器停止之前"的等待时间(优雅退役宽限期),默认值为 60 秒,优先级为 app 级 > 全局级 > 内置默认值。在 0.29.0 的安装脚本中,已通过 prop migrate-config-to-property checks wait-to-retire DOKKU_WAIT_TO_RETIRE 自动完成旧环境变量到属性的迁移(见 plugins/checks/install),因此升级时旧值会自动带入;此后请改用 checks:set 管理。
源码中,wait-to-retire 的计算逻辑位于 plugins/checks/internal-functions,部署时由 plugins/scheduler-docker-local/scheduler-deploy 通过 checks-get-property trigger 读取;checks:report 提供 wait-to-retire、global-wait-to-retire、computed-wait-to-retire 三个字段(见 plugins/checks/report.go)。关于该属性的完整语义与后续版本中的行为演变,可参阅 docs/deployment/zero-downtime-deploys.md 中的 wait-to-retire 小节。
变更六:domains-setup trigger、URLS 文件与 get_app_urls 移除
0.29.0 移除了一批与应用域名/URL 相关的旧机制:
domains-setuptrigger 被移除:应用的初始域名现在在应用创建时自动配置,不再需要单独的 trigger;URLS文件不再生成/引用:旧版本为应用生成的URLS文件(存放应用 URL 列表)已被废弃;- 公共函数
get_app_urls被移除:该函数不再可用。
新的 URL 获取方式是 domains-urls 插件 trigger。源码层面,domains 插件的实现位于 plugins/domains/domains-urls:它接收 APP 与 URL_TYPE(url 或 urls)参数,优先通过 app-urls trigger 获取 URL,否则回退到 fn-domains-generate-urls 按默认 scheme(存在证书时为 https/443,否则 http/80)生成;url 类型只输出首个匹配 URL,urls 类型输出排序后的完整列表。
对外调用入口也已统一:dokku urls 子命令在 plugins/00_dokku-standard/subcommands/urls 中通过 plugn trigger domains-urls "$APP" "$URL_TYPE" 获取 URL,公共函数 fn-app-urls 在 plugins/common/functions 中同样走 domains-urls trigger。
迁移建议:
- 插件或脚本中调用
get_app_urls的,请改为调用plugn trigger domains-urls "$APP" urls(或url); - 依赖
URLS文件路径的监控/发布脚本,请改为读取dokku urls <app>的输出; - 自定义插件若实现了
domains-setuptrigger,请移除,并改为在post-create阶段自行配置域名逻辑。
变更七:Ubuntu 系统上 Nginx 初始化改用 systemctl
0.29.0 起,在 Ubuntu 系统且存在 /usr/bin/systemctl 时,Nginx 的初始化命令通过 systemctl 执行(而非直接调用 service 或其他方式)。
源码中,plugins/nginx-vhosts/install 会检测 systemctl 路径:当 /usr/bin/systemctl 可执行时优先使用之。类似的做法也见于 plugins/20_events/install(重启 rsyslog 时检测 systemctl 路径)与 plugins/builder/install-builder-prune(通过 systemctl 管理 docker-builder-prune 定时器)。
这一变更主要影响:
- 自定义 init 脚本或第三方插件中直接操作 nginx 服务的逻辑,建议统一改用
systemctl感知的方式; - 若你的环境没有
/usr/bin/systemctl(例如容器内或精简系统),Dokku 会回退到原有的初始化方式,行为不变。
升级清单与检查步骤
综合以上变更,给出升级 0.29.0 时的推荐检查清单:
- 脚本检查:全局搜索对
run:detached返回值按容器 ID 处理的逻辑,改为按容器名处理;搜索旧 cron 任务 ID 的持久化记录并刷新。 - 构建流程检查:确认
nginx.conf.sigil与Procfile在源码中可用;如路径特殊,提前配置nginx-conf-sigil-path与procfile-path;检查git:from-image的源镜像内容。 - Hook 检查:将自定义
pre-restorehook 重命名为scheduler-pre-restore;如需全局恢复前置逻辑,实现新的pre-restore。 - 配置迁移确认:验证
checks:report中wait-to-retire是否已自动迁移;清理环境中残留的DOKKU_WAIT_TO_RETIRE变量,改用dokku checks:set。 - URL 获取方式更新:移除对
URLS文件与get_app_urls的依赖,统一改用domains-urlstrigger 或dokku urls。 - 系统环境确认:Ubuntu 用户确认
/usr/bin/systemctl存在且 nginx 初始化正常;无 systemctl 的环境验证回退路径。 - 验证:升级后运行
dokku run:detached node-js-app echo ok、dokku urls node-js-app、dokku checks:report node-js-app,逐一核对新输出格式与属性值。
结语
0.29.0 迁移指南所涵盖的七项变更,本质上都是在为 Dokku 更彻底的插件化与属性化打基础:输出更稳定、文件提取时机更贴近源码、hook 职责更清晰、配置项统一收敛到属性体系。按本文清单逐项检查,即可平滑完成升级,并顺带消除一批因"镜像内找文件""环境变量读配置""旧 hook 名"造成的隐患。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00