Skip to content

WSL 開發環境改為在 Ubuntu 中執行 Docker

Published: 7 分鐘

雖然 Docker Desktop for WSL 利用 WSL 來執行 Linux 容器,一方面提高容器在 Windows 環境的執行效率,一方面也提高記憶體等資源與主機系統的共用程度。雖然相對之前採用完整虛擬機相對節省資源,但對山姆鍋的低配 Surface Pro 來說還是太佔資源。也由於 WSL 2 已經可以直接執行 Docker engine 來支援 Linux 容器的執行,所以決定改採用這個方式來提供 Docker 服務。

在「Docker Desktop for WSL2 容器化開發環境」這篇文章說明山姆鍋為何嘗試改造 Surface Pro 成為替代的開發環境,本文是基於該環境設定所做的修改。

改在 WSL 內執行 Docker Engine 的優缺點

雖說主要優點是節省執行時期的系統資源,但因為 WSL Ubuntu 尚並不支援 Systemd,這會導致像 Docker CE 這樣以 daemon 形式執行的服務無法隨 Ubuntu 系統啟動時自動執行。這也不難理解,畢竟 WSL 只是用來作為開發用途,不是真正用來執行對外服務。由於這個 Surface Pro 只有在用作工作時才需要執行 Ubuntu 環境(主要用途還是移動時在 Windows 環境使用),這點對山姆鍋來說不算是問題。

失敗的嘗試

從 Google 搜尋相關的教學文章會發現有些會說只需要透過 sudo apt install docker.io 安裝就可以。但山姆鍋試過後發現這樣的安裝方式並無法使用 sudo service docker start 指令來正常啟動 Docker engine,會出現無法找到 “docker” 服務的錯誤。也許是山姆鍋的操作步驟有錯誤,但改用 Docker 官方安裝文件卻可以正常運作。所以,最後是採用 Docker 官方的安裝步驟。

安裝 Docker CE

安裝方式就是按照 Docker 官方提供的文件說明,按照步驟在 Ubuntu 18.04 系統中進行。如前面所述,這樣的安裝方式並無法自動執行 Docker 服務,需要自行手動執行下列指令來啟動:

sudo service docker start

一旦 Docker 服務啟動後,操作就跟在其它環境相同。

Start docker service

讓 Windows 環境可以連到 WSL 中的 Docker

山姆鍋自己目前並沒有這個需求,但如果您需要讓 WSL 中的 Docker 服務可以被 Windows 的程式存取(甚至其它電腦,但不建議),需要額外做一些設定。

開放 Docker 服務的 TCP 埠

預設 Docker engine 只監聽 Unix socket 來讓客戶端連線操作,為了讓 Windows 環境中的程式可以存取,需要開放可以使用 TCP 透過網路存取。

使用 vim 或者其它文字編輯器修改檔案 “/etc/default/docker” 中的 DOCKER_OPTS 如下所示:

DOCKER_OPTS="-H tcp:127.0.0.1:2375 -H unix:///var/run/docker.sock"

您也可根據需要增加其它給 Docker engine 的參數。 如果 Docker 已經在執行,需要重啟讓新參數生效。

$ sudo servie docker restart

設定 Windows 環境變數

Docker 的客戶端大多可以透過 DOCKER_HOST 這個環境變數來改變要連線的 Docker 服務。所以,需要在 Windows 環境中新增該環境變數,內容為 tcp://127.0.0.1:2375

在 Windows 10 可以透過「開始」選單,輸入 “系統” 找到控制台中的「系統」選項

Start control panel

打開後選 「進階系統設定」—> 「環境變數(N)…」後,在對話筐中新增。

Add docker host

登入時啟動 WSL 以及 Docker 服務

雖說作為開發環境手動執行 Docker 服務也不是什麼問題,在不使用時還可以節省系統資源。但如果是專門用來開發的電腦,登入後就將環境準備好還是比較方便的。WSL環境中的Ubuntu系統沒有支援Systemd來自動啟用服務這點,有大牛提出 可行的方案。雖然高竿但這種作法對於山姆鍋的需求過於複雜,畢竟目的是要啟動服務而不是有盡可能完整的 Systemd 機制。

山姆鍋的作法是藉為 Windows 允許使用者登入系統時可以自動執行指定腳本的機制來實現啟動Ubuntu服務的目的。基本的步驟如下:

  1. 確定您 Ubuntu 環境預設的帳戶已經可以不用密碼(passwordless)透過 sudo 執行程式。
  2. 在 Windows C 槽 建立一個目錄用來存放腳本,這裡山姆鍋是放在 “C:\Users\sam\wsl-scripts” 目錄中。
  3. 在上述目錄建立 run-start-services.vbs 以及 start-services.bat 兩個腳本檔案。
  4. run-start-services.vbs 複製到 shell:startup 這個特殊目錄。
  5. 重新啟動 Windows 登入後,驗證 Docker 服務是否成功啟動。

run-start-services.vbs 腳本內容:

Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "C:\Users\sam\wsl-scripts\start-services.bat" & Chr(34), 0
Set WinScriptHost = Nothing

start-services.bat 腳本內容:

wsl.exe sudo service docker start

wsl.exe 後面的參數就是要在預設的 WSL 環境(山姆鍋的是 Ubuntu 18.04)中執行的指令,所以也可以更換成 WSL 中的一個腳本來同時啟動多個服務。因為,山姆鍋的需求只有啟動 Docker 服務,所以只要執行 sudo service docker start 即可。一旦 Docker 服務啟動,設定好會自動執行(e.g. restart=always)的容器也會自動啟動。

要將 run-start-services.vbs 放到 shell:startup 這個特殊目錄,在 Windows 環境開啟「檔案總管」,在位址列中輸入 shell:startup,將 run-start-services.vbs 複製過來(不是複製捷徑) 。放在這個 shell:startup 特殊目錄的腳本會在您登入Windows系統時自動執行。

注意:因為透過 VBScript 來隱藏命令視窗,shell:startup 目錄中的腳本在登入看到 Windows 桌面時可能還在背景執行,因為第一次執行 wsl.exe 啟動對應的WSL環境需要一些時間。

老實說,山姆鍋使用這個方法遇到幾次服務沒有正常啟動,但因為不是必需機制,所以就沒花時間深究。不過,您可以另外參考這篇文章的作法,至於該方式是不是真的有效,就需要您自己實驗了。

小結

除了比較節省系統資源外,在 WSL 中執行 Docker 服務也可以避開在「Docker Desktop for WSL2 容器化開發環境」提到的 k3d 所遇到的問題。由於現在 Windows 環境中並沒有安裝 Docker Desktop。所以,VS Code 的 Remote - Containers 延伸模組並無法運作,這是因為該模組需要使用 Docker 的命令列工具。

因為上述的問題,陸續在實驗:

  1. 使用瀏覽器 IDE 來取代桌面版的 VS Code。
  2. 安裝 X Server,使用完整 Linux 桌面環境。
  3. Vim + SpaceVim 另類的終端機 IDE。

參考資料

  1. Execute Batch File without Command line visible
郭信義 (Sam Kuo)

奔騰網路科技技術長,專長分散式系統、Web 應用與雲端服務架構、設計、開發、部署與維運。工作之餘,喜歡關注自由軟體的發展與應用,偶爾寫一下部落格文章。