把 Windows 裝進 Docker 容器裡

牧之丨發表於2024-03-23

本篇文章聊聊如何在 Docker 裡執行 Windows 作業系統, Windows in Docker Container(WinD)。

寫在前面

我日常使用 macOS 和 Ubuntu 來學習和工作,但是時不時會有 Windows 使用的場景,不論是執行某個指定的軟體,還是要做一些跨平臺軟體的功能驗證。

在去年開源 soulteary/docker-chatgpt[1] 之前,還折騰過將 Chrome 容器化,提供有介面服務能力容器的事情,如果當時有這個方案,或許折騰過程能更簡單一些。

環境準備

我們依舊是先從環境準備開始。想要使用這個方案,我們需要準備的東西有三個:安裝了 Docker 的作業系統(我使用 Ubuntu)、Windows 作業系統的安裝光碟(從 WinXP ~ Win11 都行)、開源專案 dockur/windows[2] 的 Docker 映象。

安裝 Ubuntu 作業系統和 Docker

這套方案中採用了 KVM 加速,所以體驗最好的方案是使用或者安裝一個 Linux 環境,如果你本身就在使用 Ubuntu 之類的支援 KVM 非常方便的作業系統的話,那麼只需要安裝 Docker 就好啦。

如果你確實需要在容器中執行 Windows,想從零開始,可以參考之前的文章《在筆記本上搭建高價效比的 Linux 學習環境:基礎篇[3]》的方法來進行實踐。安裝 Ubuntu 的流程和以往並沒有太大不同,依舊是老生常談的三步曲:下載映象、製作啟動盤、安裝系統。

如果你已經有了可以使用的 Linux 環境,可以參考上面文章中的 “更簡單的 Docker 安裝” 章節,完成基礎環境的準備。

完成作業系統和 Docker 的準備後,我們還需要檢查作業系統是否支援 KVM,需要先安裝 cpu-checker

sudo apt install cpu-checker -y

然後,執行 kvm-ok,順利的話,將能夠看到類似下面的日誌輸出:

# sudo kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

獲取 WIndows 作業系統光碟

雖然開源專案 dockur/windows[4] 會根據使用者指令,從 dl.bobpony.comarchive.org,以及微軟官網自動下載合適的英文版系統映象,但如果你想更快的完成系統的安裝,或者想快速的啟動多個 Windows Docker 容器,那麼手動下載 Windows 光碟還是非常有必要的。

開源專案包含了一些自動安裝的預設配置,不過,這需要使用英文版的作業系統,你可以從這裡下載[5]

當然,如果你需要使用中文版的作業系統,同樣可以從官方下載[6],在初始化作業系統的時候,相比英文作業系統你需要額外點一些“下一步”。

獲取 Windows in Docker 容器映象

獲取在 Docker 中執行 Windows 的容器映象很簡單:

docker pull dockurr/windows

當然,如果不能夠直接下載,也可以選擇本地構建:

git clone https://github.com/dockur/windows.git
cd windows
docker build -t dockurr/windows .

這個映象主要依賴了幾項技術:

•qemus/qemu-docker[7],在容器中使用 QEMU,能夠提供接近本機速度的虛擬機器的網路、IO 速度等。•christgau/wsdd[8],讓容器中的 Windows 能夠出現在區域網中的其他裝置的共享裝置中。(Windows 10 的 1511 版本後,預設開始禁用 SMBv1,NetBIOS 裝置發現功能失效,導致其他裝置不能對其進行服務發現)。•qemus/virtiso[9],精簡到 27MB 的 KVM/QEMU Virtio 驅動程式,能夠讓 Windows 在 Docker 環境中正常使用。•krallin/tini[10],正確啟動 Docker 中 QEMU,以及確保程序異常能夠被正確處理,或正確的終止容器程序。

好了,準備工作就緒後,我們就可以開始使用這個有趣的技術方案啦。

基礎使用

我們先聊聊最簡單的使用方案,啟動一個“無狀態”的臨時的 Windows 作業系統,容器會自動下載我們所需要的映象:

version: "3"
services:
windows:
image: dockurr/windows
container_name: windows
devices:
- /dev/kvm
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
stop_grace_period: 2m
restart: on-failure

將上面的配置儲存為 docker-compose.yml,然後使用 docker compose updocker compose -d 啟動服務。

因為我們沒有指定本地的映象,所以如果你的網路環境訪問微軟 CDN 不夠快的話,啟動過程需要等待一些時間。

# docker compose up     
[+] Running 2/1
✔ Network win_default Created 0.1s
✔ Container windows Created 0.1s
Attaching to windows
windows | ❯ Starting Windows for Docker v2.04...
windows | ❯ For support visit https://github.com/dockur/windows
windows |
windows |
windows | ❯ Downloading Windows 11...
windows | [i] Downloading Windows media from official Microsoft servers...
windows | [i] Downloading Windows 11...
windows | [+] Got latest ISO download link (valid for 24 hours): https://software.download.prss.microsoft.com/dbazure/Win11_23H2_English_x64v2.iso?t=c603adeb-c6d7-4bb9-b084-875f3beabfc2&P1=1710146067&P2=601&P3=2&P4=ynPQkgNxZoZxQkmfORJRE5yaf94m7ONuLVngMtHmDfsYTooFKSXiAdWXTKJ8dpoF2WuDkUZ4fkP1u%2bhwAh%2brAdghU%2f1ssngioKg2aLDe2UXOG3ESUAGTyRk1q515ONoXIvyJby2xPoKBVoj%2bsNp6ECqosBjx9HllmF3saRvQFPQox6v8kuhtMxyuNiXT%2fYgKppSZOifx34t6YQb0Hpo6gTkLjxlxiFBF42jLt%2blVhf1HW7ELEtvVUW7eAn9UGfs9HF6yC3p1ep7ouKYNrY0Ek0fo%2bn2v%2by3bTGbqg8lHfXjxb6bPHGE6HWP3sSZDZw4JmPt53hr1uQl%2fmjT50p504Q%3
windows | #=#=#
windows | #=#=#
0.0%
0.1%
0.2%
0.3%
...
####################################################################### 99.7%
####################################################################### 99.8%
####################################################################### 100.0%
######################################################################## 100.0%

windows |
windows | [+] Successfully downloaded Windows image!
windows |
windows | ❯ Extracting Windows 11 image...
windows | ❯ Adding XML file for automatic installation...
windows | ❯ Building Windows 11 image...
windows | ❯ Creating a 64G growable disk image in raw format...
windows | ❯ Booting Windows using QEMU emulator version 8.2.1 ...
windows |
...

當一切就緒後,我們可以使用兩個方式來訪問這個執行在 Docker 中的 Windows。

第一種方法,是使用瀏覽器訪問容器所在主機的 IP地址:8006

圖片在容器中自動部署的 Windows

容器啟動後,會自動下載、部署 Windows,稍等片刻,就能夠在瀏覽器中正常使用它啦:

圖片在瀏覽器中訪問 Windows

第二種方法,是使用支援 RDP 遠端訪問功能的軟體,在軟體伺服器地址和埠內容中分別填寫 IP地址3389,在使用者名稱欄填寫 docker,密碼保持空白即可。

圖片在 RDP 客戶端中訪問 Windows

加速使用 Windows 容器

圖片預設情況,每次啟動都需要見到它

當然,如果你的網路環境不是那麼好,或者你不想每次啟動容器都要等待很久,可以使用下面的方法。

讓部署使用加速,主要和兩個細節有關:是否進行了容器內容的持久化,是否提供了高效能的安裝映象下載方式。

比如,我們在上面的準備工作中,我們預先下載好 Windows 的安裝映象,然後將檔案重新命名為 win11x64.iso,接著將檔案放置在目錄的 ./iso 子目錄中。那麼,藉助 Nginx,可以讓整個安裝部署過程變的飛快。

version: "3"
services:
windows:
image: dockurr/windows
container_name: windows
devices:
- /dev/kvm
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
stop_grace_period: 2m
restart: on-failure
environment:
VERSION: "http://winiso/win11x64.iso"
MANUAL: "N"
volumes:
- ./win:/storage
depends_on:
- winiso


winiso:
image: nginx:alpine
container_name: winiso
restart: on-failure
volumes:
- ./iso:/usr/share/nginx/html

在上面的配置中,我們增加了一個用來將本地的 Windows 安裝檔案轉換為 dockurr/windows 快速可安裝的線上地址的容器。

將配置檔案儲存為 docker-compose.yml,然後使用 docker compose up 或者 docker compose up -d 啟動配置,我們將看到類似下面的日誌:

windows  | .
windows | .
winiso | 172.20.2.3 - - [11/Mar/2024:03:54:47 +0000] "GET /win11x64.iso HTTP/1.1" 200 6813366272 "-" "Wget/1.21.4" "-"
windows | . 99% 1.59G 0s
windows |
windows | 6651904K .
windows |
windows | 100% 1.95G
windows | =3.7s
windows |
windows |
windows | ❯ Extracting downloaded ISO image...
windows | ❯ Detecting Windows version from ISO image...
windows | ❯ Detected: Windows 11
windows | ❯ Adding XML file for automatic installation...
windows | ❯ Building Windows 11 image...
windows | ❯ Creating a 64G growable disk image in raw format...
windows | ❯ Booting Windows using QEMU emulator version 8.2.1 ...

下載映象的速度馬上從幾MB、幾十MB增加到了接近每秒 2GB,不到 4s 就能完成映象的下載和處理。

因為在配置中增加了 volumes 卷的持久化(- ./win:/storage),所以我們可以放心的停止或者重新啟動容器,而不必擔心每次都要重新初始化“一臺”新的 Windows Docker 容器。

使用技巧

聊聊其他的使用技巧。

更換 Windows 版本(不提前準備映象)

如果你的網路環境非常棒,不需要提前下載安裝映象,或者直接使用雲主機進行專案部署,那麼可以考慮直接調整配置檔案中的內容為合適的數值:

environment:
VERSION: "win11"

支援我們調整使用的值包含:win11win10ltsc10win81win7vistawinxp20222019201620122008

調整 Windows 容器資源配置

預設情況下,這個 Windows 容器會使用 vCPU x2、4GB 記憶體、64G 的磁碟空間,來滿足 Win11 的最低安裝需求。我們可以根據自己的實際需求,來動態的調整容器的硬體資源限制。

environment:
RAM_SIZE: "8G"
CPU_CORES: "4"
DISK_SIZE: "256G"

比如,在上面的配置中,我們調整 CPU 核心數到 4,記憶體到 8GB,磁碟到 256GB。

為容器分配獨立的 IP 地址

預設情況下,Docker 會共享宿主機的 IP,如果我們想要讓容器擁有獨立的 IP 地址,需要先建立一個 macvlan 網路:

docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vlan

建立完網路卡後,調整上面使用的容器配置,根據自己的需求指定容器 IP 即可:

services:
windows:
container_name: windows
..<snip>..
networks:
vlan:
ipv4_address: 192.168.0.100

networks:
vlan:
external: true

使用一整塊磁碟

如果你的主機上有多塊磁碟,或者想將某一塊磁碟完整的分配給 Windows,可以採用下面的方法,其中 DEVICE 將作為你的主磁碟:

environment:
DEVICE: "/dev/sda"
DEVICE2: "/dev/sdb"
devices:
- /dev/sda
- /dev/sdb

在 Docker 中的 Windows 使用 USB 裝置

我們首先需要使用 lsusb 來獲取 USB 裝置的 VendorIDProductID ,然後將這些資訊新增到配置中:

environment:
ARGUMENTS: "-device usb-host,vendorid=0x1234,productid=0x1234"
devices:
- /dev/bus/usb

最後

本篇文章先聊到這裡,下一篇文章見。

--EOF

引用連結

[1] soulteary/docker-chatgpt: https://github.com/soulteary/docker-chatgpt
[2] dockur/windows: https://github.com/dockur/windows
[3] 在筆記本上搭建高價效比的 Linux 學習環境:基礎篇: https://soulteary.com/2022/06/21/building-a-cost-effective-linux-learning-environment-on-a-laptop-the-basics.html
[4] dockur/windows: https://github.com/dockur/windows
[5] 這裡下載: https://www.microsoft.com/en-us/software-download/windows11
[6] 官方下載: https://www.microsoft.com/zh-cn/software-download/windows11
[7] qemus/qemu-docker: https://github.com/qemus/qemu-docker
[8] christgau/wsdd: https://github.com/christgau/wsdd
[9] qemus/virtiso: https://github.com/qemus/virtiso
[10] krallin/tini: https://github.com/krallin/tini


相關文章