
Dokku OpenResty 代理插件实战指南Docker 标签驱动的流量路由与 Lets Encrypt 集成【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku本文面向在 Dokku 平台上希望以 OpenResty 替代默认 nginx 反向代理的开发者。作为 0.31.0 版本引入的新能力Dokku 通过 openresty-vhosts 插件 与dokku/openresty-docker-proxy镜像协作采用Docker 容器标签label机制实现应用路由、HTTPS 自动证书签发与自定义配置注入。读完本文你将掌握从 nginx 平滑切换到 OpenResty 的完整流程、全部openresty:命令的用法、可调优的属性体系以及基于源码的实现原理。一、OpenResty 代理插件概览OpenResty 是一个基于 nginx 与 LuaJIT 构建的高性能 Web 平台。Dokku 对其的集成并非像 nginx 插件那样由 Dokku 直接渲染并管理站点配置文件而是利用 openresty-docker-proxy 项目实现的Docker 标签label集成Dokku 在部署应用容器时把路由所需的标签注入容器OpenResty 容器监听 Docker 事件并依据标签自动完成配置与流量转发。当前仓库中该插件位于 plugins/openresty-vhosts其 Dockerfile 的FROM指令表明默认镜像为dokku/openresty-docker-proxy:0.12.1。插件的命令面command surface由 commands 与 command-functions 提供属性解析与默认值逻辑则集中在 report.go 中。插件对外暴露的完整命令如下openresty:report [app] [flag] # Displays a openresty report for one or more apps openresty:logs [--num num] [--tail] # Display openresty log output openresty:set app property (value) # Set or clear an openresty property for an app openresty:show-config app # Display openresty compose config openresty:start # Starts the openresty server openresty:stop # Stops the openresty server此外commands文件还注册了openresty:labels:add、openresty:labels:remove、openresty:labels:show三个标签管理子命令以及openresty:help。前提条件使用openresty插件集成要求 Docker 安装有docker-compose-plugin因为 OpenResty 容器是通过docker compose up方式启动的。具体安装过程请参阅 Docker 官方文档。从源码看command-functions 中的cmd-openresty-show-config、cmd-openresty-start、cmd-openresty-stop在启动前都会调用fn-is-compose-installed检查未安装时会直接报错Required docker compose plugin is not installed。二、理解 OpenResty 的路由规则OpenResty 插件与 nginx 插件的路由方式有本质区别其路由规则如下标签驱动OpenResty 集成通过附加在容器上的 Docker 标签暴露。标签的变更需要重新部署或重建rebuild应用才会生效。仅 web 容器OpenResty 会尊重其他容器上的标签但插件只为web进程容器注入 OpenResty 标签。端口受限目前仅支持http:80与https:443的端口映射。即时路由只要容器处于运行状态并通过健康检查请求就会被路由。这些规则在 core-post-deploy 触发器中得到印证该触发器在应用部署后检查proxy-type若应用代理类型为openresty则输出Routing app via openresty日志并清理旧的自定义 include 目录缓存。三、从 nginx 切换到 OpenResty[!WARNING] 在同一个 Dokku 实例上同时使用多个代理插件会导致请求路由冲突应避免这样做。由于默认代理实现是 nginx建议在切换到 OpenResty 之前先停止 nginx 服务。为指定应用启用 OpenResty只需设置其代理类型dokku proxy:set node-js-app type openresty这会启用基于 Docker 标签的 OpenResty 集成。所有后续部署都会向容器注入 OpenResty 读取并路由请求所需的标签。由于这种标签机制在请求成功路由之前必须执行一次部署或重建dokku ps:rebuild node-js-app域名或端口映射的任何变更同样需要一次部署或重建才能生效。四、OpenResty 容器的生命周期管理启动 OpenResty 容器dokku openresty:start该命令通过docker compose up启动 OpenResty 容器。从 command-functions 的源码可以看到cmd-openresty-start会先写入全局属性proxy-statusstarted再基于 sigil 模板生成临时的 compose 文件最后调用common compose-up启动服务。停止 OpenResty 容器dokku openresty:stopOpenResty 容器会被停止并从系统中移除若容器本就不在运行此命令不执行任何操作。源码中对应cmd-openresty-stop它会写入proxy-statusstopped并调用common compose-down参见 command-functions。查看 OpenResty 的 compose 配置调试时可以用以下命令查看 OpenResty 的 compose 配置dokku openresty:show-config该命令通过fn-openresty-template-compose-file渲染 compose.yml.sigil 模板后原样输出。从模板源码可以一窥 OpenResty 容器的真实形态--- services: openresty: image: {{ $.OPENRESTY_IMAGE }} environment: - OPENRESTY_LABEL_PREFIXopenresty. {{ if $.OPENRESTY_LETSENCRYPT_EMAIL }} - OPENRESTY_LETSENCRYPT_EMAIL{{ $.OPENRESTY_LETSENCRYPT_EMAIL }} - OPENRESTY_LETSENCRYPT_CA{{ $.OPENRESTY_LETSENCRYPT_SERVER }} {{ end }} network_mode: bridge ports: - 80:80 {{ if $.OPENRESTY_LETSENCRYPT_EMAIL }} - 443:443 {{ end }} restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - {{ $.OPENRESTY_DATA_DIR }}:/etc/resty-auto-ssl几个值得注意的实现细节容器以bridge网络模式运行标签前缀固定为openresty.只有设置了letsencrypt-email时才会映射443:443端口并注入OPENRESTY_LETSENCRYPT_CA环境变量——这解释了为何默认情况下 https 端口映射会被忽略容器以只读方式挂载 Docker socket/var/run/docker.sock用于监听容器事件以动态发现路由证书持久化数据存放在DOKKU_LIB_ROOT/data/openresty-vhosts/.docker-letsencrypt目录参见 internal-functions 中的fn-openresty-template-compose-filerestart: unless-stopped保证容器在宿主机重启后自动恢复。五、自定义 OpenResty 容器镜像默认的 OpenResty 镜像在 Dockerfile 中被硬编码为dokku/openresty-docker-proxy:0.12.1但用户可以通过--global标志设置image属性来替换dokku openresty:set --global image dokku/openresty-docker-proxy:0.5.6这里的镜像解析逻辑fallback可以在 report.go 的dockerfileFromImage函数中看到如果全局属性未设置插件会读取插件目录下Dockerfile的FROM行将其作为计算后的默认镜像。六、查看 OpenResty 容器日志使用openresty:logs命令检查 OpenResty 容器日志dokku openresty:logs该命令支持以下修饰参数--num NUM # the number of lines to display --tail # continually stream logs组合使用示例——持续显示日志流并保留最近 10 行历史dokku openresty:logs --tail --num 10从源码看fn-openresty-logsinternal-functions内部是对容器openresty-openresty-1执行docker logs--tail对应--follow参数cmd-openresty-logs的解析逻辑还支持-n/-t短选项--num的默认值为 100 行参见 command-functions。七、为应用自定义 OpenResty 设置属性设置机制OpenResty 插件通过openresty:set支持nginx:set命令所支持的全部属性属性细节可参阅 nginx 代理文档。命令格式为dokku openresty:set app property (value例如dokku openresty:set node-js-app client-max-body-size 50m注意OpenResty 会使用最旧运行中的容器进行配置因此新配置可能要到旧容器在部署期间/之后按你的零停机zero-downtime设置被回收后才会生效。自定义模板的限制目前 OpenResty 插件不允许完全自定义管理应用 vhost 的模板。应用会使用 OpenResty 容器提供的模板来代理请求用户只能通过下述方式配置模板的局部内容。注入自定义片段snippetsOpenResty 插件允许在应用仓库中放置模板文件使其自动注入 OpenResty 配置。请务必在部署前验证配置的正确性否则可能导致 OpenResty 代理层宕机。应用仓库中以下目录内的*.conf文件会被自动注入openresty/http-includes/注入到为应用提供 http(s) 请求服务的server块中openresty/http-location-includes/注入到应用对应server块中代理到应用的那个location块内。自定义片段的文件名只能包含字母数字、下划线和点号字符。出于安全原因包含其他字符的文件名将被忽略。源码侧fn-openresty-get-http-includes-dir与fn-openresty-get-location-includes-dirinternal-functions会在DOKKU_LIB_ROOT/data/openresty-vhosts/app-$APP/下查找对应目录而 core-post-deploy 会在部署完成后清理标记为.missing的旧 include 目录缓存确保新部署的片段生效。八、标签管理Label ManagementOpenResty 插件允许为应用添加自定义容器标签。这些标签在部署期间注入容器可用来配置插件默认行为之外的 OpenResty 行为。上游 openresty-docker-proxy见 command-functions。添加标签dokku openresty:labels:add node-js-app openresty.directive value这会为应用容器添加标签openresty.directivevalue。添加后需要重建或重新部署应用标签才会应用到运行中的容器dokku ps:rebuild node-js-app移除标签dokku openresty:labels:remove node-js-app openresty.directive移除指定标签后同样需要重建或重新部署dokku ps:rebuild node-js-app查看标签查看应用的全部自定义容器标签dokku openresty:labels:show node-js-app查看某个具体标签的值传入标签名dokku openresty:labels:show node-js-app openresty.directive九、SSL 配置与 Lets Encrypt 集成OpenResty 插件只支持其 letsencrypt 集成提供的自动 SSL 证书certs插件托管的证书会被忽略。这一点与前面 compose 模板中443端口依赖letsencrypt-email的设计完全一致。启用 letsencrypt 集成默认情况下 letsencrypt 处于禁用状态https 端口映射被忽略。通过--global标志设置letsencrypt-email属性即可启用dokku openresty:set --global letsencrypt-email automateddokku.sh启用后需要重启 OpenResty 容器并重建应用此后所有 http 请求都会被重定向到 https。自定义 letsencrypt 服务器letsencrypt 集成默认使用 letsencrypt 生产服务器。要切换到其他 ACME 目录设置letsencrypt-server全局属性dokku openresty:set --global letsencrypt-server https://acme-staging-v02.api.letsencrypt.org/directory切换后同样需要重启容器并重建应用才能从新服务器获取证书。生产服务器的默认值为https://acme-v02.api.letsencrypt.org/directory见 internal-functions 的fn-openresty-computed-letsencrypt-server。限制 letsencrypt 仅对特定域名签发[!WARNING] 修改该值若导致值无效OpenResty 可能无法启动。更改默认值时应格外谨慎。当服务器 IP 上可能解析了无效域名时限制 letsencrypt 仅对白名单域名签发证书可以减少对 letsencrypt 服务器的垃圾请求。默认允许所有域名申请证书但可以通过allowed-letsencrypt-domains-func-base64全局属性进行限制。该属性的默认内部值是return true的 base64 编码它作为一段返回布尔值的Lua 函数体运行。恢复默认值的写法value$(echo return true | base64 -w 0) dokku openresty:set --global allowed-letsencrypt-domains-func-base64 $value由于这是全局值修改后应停止并重新启动 OpenResty 使其生效dokku openresty:stop dokku openresty:start更复杂的示例仅对特定域名列表签发证书。Lua 函数体内可访问变量domainbodyallowed_domains {domain.com, extra-domain.com} for index, value in ipairs(allowed_domains) do if value domain then return true end end return false value$(echo $body | base64 -w 0) dokku openresty:set --global allowed-letsencrypt-domains-func-base64 $value要恢复默认值在重启 OpenResty 之前指定一个空值即可dokku openresty:set --global allowed-letsencrypt-domains-func-base64从源码看report.go 中--openresty-computed-allowed-letsencrypt-domains-func-base64会以return true作为默认值并做 base64 编码而fn-openresty-template-compose-file会把该值作为ALLOWED_DOMAINS_FUNC_BASE64参数传入 sigil 模板internal-functions。十、查看应用 OpenResty 报告使用openresty:report命令查看应用的 OpenResty 配置报告dokku openresty:report输出示例 node-js-app openresty information Openresty image: dokku/openresty-docker-proxy:0.5.6 Openresty letsencrypt email: automateddokku.sh python-app openresty information Openresty image: dokku/openresty-docker-proxy:0.5.6 Openresty letsencrypt email: automateddokku.sh ruby-app openresty information Openresty image: dokku/openresty-docker-proxy:0.5.6 Openresty letsencrypt email: automateddokku.sh也可以只针对单个应用dokku openresty:report node-js-app node-js-app openresty information Openresty image: dokku/openresty-docker-proxy:0.5.6 Openresty letsencrypt email: automateddokku.sh传入 flag 可以只输出特定信息的值例如dokku openresty:report node-js-app --openresty-computed-letsencrypt-email报告实现位于 report.goCommandReportsubcommands.go会遍历所有应用逐一生成报告并支持--format json输出格式。十一、OpenResty 属性全景表理解属性作用域是正确调优的前提。插件共定义五个全局专属global-only属性image、log-level、letsencrypt-email、letsencrypt-server、allowed-letsencrypt-domains-func-base64。其余属性既可按应用设置也可用--global全局设置全局值适用于任何没有应用级值的应用否则使用内置默认值。关于报告 flag 的取值规则由 report.go 实现可对照 internal-functions 中的同名函数验证全局专属属性暴露两个 flag--openresty-global-property返回原始存储值从未设置时为空--openresty-computed-property返回生效值全局值存在则取全局值否则取内置默认值。应用或全局属性暴露三个 flag--openresty-property返回原始应用级值未设置时为空--openresty-global-property返回原始全局值未设置时为空--openresty-computed-property返回生效值解析优先级为应用级值 → 全局值 → 内置默认值。下表为全部属性、作用域、默认值、报告 flag 与说明PropertyScopeDefaultReport flagsDescriptionaccess-log-formatapp or globalnone--openresty-access-log-format,--openresty-global-access-log-format,--openresty-computed-access-log-formatCustom nginxlog_formatdirective used for the access logaccess-log-pathapp or global/var/log/nginx/{app}-access.log--openresty-access-log-path,--openresty-global-access-log-path,--openresty-computed-access-log-pathPath inside the openresty container where access logs are writtenallowed-letsencrypt-domains-func-base64global onlyallow-all stub--openresty-global-allowed-letsencrypt-domains-func-base64,--openresty-computed-allowed-letsencrypt-domains-func-base64Base64-encoded Lua function deciding which domains may request a letsencrypt certificatebind-address-ipv4app or globalnone--openresty-bind-address-ipv4,--openresty-global-bind-address-ipv4,--openresty-computed-bind-address-ipv4IPv4 address the openresty server block binds tobind-address-ipv6app or global::--openresty-bind-address-ipv6,--openresty-global-bind-address-ipv6,--openresty-computed-bind-address-ipv6IPv6 address the openresty server block binds toclient-body-timeoutapp or global60s--openresty-client-body-timeout,--openresty-global-client-body-timeout,--openresty-computed-client-body-timeoutTime allowed to read the request body from the clientclient-header-timeoutapp or global60s--openresty-client-header-timeout,--openresty-global-client-header-timeout,--openresty-computed-client-header-timeoutTime allowed to read the request header from the clientclient-max-body-sizeapp or global1m--openresty-client-max-body-size,--openresty-global-client-max-body-size,--openresty-computed-client-max-body-sizeMaximum allowed request body sizeerror-log-pathapp or global/var/log/nginx/{app}-error.log--openresty-error-log-path,--openresty-global-error-log-path,--openresty-computed-error-log-pathPath inside the openresty container where error logs are writtenhstsapp or globaltrue--openresty-hsts,--openresty-global-hsts,--openresty-computed-hstsWhentrue, emits aStrict-Transport-Securityheader on HTTPS responseshsts-include-subdomainsapp or globaltrue--openresty-hsts-include-subdomains,--openresty-global-hsts-include-subdomains,--openresty-computed-hsts-include-subdomainsAdds theincludeSubDomainsdirective to the HSTS headerhsts-max-ageapp or global15724800--openresty-hsts-max-age,--openresty-global-hsts-max-age,--openresty-computed-hsts-max-agemax-agevalue (seconds) in the HSTS headerhsts-preloadapp or globalfalse--openresty-hsts-preload,--openresty-global-hsts-preload,--openresty-computed-hsts-preloadAdds thepreloaddirective to the HSTS headerimageglobal onlyparsed fromplugins/openresty-vhosts/Dockerfile--openresty-global-image,--openresty-computed-imageDocker image used to run the openresty containerkeepalive-timeoutapp or global75s--openresty-keepalive-timeout,--openresty-global-keepalive-timeout,--openresty-computed-keepalive-timeoutTime an idle keep-alive connection stays openletsencrypt-emailglobal onlynone--openresty-global-letsencrypt-email,--openresty-computed-letsencrypt-emailContact email enabling letsencrypt; empty disables https issuanceletsencrypt-serverglobal onlyhttps://acme-v02.api.letsencrypt.org/directory--openresty-global-letsencrypt-server,--openresty-computed-letsencrypt-serverACME directory used when requesting certificateslingering-timeoutapp or global5s--openresty-lingering-timeout,--openresty-global-lingering-timeout,--openresty-computed-lingering-timeoutTime openresty waits for more client data when closing a connectionlog-levelglobal onlyERROR--openresty-global-log-level,--openresty-computed-log-levelOpenresty log levelproxy-buffer-sizeapp or globalsystem pagesize--openresty-proxy-buffer-size,--openresty-global-proxy-buffer-size,--openresty-computed-proxy-buffer-sizeBuffer size for reading the first part of the upstream responseproxy-bufferingapp or globalon--openresty-proxy-buffering,--openresty-global-proxy-buffering,--openresty-computed-proxy-bufferingWhether openresty buffers upstream responses (onoroff)proxy-buffersapp or global8 {pagesize}--openresty-proxy-buffers,--openresty-global-proxy-buffers,--openresty-computed-proxy-buffersNumber and size of buffers used for an upstream responseproxy-busy-buffers-sizeapp or global2 * pagesize--openresty-proxy-busy-buffers-size,--openresty-global-proxy-busy-buffers-size,--openresty-computed-proxy-busy-buffers-sizeMaximum buffer size that can be busy sending a response to the clientproxy-connect-timeoutapp or global60s--openresty-proxy-connect-timeout,--openresty-global-proxy-connect-timeout,--openresty-computed-proxy-connect-timeoutTime to establish a connection to the upstreamproxy-read-timeoutapp or global60s--openresty-proxy-read-timeout,--openresty-global-proxy-read-timeout,--openresty-computed-proxy-read-timeoutTime to read a response from the upstreamproxy-send-timeoutapp or global60s--openresty-proxy-send-timeout,--openresty-global-proxy-send-timeout,--openresty-computed-proxy-send-timeoutTime to transmit a request to the upstreamsend-timeoutapp or global60s--openresty-send-timeout,--openresty-global-send-timeout,--openresty-computed-send-timeoutTime between two successive write operations to the clientunderscore-in-headersapp or globaloff--openresty-underscore-in-headers,--openresty-global-underscore-in-headers,--openresty-computed-underscore-in-headersWhether to allow underscores in client request header field namesx-forwarded-for-valueapp or global$remote_addr--openresty-x-forwarded-for-value,--openresty-global-x-forwarded-for-value,--openresty-computed-x-forwarded-for-valueValue used for theX-Forwarded-Forheaderx-forwarded-port-valueapp or global$server_port--openresty-x-forwarded-port-value,--openresty-global-x-forwarded-port-value,--openresty-computed-x-forwarded-port-valueValue used for theX-Forwarded-Portheaderx-forwarded-proto-valueapp or global$scheme--openresty-x-forwarded-proto-value,--openresty-global-x-forwarded-proto-value,--openresty-computed-x-forwarded-proto-valueValue used for theX-Forwarded-Protoheaderx-forwarded-sslapp or globalnone--openresty-x-forwarded-ssl,--openresty-global-x-forwarded-ssl,--openresty-computed-x-forwarded-sslValue used for theX-Forwarded-Sslheader (e.g.on/off)补充几点从源码确认的默认值细节access-log-path与error-log-path的默认值形如/var/log/nginx/{app}-access.log与/var/log/nginx/{app}-error.log日志根目录常量openrestyLogRoot /var/log/nginx定义在 report.goproxy-buffer-size、proxy-buffers、proxy-busy-buffers-size的默认值依赖系统内存页大小report.go 通过os.Getpagesize()计算shell 侧则调用 nginx-vhosts 插件的pagesize程序见 internal-functions 的fn-get-pagesizehsts属性的计算逻辑比较特殊--openresty-computed-hsts在应用级与全局级都未设置时取默认值true见 report.go 的openrestyHstsIsEnabled。十二、关键实现原理与调试建议综合以上源码分析可以将 OpenResty 代理的整体工作流概括为属性层属性通过openresty:set存储安装时由install触发器调用fn-plugin-property-setup openresty完成初始化见 install并创建数据目录DOKKU_LIB_ROOT/data/openresty-vhosts/.docker-letsencrypt用于证书持久化。配置层openresty:start/openresty:show-config通过 sigil 模板compose.yml.sigil渲染 compose 文件其参数镜像、letsencrypt 邮箱/服务器、允许域名函数由 internal-functions 的fn-openresty-template-compose-file汇总注入。路由层部署时 core-post-deploy 触发Routing app via openresty应用容器的openresty.*标签随之写入OpenResty 容器通过只读挂载的 Docker socket 监听事件依据标签动态路由。HTTPS 层设置letsencrypt-email后compose 模板才会映射443:443并注入 ACME 环境变量证书数据持久化到宿主机的.docker-letsencrypt数据卷。排障建议标签变更后请求未生效请先执行dokku ps:rebuild app标签注入发生在部署阶段仅重启容器不会重新注入标签怀疑配置问题用dokku openresty:show-config检查最终渲染的 compose 配置确认镜像、端口映射与 letsencrypt 环境变量是否符合预期需要观察 OpenResty 行为用dokku openresty:logs --tail持续跟踪容器日志结合dokku openresty:report app --openresty-computed-property逐项核对生效属性值全局属性如allowed-letsencrypt-domains-func-base64修改后先dokku openresty:stop再dokku openresty:start使其生效避免因值无效导致 OpenResty 无法启动。延伸阅读nginx 代理插件文档了解 OpenResty 属性体系所兼容的 nginx 属性细节SSL 配置文档对比certs插件托管证书与 letsencrypt 自动证书的差异域名管理文档理解域名变更为何要求重建应用proxy 插件源码openresty:labels:*系列命令的通用标签实现【免费下载链接】dokkuA docker-powered PaaS that helps you build and manage the lifecycle of applications项目地址: https://gitcode.com/GitHub_Trending/do/dokku创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考