Dokku Docker Local Scheduler 深度指南:默认调度器原理、并行部署与资源限制配置
本文以 Dokku 的
scheduler-docker-local插件为核心,系统讲解 Dokku 在单机 Docker 环境下管理应用生命周期的默认调度器:从调度器切换、amd64/arm64 跨架构部署、init 进程注入、进程级并行调度,到scheduler-docker-local:report报告命令与资源限制属性的完整用法。读完本文,你将能够熟练配置单机调度行为、诊断部署并行度瓶颈,并在需要时通过app.json精细控制每个进程类型的启动并发度。
调度器概览:Dokku 的默认单机调度器
scheduler-docker-local 是 Dokku 内置的调度器插件(位于 plugins/scheduler-docker-local),负责在单台服务器上使用 Docker 直接管理应用容器的完整生命周期。与所有调度器一样,它以应用为单位进行设置——Dokku 通过 scheduler:set 命令为每个应用指定使用哪个调度器。
该插件是 Dokku 的默认调度器。若要显式将某个应用切回 docker-local(例如应用此前被配置为其他调度器,如 scheduler-k3s),可执行:
dokku scheduler:set node-js-app selected docker-local
由于 docker-local 本就是默认值,将 selected 属性置空同样是恢复默认调度器的合法方式:
dokku scheduler:set node-js-app selected
也就是说,dokku scheduler:set <app> selected(不带值)即可把应用调度器重置回 docker-local。
该插件包含两个核心子命令(自 0.12.12 起新增):
scheduler-docker-local:report [<app>] [<flag>] # Displays a scheduler-docker-local report for one or more apps scheduler-docker-local:set [<app>|--global] <key> (<value>) # Set or clear a scheduler-docker-local property for an app or globally
从源码看,set 子命令对属性键做了白名单校验:只接受 init-process 与 parallel-schedule-count 两个键,传入其他键会直接报错;当带值写入时通过 fn-plugin-property-write 落盘,无值(空值)时则执行 fn-plugin-property-delete 完成清除(见 plugins/scheduler-docker-local/subcommands/set)。
在 arm64 主机上部署 amd64 镜像
自 0.33.0 起支持。
目前许多 buildpack 类构建器只产出 amd64 架构的镜像。scheduler-docker-local 会在每次部署时自动检测镜像架构:如果镜像架构为 amd64 而当前主机不是 amd64(即 arm64 部署目标),则自动为容器追加 --platform=linux/amd64 参数,使其能够借助 Docker 的模拟层在 arm64 主机上运行。
对应实现在容器启动逻辑 plugins/scheduler-docker-local/bin/scheduler-deploy-process-container 中:
local DOKKU_IMAGE_ARCHITECTURE="$("$DOCKER_BIN" image inspect --format '{{.Architecture}}' "$IMAGE")"
if [[ "$DOKKU_IMAGE_ARCHITECTURE" == "amd64" ]] && [[ "$(dpkg --print-architecture 2>/dev/null || true)" != "amd64" ]]; then
dokku_log_warn "Detected linux/amd64 image, forcing --platform=linux/amd64"
DOCKER_ARGS+=" --platform=linux/amd64"
fi
即:通过 docker image inspect 读取镜像的 Architecture,与主机架构(dpkg --print-architecture)比对后自动注入平台参数,全程无需人工干预。需要注意的是,该能力依赖 Docker 在目标主机上的跨架构运行支持(如 binfmt/qemu),且模拟运行在性能上会有一定开销。
控制 init 进程注入(init-process 属性)
默认情况下,scheduler-docker-local 在启动应用容器时通过 Docker 的 --init 标志注入一个 init 进程(用于回收僵尸进程)。但对于某些应用——例如镜像内部本身已使用 S6 作为 init 的容器——额外的 init 进程注入可能反而导致进程启动异常。
此时可为应用显式关闭 init 注入:
dokku scheduler-docker-local:set node-js-app init-process false
如需重新启用,将 init-process 置空即可(空值会删除该属性,恢复默认行为):
dokku scheduler-docker-local:set node-js-app init-process
默认值也可以通过 --global 标志在全局范围配置,应用级取值优先于全局值:
# 全局关闭 init 进程注入
dokku scheduler-docker-local:set --global init-process false
# 清除全局值,恢复默认(true)
dokku scheduler-docker-local:set --global init-process
一个重要的自动特判:当既没有应用级值、也没有全局值时,凡是带有 org.opencontainers.image.vendor=linuxserver.io 标签的镜像,init 注入会被强制关闭,无需任何手动配置。这是因为 linuxserver.io 的镜像统一使用 s6-overlay 作为 init。该逻辑在 plugins/scheduler-docker-local/bin/scheduler-deploy-process 中体现:
INJECT_INIT_FLAG="$(fn-scheduler-docker-local-init-process "$APP")"
if [[ -z "$INJECT_INIT_FLAG" ]]; then
INJECT_INIT_FLAG="$(fn-plugin-property-get-default "scheduler-docker-local" "--global" "init-process" "")"
fi
if [[ -z "$INJECT_INIT_FLAG" ]]; then
image_vendor="$("$DOCKER_BIN" image inspect --format '{{ index .Config.Labels "org.opencontainers.image.vendor" }}' "$IMAGE")"
if [[ "$image_vendor" == "linuxserver.io" ]]; then
INJECT_INIT_FLAG="false"
else
INJECT_INIT_FLAG="true"
fi
fi
最终,--init 参数在容器创建时按 INJECT_INIT_FLAG 决定是否追加(见 plugins/scheduler-docker-local/bin/scheduler-deploy-process-container)。
并行部署多个进程类型(parallel-schedule-count 属性)
自 0.25.5 起支持。
默认情况下,Dokku 按顺序逐个部署应用的进程类型,且 web 进程总是最先被部署。通过设置 parallel-schedule-count 属性(默认值为 1)可以提升并行度——该值表示一次最多可并行调度多少个进程类型(web 进程除外)。
# 将并行度从每次 1 个进程类型提升到 4 个进程类型
dokku scheduler-docker-local:set node-js-app parallel-schedule-count 4
恢复默认(逐个部署):
dokku scheduler-docker-local:set node-js-app parallel-schedule-count
同样支持全局配置,应用级优先于全局:
dokku scheduler-docker-local:set --global parallel-schedule-count 4
dokku scheduler-docker-local:set --global parallel-schedule-count
并行调度的失败语义
若并行度提高后某个进程类型调度失败,则:
- 已在执行中的进程类型会继续处理完毕;
- 尚未开始调度的进程类型会被跳过;
- 部署最终以失败收尾。
另外,容器调度的输出按接收顺序显示,因此当存在 stderr 输出时,展示顺序可能与实际调度顺序不一致,属正常现象。
性能注意事项
提高 parallel-schedule-count 会显著增加主机 CPU 占用,因为多个应用容器及其进程会同时启动。不建议把该值设置得高于主机的 CPU 核数,请根据服务器实际负载谨慎取值,以免压垮宿主机。
从实现层面看,scheduler-deploy 触发器把除 web 之外的所有进程类型写入临时文件,随后用 GNU parallel 工具以 --jobs 指定并行度执行(--halt soon,fail=1 表示任一失败即尽快终止);web 进程则始终被单独、首先处理(见 plugins/scheduler-docker-local/scheduler-deploy)。
进程内部的并行度提升(app.json max_parallel)
自 0.26.0 起支持。
parallel-schedule-count 控制的是不同进程类型之间的并行度;而默认情况下,同一个进程类型内部的多个实例仍然是逐个部署的。若要提升某进程类型内部实例的启动并行度,可在应用的 app.json 中为对应进程类型设置 formation 键下的 max_parallel:
{
"formation": {
"web": {
"max_parallel": 1
},
"worker": {
"max_parallel": 4
}
}
}
- 省略或删除某个进程类型的
max_parallel条目,该进程类型将恢复为一次启动 1 个实例; - 该机制可以与
parallel-schedule-count组合使用,进一步加速部署; - 与上文相同的性能提醒同样适用:
max_parallel越大,容器启动期间宿主机 CPU 占用越高,不建议超过 CPU 核数。
源码侧,max_parallel 是 plugins/app-json/appjson.go 中 formation 结构体定义的字段(MaxParallel *int),部署时通过 app-json-process-deploy-parallelism 触发器读取并传递给容器部署流程(见 plugins/scheduler-docker-local/bin/scheduler-deploy-process)。
关于 app.json 的存放位置与自定义路径,可参考 deployment-tasks 文档。
查看调度器配置报告(scheduler-docker-local:report)
使用 scheduler-docker-local:report 命令可以查看应用当前的调度器配置报告:
dokku scheduler-docker-local:report
输出示例:
=====> node-js-app scheduler-docker-local information
Scheduler docker local computed init process: true
Scheduler docker local computed parallel schedule count:1
Scheduler docker local global init process: true
Scheduler docker local global parallel schedule count: 1
Scheduler docker local init process:
Scheduler docker local parallel schedule count:
也支持针对单个应用查看:
dokku scheduler-docker-local:report node-js-app
还可以通过 flag 只输出某一项的具体值,便于脚本化取值:
dokku scheduler-docker-local:report node-js-app --scheduler-docker-local-computed-init-process
使用 --global 时只报告全局键:
dokku scheduler-docker-local:report --global
全部可用的报告键
| 键 | 含义 |
|---|---|
--scheduler-docker-local-init-process |
应用级 init-process 原始值(未设置时为空) |
--scheduler-docker-local-computed-init-process |
生效的 init-process 值:应用级优先,其次全局值,最后默认 true |
--scheduler-docker-local-global-init-process |
全局 init-process 值(默认 true) |
--scheduler-docker-local-parallel-schedule-count |
应用级 parallel-schedule-count 原始值(未设置时为空) |
--scheduler-docker-local-computed-parallel-schedule-count |
生效的并行度:应用级优先,其次全局值,最后默认 1 |
--scheduler-docker-local-global-parallel-schedule-count |
全局并行度值(默认 1) |
报告还支持 JSON 输出,便于外部工具区分"应用显式设置的值"与"回退到默认值":
dokku scheduler-docker-local:report node-js-app --format json
报告功能的实现位于 plugins/scheduler-docker-local/report.go:ReportSingleApp 为不同作用域(--global 与普通应用)注册不同的报告 flag 集合,而 reportComputedInitProcess 等计算函数严格遵循"应用级 → 全局级 → 默认值"的三级回退逻辑(如 reportComputedInitProcess 在两层取值均为空时返回 "true")。Shell 侧对应的取值函数(fn-scheduler-docker-local-*)定义于 plugins/scheduler-docker-local/internal-functions,两者逻辑保持一致。
调度器接口与能力范围
scheduler-docker-local 通过 plugn 触发器机制与 Dokku 核心集成,在单机 Docker 上实现了以下功能:
apps:cloneapps:destroyapps:renamedeployenterlogsps:inspectps:stoprun
对应到插件目录下的触发器脚本,包括 scheduler-deploy、scheduler-enter、scheduler-inspect、scheduler-logs、scheduler-run、scheduler-stop、scheduler-app-status、scheduler-register-retired、scheduler-retire、scheduler-is-deployed 等,构成了完整的容器生命周期管理链。
日志支持
logs 命令的应用日志直接通过 docker CLI 从运行中的容器获取。由于容器被销毁后日志即丢失,如需跨部署持久化日志,建议使用 Dokku 的 vector 日志集成,将日志发送到其他服务或第三方日志平台。
支持的资源管理属性
docker-local 调度器支持少量资源 limits(限制)与 reservations(预留)属性,通过 Dokku 的资源管理能力作用于 Docker 运行参数:
资源限制(Resource Limits)
| 属性 | Docker 选项 | 说明 |
|---|---|---|
cpu |
--cpus |
进程可访问的 CPU 数量(核数) |
memory |
--memory |
内存限制,须带后缀:b(字节)、k(千字节)、m(兆字节)、g(吉字节),默认单位为 m |
memory-swap |
--memory-swap |
内存+交换区限制,后缀规则同上 |
nvidia-gpus |
--gpus |
进程可访问的 NVIDIA GPU 数量 |
资源预留(Resource Reservations)
| 属性 | Docker 选项 | 说明 |
|---|---|---|
memory |
--memory-reservation |
内存软性预留,后缀规则同上,默认单位为 m |
上述属性均映射到 Docker Runtime Options 文档中对应的资源约束语义,实际生效参数由 Docker 守护进程执行。
属性一览(Settable properties)
scheduler-docker-local 支持设置的全部属性汇总如下:
| 属性 | 作用域 | 默认值 | 报告 flag | 描述 |
|---|---|---|---|---|
init-process |
应用 + 全局 | true |
--scheduler-docker-local-init-process、--scheduler-docker-local-global-init-process、--scheduler-docker-local-computed-init-process |
为 true 时以 Docker 的 --init 标志运行容器(回收僵尸进程);linuxserver.io 镜像自动豁免 |
parallel-schedule-count |
应用 + 全局 | 1 |
--scheduler-docker-local-parallel-schedule-count、--scheduler-docker-local-global-parallel-schedule-count、--scheduler-docker-local-computed-parallel-schedule-count |
一次部署中并行调度的最大容器数(web 进程除外) |
两条属性均支持"应用级优先、全局级兜底、内置默认值最后兜底"的三级取值链,且都能通过置空值的方式清除恢复默认,配合 --format json 报告可以清晰审计每个应用实际生效的调度配置。对于大多数单机部署场景,保持默认值即可;只有在跨架构部署、自定义 init 或追求更快的大规模并发启动时,才需要调整上述配置。
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 StartedRust4.2 K634
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown300
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java101
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java50
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript60
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python280