登录
  • 人们都希望被别人需要 却往往事与愿违
  • 人们总以为自己生活的时代糟糕透顶, 总是向往过去的黄金时代。但在我们如今认为是身处黄金年代的那些人看来, 他们当时所处的世界同样是苍白无力的@伍迪.艾伦

使用Docker跑Windows!

瞎搞 Benny小土豆 1048次浏览 6142字 4个评论
文章目录[显示]

本精神病人又来闹妖啦!


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

-<255:%>- docker run --rm -it ubuntu:20.04 bash
Unable to find image 'ubuntu:20.04' locally
20.04: Pulling from library/ubuntu
7b1a6ab2e44d: Already exists
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:20.04

[email protected]:/# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
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,不管了先跑为敬:

-<130:%>- docker run mcr.microsoft.com/windows:20H2
Unable to find image 'mcr.microsoft.com/windows:20H2' locally
20H2: Pulling from windows
docker: no matching manifest for linux/amd64 in the manifest list entries.
See 'docker run --help'.

使用Docker跑Windows!

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

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

使用Docker跑Windows!

这不就又回到了开头嘛。

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


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

套娃嘛,我最强。

运行环境检查

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

KVM支持

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

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

ESXi是这样的

使用Docker跑Windows!

Fusion是这样的

使用Docker跑Windows!

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

容器启用 privileged mode

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

在容器内准备qemu一箩筐

以Ubuntu 20.04为例

apt update && apt install qemu-kvm

准备ISO

以alpine为例,方便测试

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指定光驱

qemu-system-x86_64 -nographic -enable-kvm -cdrom /root/alpine-virt-3.15.0-x86_64.iso

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

使用Docker跑Windows!

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

使用Docker跑Windows!

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

使用VNC

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

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

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

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

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

qemu-system-x86_64 -nographic -enable-kvm -m 4096 -cpu host -smp 2 -cdrom /root/ubuntu-20.04.3-desktop-amd64.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可破

brew install --cask vnc-viewer

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

使用Docker跑Windows!

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

使用Docker跑Windows!

分配磁盘

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

qemu-img create -f qcow2 /root/test.qcow2 16G

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

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

安装Ubuntu Desktop

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

qemu-system-x86_64 -nographic -enable-kvm -m 4096 -cpu host -smp 4 -drive file=/root/test.qcow2 -cdrom /root/ubuntu-20.04.3-desktop-amd64.iso -vnc 0.0.0.0:0

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

启动VM

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

qemu-system-x86_64 -nographic -enable-kvm -m 4096 -cpu host -smp 4 -drive file=/root/test.qcow2 -vnc 0.0.0.0:0

跑arm……

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

apt install qemu-system-arm

dd if=/dev/zero of=flash0.img bs=1M count=64
dd if=/usr/share/qemu-efi/QEMU_EFI.fd of=flash0.img conv=notrunc
dd if=/dev/zero of=flash1.img bs=1M count=64

qemu-system-aarch64 -m 1024 -cpu cortex-a57 -M virt -nographic -pflash flash0.img -pflash flash1.img -drive if=none,file=alpine-virt-3.15.0-aarch64.iso,id=hd0 -device virtio-blk-device,drive=hd0 -net nic -net user

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

vi /etc/network/interfaces

auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp

然后ifup eth0即可

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

qemu-img create -f qcow2 ubuntu.qcow2 8G

mount -o loop ubuntu-20.04.3-live-server-arm64.iso /mnt

cp /mnt/casper/vmlinuz ./
cp /mnt/casper/initrd ./

qemu-system-aarch64 -m 1024 -cpu cortex-a57 -smp cpus=4 -M virt -nographic \
-kernel ./vmlinuz -initrd ./initrd \
-drive file=ubuntu.qcow2,if=none,format=qcow2,id=hd0 -device virtio-blk-device,drive=hd0 \
-drive file=ubuntu-20.04.3-live-server-arm64.iso,if=none,format=raw,id=hd1 -device virtio-blk-device,drive=hd1 \
-net nic -net user

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

使用Docker跑Windows!

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

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

binfmt

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

docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d

然后跑吧

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来初始化我们的密码

cat >user-data <<EOF
#cloud-config
password: 123456
chpasswd: { expire: False }
ssh_pwauth: True
EOF

cloud-localds user-data.img user-data

qemu-system-x86_64 -nographic -enable-kvm -m 2048 -cpu host -smp 4 -drive file=/root/focal-server-cloudimg-amd64.img -drive file=user-data.img,format=raw

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

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

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

[email protected]:~# qemu-img resize focal-server-cloudimg-amd64.img +5G
Image resized.

[email protected]:~# qemu-img info focal-server-cloudimg-amd64.img
image: focal-server-cloudimg-amd64.img
file format: qcow2
virtual size: 7.2 GiB (7730102272 bytes)
disk size: 601 MiB
cluster_size: 65536
Format specific information:
compat: 0.10
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

 


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/docker-windows-container.html
喜欢 (12)
分享:-)
Benny小土豆
关于作者:
If you have any further questions, feel free to contact me in English or Chinese.
发表我的评论(代码和日志请使用Pastebin或Gist)
取消评论

                     

去你妹的实名制!

  • 昵称 (必填)
  • 邮箱 (必填,不要邮件提醒可以随便写)
  • 网址 (选填)
(4)个小伙伴在吐槽
  1. Docker 除了用到 cgroup 也用到了 namespace 不過為啥要加一層 docker container? 直接跑 qemu 也可以呀,或者套一層 libvirt virsh 也挺好用的,也可以用 XML 定制自己的 virtual machine,跟寫 Dockerfile 工作量差不了多少。
    去你妹的实名制!2021-12-25 19:12 回复
    • Benny小土豆
      因为不希望对宿主机造成任何影响,直接就是干干净净的(concourse来背锅(
      --本评论由Telegram Bot回复~❤️
      Benny小土豆2021-12-25 19:18 回复
      • 快用 Guix
        去你妹的实名制!2021-12-25 19:57 回复
        • Benny小土豆
          你走 就你最皮
          --本评论由Telegram Bot回复~❤️
          Benny小土豆2021-12-25 19:57