Docker Run to Compose - Docker命令转换为Compose YAML 在线工具
将docker run命令转换为docker-compose.yml格式。即时解析端口、卷、环境变量和30多个Docker标志 — 100%客户端处理,您的数据永远不会离开浏览器。
常见问题
什么是Docker Run to Compose转换器?
Docker Run to Compose转换器是一个将docker run CLI命令转换为docker-compose.yml(Docker Compose)YAML配置文件的工具。当您使用docker run -d --name nginx -p 80:80 nginx:latest这样的命令运行容器时,转换器会生成包含services、ports、volumes等指令的等效Compose YAML。这很有用,因为Compose文件可以进行版本控制、可重现,并且可以管理多容器应用程序。
如何使用这个Docker Run to Compose转换器?
将您的docker run命令粘贴到输入区域(可以包含或不包含docker run前缀)。转换会在您输入时自动实时进行。在输出区域查看生成的docker-compose.yml YAML。根据需要调整选项:选择Compose版本(Latest、v3.x或v2.x)和缩进(2或4个空格)。点击复制按钮将YAML复制到剪贴板,或点击下载将其保存为docker-compose.yml文件。
我的数据安全吗?会发送到服务器吗?
您的数据100%安全,永远不会离开您的浏览器。所有解析和转换完全在您设备上运行的客户端JavaScript中进行。没有Docker命令、环境变量、密码、API密钥或任何其他数据会被传输到任何服务器。您可以通过断开互联网来验证——初始页面加载后,该工具完全离线工作。
支持哪些docker run标志?
此转换器支持30多个常用的Docker run标志,包括:端口映射(-p)、卷(-v、--mount)、环境变量(-e、--env-file)、容器名称(--name)、重启策略(--restart)、网络(--network)、工作目录(-w)、用户(-u)、主机名(-h)、入口点(--entrypoint)、标签(-l)、Linux能力(--cap-add、--cap-drop)、特权模式(--privileged)、设备(--device)、日志(--log-driver、--log-opt)、资源限制(--memory、--cpus)、健康检查等。没有直接Compose对应的标志(如--rm)会显示警告。
Docker Compose版本(v2、v3、latest)有什么区别?
Docker Compose经历了多个规范版本的演进。版本2.x引入了services、networks和volumes作为顶级键,使用mem_limit等键进行资源约束。版本3.x为Docker Swarm兼容性而设计,将资源限制移至deploy.resources下。Latest(Common Specification)是省略version字段并使用最新语法的现代格式。对于大多数新项目,请使用Latest。
可以粘贴带反斜杠的多行docker run命令吗?
可以,转换器完全支持带反斜杠(\)换行的多行命令,这在从shell脚本、文档或README文件复制命令时很常见。工具会在转换前自动将其规范化为单个命令。只需原样粘贴多行命令即可。
为什么转换后的输出与预期不同?
常见原因包括:(1) 标志顺序——Compose YAML有标准的键顺序,可能与命令中的标志顺序不同。(2) 隐式默认值——-d(分离模式)等标志在Compose中是默认的,可能不会显式出现。(3) 版本差异——资源限制(--memory、--cpus)在v2和v3 Compose格式中表示方式不同。(4) 不支持的标志——--rm等标志在Compose中没有直接等效项,会以警告形式显示。
代码示例
// Docker Run to Docker Compose converter
// Parses docker run command and generates docker-compose.yml YAML
function parseDockerRun(command) {
const normalized = command.replace(/\\\s*\n/g, ' ').trim();
const stripped = normalized.replace(/^docker\s+run\s+/, '');
const tokens = tokenize(stripped);
const options = {
image: '', name: '', ports: [], volumes: [],
envVars: [], network: '', restart: '',
workdir: '', hostname: '', command: [],
detach: false, privileged: false,
};
let i = 0;
while (i < tokens.length) {
const token = tokens[i];
if (token === '-p' || token === '--publish') {
const val = tokens[++i];
const parts = val.split(':');
options.ports.push({ host: parts[0], container: parts.slice(1).join(':') });
} else if (token === '-v' || token === '--volume') {
const val = tokens[++i];
const parts = val.split(':');
options.volumes.push({ host: parts[0], container: parts[1], mode: parts[2] || '' });
} else if (token === '-e' || token === '--env') {
const val = tokens[++i];
const eq = val.indexOf('=');
options.envVars.push({ key: val.substring(0, eq), value: val.substring(eq + 1) });
} else if (token === '--name') { options.name = tokens[++i]; }
else if (token === '--restart') { options.restart = tokens[++i]; }
else if (token === '--network') { options.network = tokens[++i]; }
else if (token === '-d') { options.detach = true; }
else if (!token.startsWith('-')) {
options.image = token;
options.command = tokens.slice(i + 1);
break;
}
i++;
}
return options;
}
function tokenize(input) {
const tokens = [];
let current = '', inSQ = false, inDQ = false;
for (const char of input) {
if (char === "'" && !inDQ) { inSQ = !inSQ; }
else if (char === '"' && !inSQ) { inDQ = !inDQ; }
else if (char === ' ' && !inSQ && !inDQ) {
if (current) { tokens.push(current); current = ''; }
} else { current += char; }
}
if (current) tokens.push(current);
return tokens;
}
function generateComposeYaml(options, indent = 2) {
const pad = ' '.repeat(indent);
const p2 = pad.repeat(2), p3 = pad.repeat(3);
const name = options.name || options.image.split('/').pop().split(':')[0] || 'app';
let yaml = `services:\n${pad}${name}:\n${p2}image: ${options.image}\n`;
if (options.name) yaml += `${p2}container_name: ${options.name}\n`;
if (options.restart) yaml += `${p2}restart: ${options.restart}\n`;
if (options.ports.length > 0) {
yaml += `${p2}ports:\n`;
options.ports.forEach(p => yaml += `${p3}- "${p.host}:${p.container}"\n`);
}
if (options.volumes.length > 0) {
yaml += `${p2}volumes:\n`;
options.volumes.forEach(v => {
const mode = v.mode ? `:${v.mode}` : '';
yaml += `${p3}- ${v.host}:${v.container}${mode}\n`;
});
}
if (options.envVars.length > 0) {
yaml += `${p2}environment:\n`;
options.envVars.forEach(e => yaml += `${p3}- ${e.key}=${e.value}\n`);
}
if (options.network) {
yaml += `${p2}networks:\n${p3}- ${options.network}\n`;
}
return yaml;
}
// Example usage
const cmd = 'docker run -d --name nginx -p 80:80 -v ./html:/usr/share/nginx/html nginx:latest';
const opts = parseDockerRun(cmd);
console.log(generateComposeYaml(opts));