Dokku 一次性任务(One-off Tasks)实战指南:用 run 命令在应用容器中执行临时命令
【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku
本文围绕 Dokku 平台的一次性任务(one-off tasks)功能展开,系统讲解run、run:detached、run:list、run:logs、run:stop等核心命令的用法与行为细节,并结合 plugins/run 插件与 scheduler-docker-local 调度器的源码,说明容器生命周期、TTL 回收、标签约束与日志查看的底层实现。读完本文,你将掌握在 Dokku 应用中安全、可控地执行数据库迁移、脚本调试、Procfile 进程命令等一次性操作,并能理解其超时回收与日志采集机制,为排障与自动化运维打下基础。
一、什么是一次性任务(One-off Tasks)
在 PaaS 平台上,应用进程通常由平台统一调度管理,用户无法随意docker exec进入容器或直接以任意命令启动进程。Dokku 提供了一次性任务机制:通过dokku run在与当前已部署应用完全相同的镜像基础上,临时启动一个全新的容器来执行你指定的命令。
Dokku 对一次性任务的支持由核心插件 plugins/run(plugin.toml 中描述为 "dokku core run plugin",插件描述为 "Run a one-off process inside a container")实现,容器启动的实际逻辑则由应用所使用的调度器承接,例如 scheduler-docker-local/scheduler-run。
一次性任务非常适合以下场景:
- 执行数据库迁移(如
rails db:migrate、alembic upgrade head); - 进入应用环境调试、运行交互式控制台(如
rails console、python manage.py shell); - 运行一次性脚本、数据修复任务;
- 复现线上环境问题,验证依赖与配置。
二、命令总览
dokku run:help会输出 run 插件支持的完整命令列表(见 plugins/run/help-functions):
run [-e|--env KEY=VALUE] [--no-tty] [--ttl-seconds SECONDS] <app> <cmd> # 使用当前应用镜像启动新容器执行命令 run:detached [-e|-env KEY=VALUE] [--force-tty] [--ttl-seconds SECONDS] <app> <cmd> # 以分离模式启动新容器执行命令 run:list [--format json|stdout] <app> # 列出某应用的全部 run 容器 run:logs <app|--container CONTAINER> [-h] [-t] [-n num] [-q] # 查看 run 容器日志 run:retire [<app>] # 回收所有超过活跃期限的 run/cron 容器 run:stop <app|--container CONTAINER> # 停止某应用的全部 run 容器或指定 run 容器其中run:retire在文档的命令列表中同样存在(plugins/run/help-functions),用于停止超过活跃期限的容器,与 TTL 机制配套使用。
三、运行一次性命令:dokku run
3.1 基本用法
dokku run会根据当前已部署应用正在使用的镜像启动一个全新容器,并在其中执行命令:
# 在 node-js-app 应用的 /app 目录下运行 ls -lah dokku run node-js-app ls -lah # 传入自定义环境变量 dokku run --env "NODE_ENV=development" --env "PATH=/custom/path" node-js-app npm run mytask[!IMPORTANT] 从 0.25.0 版本起,一次性容器在进程退出后会被自动删除,无需手动清理。
在源码层面,cmd-run会设置DOKKU_RM_CONTAINER=1,随后调用fn-run触发调度器的scheduler-run(见 plugins/run/internal-functions)。调度器收到该变量后,会在 docker 启动参数中加入--rm(见 scheduler-docker-local/scheduler-run),从而保证容器在退出后被 Docker 守护进程自动移除。
3.2 参数说明
fn-run的参数解析逻辑(见 plugins/run/internal-functions)支持以下参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
-e, --env KEY=VALUE | 注入自定义环境变量,可多次使用 | 无 |
--no-tty | 禁用交互式 TTY(0.25.0 新增) | 尽可能启用 TTY |
--ttl-seconds SECONDS | 容器最大存活时间(秒),超时后被回收 | 86400(24 小时) |
--cron-id | 关联 cron 任务标识(供 cron 插件内部使用) | 无 |
--concurrency-policy | cron 并发策略:allow/forbid/replace(供 cron 插件内部使用) | allow |
源码还会对参数做合法性校验:若--ttl-seconds为空则回退到86400,若非数字则直接报错--ttl-seconds must be a positive integer;若同时指定--force-tty与--no-tty则报错(见 plugins/run/internal-functions)。
3.3 运行 Procfile 中定义的命令
如果应用根目录的Procfile中定义了进程命令,dokku run会先尝试把第一个参数当作 Procfile 中的 key 来解析:
# Procfile 内容示例 console: bundle exec racksh# 运行 my-app 的 Procfile 中 console 命令,等价于 bundle exec racksh dokku run my-app console调度器源码中,会先通过procfile-get-command触发器查询该 key 对应的命令,命中后输出Found 'console' in Procfile, running that command,并为容器打上com.dokku.process-type标签(见 scheduler-docker-local/scheduler-run)。未命中时,参数会被当作普通 shell 命令直接执行。
3.4 指定容器标签
可以为一次性容器附加自定义标签,便于后续用 Docker 过滤与管理:
dokku --label=com.example.test-label=value run node-js-app ls -lah[!WARNING] 为避免与 Dokku 内部机制冲突,不要使用以
com.dokku或org.label-schema开头的标签。调度器在构造 docker 参数时,会从DOKKU_GLOBAL_FLAGS中筛选出--label开头的全局参数附加到容器上(见 scheduler-docker-local/scheduler-run),同时 Dokku 自身也会写入com.dokku.container-type、com.dokku.app-name、com.dokku.active-deadline-seconds等内部标签(见 scheduler-docker-local/scheduler-run)。
3.5 禁用 TTY
一次性容器默认在可行的情况下以交互模式(TTY)运行。若你的命令在无终端环境下执行(如 CI 流水线),可以显式禁用:
# 0.25.0 版本新增 dokku run --no-tty node-js-app ls -lah调度器在has_tty为真且未禁用 TTY 时,会向 docker 参数追加--interactive --tty(见 scheduler-docker-local/scheduler-run);非交互模式下,DOKKU_DISABLE_TTY=true会使has_tty返回假,从而去掉这两个标志。
3.6 默认命令:未指定命令时的行为
dokku run <app>(不带命令)时会启动一个交互式 shell。调度器源码中,当RUN_COMMAND为空时,会依次读取应用级与全局的scheduler插件的shell属性,若都未设置则回退到/bin/bash(见 scheduler-docker-local/scheduler-run)。该属性可通过属性命令进行配置。
四、运行分离容器:dokku run:detached
从 0.25.0 版本起,可以以"分离模式"启动一次性容器,命令立即返回容器名称(使用 k3s 调度器时返回 pod 名称):
# 立即返回新容器的名称,如 node-js-app.run.XXXXX dokku run:detached node-js-app ls -lah分离容器默认不带 TTY,进程退出后同样会被删除。若需要后台运行一个可交互会话,可配合--force-tty:
dokku run:detached --force-tty node-js-app bash此时容器仍会在命令终止时退出,但在运行期间可以被 attach。
源码层面,cmd-run-detached同时设置了DOKKU_DETACH_CONTAINER=1与DOKKU_RM_CONTAINER=1(见 plugins/run/internal-functions);fn-run中还会在未显式指定--force-tty时自动设置DOKKU_DISABLE_TTY=true。调度器在分离模式下不会附带--attach,启动后直接通过docker container inspect --format "{{.Name}}"输出容器名(见 scheduler-docker-local/scheduler-run)。
五、TTL 超时与自动回收机制
5.1 默认存活期限与覆盖
一次性容器默认最长运行24 小时(86400 秒),到达期限后会被回收。可以通过--ttl-seconds调整:
# 让容器最多运行 10 分钟 dokku run --ttl-seconds 600 node-js-app npm run mytaskTTL 值会以com.dokku.active-deadline-seconds标签写入容器(见 scheduler-docker-local/scheduler-run)。
5.2 回收周期与精度说明
超过运行时限的一次性容器每 5 分钟回收一次,因此--ttl-seconds是近似值——你的应用实际运行时长可能比设定值多出最多 5 分钟。回收动作由scheduler-run-retire触发器执行(对应run:retire命令)。
5.3 回收逻辑的源码实现
在 docker-local 调度器中,回收逻辑会:
- 按
com.dokku.container-type标签筛选 run/cron 类型容器,若指定了应用则叠加com.dokku.app-name过滤(见 scheduler-docker-local/scheduler-run-retire); - 读取每个容器的
com.dokku.active-deadline-seconds标签换算成截止时间戳,与容器启动时间比较(见 scheduler-docker-local/scheduler-run-retire); - 对超时容器依次执行
container update --restart=no、stop、kill、rm(见 scheduler-docker-local/scheduler-run-retire),并尊重应用配置的stop-timeout-seconds停止超时。
此外,fn-run内部还透传了DOKKU_CRON_ID与DOKKU_CONCURRENCY_POLICY,供 cron 插件复用同一套 run 机制执行定时任务,并支持forbid(存在同 ID 运行中容器则退出)与replace(替换正在运行的容器)两种并发策略(见 scheduler-docker-local/scheduler-run)。
六、查看一次性容器日志:dokku run:logs
6.1 基本用法
# 查看 node-js-app 所有 run 容器的日志 dokku run:logs node-js-app日志通过应用所使用调度器的 "live tailing" 能力拉取,因此历史部署产生的日志通常不可用。若需要长期保留日志用于排障,建议将日志持久化并外送,可参考 docs/deployment/logs.md 中关于 Vector 日志集成的说明,把日志转发到第三方平台。
6.2 行为修饰参数
run:logs支持以下修饰参数(解析见 plugins/run/internal-functions):
| 参数 | 说明 | 默认值 |
|---|---|---|
--container NAME | 只显示指定容器的日志,容器名形如node-js-app.run.1234 | 无(取全部) |
-n, --num NUM | 显示的行数 | 100 |
-t, --tail | 持续流式输出日志 | 关闭 |
-q, --quiet | 输出原始日志,不带颜色、时间与名称 | 关闭 |
示例:持续跟踪指定一次性进程的日志:
dokku run:logs -t --container node-js-app.run.1234当指定--container时,源码会校验容器名必须含两个.、第二段必须为run,且应用名需与容器名前缀一致,否则报错(见 plugins/run/internal-functions)。
七、列出一次性容器:dokku run:list
[!IMPORTANT] 从 0.25.0 版本起提供。
dokku run:list node-js-app输出示例:
=====> node-js-app run containers NAMES COMMAND CREATED node-js-app.run.28689 "/exec sleep 15" 2 seconds ago说明:
COMMAND列显示的是 Docker 实际执行的命令,可能与dokku run传入的原始命令不完全一致(例如 herokuish 镜像会通过/exec包装执行)。
输出也支持 JSON 格式,便于脚本化处理:
dokku run:list node-js-app --format json[ { "name": "node-js-app.run.28689", "state": "running", "command": "\"/exec 'sleep 15'\"", "created_at": "2022-08-03 05:47:44 +0000 UTC" } ]源码中,stdout 格式通过docker container ls --all --no-trunc配合com.dokku.app-name与com.dokku.container-type=run两个标签过滤输出(scheduler-docker-local/scheduler-run-list);JSON 格式则通过jq将字段映射为name、state、command、created_at(见 scheduler-docker-local/scheduler-run-list)。另支持--quiet输出无表头的裸格式。
八、停止一次性容器:dokku run:stop
[!IMPORTANT] 从 0.29.0 版本起提供。
停止指定的一次性容器,输出被停止容器的名称:
# 先启动一个运行 300 秒的容器,输出类似 node-js-app.run.2313 dokku run node-js-app sleep 300 # 停止该容器 dokku run:stop --container node-js-app.run.2313输出:
node-js-app.run.2313也可以直接指定应用名,停止该应用的全部 run 容器:
dokku run:stop node-js-app输出:
node-js-app.run.2313 node-js-app.run.574源码中,停止指定容器时同样会校验容器名格式(两个.、第二段为run),停止顺序为docker container stop,若失败再kill,并遵循应用配置的stop-timeout-seconds;若未指定容器,则列出该应用全部container-type=run的容器逐一停止(见 scheduler-docker-local/scheduler-run-stop)。无容器时会输出No run containers exist。
九、执行流程全景:一次dokku run背后的调用链
综合以上源码,dokku run <app> <cmd>的完整调用链如下:
- 用户输入命令后,进入 run 插件子命令入口 plugins/run/subcommands/default(
run:detached则进入 plugins/run/subcommands/detached); cmd-run设置DOKKU_RM_CONTAINER=1,fn-run解析--env、--ttl-seconds、--no-tty等参数并做合法性校验;fn-run通过get_app_scheduler获取应用调度器(默认docker-local),触发scheduler-run触发器(见 plugins/run/internal-functions);- docker-local 调度器从当前运行镜像解析出发布镜像(
image-stage必须为release,否则报错提示先成功部署应用,见 scheduler-docker-local/scheduler-run),组合docker-args-run、docker-args-process-run触发器返回的启动参数; - 依次附加环境变量、
DYNO环境变量、--rm、TTY 标志、TTL 标签、内部标签与全局--label参数; - 解析 Procfile 命令或直接使用传入命令,创建并启动容器;前台模式附带
--attach并等待退出码,分离模式直接输出容器名; - 最后触发
scheduler-post-run触发器,向事件系统上报执行结果(见 scheduler-docker-local/scheduler-run)。
此外,调度器还会根据镜像架构自动处理跨平台问题:当镜像为linux/amd64而宿主机不是 amd64 架构时,会自动附加--platform=linux/amd64以保证可执行(见 scheduler-docker-local/scheduler-run)。
十、常见问题与最佳实践
- 提示 "Invalid image stage detected":说明应用当前没有成功部署过(或镜像非 release 阶段),先执行一次正常部署再运行
dokku run。 - 长时间任务不要依赖默认 TTL:默认 24 小时且每 5 分钟回收一次,若任务可能超时,请用
--ttl-seconds显式设置并预留回收间隔余量。 - 日志持久化:
run:logs依赖 live tailing,历史日志不可回溯,关键任务的日志应主动写入外部存储或日志平台。 - 标签冲突规避:自定义标签务必避开
com.dokku、org.label-schema前缀,以免干扰 Dokku 内部标签过滤逻辑。 - 脚本化集成:
run:list --format json与run:logs --quiet适合在 CI/CD 与运维脚本中解析使用;无命令执行时可通过scheduler插件的shell属性自定义默认 shell。 - 权限与资源:一次性容器与应用容器共用镜像与网络配置,注意其中的环境变量与挂载可能带来的副作用,执行前确认命令与参数无误。
一次任务机制是 Dokku 日常运维中最常被使用的入口之一:它既保持了"镜像一致、环境一致"的可复现性,又通过 TTL、自动回收、命名规范(<app>.run.<id>)与标签体系保证了资源可控与可观测。理解其背后从 run 插件到调度器的完整链路,能帮助你在迁移数据库、调试、批量脚本等场景中更稳妥地使用它。
【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考