
Dokku Deployment Tasks 指南使用 app.json 与 Procfile release 在部署生命周期中执行任务【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokkuDokku 的 Deployment Tasks 机制允许你在应用完全部署之前或之后的关键节点执行命令典型场景包括数据库初始化检查、数据库迁移、静态资源收集如 Django 的collectstatic、CDN 同步与缓存预热。本文以官方文档 docs/advanced-usage/deployment-tasks.md 为主线结合 app-json 插件 源码与 单元测试完整讲解app.json的scripts.dokku.predeploy、scripts.dokku.postdeploy、scripts.postdeploy与Procfile的release命令的使用时机、执行顺序、镜像提交语义以及appjson-path属性的配置与排查方法。什么是 Deployment Tasks在 Dokku 中应用的部署由 release镜像构建完成后的发布阶段与 deploy调度容器两大部分组成。Deployment Tasks 是在这一流程中插入的钩子用于在应用尚未完全就绪时执行一次性或每次部署都会运行的操作。官方文档给出的典型用例包括检查数据库是否已初始化运行数据库迁移执行任何需要为服务器准备环境的命令例如 Django 的collectstatic。所有任务都在构建好的 Docker 镜像上下文中执行——除非应用挂载了 volume否则这些命令不会影响宿主机。需要在 release 阶段于宿主机上执行命令的场景请参考 插件创建文档 构建自定义插件。四种任务阶段的选择与限制Dokku 提供四类 Deployment Task各自有不同的适用场景与镜像变更提交语义任务阶段来源执行时机镜像变更是否提交典型用例scripts.dokku.predeployapp.json镜像构建完成之后、容器调度之前是以不同方式打包资源从源码安装自定义包或将二进制文件复制到镜像中scripts.dokku.postdeployapp.json容器调度之后否通知 Slack 部署完成与中心负载均衡器协调流量路由scripts.postdeployapp.json容器调度之后且仅应用首次创建部署时执行一次否设置 OAuth 客户端与 DNS向应用的测试数据库加载种子/测试数据releaseProcfile镜像构建完成之后、容器调度之前且在scripts.dokku.predeploy之后否将 CSS、JS 等资源从 slug 发送到 CDN/S3预热或失效缓存运行数据库迁移选择建议需要修改镜像内容如安装包、复制二进制时使用scripts.dokku.predeploy因为只有该阶段会把变更提交回镜像只通知外部系统、不改变镜像时使用scripts.dokku.postdeploy或Procfile的release只在应用首次创建后执行一次如初始化 OAuth、加载种子数据时使用scripts.postdeploy。各阶段失败时的行为WARNING任何失败的app.jsonDeployment Task 都会导致部署失败。但无论哪个阶段失败都不会影响已运行的容器deploy 会回滚到上一版本。与 Dockerfile ENTRYPOINT 的交互如果应用使用 Dockerfile 构建且声明了ENTRYPOINTDeployment Task 的命令会原样传递给该 entrypoint。唯一的例外是以下四种 tini 包装型 entrypoint它们会被跳过即任务命令直接以 shell 执行不再经过 entrypoint[/tini, --][/bin/tini, --][/usr/bin/tini, --][/usr/local/bin/tini, --]这一逻辑在 plugins/app-json/functions.go 的constructScript中有源码级实现nonSkippableEntrypoints映射中列出的 tini entrypoint 会被跳过其余 entrypoint 存在时命令会通过shellquote.Split拆分为单词后原样作为容器命令执行。配置 app.json 的位置appjson-path 属性Dokku 会按部署方式在不同的基准目录中查找app.json通过git:from-image与git:load-image部署时基准目录为 Docker 镜像的WORKDIR其他部署方式git push、git:from-archive、git:sync基准目录为源码树根目录。在 monorepo 等场景下你可能希望指定其他路径可通过app-json:set命令设置appjson-path属性dokku app-json:set node-js-app appjson-path .dokku/app.json关键语义该值始终是相对于基准搜索目录的路径在任何上下文中都不会被当作绝对路径处理若该文件在仓库中不存在Dokku 会继续构建流程如同仓库没有app.json一样参见 tests/unit/app-json.bats 中的app-nonexistent.json测试传入空值可恢复默认dokku app-json:set node-js-app appjson-pathappjson-path也支持全局设置全局默认值为app.json仅当应用未设置专属值时才会使用全局值dokku app-json:set --global appjson-path global-app.json同样传入空值即可恢复默认dokku app-json:set --global appjson-path从源码看appjson-path是 app-json 插件唯一支持的属性在 plugins/app-json/appjson.go 中DefaultProperties与GlobalProperties均只声明了appjson-path一个键。查看 app-json 报告app-json:reportIMPORTANTapp-json:report自 0.25.0 起可用。运行app-json:report不带应用名则列出所有应用dokku app-json:report输出示例 node-js-app app-json information App-json computed appjson path: app2.json App-json global appjson path: App-json appjson path: app2.json python-sample app-json information App-json computed appjson path: app.json App-json global appjson path: App-json appjson path: ruby-sample app-json information App-json computed appjson path: app.json App-json global appjson path: App-json appjson path:三个字段的含义appjson-path应用级原始值未设置时为空global-appjson-path全局原始值未设置时为空computed-appjson-path部署时实际生效的值优先级为应用级值 → 全局值 → 内置默认值app.json。指定应用查询dokku app-json:report node-js-app只输出单项值便于脚本消费使用--app-json-appjson-path等 flagdokku app-json:report node-js-app --app-json-appjson-path输出app2.jsoncomputed-appjson-path的计算逻辑在 plugins/app-json/report.go 中实现依次取应用级值、全局值均为空时回落到app.json。支持的其他 flag 还包括--app-json-computed-appjson-path与--app-json-global-appjson-path。该行为有完整的单元测试覆盖见 tests/unit/app-json.batsround-trip、raw vs computed vs global 等用例。编写 Deployment Tasksapp.json 部署任务Dokku 对 Heroku 的app.json清单提供有限支持与 Deployment Tasks 相关的键有三个scripts.dokku.predeploy在应用 Docker 镜像构建之后、任何容器调度之前运行此阶段的镜像变更会被提交scripts.dokku.postdeploy在应用容器调度之后运行此阶段的镜像变更不会被提交scripts.postdeploy在应用容器调度之后运行此阶段的镜像变更不会被提交且仅在应用首次创建部署时执行一次。目前 Dokku 仅支持上述scripts.dokku.predeploy与scripts.dokku.postdeployscripts.postdeploy同样可用app.json中的其他字段会被忽略可以省略。示例{ scripts: { dokku: { predeploy: touch /app/predeploy.test, postdeploy: curl https://some.external.api.service.com/deployment?statesuccess }, postdeploy: curl https://some.external.api.service.com/created?statesuccess } }从源码看这三个键在 plugins/app-json/appjson.go 的Scripts结构体中均有对应的 JSON 字段映射scripts.dokku.predeploy、scripts.dokku.postdeploy、scripts.postdeploy而解析函数ReadAppJSON使用 hujson 解析意味着文件内容允许 JSONC带注释的 JSON语法。取值逻辑在getPhaseScriptplugins/app-json/functions.go中heroku.postdeploy阶段读取Scripts.Postdeploypredeploy阶段读取Scripts.Dokku.Predeploy其余阶段读取Scripts.Dokku.Postdeploy。Procfile release 命令IMPORTANTrelease命令自 0.14.0 起可用。Procfile支持特殊的release命令行为类似 Heroku 的 Release Phase在应用 Docker 镜像构建之后、任何容器调度之前执行且运行于scripts.dokku.predeploy之后。使用方法是在 Procfile 中添加release段release: curl https://some.external.api.service.com/deployment?statebuilt与scripts.dokku.predeploy不同release阶段对磁盘的变更不会持久化到镜像。WARNING对release命令进行扩容scaling很可能会引发部署中的未知问题强烈不建议这样做。release命令的读取通过procfile-get-command触发器完成plugins/app-json/functions.go并在executeScript中以phaseSource Procfile标记来源。底层执行机制任务是如何运行的从源码层面看Deployment Tasks 的执行由 app-json 插件的两个核心触发器驱动pre-release-builderplugins/app-json/triggers.go在处理完app.json中的环境变量之后执行predeploy任务post-release-builderplugins/app-json/triggers.go依次执行release任务、依据app.json的formation设置进程伸缩并在首次部署时通过heroku.postdeploy属性做幂等标记执行scripts.postdeploypost-deployplugins/app-json/triggers.go执行scripts.dokku.postdeploy且会提前判断任务是否存在避免对无 postdeploy 任务的应用做多余的镜像解析。这些触发器由部署主流程调用release_and_deployplugins/common/functions先调用dokku_release触发builder-release成功后通过cmd-deploy触发scheduler-deploy从而形成构建 → predeploy → release → 调度容器 → postdeploy的完整链条。任务的容器执行细节体现在executeScriptplugins/app-json/functions.go中通过docker-args-deploy与docker-args-process-deploy触发器收集部署参数并过滤掉--cpus、--memory、--publish、--restart、-p、-P等资源限制与端口发布类参数为任务容器打上dokku_phase_scriptphase标签herokuish 镜像额外挂载cache-app:/tmp/cacheCNBpack镜像则使用--entrypoint/cnb/lifecycle/launcher覆盖默认入口以应用的 shellDOKKU_APP_SHELL执行set -e包装的脚本herokuish 镜像还会先 source/app/.profile.d/*并设置HOME/app以/开头的命令会先校验二进制可执行性plugins/app-json/functions.go任务失败时输出容器日志并令整个部署失败只有predeploy阶段会把执行容器的变更通过docker container commit提交回镜像同时保留 Dockerfile 的ENTRYPOINT/CMD变更并写入com.dokku.app-name、com.dokku.phase-phase标签其他阶段执行完毕后容器被清理、变更丢弃。这一提交与否的区别在 tests/unit/app-json.bats 中得到验证predeploy写入的/app/predeploy.test在后续dokku run中仍存在而postdeploy写入的/app/postdeploy.test不存在。完整示例一次带迁移与通知的部署综合以上内容一个完整的实践配置如下。项目根目录app.json{ scripts: { dokku: { predeploy: python manage.py collectstatic --noinput, postdeploy: curl -X POST https://hooks.example.com/deploy?statesuccess }, postdeploy: curl -X POST https://hooks.example.com/app-created } }项目根目录Procfileweb: gunicorn myapp.wsgi --bind 0.0.0.0:$PORT release: python manage.py migratemonorepo 场景下指定清单文件位置dokku app-json:set my-app appjson-path services/web/app.json随后正常推送代码即可触发上述全部任务部署日志中会出现类似下面的提示对应 tests/unit/app-json.bats 中的断言文本Executing predeploy task from app.json: python manage.py collectstatic --noinput Executing release task from Procfile in ephemeral container: python manage.py migrate Executing postdeploy task from app.json in ephemeral container: ...如需排查某个应用实际使用的 app.json 路径直接查询计算值dokku app-json:report my-app --app-json-computed-appjson-path小结Deployment Tasks 将部署前的镜像准备与部署后的外部协调以声明式清单app.json和进程文件Procfile的形式固化下来。使用时把握三点即可需要变更镜像内容就用scripts.dokku.predeploy仅通知外部系统就用scripts.dokku.postdeploy或Procfile release只执行一次的应用初始化用scripts.postdeploy。配合appjson-path与app-json:reportmonorepo 与多应用环境下也能精确控制任务清单的位置与生效路径。【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考