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 ,期待有一天能达到或者接近容器的性能,又快又方便又安全,岂不美哉!