目录

魔改dockur制作可迁移的Windows镜像(单文件)

修改dockur制作Windows镜像

https://github.com/dockur/windows

拉取测试的版本: v4.33

原始仓库的镜像默认只是一个ISO下载器和网络自动设置器,本质上不包含Windows镜像,容器启动后镜像会将系统安装到挂载出的盘中。

由于默认的镜像存在无法持久化保存修改的问题,这里需要修改镜像并重新打包。最终只会保存一个文件,即容器导出的tar包。

tar包打出来的大小会比较大,目前我打出来是26.3G。(这个大小不受系统内安装了多少软件影响,这是写入卷默认的大小)

1. 克隆仓库

1
git clone https://github.com/dockur/windows.git
1
cd windows

由于需要进入其src目录下的install.sh,先执行以下命令先查询行:

1
sed -n '/rm -f "\$STORAGE\/windows\.old"/,/rm -f "\$STORAGE\/windows\.type"/p' src/install.sh

查看结果是否为:

1
2
3
4
5
6
7
8
9
  rm -f "$STORAGE/windows.old"
  rm -f "$STORAGE/windows.vga"
  rm -f "$STORAGE/windows.net"
  rm -f "$STORAGE/windows.usb"
  rm -f "$STORAGE/windows.args"
  rm -f "$STORAGE/windows.base"
  rm -f "$STORAGE/windows.boot"
  rm -f "$STORAGE/windows.mode"
  rm -f "$STORAGE/windows.type"

如果是的话,执行以下命令删除这些行:

1
sed -i '/rm -f "\$STORAGE\/windows\.old"/,/rm -f "\$STORAGE\/windows\.type"/d' src/install.sh

2. 修改Dockerfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
ARG VERSION_ARG="latest"
# FROM scratch AS build-amd64
FROM debian:bookworm-slim AS build-amd64

COPY --from=qemux/qemu:7.11 / /

RUN echo "deb https://mirrors.tuna.tsinghua.edu.cn/debian bookworm main contrib non-free non-free-firmware\n\
deb https://mirrors.tuna.tsinghua.edu.cn/debian bookworm-updates main contrib non-free non-free-firmware\n\
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware" \
> /etc/apt/sources.list

ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN="true"

RUN set -eu && \
    apt-get update && \
    apt-get --no-install-recommends -y install \
        wsdd \
        samba \
        wimtools \
        dos2unix \
        cabextract \
        libxml2-utils \
        libarchive-tools \
        netcat-openbsd && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# COPY --chmod=755 ./src /run/
# COPY --chmod=755 ./assets /run/assets
# ADD --chmod=664 https://github.com/qemus/virtiso-whql/releases/download/v1.9.45-0/virtio-win-1.9.45.tar.xz /drivers.txz

COPY ./src /run/
RUN chmod -R 755 /run/
COPY ./assets /run/assets/
RUN chmod -R 755 /run/assets/
ADD https://cdn.spiritlhl.net/https://github.com/qemus/virtiso-whql/releases/download/v1.9.45-0/virtio-win-1.9.45.tar.xz /drivers.txz
RUN chmod 664 /drivers.txz

# FROM dockurr/windows-arm:${VERSION_ARG} AS build-arm64
# FROM build-${TARGETARCH}
# VOLUME /storage
RUN mkdir -p /storage && df -h /storage
ARG VERSION_ARG="0.00"
RUN echo "$VERSION_ARG" > /run/version

EXPOSE 3389 8006

ENV RAM_SIZE="4G"
ENV CPU_CORES="2"
# 减少C盘默认大小,实际使用最多16G
# ENV DISK_SIZE="64G"
ENV DISK_SIZE="20G"

ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"]

参考上面的Dockerfile进行修改:

  • 加入docker.spiritlhl.news加速原始镜像下载。
  • 注释掉VOLUME /storage,去除挂载并改成RUN mkdir -p /storage && df -h /storage
  • 将带--chmod的行改成使用COPYRUN chmod的两行命令。
  • 注释掉FROM build-${TARGETARCH}

如果当前部署机是x86的,就注释掉以下内容:

1
FROM dockurr/windows-arm:${VERSION_ARG} AS build-arm64

并修改FROM scratch AS build-amd64为:

1
FROM debian:bookworm-slim AS build-amd64

同时加入清华源加速部分依赖下载,注意不能删除/etc/apt/sources.list.d/下的文件,有一些包必须通过官方源下载即便很慢:

1
2
3
4
RUN echo "deb https://mirrors.tuna.tsinghua.edu.cn/debian bookworm main contrib non-free non-free-firmware\n\
deb https://mirrors.tuna.tsinghua.edu.cn/debian bookworm-updates main contrib non-free non-free-firmware\n\
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware" \
> /etc/apt/sources.list

如果当前部署机是arm64的,就注释掉以下内容:

1
FROM scratch AS build-amd64

3. 打包镜像并导出tar包

执行以下命令打包镜像并导出tar包:

1
2
docker build -t windows:builder .
docker save -o builder.tar windows:builder

4. 下载Windows镜像

https://down.idc.wiki/ISOS/Windows/ 中找到要使用的ISO镜像进行下载,例如:

1
wget https://down.idc.wiki/ISOS/Windows/Server%202022/zh-cn_windows_server_2022_x64_dvd_6c73507d.iso && chmod 777 zh-cn_windows_server_2022_x64_dvd_6c73507d.iso

下载镜像大概需要10分钟。

或者不使用这里的镜像,下面开设的时候不挂载-v ./zh-cn_windows_server_2022_x64_dvd_6c73507d.iso:/boot.iso而是使用--env VERSION="2019"这种方法指定下载官方的iso文件,也可以。这块参考 https://github.com/dockur/windows 仓库中的说明。

5. 开设虚拟机容器

使用下载的ISO镜像开设虚拟机容器:

1
docker load -i builder.tar
1
docker run -it -d -e RAM_SIZE="8G" -e CPU_CORES="4" --name win2022 -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v ./zh-cn_windows_server_2022_x64_dvd_6c73507d.iso:/boot.iso --stop-timeout 120 windows:builder

整个开设过程大约需要90分钟。

6. 设置容器无需重新下载和安装镜像

执行

1
docker exec win2022 sh -c 'echo "data.img" > /storage/windows.boot'

PS: 本操作借鉴自 https://github.com/dockur/windows/issues/1192

7. 设置虚拟机C盘自动扩容

由于原先系统制作的时候Dockerfile中预定义的硬盘为20G,实际开设过程中需要增大硬盘大小,否则会出现C盘使用一段时间后磁盘写满的情况,所以需要在开设的时候指定扩容硬盘,但这样依然没有自动扩容硬盘到C盘,虚拟机中进入磁盘管理器后可以看到有未分配的硬盘。

需要在打包镜像前创建一个bat脚本,创建定时任务在系统启动后执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
    exit /b
)
set "dptemp=%temp%\extend_c_drive.txt"
> "%dptemp%" (
    echo select volume C
    echo extend
)
diskpart /s "%dptemp%"
del "%dptemp%"

在 设置 – 控制面板 – 计划任务 – 创建基本任务 – 当前用户登录时启动任务(L) – 选择这个bat程序文件 – 创建任务

8. 设置开机自启程序

类似上述操作,事先查找到要开机自启动的桌面的程序路径,右键点开图标的属性(R),复制粘贴属性(R)中的目标(T)的地址,替换下面的"路径"为对应的路径

1
2
3
@echo off
setlocal enabledelayedexpansion
start "" "路径"

9. 提交并导出最终镜像

提交虚拟机容器并导出镜像:

1
docker commit win2022 windows:2022 && docker save -o win2022.tar windows:2022

注意当前宿主机必须至少拥有100G空闲的硬盘在路径/上,否则会出现类似write ./.docker_temp_336929345: no space left on device这样的报错。

这个导出并保存为文件的命令执行时间在60分钟左右。

10. 加载并运行最终镜像

如果使用这个tar包开设虚拟机,执行以下命令:

1
docker load -i win2022.tar && docker run -it -d -e RAM_SIZE="8G" -e CPU_CORES="4" --name win2022 -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN --stop-timeout 120 windows:2022

这个过程大概需要5分钟。

如果需要增加硬盘大小,那么就设置

1
-e DISK_SIZE="35G"

如果需要外挂数据,那么就

1
-v 宿主机的那个文件夹的绝对路径:/data

然后在开设的win中:

  • 打开文件资源管理器
  • 点击左侧的网络选项。
  • 找到名为host.lan的计算机。
  • 双击host.lan,看到一个名为Data的共享文件夹,该共享文件夹对应挂载的文件夹。

关于GPU

这样制作的镜像GPU无法在容器内给到Windows的虚拟机使用的,即便可以在容器中安装驱动并成功使用,也无法转发给容器内的虚拟机

相关尝试 https://github.com/dockur/windows/issues/22

关于端口

只能使用官方给的端口,无法自行修改,要修改的话需要修改基础镜像中复制的 qemus/qemu 镜像

目前容器内的端口是

web端启动的NoVNC端口是 8006

RDP启动的端口是 3389

如果需要使用对应服务,需要在docker启动时指定映射容器的这两个端口

后记

虽然这样持久化保存了系统镜像到了docker的写入层,但是镜像体积会非常大,我打包win的server的2022打包的tar包总计26.3G大小。

造成这样的原因是默认的挂载点被我修改删掉了,没法约束对应storage文件夹的大小了,默认就是docker分配的匿名挂载的大小。

同时启动速度极慢,不如直接通过ProxmoxVE或者Kubevirt的直接启动qcow2文件来得快。

在浏览器端的VNC无法使用复制粘贴功能,这块没有解决的方法,系QEMU本身不支持的问题(仅限Windows虚拟机)