博主头像
MoYan's Blog

前进,不择手段的前进!

在Docker中安装Windows小记

现在主力机是Linux的,但是有些时候还是得用下Windows的软件。又不想污染系统的环境,于是找到了dockur/windows这个镜像。

看了它的介绍后,发现它很符合我的需求。不仅支持RDP,还支持网页的连接查看。

特性

  • 支持KVM
  • 支持自动下载iso
  • 支持RDP
  • 支持noVNC

安装

官方给的是这个,但我觉得还能完善一些

docker run -it --rm -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN --stop-timeout 120 dockurr/windows
docker run -d --name windows --cap-add NET_ADMIN -e LANGUAGE=Chinese -e RAM_SIZE=4G --device /dev/kvm --device /dev/net/tun --device /dev/bus/usb --net host -v /mnt/win/data:/data:rw  --stop-timeout 120 --network host dockurr/windows

我的这个命令添加了:

  • 添加内存限制(-e RAM_SIZE=4G
  • 添加USB设备映射(--device /dev/bus/usb
  • 使用host网络(--network host
  • 添加数据盘挂载(-v /mnt/win/data:/data:rw

ok, 启动完容器就可以用浏览器打开http://127.0.0.1:8006,静待他自己安装了。

更换Windows版本

默认情况下,它将会安装 Windows 11 专业版。但是你可以修改环境变量VERSION以选择需要安装的版本,版本代号见下表。

比如你要安装Windows 11 LTSC,那么,你就可以添加一个参数:

-e VERSION=11l

| | 版本 | 大小 |
| ------ | ------------------------ | -------- |
| 11 | Windows 11 Pro | 5.4 GB |
| 11l | Windows 11 LTSC | 4.2 GB |
| 11e | Windows 11 Enterprise | 5.8 GB |
| | | |
| 10 | Windows 10 Pro | 5.7 GB |
| 10l | Windows 10 LTSC | 4.6 GB |
| 10e | Windows 10 Enterprise | 5.2 GB |
| | | |
| 8e | Windows 8.1 Enterprise | 3.7 GB |
| 7e | Windows 7 Enterprise | 3.0 GB |
| ve | Windows Vista Enterprise | 3.0 GB |
| xp | Windows XP Professional | 0.6 GB |
| | | |
| 2025 | Windows Server 2025 | 5.0 GB |
| 2022 | Windows Server 2022 | 4.7 GB |
| 2019 | Windows Server 2019 | 5.3 GB |
| 2016 | Windows Server 2016 | 6.5 GB |
| 2012 | Windows Server 2012 | 4.3 GB |
| 2008 | Windows Server 2008 | 3.0 GB |
| 2003 | Windows Server 2003 | 0.6 GB |

使用

FreeRDP的使用

一旦你启动了容器,并且Windows启动完毕,那么你就可以通过http://127.0.0.1:8006或者RDP连接到Windows。使用浏览器的noVNC,就不再赘述,这里主要介绍FreeRDP的使用。

xfreerdp /u:docker /video /async-update /async-input /v:127.0.0.1 +fonts /p: +clipboard /auto-reconnect-max-retries:5 /cert-ignore +drives

脚本

为了方便启动和管理这个容器,我拿Python写了个小脚本,现在放在这里。

记得先pip install docker

#!/usr/bin/python3

import docker
from docker.errors import NotFound
import subprocess
import sys
import webbrowser

# 创建 Docker 客户端
client = docker.from_env()


def get_status():
    try:
        # 获取容器状态
        container = client.containers.get("windows")
        if container.status == "running":
            return "running"
        else:
            return "die"
    except NotFound:
        return "not"


def start_rdp():
    cmd = [
        "xfreerdp",
        "/u:docker",
        "/video",
        "/async-update",
        "/async-input",
        "/v:127.0.0.1",
        "+fonts",
        "/p:",
        "+clipboard",
        "/auto-reconnect-max-retries:5",
        "/cert-ignore",
        "+drives",
    ]
    if "-f" not in sys.argv:
        cmd.append("/f")
    else:
        cmd.append("/dynamic-resolution")
    subprocess.run(cmd)


def start_container():
    print("正在启动Windows")
    container = client.containers.get("windows")
    container.start()


def start():
    status = get_status()
    if status == "die":
        start_container()
    elif status == "not":
        print("正在创建Windows")
        client.containers.create(
            "dockurr/windows",
            name="windows",
            detach=True,
            cap_add=["NET_ADMIN"],
            environment={"LANGUAGE": "Chinese", "RAM_SIZE": "4G"},
            devices=["/dev/kvm", "/dev/net/tun", "/dev/bus/usb"],
            network="host",
            volumes={  # 卷挂载
                "/mnt/win": {"bind": "/storage", "mode": "rw"},
                "/mnt/win/data": {"bind": "/data", "mode": "rw"},
            },
        )
        start_container()
    print("正在启动XFreeRDP")
    start_rdp()


def stop():
    status = get_status()
    if status == "running":
        container = client.containers.get("windows")
        container.stop()


def main():
    if "start" in sys.argv:
        start()
    elif "stop" in sys.argv:
        stop()
    elif "vnc" in sys.argv:
        webbrowser.open(
            "http://localhost:8006/?resize=scale&reconnect=true&autoconnect=true"
        )
    else:
        start()


if __name__ == "__main__":
    main()

启动容器并且全屏启动RDP:

runwin

启动容器并且以动态分辨率启动RDP:

runwin -f

启动容器并且打开noVNC:

runwin

停止容器:

runwin stop

原理

Docker里面塞个qemu,qemu里运行Windows。SMB实现文件共享。
(没错,就这么简单)

在Docker中安装Windows小记
https://blog.moyanjdc.top/archives/5/
本文作者 MoYan
发布时间 2024-12-19
许可协议 CC BY-NC-SA 4.0
仅有 1 条评论
  1. 评论头像

    bilibili2233-1

    MoYan 博主 December 20th, 2024 at 03:37 pm 回复
发表新评论