Docker Run 轉 Compose

貼上 docker run 命令,直接生成可用的 Compose 服務定義:埠、卷、環境變數、網路、健康檢查與重啟策略,全部在瀏覽器中轉換。

把冗長的 docker run 命令變成可以提交進倉庫的 Compose 檔案。 按你平時輸入的樣子貼上命令即可,含換行續行也沒問題。沒有 Compose 對應項的引數會列進說明,而不是被悄悄丟棄。

從臨時命令到可復現的檔案

為什麼轉換不是純機械替換

docker run 命令和 Compose 服務描述的是同一個容器,但回答的問題不同:命令說的是"現在做什麼",檔案說的是"這個服務執行時應當是什麼狀態"。絕大多數引數可以乾淨地對映過去,而對映不過去的那些,幾乎都是在描述"執行這個動作"而不是容器本身。

最典型的是 detach。寫 -d 是告訴守護程序不要佔住你的終端,這是本次呼叫的屬性,不是服務的屬性。在 Compose 中同樣的意圖由命令列的 docker compose up -d 表達,所以這個引數會從檔案裡消失。--rm 同理:它要求本次執行結束後清理,Compose 的對應做法是用完執行 docker compose down。

互動類引數介於兩者之間。-i 和 -t 確實有對應的 Compose 鍵 stdin_open 與 tty,因為"保持一個可連線的 shell"有可能是服務的真實屬性,所以它們會被轉換而不是丟棄——儘管多數長期執行的服務並不需要。

引號是轉換出錯的高發區

轉換失敗最常見的原因,是命令在貼上之前就已經丟了 shell 引號。以健康檢查為例:整條檢測命令必須作為一個引數傳入,所以在命令列裡要用引號包起來。如果去掉引號再貼上,這些詞就變成了獨立引數,映象名會從錯誤的位置被讀取,結果自然是錯的。

本工具會按 shell 的規則分詞,正確處理單引號、雙引號、反斜槓轉義以及反斜槓換行續行,因此直接從腳本里複製出來的命令能保持原有結構。輸出時再按 YAML 規則重新加引號,這一點比多數人以為的更重要:像 8080:80 這樣的埠對映在 YAML 中必須加引號,因為未加引號的冒號分隔值存在歧義,歷史上有解析器會把 22:00 讀成六十進位制數字。

網路,以及檔案無法得知的資訊

網路是唯一一處即使忠實轉換也仍需你來決策的地方。如果命令加入的是 host、none 或 bridge,那屬於模式,會轉成 network_mode;其他名稱則指向一個已經存在的網路,於是服務會得到一條 networks 記錄,並在檔案中把該網路宣告為 external。

這條宣告是對你所處環境的陳述:它表示該網路由本檔案之外的機制管理。如果你更希望由 Compose 建立並持有這個網路,刪掉 external 讓它正常定義即可。工具無法替你判斷,因為原始命令只能證明"執行那一刻網路是存在的"。

繫結掛載同樣需要謹慎。像 /srv/site 這樣的路徑只在寫下命令的那臺機器上成立。一旦服務定義進入會被提交和共享的檔案,改用相對路徑或具名卷通常是更好的選擇。

自研實現,內建手寫的 shell 分詞器與 YAML 生成器。不打包任何第三方解析庫,你的命令不會離開瀏覽器。

常見問題

為什麼輸出裡沒有 -d?
detach 描述的是你如何啟動容器,而不是容器本身。在 Compose 中用 docker compose up -d 表達同樣的意圖,因此它不屬於檔案內容。
可以貼上帶反斜槓的多行命令嗎?
可以。反斜槓換行續行會在解析前被合併,所以你可以直接從指令碼或文件裡複製命令,無需重新排版。
為什麼埠被加上了引號?
YAML 中未加引號的冒號分隔值存在歧義,部分解析器會把 22:00 當成數字。給埠對映加引號是官方推薦的寫法。
生成的網路上的 external: true 是什麼意思?
它告訴 Compose 該網路已經存在,不應由本檔案建立或刪除。如果希望由 Compose 自己管理網路,去掉這個標記即可。
不支援的引數會被靜默忽略嗎?
不會。所有無法對映的內容都會列在轉換說明中,便於你自行決定如何處理,而不是事後才發現遺漏。
我的命令會被上傳嗎?
不會。分詞與 YAML 生成都由手寫程式碼在瀏覽器中完成,命令不會離開當前頁面。