Skip to content

实现 Docker 转 Compose 工具

分类:developer | 标签:docker、compose、运维 将 docker run 命令转为 compose 片段

2.1 功能说明

将 docker run 命令转为 compose 片段

2.1.1 使用指南

功能说明

docker run 命令解析为 docker-compose.yml 片段(services 段落)。

使用场景

把临时运行命令固化为可版本化的 Compose 配置。

2.2 代码实现

2.2.1 组件结构

本工具是一个基于 Vue 3 <script setup> 语法的单文件组件(SFC),统一包裹在 ToolPageShell 组件内,由它提供页面标题、工具 ID、分类与「使用指南」插槽等通用外壳;核心业务逻辑(响应式状态、计算属性、事件处理函数)全部写在 <script setup> 中,输入/输出通过 el-inputel-button 等 Element Plus 组件与用户交互,所有数据均在浏览器本地处理,不会上传服务器。

2.2.2 核心逻辑概览

<script setup> 中定义的主要函数/方法:

  • tokenize()
  • run()
  • copy()
  • clear()

2.2.3 关键实现代码

以下是该工具的完整 <script setup> 实现(核心代码)。模板(<template>)与样式(<style>)已省略。

vue
import { ref } from 'vue'
import { dump as yamlDump } from 'js-yaml'
import ToolPageShell from '@/components/ToolPageShell.vue'

const cmd = ref('')
const output = ref('')
const error = ref('')

function tokenize(s) {
  const re = /"([^"]*)"|'([^']*)'|(\S+)/g
  const out = []; let m
  while ((m = re.exec(s))) out.push(m[1] ?? m[2] ?? m[3])
  return out
}
function run() {
  error.value = output.value = ''
  const raw = cmd.value.trim()
  if (!raw) { error.value = '请输入 docker run 命令'; return }
  const tokens = tokenize(raw)
  // strip leading "docker" and "run"
  let i = 0
  if (tokens[i] === 'docker') i++
  if (tokens[i] === 'run') i++
  const svc = { image: '' }
  const ports = [], volumes = [], env = {}, networks = [], command = []
  let image = ''
  for (; i < tokens.length; i++) {
    const t = tokens[i]
    if (t === '-d' || t === '--detach') continue
    else if (t === '--rm') continue
    else if (t === '-it') { svc.tty = true; svc.stdin_open = true }
    else if (t === '-i' || t === '--interactive') svc.stdin_open = true
    else if (t === '-t' || t === '--tty') svc.tty = true
    else if (t === '--name') { svc.container_name = tokens[++i] }
    else if (t === '-p' || t === '--publish') ports.push(tokens[++i])
    else if (t === '-v' || t === '--volume') volumes.push(tokens[++i])
    else if (t === '-e' || t === '--env') { const kv = tokens[++i].split('='); env[kv[0]] = kv.slice(1).join('=') }
    else if (t === '--network') networks.push(tokens[++i])
    else if (t === '--restart') svc.restart = tokens[++i]
    else if (t === '--entrypoint') svc.entrypoint = tokens[++i]
    else if (image === '') image = t
    else command.push(t)
  }
  if (!image) { error.value = '未识别到镜像名'; return }
  const name = (svc.container_name || image.split('/').pop().split(':')[0]).replace(/[^a-zA-Z0-9_-]/g, '')
  const service = { image }
  if (svc.container_name) service.container_name = svc.container_name
  if (ports.length) service.ports = ports
  if (volumes.length) service.volumes = volumes
  if (Object.keys(env).length) service.environment = env
  if (networks.length) service.networks = networks
  if (svc.restart) service.restart = svc.restart
  if (svc.tty) service.tty = true
  if (svc.stdin_open) service.stdin_open = true
  if (svc.entrypoint) service.entrypoint = svc.entrypoint
  if (command.length) service.command = command
  try {
    output.value = yamlDump({ version: '3.8', services: { [name]: service } })
  } catch (e) { error.value = '生成失败:' + e.message }
}
function copy() { if (output.value) navigator.clipboard?.writeText(output.value) }
function clear() { cmd.value = output.value = error.value = '' }

2.3 效果截图

Docker 转 Compose 效果截图

工具访问地址:https://www.i91tools.com/tools/docker-run-to-compose