Dokku docker-options 插件完全指南:在 build / deploy / run 阶段精细化定制容器选项
本文基于 Dokku 核心插件
docker-options(自 0.3.17 起提供)编写。该插件允许你在应用的**构建(build)、部署(deploy)、一次性运行(run)**三个不同阶段,为 Dokku 创建的容器传入自定义的 Docker 容器选项(如--ulimit、--shm-size、--gpus、--label等),并可进一步按 Procfile 中的进程类型(process type)进行作用域限定。读完本文,你将掌握 docker-options 的命令体系、阶段与进程语义、引号与转义规则、报告输出格式,以及底层属性存储与升级迁移机制,能够为 Dokku 应用精确配置容器运行参数。
为什么需要 docker-options
Dokku 负责把应用从源码构建成镜像、部署为容器并管理其生命周期,但它并不会把 Docker 的全部能力暴露成 Dokku 命令。docker-options 插件正是为此设计的"透传通道":你把 Docker 语法写好的容器选项交给它,Dokku 会在创建容器时把它们原样拼接到 docker run 的参数中。
插件提供的命令一览:
docker-options:add [--process PROC...] <app> <phase(s)> OPTION # 为应用在指定阶段添加 Docker 选项
docker-options:clear [--process PROC...] <app> [<phase(s)>...] # 清空应用的 docker options
docker-options:list <app> [--process PROC] --phase PHASE # 列出某一进程+阶段组合下的选项
docker-options:remove [--process PROC...] <app> <phase(s)> OPTION # 从应用的指定阶段移除 Docker 选项
docker-options:report [<app>] [<flag>] [--format json|stdout] # 展示一个或多个应用的 docker options 报告
三个核心阶段:build、deploy、run
Dokku 在应用生命周期的多个"阶段"创建容器,docker-options 插件允许你为不同阶段分别配置参数,阶段由 docker-options:add 等命令的第二个位置参数(可逗号分隔多个)指定。
build(构建阶段):提供在构建过程中、各 builder 构建镜像时可用的容器选项。- 需要特别注意的是,某些 builder 可能会丢弃或忽略自身不支持的选项。例如
dockerfilebuilder 不支持挂载卷(mounted volumes)。这一过滤逻辑在源码中有明确体现:triggers.go 中的emitFilteredOptions会针对dockerfile、nixpacks、railpack三类 image source 过滤掉--link、-v、--volume前缀的选项,而对herokuish则过滤--file、--build-args。
- 需要特别注意的是,某些 builder 可能会丢弃或忽略自身不支持的选项。例如
deploy(部署阶段):作用于已部署的进程类型。覆盖应用Procfile中声明的每个进程类型以及应用默认部署的进程。- 对于运行中的容器而言,
deploy通常是你最应该使用的阶段。deploy阶段的选项会在每次进程部署时通过docker-args-process-deploy触发机制注入,参见 triggers.go 中的TriggerDockerArgsProcessDeploy。
- 对于运行中的容器而言,
run(运行阶段):作用于dokku run、dokku run:detached创建的一次性容器,以及app.json中声明的 cron 任务所创建的容器。
[!IMPORTANT]
run阶段并不与docker run或docker container run命令一一对应。在run阶段指定的容器选项只会被run插件与 cron 任务创建的容器使用。请务必根据自己的用例,把选项添加到正确的阶段。
此外,docker options 的增删不会影响任何已经运行的容器,只会作用于修改之后创建的容器。因此修改应用的 docker options 后,必须执行 dokku ps:rebuild 或重新部署才能生效。
从源码看,阶段集合被定义为固定的三个:availablePhases = []string{"build", "deploy", "run"}(见 internal-functions.go)。任何不属于这三个值的阶段参数都会在 parsePhases 中直接报错:Phase(s) must be one of [build deploy run]。
支持的 Docker 选项范围
docker-options 支持的选项以 Docker 官方 docker run 的 [OPTIONS] 部分为准。插件不会用它来修改容器运行的进程或命令,也就是说:
docker run [OPTIONS] [CONTAINER_COMMAND] [ARG...]
其中 [OPTIONS] 正是由 docker-options 插件拼接的部分,而 [CONTAINER_COMMAND] 与 [ARG] 是容器中启动的进程及其参数,它们来自 Dokku 的进程模型。若你想修改 Dockerfile 构建出的容器所运行的命令,请参考 Dockerfile builder 文档中自定义运行命令一节,或通过 Procfile 定义多进程 来实现。
调度器(Scheduler)支持差异
Docker options 使用 Docker 自身的词汇书写,在 docker-local 调度器下会被逐字原样传递给 docker run。而其他调度器只翻译自身运行时中有对应物的子集,忽略其余部分。
k3s调度器会将其中的--cap-add、--cap-drop、--privileged、--sysctl翻译为 Kubernetes 等价物。具体细节(包括"只能设置 namespaced sysctl"的限制)参见 k3s 调度器文档。- 例如给应用设置非特权端口起始值:
dokku docker-options:add node-js-app deploy "--sysctl net.ipv4.ip_unprivileged_port_start=1024"
从源码实现看,docker-local 调度器通过 docker-args-* 系列触发机制消费这些选项:triggers.go 中的 TriggerDockerArgs 会原样回显 stdin,再追加默认作用域下该阶段的选项;而 TriggerDockerArgsProcessDeploy 则负责追加进程作用域的 deploy 选项。
挂载卷与宿主目录:优先使用 storage 插件
Docker 通过 -v / --volume 标志支持卷与宿主目录挂载。为了简化用法,Dokku 提供了 storage 插件作为持久化存储的抽象层。在大多数情况下,Dokku 项目推荐使用持久化存储插件,而不是直接在不同阶段操作 docker options。如何为应用挂载持久化存储,请参阅 持久化存储文档。
命令实战
添加 Docker 选项(docker-options:add)
docker-options:add 接收:应用名、逗号分隔的阶段列表、以及要添加的 docker option。
给应用在 deploy 阶段添加 --ulimit nofile=12:
dokku docker-options:add node-js-app deploy "--ulimit nofile=12"
同时指定多个阶段(用逗号分隔):
dokku docker-options:add node-js-app deploy,run "--ulimit nofile=12"
一次调用添加多个 docker 选项。每个 --flag [value] 组按 flag 边界被识别,为引号安全做 shell 分词,并作为独立条目存储,因此可以完整地通过 docker-options:report 与 docker-options:list 往返:
dokku docker-options:add node-js-app deploy "--ulimit nofile=12" "--shm-size 256m"
这一行为对应源码中的 SplitOptionString(见 dockeroptions.go):它用 shell 解析器做字面量分词(literalFields),再通过 groupOptionTokens 按 flag 边界分组——--build-arg X=Y --link a 会被拆成 ["--build-arg" "X=Y"] 与 ["--link" "a"] 两个独立条目,每个条目单独存储。
引号、转义与 shell 展开语义
选项值会按原样存储并传递给容器。引号只控制一个值如何被拆分成单词——不会发生任何 shell 展开,因此 $(...)、反引号、$VAR 与 glob 通配符都会被当作字面量处理,而不是被 shell 解释。这正是 Traefik 路由规则这类值可以被原样应用的原因:
dokku docker-options:add node-js-app deploy '--label "traefik.http.routers.web.rule=Host(`node-js-app.example.com`) && PathPrefix(`/api`)"'
从源码看,dockeroptions.go 中的 literalFields 使用 mvdan.cc/sh/v3/syntax 解析器直接分词:引号界定单词并被剥离,但参数展开、命令替换等元字符被逐字保留;存储时 quoteShellArg 只对含 shell 特殊字符的 token 加单引号包裹,保证存储形式可读且能通过 eval set -- "$line" 完整往返。
[!WARNING] 0.38.25 之前添加的选项,在创建容器时会被 shell 展开。任何依赖 shell 展开(
$(...)、反引号或$VAR)的选项,在升级后都会被当作字面字符串处理,必须以已解析的值重新添加:dokku docker-options:remove node-js-app deploy "--group-add \$(getent group docker | cut -d: -f3)" dokku docker-options:add node-js-app deploy "--group-add $(getent group docker | cut -d: -f3)"
关于 --process 的位置
一个放错位置的 --process PROC(即放在应用名之后而不是之前)会被当作子命令 flag 处理,而不是存储为 docker option。因此下面两种调用行为完全一致:
dokku docker-options:add --process web node-js-app deploy "--ulimit nofile=12" "--shm-size 256m"
dokku docker-options:add node-js-app deploy "--ulimit nofile=12" "--shm-size 256m" --process web
原因在于子命令使用 pflag 且设置了 SetInterspersed(false)(见 src/subcommands/subcommands.go):出现在应用名之后的 --process 会成为位置参数,被拼入 option 字符串后,SplitOptionString 会把它从选项内容中"提升"回进程列表,而不是作为 docker option 存储。
移除 Docker 选项(docker-options:remove)
docker-options:remove 接收:应用名、逗号分隔的阶段列表、要移除的 docker option。
dokku docker-options:remove node-js-app run "--ulimit nofile=12"
多阶段移除:
dokku docker-options:remove node-js-app deploy,run "--ulimit nofile=12"
一次调用移除多个选项(与 add 的分词规则一致):
dokku docker-options:remove node-js-app deploy "--ulimit nofile=12" "--shm-size 256m"
已存储的选项按 shell 单词匹配,而不是按精确字符串匹配,因此只要值与存储值等价即可,无需字节级一致。用一种引号方式存储的选项,可以用另一种引号方式移除:
dokku docker-options:add node-js-app deploy "--label 'com.example.owner=platform team'"
dokku docker-options:remove node-js-app deploy '--label "com.example.owner=platform team"'
这一"等价匹配"由 dockeroptions.go 中的 optionsEqual 实现:先做精确字符串相等短路,否则对两侧分别做 shell 字面量分词后逐词比较。
清空应用的 Docker 选项(docker-options:clear)
docker-options:clear 可移除应用的所有 docker options:
dokku docker-options:clear node-js-app
-----> Clearing docker-options for node-js-app on all phases
也可以指定一个或多个合法阶段,阶段用逗号分隔;指定非法阶段会报错:
dokku docker-options:clear node-js-app run
-----> Clearing docker-options for node-js-app on phase run
dokku docker-options:clear node-js-app build,run
-----> Clearing docker-options for node-js-app on phase build
-----> Clearing docker-options for node-js-app on phase run
查看 docker-options 报告(docker-options:report)
[!IMPORTANT] 自 0.8.1 起提供。
docker-options:report 可以查看应用的 docker options 状态。不带应用名时,输出所有应用的信息:
dokku docker-options:report
=====> node-js-app docker options information
Docker options build:
Docker options deploy: --ulimit nofile=12 --shm-size 256m
Docker options run: --ulimit nofile=12 --shm-size 256m
=====> python-sample docker options information
Docker options build:
Docker options deploy:
Docker options run:
=====> ruby-sample docker options information
Docker options build:
Docker options deploy:
Docker options run:
也可以针对单个应用:
dokku docker-options:report node-js-app
=====> node-js-app docker options information
Docker options build:
Docker options deploy: -v /var/log/node-js-app:/app/logs
Docker options run: -v /var/log/node-js-app:/app/logs
还可以传入 flag,只输出你关心的那部分信息:
dokku docker-options:report node-js-app --docker-options-build
当配置了进程级选项(见下文)时,报告会为每一个已配置的 process.deploy 组合额外暴露一个动态 flag,命名为 --docker-options-deploy.<process>:
dokku docker-options:report node-js-app --docker-options-deploy.web
JSON 格式报告
通过 --format json 可获得机器可读的 JSON 视图:
dokku docker-options:report node-js-app --format json
JSON 报告包含既有的字符串键(build、deploy、run,以及配置了进程时额外的 deploy.<process>),并为这些简写键提供并行的 -list 键。每个 -list 的值是 JSON 数组,数组元素对应 docker-options:add 时原始存储的每一条选项,这样导出工具可以无损往返包含空格的选项,而无需拆分旧式的空格拼接字符串。空阶段输出空数组([])。已弃用的 docker-options-* 前缀键保持不变,不增加 -list 同伴键。
{
"build": "",
"build-list": [],
"deploy": "-v /logs:/logs --memory=512m",
"deploy-list": ["-v /logs:/logs", "--memory=512m"],
"run": "",
"run-list": [],
"deploy.web": "-p 8080:5000",
"deploy.web-list": ["-p 8080:5000"],
"docker-options-build": "",
"docker-options-deploy": "-v /logs:/logs --memory=512m",
"docker-options-run": "",
"docker-options-deploy.web": "-p 8080:5000"
}
JSON 组装逻辑见 report.go 中的 buildJSONReportData:默认作用域的三个阶段都会生成 -list 数组,进程作用域的每个 deploy.<process> 同样有 -list 同伴。注意 --format json 不能与 info flag 同时指定,否则会报错。
列出某一进程+阶段的选项(docker-options:list)
docker-options:list 打印存储在单个进程+阶段组合下的选项,每行一条。省略 --process 时列出默认作用域:
dokku docker-options:list node-js-app --process web --phase deploy
dokku docker-options:list node-js-app --phase deploy
从源码看(CommandList,见 functions.go),--phase 是必填参数,且必须是 build/deploy/run 之一;当指定 --process 时,若阶段不是 deploy 会报错:--process is only supported for the deploy phase。
进程级选项(Process-Specific Options)
[!IMPORTANT] 自 0.38.0 起提供。
docker options 可以通过一个或多个 --process flag 限定到应用 Procfile 中声明的特定进程类型。这在某个 deploy 阶段选项(例如端口映射)只适用于一种进程类型、却会与其他进程冲突时非常有用——典型场景是 web 进程需要发布 -p 6789:5000,而 worker 进程绝不能绑定该端口。
作用域规则
- 进程作用域仅支持
deploy阶段。build阶段每个应用只运行一次,run阶段面向临时命令与 cron 任务,两者都没有 Procfile 进程类型的概念,因此都会拒绝--process。 - 没有
--globalflag。省略--process保持历史行为:选项作用于应用中的每一个容器。刻意不设--global是有意为之:在 Dokku 其他位置,--global表示"跨所有应用"(如dokku config:set --global),在这个永远只作用于单个应用的插件里会造成误导。 - 进程作用域的约束在源码 internal-functions.go 的
ValidateProcessFlag中强制校验:processScopedPhases仅包含deploy,且_default_作为保留值不可传给--process。
设置进程级选项
# 只给 web 进程添加端口映射
dokku docker-options:add --process web node-js-app deploy "-p 6789:5000"
# 只给 worker 进程添加 GPU 挂载
dokku docker-options:add --process worker node-js-app deploy "--gpus all"
多个 --process flag 可以组合,在一次调用中把同一选项应用到多个进程类型:
dokku docker-options:add --process web --process api node-js-app deploy "-v /shared:/shared"
如果 --process 指定的进程类型当前不在应用的 Procfile 中,命令仍会成功,但会输出一条警告(WarnIfProcessNotInProcfile,见 internal-functions.go)。这允许你在一次会新增该进程类型的部署之前,提前配置好选项。
_default_ 值是内部保留值,不能传给 --process。
移除与清空进程级选项
# 从单个进程移除单个选项
dokku docker-options:remove --process web node-js-app deploy "-p 6789:5000"
# 清空某个进程+阶段的全部选项
dokku docker-options:clear --process worker node-js-app deploy
不带 --process 时,:remove 与 :clear 只作用于默认作用域——进程级列表不会被触碰。
进程+阶段组合的存储模型
从源码看,每个选项条目存储在形如 <processType>.<phase> 的属性键下(propertyKey,见 dockeroptions.go),例如 web.deploy、_default_.build。默认作用域使用保留键 _default_(DefaultProcessType 常量),docker-options:report 把它渲染成固定的 build/deploy/run 键,进程级配置则动态生成 deploy.<process> 键。应用被克隆或重命名时,这些属性会通过 TriggerPostAppCloneSetup / TriggerPostAppRenameSetup(triggers.go)随应用一起复制或迁移。
内部属性与升级迁移机制
以下属性由 docker-options 插件内部记录,不会通过 docker-options:report 暴露:
| 属性 | 作用域 | 说明 | 源码位置 |
|---|---|---|---|
migrated-from-files |
全局 | 全局迁移哨兵,记录旧的 DOCKER_OPTIONS_<PHASE> 扁平文件存储已排空进插件属性 |
functions.go 在安装期迁移运行后写入 "true" |
migrated-build |
每应用 | 记录应用的旧 DOCKER_OPTIONS_BUILD 文件已排空进 _default_.build 属性列表。仅当旧文件包含非空内容时设置 |
functions.go 在每个阶段排空后写入 "true" |
migrated-deploy |
每应用 | 记录旧 DOCKER_OPTIONS_DEPLOY 文件已排空进 _default_.deploy 属性列表。仅当旧文件包含非空内容时设置 |
functions.go 在每个阶段排空后写入 "true" |
migrated-run |
每应用 | 记录旧 DOCKER_OPTIONS_RUN 文件已排空进 _default_.run 属性列表。仅当旧文件包含非空内容时设置 |
functions.go 在每个阶段排空后写入 "true" |
migrated-traefik-backticks |
全局 | 全局哨兵,记录存储的 Traefik label 中带多余反斜杠的反引号已被修复 | functions.go 安装期修复运行后写入 "true" |
migrated-canonical-options |
全局 | 全局哨兵,记录存储的选项已被重写为规范形式:为旧扁平文件排空时未加引号的 shell 元字符值补上引号,并把携带多个 flag 的条目拆分 | functions.go 安装期重写运行后写入 "true" |
这些迁移体现了插件的演进路径:早期版本把选项存为每个应用目录下的 DOCKER_OPTIONS_<PHASE> 扁平文件,后来迁移为 Dokku 的属性(property)存储,并附带多层幂等保护(每阶段全局哨兵 + 每应用哨兵)。安装触发(TriggerInstall,见 triggers.go)会依次执行:属性目录初始化 → 旧文件迁移 → Traefik label 反引号修复 → 规范化重写。此外,升级周期还会把上一版本遗留的 .migrated 文件哨兵转换为新的每阶段属性(convertLegacyMigratedMarker)。
最佳实践小结
- 运行容器用
deploy,一次性命令用run,构建期才用build,并且要意识到 builder 可能忽略不支持的选项(如 dockerfile builder 不支持挂载卷)。 - 卷挂载优先用
storage插件,而不是直接操作 docker options。 - 记住修改后必须
dokku ps:rebuild或重新部署,docker options 不会作用于已运行的容器。 - 多进程应用利用
--process做作用域隔离(如 web 发布端口、worker 挂载 GPU),但要注意进程作用域只在deploy阶段合法。 - 选项值是字面量,不做 shell 展开——依赖
$(...)等展开的旧配置(0.38.25 之前)升级后需以已解析的值重新添加。 - 导出备份时优先用
--format json的-list键,它能保留每条选项的原始边界,避免空格拼接带来的往返失真。
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