本文发自 http://www.binss.me/blog/what-is-kata-containers/,转载请注明出处。
自从跟着老板开坑后就闷头搞 QEMU 和 KVM ,好久没碰 Docker 。直到最近在一个 talk 上听说了 Kata Containers ,瞬间来了精神 。于是搜索了一番资料,获得了一些新的资讯。
Kata Containers 是什么
基于轻量级虚拟机的容器,不同容器跑在一个个不同的虚拟机(kernel)上,比起传统容器提供了更好的隔离性和安全性。同时继承了容器快速启动和快速部署等优点。
轻量级虚拟机,就是号称我比你快安全性还比你更屌的那些,此类的 paper 比比皆是,比如 SOSP'17 的 My VM is Lighter (and Safer) than your Container 。但一直不成气候的原因,我个人觉得就是没有对接工业界的标准,比如说 OCI 。像 Docker 最成功的地方在于构建了一套快速部署的容器生态,比如说你需要跑一个 nginx 容器,那么只需 docker pull nginx
即可把 image 从仓库拉到本地,然后 run 一下就跑起来了。
如果我们能够利用起 Docker 构建的这套 “上层建筑”,再将其底层替换成我们自己的实现,岂不美哉?
根据 OCI 的 specification,虚拟机 runtime 阵营主要有 hyperhq/runv 和 clearcontainers/runtime
runV 看名字就是和 docker 的 runC 对着干的。通过对接 Docker/Containerd 的接口,使其可以作为 docker 的 runtime 运行容器。
而 clearcontainers 是 Intel 搞出的一套 runtime。同样可以作为 docker 的 runtime 运行容器。
Kata Containers 是这两个项目合并,代表了虚拟机容器阵营的前进方向:
所以 Kata Containers 能够干什么呢?
关于该项目,官网 的内容也比较简单,网上也只有寥寥几篇新闻稿,通过以下几幅图我们可以先窥一斑:
区别于传统容器共享同一个 kernel ,Kata 容器每个容器都使用专有内核,更安全。
作为 runtime ,上接 docker / kubernetes / openstack 生态。
那么我如何才能使用 Kata Containers 呢?
还在开发中。根据 zhihu 的消息,比较稳定的版本,保守的话估计是今年(2018)H1,激进的话最早也要今年(2018)Q1,赶上 Ubuntu 18.04 。
相信看到这里的你和我一样索然无味,既然 Kata 还不能用,那么我们先来折腾下 runV 和 clearcontainers 。所以说本文其实是一篇安装配置文章。
runV
首先需要安装 docker ,这点就不多说了。
安装
首先下载、编译、安装 runV:
apt-get install autoconf automake pkg-config make gcc golang qemu libvirt-bin libvirt-dev
mkdir $GOPATH/src/github.com/hyperhq
cd $GOPATH/src/github.com/hyperhq
git clone https://github.com/hyperhq/runv/
cd runv
./autogen.sh
./configure --without-xen
make
sudo make install
注意除了当前用户需要配置 $GOPATH 外,root 也需要设置,否则在最后一步 sudo 时找不到 $GOPATH 会报错安装不上。
然后需要安装 hyperstart,来为运行容器的 Guest OS 提供 kernel 和 initrd ,这个 kernel 是定制过的,可能后续会做成 Unikernel 。
git clone https://github.com/hyperhq/hyperstart.git
cd hyperstart
./autogen.sh
./configure
make
sudo mkdir /var/lib/hyper/
sudo cp build/hyper-initrd.img build/arch/x86_64/kernel /var/lib/hyper
会将生成的 hyper-initrd.img 、kernel 拷贝到 /var/lib/hyper
目录下。
配置
修改 docker 默认的 runtime 为 runv ,即往 /etc/docker/daemon.json
写入:
{
"default-runtime": "runv",
"runtimes": {
"runv": {
"path": "runv"
}
}
}
然后重启 docker :
sudo systemctl restart docker
然后就可以通过 docker 来跑虚拟机容器了:
docker run --rm -it busybox
观察
我们查看运行的进程:
root 25711 0.0 0.0 486732 20488 ? Ssl 20:21 0:00 runv --root /run/runv --log_dir /var/log/hyper proxy --vmid vm-JUmNdtgAMR --hyperstart-ctl-sock unix:///var/run/hyper/vm-JUmNdtgAMR/hyper.sock --hyperstart-stream-sock unix:///var/run/hyper/vm-JUmNdtgAMR/tty.sock --proxy-hyperstart /var/run/hyper/vm-JUmNdtgAMR/hyperstartgrpc.sock
root 25731 0.0 0.0 409768 22288 ? Ssl 20:21 0:00 runv --root /run/runv --log_dir /var/log/hyper watcher --watch-vm-console /var/run/hyper/vm-JUmNdtgAMR/console.sock --console-proto telnet --watch-hyperstart --watch-vm
root 25732 0.0 0.0 500660 24220 pts/19 Ssl+ 20:21 0:00 runv --root /run/runv --log_dir /var/log/hyper/shim-1f2a463701d94e31b22b929c5136ae24c24c0081f4012d886ca42a59f4bc2410 shim --container 1f2a463701d94e31b22b929c5136ae24c24c0081f4012d886ca42a59f4bc2410 --process init --proxy-stdio --proxy-exit-code --proxy-signal --proxy-winsize
root 181072 0.0 0.0 412744 20768 ? Ssl Dec24 0:01 runv --root /run/runv --log_dir /var/log/hyper proxy --vmid vm-HhvgYYBcQT --hyperstart-ctl-sock unix:///var/run/hyper/vm-HhvgYYBcQT/hyper.sock --hyperstart-stream-sock unix:///var/run/hyper/vm-HhvgYYBcQT/tty.sock --proxy-hyperstart /var/run/hyper/vm-HhvgYYBcQT/hyperstartgrpc.sock
...
root 25722 0.1 0.1 677436 125788 ? Sl 20:21 0:02 /usr/bin/qemu-system-x86_64 -machine pc-i440fx-2.1,accel=kvm,usb=off -global kvm-pit.lost_tick_policy=discard -cpu host -kernel /var/lib/hyper/kernel -initrd /var/lib/hyper/hyper-initrd.img -append console=ttyS0 panic=1 no_timer_check iommu=off -realtime mlock=off -no-user-config -nodefaults -no-hpet -rtc base=utc,clock=vm,driftfix=slew -no-reboot -display none -boot strict=on -m size=128,slots=1,maxmem=32768M -smp cpus=1,maxcpus=8 -numa node,nodeid=0,cpus=0-7,mem=128 -qmp unix:/var/run/hyper/vm-JUmNdtgAMR/qmp.sock,server,nowait -serial unix:/var/run/hyper/vm-JUmNdtgAMR/console.sock,server,nowait -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x2 -device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3 -chardev socket,id=charch0,path=/var/run/hyper/vm-JUmNdtgAMR/hyper.sock,server,nowait -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charch0,id=channel0,name=sh.hyper.channel.0 -chardev socket,id=charch1,path=/var/run/hyper/vm-JUmNdtgAMR/tty.sock,server,nowait -device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charch1,id=channel1,name=sh.hyper.channel.1 -fsdev local,id=virtio9p,path=/var/run/hyper/vm-JUmNdtgAMR/share_dir,security_model=none -device virtio-9p-pci,fsdev=virtio9p,mount_tag=share_dir -daemonize -pidfile /var/run/hyper/vm-JUmNdtgAMR/pidfile -D /var/log/hyper/qemu/vm-JUmNdtgAM.log
可见 runV 是作为一个中间件,底层跑的是 QEMU 和 KVM 。整体架构是:
docker - containerd - runv-shim - runv-proxy - QEMU - KVM
Intel Clear Container
安装
sudo sh -c "echo 'deb http://download.opensuse.org/repositories/home:/clearcontainers:/clear-containers-3/xUbuntu_$(lsb_release -rs)/ /' >> /etc/apt/sources.list.d/clear-containers.list"
wget -qO - http://download.opensuse.org/repositories/home:/clearcontainers:/clear-containers-3/xUbuntu_$(lsb_release -rs)/Release.key | sudo apt-key add -
sudo -E apt-get update
sudo -E apt-get -y install cc-runtime cc-proxy cc-shim
配置
像 runV 一样,修改 docker 默认的 runtime 为 rcc-runtime ,即往 /etc/docker/daemon.json
写入:
{
"default-runtime": "cc-runtime",
"runtimes": {
"cc-runtime": {
"path": "/usr/bin/cc-runtime"
}
}
}
然后重启 docker :
sudo systemctl restart docker
启动 cc-proxy:
sudo systemctl enable cc-proxy.socket
sudo systemctl start cc-proxy.socket
然后就可以通过 docker 来跑虚拟机容器了:
docker run --rm -it busybox
观察
感觉 cc-runtime 明显比 runV 快。
我们查看运行的进程:
root 140668 0.0 0.0 413956 3904 ? Sl 20:02 0:00 docker-containerd-shim 5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a /var/run/docker/libcontainerd/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a /usr/bin/cc-runtime
root 140785 0.0 0.0 187760 7252 ? Sl 20:02 0:00 /usr/libexec/clear-containers/cc-proxy -uri unix:///run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/proxy.sock
root 140792 0.0 0.0 4368 664 pts/21 Ss+ 20:02 0:00 /usr/libexec/clear-containers/cc-shim -c 5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a -t CxUmdrsTsov3PDMh0BWhRZlnV21mFB3ZboUSsjV9y8E= -u unix:///run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/proxy.sock
root 140793 0.0 0.0 4368 120 pts/21 S+ 20:02 0:00 /usr/libexec/clear-containers/cc-shim -c 5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a -t CxUmdrsTsov3PDMh0BWhRZlnV21mFB3ZboUSsjV9y8E= -u unix:///run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/proxy.sock
root 140726 3.0 0.2 5935252 146892 ? Sl 20:02 0:03 /usr/bin/qemu-lite-system-x86_64 -name pod-5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a -uuid a9ea1387-5e7c-4c7f-97ca-7288cde30a5a -machine pc,accel=kvm,kernel_irqchip,nvdimm -cpu host -qmp unix:/run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/a9ea1387-5e7c-4c7,server,nowait -qmp unix:/run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/a9ea1387-5e7c-4c7,server,nowait -m 2048M,slots=2,maxmem=65206M -device virtio-serial-pci,id=serial0 -device virtconsole,chardev=charconsole0,id=console0 -chardev socket,id=charconsole0,path=/run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/console.sock,server,nowait -device nvdimm,id=nv0,memdev=mem0 -object memory-backend-file,id=mem0,mem-path=/usr/share/clear-containers/clear-19790-containers.img,size=235929600 -device pci-bridge,bus=pci.0,id=pci-bridge-0,chassis_nr=1,shpc=on -device virtserialport,chardev=charch0,id=channel0,name=sh.hyper.channel.0 -chardev socket,id=charch0,path=/run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/hyper.sock,server,nowait -device virtserialport,chardev=charch1,id=channel1,name=sh.hyper.channel.1 -chardev socket,id=charch1,path=/run/virtcontainers/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a/tty.sock,server,nowait -device virtio-9p-pci,fsdev=extra-9p-hyperShared,mount_tag=hyperShared -fsdev local,id=extra-9p-hyperShared,path=/run/hyper/shared/pods/5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a,security_model=none -netdev tap,id=network-0,vhost=on,vhostfds=3:4:5:6:7:8:9:10,fds=11:12:13:14:15:16:17:18 -device driver=virtio-net-pci,netdev=network-0,mac=02:42:ac:11:00:02,mq=on,vectors=18 -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=discard -vga none -no-user-config -nodefaults -nographic -daemonize -kernel /usr/share/clear-containers/vmlinuz-4.9.60-82.container -append root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro rw rootfstype=ext4 tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k panic=1 console=hvc0 console=hvc1 initcall_debug iommu=off cryptomgr.notests net.ifnames=0 quiet systemd.show_status=false init=/usr/lib/systemd/systemd systemd.unit=clear-containers.target systemd.mask=systemd-networkd.service systemd.mask=systemd-networkd.socket ip=::::::5359409043a5fd13d9898a37af0422907c811d24661b2c4cc4ae6ff6db1aea8a::off:: -smp 48,cores=48,threads=1,sockets=1
嗯? qemu-lite-system-x86_64 是什么东西?Google 了一下,发现是 Intel 自己魔改的一个轻量级 QEMU 。
这时想起了 Intel Clear Container 吹的:
Clear Containers boot time and memory footprint are significantly optimized by using a specific QEMU version called qemu-lite
虽然它的默认 machine type 为 pc ,但可以指定为 pc-lite:
In the past pc-lite was utilized which provided the following improvements: Removed many of the legacy hardware devices support so that the guest kernel does not waste time initializing devices of no use for containers. Skipped the guest BIOS/firmware and jumped straight to the Clear Containers kernel.
整体架构是:
(connect)
docker - containerd - containerd-shim - cc-shim - cc-proxy -
(create)
cc-runtime - QEMU-lite - KVM - VM(cc-agent)
2019.02.11 更新
看了 18 年 11 月份 Hyper.sh 在 OpenStack Summit 上的演讲,对该项目有了更多的了解,在此更新一发。
相比 gVisor,Kata 本质上还是跑 KVM 虚拟机,因此能够利用 QEMU-KVM 的诸多优化如 IO 能 Passthrough 或用 Vhost 系列等,IO 性能更好:
总结
runV 和 clear container 启动的 Guest 会暴露出 socket ,供 docker ,更准确来说是 runtime 进行管理。
它们都使用了自己的 kernel 和 initrd ,目的是加快启动速度。同时,都使用了 virtio 来提高 IO 设备的效率。
在模拟机器的类型选择上,runV 用的是 pc-i440fx ,而 clear container 默认为 pc,目前两者对 Q35 的支持还不完善。
Kata Containers 合并了 Intel Clear Containers 和 Hyper runV 两个项目,强强联手,代表了虚拟机容器阵营的前进方向。
希望在未来能够解决这两个项目当前的 Limitations ,期待有一天能达到或者接近容器的性能,又快又方便又安全,岂不美哉!
1F XXXX 6 years, 8 months ago 回复
So these container-like VMs are only some lightweight and virt-io optimized linux image?
If they are still a linux, cannot see any benefits. The virtualization layer still exists and costs a lot of performance, especially in a nested-virtualized environment.
2F ZH.Y 6 years, 7 months ago 回复
(随便猜的)可能还是看中了硬件提供的相比之下更强的隔离性?估计不希望某几个用户瞎搞然后整个host崩掉。反正我也没有研究过container,更没有看过kata container,,,,不过听上去听有趣的,以后有时间了研究一番,感谢博主提供资料。另外看了它的说明,guest kernel是像libos一样做改动吗,而且难道只有guest kernel有魔改吗,感觉hypervisor不大改也做不了啊,估计半虚拟化的各种机制,和各种硬件机制,什么VT-x, VT-d都得往上弄才能性能开销小一些?难不成还要再做一个in-kernel qemu。。好像已经暂时超出了我的知识范围了,我还是先安安静静看源码吧
3F binss MOD 6 years, 7 months ago 回复
回复 [1F] XXXX:In my opinion, the target of this project is USE AND MANAGE VM LIKE CONTAINER. We always weigh the pros and cons between safety and performance, and now some people want the latter.
4F Hawk.Z 5 years, 6 months ago 回复
目前很多互联网公司已经开始全容器化部署,未来虚拟机会完全被容器替代吗?
5F binss MOD 5 years, 6 months ago 回复
回复 [4F] Hawk.Z:我个人觉得不会,因为容器难以达到虚拟机那么高的隔离性。未来容器会往更高隔离性的方向发展(gVisor),而虚拟机会往更轻量的方向发展(Kata)
6F asdas 4 years, 11 months ago 回复
sadasd