docker run 转 docker-compose,复盘拆出 12 个坑
需求听起来简单到不值一提输入一条docker run命令输出等价的docker-compose.yml。字符串进字符串出没有网络请求没有状态。我给自己排了 30 分钟。最后花了一整天。这篇文章把过程中拆出来的 12 个坑全部摊开——包括一个写这篇文章时复查代码才抓出来的真 bug第 7 坑60 进制那个。完整实现 300 行左右已开源成单文件工具文末有链接全部代码都能对着看。第一段流水线分词split( )活不过第一个测试用例最直觉的写法一行搞定var tokens cmd.split( );然后第一个真实命令就把它打穿了docker run -e MSGhello world \ --name web nginx两个问题引号里的空格不能切行尾的\续行符要当空格处理。正则也不好使——引号可以是单引号也可以是双引号还能出现在参数中间--envAb c。老老实实写状态机核心就 12 行function tokenize(cmd){ cmd String(cmd||).replace(/\\\r?\n/g, ).trim(); // 坑1先吃掉续行符 var out[], cur, qnull; for(var i0;icmd.length;i){ var ccmd[i]; if(q){ if(cq) qnull; else curc; } // 引号内只认配对引号 else if(c||c) qc; // 引号外进入引号态 else if(/\s/.test(c)){ if(cur){out.push(cur);cur;} } else curc; } if(cur) out.push(cur); return out; }一个q变量记住当前在哪种引号里出来的 token 已经自动脱掉引号。这是整个转换器的地基它错一个字符后面全错。第二段流水线参数解析docker 的 flag 有三副面孔同一个环境变量用户可能写成三种形态docker run -e Ab img # 短选项 空格 docker run --env Ab img # 长选项 空格 docker run --envAb img # 长选项 等号第三种最阴险--envAb里有两个只能切第一刀坑 2var keya, valnull, eqa.indexOf(); if(a.slice(0,2)-- eq0){ keya.slice(0,eq); vala.slice(eq1); }接着是坑 3-d后面不跟值-p后面必须跟一个值。你不查表就没法知道下一个 token 是「当前 flag 的值」还是「下一个 flag」。没有捷径把 docker run 的参数表抄成两个白名单var FLAG_ARG {-p:1,--publish:1,-v:1,--volume:1,-e:1,--env:1, --name:1,--restart:1,--network:1, /* ...30 个 */}; var FLAG_BOOL{-d:1,--detach:1,--rm:1,--privileged:1, -t:1,--tty:1,-i:1,--interactive:1, /* ... */};坑 4是分界线问题docker run -w /app node:20 npm start里npm start不是参数是容器启动命令。规则是遇到第一个不以-开头且不是某个 flag 的值的 token它就是镜像名镜像名之后的一切原样进command哪怕它长得像 flagif(o.image){ o.command.push(a); i; continue; } // 镜像名之后全是 command if(a[0]!-){ o.imagea; i; continue; } // 第一个裸 token镜像名docker run img --rm里的--rm是传给容器的参数不是 docker 的——这条规则保证了语义正确。语义翻译有些参数在 compose 世界里根本不存在坑 5-d和--rm没有对应物。compose 服务天生就是后台常驻的-d直接丢弃--rm的「退出即删」语义靠docker compose down实现也丢弃。丢弃是对的但要静默丢弃不能报错——用户的命令没有错。坑 6--network mynet要写两处。服务里声明加入网络顶层还得声明这个网络是外部已存在的漏掉第二处docker compose up直接报错services: web: networks: - mynet networks: # 这一段最容易忘 mynet: external: true坑 10资源限制有版本裂缝。--memory 512m在 compose v2 语法里是mem_limit在 v3 Swarm 里是deploy.resources.limits。本地开发场景docker compose up对mem_limit的支持最直接选它——但选择本身就是坑你得知道自己在哪条兼容线上。第三段流水线YAML 输出看起来最简单坑最深坑 7本文最值钱的一个YAML 1.1 的 60 进制陷阱。写这篇文章时我复查yq()引号函数突然意识到一个问题ports: - 53:53不带引号的53:53会被 YAML 1.1 解析器读成60 进制整数 323353×6053。你想映射 DNS 端口实际得到一个叫3233的东西。只要冒号两边都是 ≤59 的纯数字就会中招22:22SSH、25:25SMTP全在雷区。而我的yq()白名单里恰好放行了冒号——意味着端口全部裸奔。修复端口一律强制加引号其他字段维持白名单策略function yqq(s){ // 强制引号版专供 ports return String(s).replace(/\\/g,\\\\).replace(//g,\\) ; } list(ports, o.ports, true); // forcetrue → 走 yqq顺手加了回归断言让这个坑永远不会复活ok(yaml sexagesimal guard, A.toCompose(docker run -p 53:53 img).indexOf(- 53:53) 0);修复的 commit 已推送。这是「写文章」这件事直接改进了代码的一次实证——把实现讲给别人听的过程就是最严格的 code review。坑 8是引号的整体策略全部加引号最安全但产物很丑全部不加则Ab c、x!y这类值会炸。折中安全字符白名单字母数字._/:-放行其余加引号并转义反斜杠和双引号。坑 9用户没写--name时服务名从哪来从镜像名剥去 tag、去 registry 路径、洗掉 YAML 不认的字符全空则兜底appvar svc o.name || String(o.image).split(:)[0].split(/).pop() .replace(/[^A-Za-z0-9_-]/g,) || app; // registry.example.com/team/api-server:v2 → api-server收尾的两个工程决策坑 11未知参数怎么办docker run 的参数有上百个白名单不可能穷尽。原则是诚实优先认不出的参数收进unknown[]转换照常完成但在产物顶部用注释亮出来# 警告: 未识别参数 --some-exotic-flag services: ...用户拿到的是「95 分答案 明确告诉你哪 5 分要自己补」这比假装 100 分或直接罢工都有用。坑 12一个 HTML 文件怎么写测试这个工具是单文件应用一个 HTML 就是全部没有构建链那测试怎么跑答案是把纯函数层和 UI 层拆成两个script第一个只有纯函数末尾挂双导出if (typeof module ! undefined module.exports) { module.exports { tokenize, parseDockerRun, toCompose }; // Node 测试用 } if (typeof window ! undefined) { window.DockerForgePure { tokenize, parseDockerRun, toCompose }; // 浏览器用 }测试脚本用正则抠出第一个script的内容new Function在 Node 里直接执行——不装任何测试框架23 条断言毫秒级跑完。UI 层则用 jsdom 做冒烟测试。CI 里node _test.js node smoke.js两行搞定。写在最后一条命令的转换器麻雀虽小分词状态机、参数语法的三形态、两个世界的语义翻译、YAML 的历史包袱、防御性输出、零框架测试——每一层都有值得较真的细节。三个可以直接带走的结论1.凡是「把一种字符串变成另一种字符串」的需求都比看起来难难点永远在两种格式各自的边角语义里2.YAML 里的值拿不准就加引号尤其是ports这种冒号分隔的字段3.把实现写成文章是性价比最高的 code review——第 7 个坑就是这么抓出来的。工具已开源MIT单 HTML 文件双击即用数据不出本机- DockerForge 在线版DockerForge — 离线 docker run 转 docker-compose 转换器- 源码300 行含全部测试https://github.com/wangzifan396-wzf/DockerForge- 同系列 82 款单文件工具导航nano-tools · 单文件零依赖工具集

相关新闻

Anki Cloze填空高级技巧:从字段验证到嵌套逻辑的完整指南 [特殊字符]

Anki Cloze填空高级技巧:从字段验证到嵌套逻辑的完整指南 [特殊字符]

Anki Cloze填空高级技巧:从字段验证到嵌套逻辑的完整指南 🚀 【免费下载链接】anki Anki is a smart spaced repetition flashcard program 项目地址: https://gitcode.com/GitHub_Trending/an/anki Anki作为智能间隔重复记忆软件,其C…

2026/10/18 5:31:30 阅读更多 →
TradingView Charting Library企业级跨平台集成架构:高性能金融图表解决方案

TradingView Charting Library企业级跨平台集成架构:高性能金融图表解决方案

TradingView Charting Library企业级跨平台集成架构:高性能金融图表解决方案 【免费下载链接】charting-library-examples Examples of Charting Library integrations with other libraries, frameworks and data transports 项目地址: https://gitcode.com/gh_m…

2026/10/19 4:52:15 阅读更多 →
Stable Zero123终极指南:从单张图片快速生成高质量3D模型的完整教程

Stable Zero123终极指南:从单张图片快速生成高质量3D模型的完整教程

Stable Zero123终极指南:从单张图片快速生成高质量3D模型的完整教程 【免费下载链接】stable-zero123 项目地址: https://ai.gitcode.com/hf_mirrors/stabilityai/stable-zero123 Stable Zero123是一个革命性的AI模型,能够从单张图片生成高质量的…

2026/10/19 5:19:11 阅读更多 →

最新新闻

开源真实世界数据集AGIBOT WORLD 2026:具身智能数据瓶颈与解法解析

开源真实世界数据集AGIBOT WORLD 2026:具身智能数据瓶颈与解法解析

如果问当前具身智能领域最缺什么,很多一线研发者会不约而同回答两个字:数据。语言模型和视觉模型这些年吃掉了海量互联网文本和图片,收益肉眼可见;但机器人操作模型完全不是这个玩法,它依赖的是机械臂在真实任务中记录…

2026/10/19 5:39:26 阅读更多 →
纯Python手写CNN:230行跑通MNIST,前向反向全透明

纯Python手写CNN:230行跑通MNIST,前向反向全透明

简介:本资源是一份面向深度学习初学者与原理探究者的纯Python卷积神经网络(CNN)实现方案,不依赖TensorFlow、PyTorch等框架,聚焦底层计算逻辑与反向传播机制的理解。适合高校学生、转行学习者及希望夯实CNN数学基础的开…

2026/10/19 5:39:26 阅读更多 →
大模型显存占用全解析:从训练到推理的算账指南

大模型显存占用全解析:从训练到推理的算账指南

跑大模型训练的人,多多少少都经历过这样的瞬间:显卡显存监控明明还剩二三十GB,任务却突然弹出一行“CUDA out of memory”;推理服务昨晚还好好的,今天并发一上来,就开始批量拒绝请求。很多人第一反应是“加…

2026/10/19 5:39:26 阅读更多 →
C# DocX库实战:免Office生成编辑Word并转PDF

C# DocX库实战:免Office生成编辑Word并转PDF

简介:面向.NET开发者的C#DocX资源包,随附源码、动态库与可直接运行的Demo工程,用于在不依赖Microsoft Office环境的前提下完成Word文档的创建、编辑、读取、内容替换以及PDF转换,能够支持自动化报告生成、在线文档编辑器、数据导出…

2026/10/19 5:39:26 阅读更多 →
MySQL 5.7定时任务实战:用事件调度器自动清理表记录

MySQL 5.7定时任务实战:用事件调度器自动清理表记录

很多做开发和运维的朋友都遇到过这类需求:业务跑着跑着,某张表的体积肉眼可见地往上涨,查了一下发现全是日志数据、临时缓存或者历史流水,留着碍事,删了又怕以后要查。尤其是 MySQL 5.7 环境里,表动不动几个…

2026/10/19 5:39:26 阅读更多 →
MCP协议深度解析:从设计思路到实战落地,智能体工具集成不再难

MCP协议深度解析:从设计思路到实战落地,智能体工具集成不再难

1. 为什么这一讲值得单独拿出来精讲MCP,全称 Model Context Protocol,是近两年在智能体工程圈子里被反复讨论的一个协议规范。如果你正在做 AI 应用开发,尤其是涉及工具调用、多智能体协作、外部数据源接入这类场景,那 MCP 基本是…

2026/10/19 5:38:26 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →