使用 Docker 跑 Windows!

实用教程 admin 来源:原文链接 3年前 (2022-05-08) 1409次浏览 0个评论

本精神病人又来闹妖啦!


自从有了这种容器化技术之后,想要做测试,构建点什么,或者简单的体验下某个 Linux Distros 的 cli 就变的无比简单:

  1. -<255:%>- docker run rm it ubuntu:20.04 bash
  2. Unable to find image ‘ubuntu:20.04’ locally
  3. 20.04: Pulling from library/ubuntu
  4. 7b1a6ab2e44d: Already exists
  5. Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
  6. Status: Downloaded newer image for ubuntu:20.04
  7.  
  8. root@aa28b038528e:/# lscpu
  9. Architecture: x86_64
  10. CPU opmode(s): 32bit, 64bit
  11. Byte Order: Little Endian

我们也可以在容器里一顿操作,然后构建出来一个东西拿来用,比如之前在编译 LEDE 固件时,我就是这么玩的。

某一天,我突然接到这样一个需求:使用 pyinstaller 把 Python 脚本编译成不同平台的二进制文件,并且要尽可能跑在容器内。这怎么做?

  • 准备 Windows macOS 和 Linux 的机器,编译然后拿文件。太麻烦了
  •  pyinstaller 交叉编译?不好意思 pyinstaller 不支持交叉编译,更准确的说是 1.5 版本移除了这个功能
  •  Linux container 跑一个 wine,wine 里跑 Windows 版本的 Python?逆向工程真的靠谱嘛?会出现很多奇奇怪怪的 bug 吧
  • 在 docker 里想办法跑个 Windows?哎嘿?

当你兴致勃勃的打开 Docker Hub,搜索 windows 发现竟然有 Windows 的 image,Windows base OS images,Windows Server Core,不管了先跑为敬:

  1. -<130:%>- docker run mcr.microsoft.com/windows:20H2
  2. Unable to find image ‘mcr.microsoft.com/windows:20H2’ locally
  3. 20H2: Pulling from windows
  4. docker: no matching manifest for linux/amd64 in the manifest list entries.
  5. See ‘docker run –help’.

docker 其实是使用了 Linux 内核的 cgroup 等技术来实现的,容器还是使用的宿主机内核,容器的进程其实就是跑在宿主机上的,宿主机还能看见只不过有一定隔离。Windows 并不用 Linux Kernel,那跑个什么嘛。上面这些 image 的 OS Arch 其实也是 windows/amd64 的。

可能更需要的是这个, 确实可以跑 Windows container,只不过需要 Windows host 啦。并且 1709 的 Windows 只能跑 1709 的 image

这不就又回到了开头嘛。

突然想起来有一个很神奇的项目 Docker-OSX,其实现,简单说是用 KVM 跑了个 macOS 的虚拟机,就像黑苹果一样。那么理论上 Windows 也一定能找到办法做到。那么就上 qemu!不行我们就软件模拟!

 

还有一个有趣的东西叫 dind – Docker In Docker。

套娃嘛,我最强。

 

运行环境检查

无论是 VM,还是物理机其实都可以。

KVM 支持

如果能有 KVM 支持的话,虚拟机应该会跑的更流畅。

如果你是 VM,CPU 支持 Intel VT-x/ AMD-v 等,那么在虚拟化软件的设置中就可以看到

ESXi 是这样的

Fusion 是这样的

勾选之后, ls /dev/kvm 就应该有结果啦

容器启用 privileged mode

docker run --privileged xxx即可,主要是为了能够在容器内访问宿主机的/dev/kvm。当然也可以用--device

在容器内准备 qemu 一箩筐

以 Ubuntu 20.04 为例

  1. apt update && apt install qemukvm

准备 ISO

以 alpine 为例,方便测试

  1. wget https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/x86_64/alpine-virt-3.15.0-x86_64.iso

创建 vm 并启动

为了 PoC,我们直接创建 vm 然后启动试试看,-nographic因为我们在 CLI 下,所以不启用图形界面,-enable-kvm因为宿主机有 kvm 支持,-cdrom指定光驱

  1. qemusystemx86_64 nographic enablekvm cdrom /root/alpinevirt3.15.0x86_64.iso

意料之中,出现了 Alpine 的启动画面

并且能看到 qemu 默认配置的内存和 CPU。这个 QEMU Virtual CPU 是不是在某些 VPS 中看到过呢?

 

想要退出 qemu,先按 ctrl a,然后松开,迅速按 x

使用 VNC

既然无图形界面的 alpine 可以,那么安装个 Ubuntu Desktop 也一定可以。

这种情况下就需要我们使用 VNC 啦。

VNC 的默认端口是 5900,我们要在启动容器的时候同时 publish 这个端口,方便我们使用 VNC 客户端

  1. docker run rm privileged p 5900:5900 it v $(pwd):/root/ bennythink/vmid bash

由于 Ubuntu Desktop 需要比较多的内存和 CPU,因此我们这里也多加几个参数

  1. qemusystemx86_64 nographic enablekvm m 4096 cpu host smp 2 cdrom /root/ubuntu20.04.3desktopamd64.iso.iso vnc 0.0.0.0:0

-m表示内存大小,单位是 MiB,也可以 -m 2g表示 2GiB 的内存

-cpu表示 CPU 类型,之前上面我们看到 CPU 是 QEMU Virtual CPU,在这里我们可以指定 CPU,比如 -cpu EPYC 表示虚拟机看到的 CPU 是 AMD EPYC,当然也要审时度势,你一个 x86-64 的 image,就别想着用 486 了。有几个特殊的值:host表示使用和宿主机一样的 CPU,base 的话比较鸡肋顾名思义就是基础的什么指令集都没有,max 会把所有的支持的指令集和 kvm 能提供的指令集都加上。

-smp就是几核心的 CPU 啦,这要看宿主机量力而行。就像 make 时要量力而行一样

-vnc表示使用 VNC,0.0.0.0 表示监听 0.0.0.0,冒号后的 0 表示 5900,如果用0.0.0.0:1,那么监听的端口就是 5901 啦,要注意哦。这种情况下开启的 VNC 是没有密码的,如果想要密码那就 -vnc 0.0.0.0:0,password 然后设置密码…… 比较复杂,建议放弃。

然后使用 VNC 客户端连接即可,要注意 macOS 自带的 VNC 客户端需要密码,但是我们并没有设置密码,因此是用不了的。使用 VNC viewer 可破

  1. brew install cask vncviewer

 

辣鸡 macOS 自带的 VNC Client 也连不上 127.0.0.1 的,辣鸡。

 

我们已经能够看到 Ubuntu 的安装界面啦,并且在这台 VM 中,网络也是通的,QEMU 分配了一个 10 段 IP. 如果你发现不能 ping,那么在 host 中 sysctl -w net.ipv4.ping_group_range='0 2147483647'就可以啦。

分配磁盘

像往常使用虚拟机一样,我们也需要为虚拟机分配一个虚拟磁盘,这样才能够安装操作系统。总不能每次都从光盘启动吧。分配虚拟磁盘也有很多讲究,比如 10G 是一下子都分配了,还是用多少分配多少?

  1. qemuimg create f qcow2 /root/test.qcow2 16G

-f 表示虚拟磁盘的格式,支持 raw 和 qcow2,raw 顾名思义就是原始的,对 vm 来说就是一个块设备。如果 vm 文件系统支持空洞,那么 raw 是一点点填满的,raw 性能较好。qcow2 是 qemu 推荐的格式,支持加密快照等等,别想了就这个吧。当然 qemu 还支持 vmdk、vdi 之类的。

需要注意的是,别给磁盘撑爆了。

安装 Ubuntu Desktop

创建好磁盘之后,使用如下命令即可开始开 vm 安装 Ubuntu

  1. qemusystemx86_64 nographic enablekvm m 4096 cpu host smp 4 drive file=/root/test.qcow2 cdrom /root/ubuntu20.04.3desktopamd64.iso vnc 0.0.0.0:0

安装过程和普通 VM 没什么差别,就是…… 慢了点。

启动 VM

安装好之后,下次我们可以直接启动 VM 了,可以删掉 – cdrom 参数

  1. qemusystemx86_64 nographic enablekvm m 4096 cpu host smp 4 drive file=/root/test.qcow2 vnc 0.0.0.0:0

跑 arm……

都知道 qemu 是个模拟神器,想要跑 arm 也不是不可能,比如跑个 liveCD 做个测试什么的:

  1. apt install qemusystemarm
  2.  
  3. dd if=/dev/zero of=flash0.img bs=1M count=64
  4. dd if=/usr/share/qemuefi/QEMU_EFI.fd of=flash0.img conv=notrunc
  5. dd if=/dev/zero of=flash1.img bs=1M count=64
  6.  
  7. qemusystemaarch64 m 1024 cpu cortexa57 M virt nographic pflash flash0.img pflash flash1.img drive if=none,file=alpinevirt3.15.0aarch64.iso,id=hd0 device virtioblkdevice,drive=hd0 net nic net user

这次启动的速度就会非常慢了,如果启动成功之后没有网络,那么要开下 dhcp,以 alpine 为例

  1. vi /etc/network/interfaces
  2.  
  3. auto lo
  4. iface lo inet loopback
  5. auto eth0
  6. iface eth0 inet dhcp

然后ifup eth0即可

如果想要安装到某个磁盘中,拿 Ubuntu 为例

  1. qemuimg create f qcow2 ubuntu.qcow2 8G
  2.  
  3. mount o loop ubuntu20.04.3liveserverarm64.iso /mnt
  4.  
  5. cp /mnt/casper/vmlinuz ./
  6. cp /mnt/casper/initrd ./
  7.  
  8. qemusystemaarch64 m 1024 cpu cortexa57 smp cpus=4 M virt nographic \
  9. kernel ./vmlinuz initrd ./initrd \
  10. drive file=ubuntu.qcow2,if=none,format=qcow2,id=hd0 device virtioblkdevice,drive=hd0 \
  11. drive file=ubuntu20.04.3liveserverarm64.iso,if=none,format=raw,id=hd1 device virtioblkdevice,drive=hd1 \
  12. net nic net user

之后开始正常的安装步骤,会比较慢,而且电脑起飞。

安装好就可以去掉 iso 那行单独启动了。

实际上,Docker 的 Multi Arch build 也是恰巧利用了 QEMU 啦。

binfmt

如果只是简单的想要跑下异构的 image 的话,可以试试 binfmt,Windows 和 Mac 的 Docker Desktop 直接支持,Linux 需要先这样:

  1. docker run rm privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d

然后跑吧

  1. docker run it platform linux/arm64 alpine sh

使用已有的 cloud image

我们当然可以选择把 OS 安装到虚拟磁盘中,但是这样要麻烦一些,安装过程比较繁琐而且很慢。有没有办法用别人已经准备好的 qcow2 呢?

当然有啦。对于 Ubuntu 来说,可以去下载 cloud image,img 结尾的就是 https://cloud-images.ubuntu.com/focal/current/

然后我们需要创建一个 user data 来初始化我们的密码

  1. cat >userdata <<EOF
  2. #cloud-config
  3. password: 123456
  4. chpasswd: { expire: False }
  5. ssh_pwauth: True
  6. EOF
  7.  
  8. cloudlocalds userdata.img userdata
  9.  
  10. qemusystemx86_64 nographic enablekvm m 2048 cpu host smp 4 drive file=/root/focalservercloudimgamd64.img drive file=userdata.img,format=raw

等待启动,用户名 ubuntu 密码 123456

之后你的所有更改实际上都会写入到这个 img 文件中,下次启动的时候就不用 user-data 啦。

那这个 img 只有 2G,不够用怎么办?qemu-img扩容!

  1. root@e769eaf9e4ab:~# qemu-img resize focal-server-cloudimg-amd64.img +5G
  2. Image resized.
  3.  
  4. root@e769eaf9e4ab:~# qemu-img info focal-server-cloudimg-amd64.img
  5. image: focalservercloudimgamd64.img
  6. file format: qcow2
  7. virtual size: 7.2 GiB (7730102272 bytes)
  8. disk size: 601 MiB
  9. cluster_size: 65536
  10. Format specific information:
  11. compat: 0.10
  12. refcount bits: 16

然后…… 如果有 LVM,那就好办了,如果没 LVM,那就 liveCD 扩容吧。所以建议一开始就qemu-img resize好。

参考资料

https://github.com/kholia/OSX-KVM

https://blog.ihomura.cn/2020/11/12/%E5%9C%A8qemu-system%E4%B8%8A%E8%B7%91arm-Debian/

https://hub.docker.com/repository/docker/bennythink/vmid

 


VPS小白 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:使用 Docker 跑 Windows!
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址