kata-container初探

时间:2024-05-20 08:14:17

概览
kata containers是由OpenStack基金会管理,但独立于OpenStack项目之外的容器项目。kata containers整合了Intel的 Clear Containers 和 Hyper.sh 的 runV,能够支持不同平台的硬件 (x86-64,arm等),并符合OCI(Open Container Initiative)规范,同时还可以兼容k8s的 CRI(Container Runtime Interface)接口规范。项目包含几个配套组件,即Runtime,Agent, Proxy,Shim等。项目已于6月份release了1.0版本。
    从docker架构上看,kata-container和原来的runc是平级的。大家知道docker只是管理容器生命周期的框架,真正启动容器最早用的是LXC,然后是runc,现在也可以换成kata了。所以说kata-container可以当做docker的一个插件,启动kata-container可以通过docker命令。Kata最大的亮点是解决了传统容器共享内核的安全和隔离问题,办法是让每个容器运行在一个轻量级的虚拟机中,使用单独的内核。 

kata-container初探

hypervisor
首先,Hypervisor启动用于容器运行的虚拟机,虚拟机包含一个极简的guest kernel和guest image。
目前1.0只支持QEMU/KVM创建虚拟机。然后在虚拟机内部真正起我们想要的容器。如果你熟悉KVM的原理,很快就能理解下面这张图。
kata-container初探

1、Guest kernel
用于启动VM。Kata-container高度优化了内核启动时间和极小的内存占用,只用于一个容器的运行。
2、Guest image
包含了initrd和rootfs
3、Root filesystem image
Mini-OS,基于Clear Linux的高度优化的容器启动微系统,只运行了init进程(systemd)和agent,真正的工作负载跟runc一样,由libcontainer创建。

比如说,执行Docker run –ti Ubuntu date命令时
1、Hypervisor使用guest kernel启动一个mini-OS镜像
2、运行在Mini-OS上下文的systemd会启动kata-agent
3、Agent会创建一个用于运行指定的命令(date)的新上下文
4、agent先设置ubuntu的根文件系统,然后在新的上下文里执行date

社区提供了osBuilder组件专门用于镜像的制作。跟openstack的ironic有点像。

内部组件
接下来介绍下kata-container的四个组件,正式介绍之前,先建立一个认知,只有agent是运行在上文提到的mini-OS里的。Runtime、proxy和shim是运行在宿主机上的。每创建一个容器就会创建一个proxy、agent和shim,而runtime只有一个。
Agent
Kata-agent是运行在guest中,管理容器和处理容器的运行。Kata-agent的执行单元是定义了一系列命名空间的沙盒。每个VM可以运行多个容器,支持k8s一个pod运行多个容器的需求。不过目前docker中,kata-runtime只能一个pod一个容器。Kata-agent通过gRPC和其他kata组件通信。Kata-agent使用libcontainer管理容器的生命周期,也就复用了runc的大部分代码。
Runtime
kata-runtime是一个OCI兼容的容器运行时,负责处理OCI运行时规范指定的所有命令并启动kata-shim实例。

Kata-runtime的配置文件是/usr/share/defaults/kata-containers/configuration.toml,可以根据实际需求修改,以下摘取了一部分参数:
[hypervisor.qemu]
path = "/usr/bin/qemu-lite-system-x86_64"
kernel = "/usr/share/kata-containers/vmlinuz.container"
initrd = "/usr/share/kata-containers/kata-containers-initrd.img"
machine_type = "pc"
kernel_params = ""
firmware = ""
machine_accelerators=""
default_vcpus = 1
default_maxvcpus = 0
default_bridges = 1
block_device_driver = "virtio-scsi"
[proxy.kata]
path = "/usr/libexec/kata-containers/kata-proxy"
[shim.kata]
path = "/usr/libexec/kata-containers/kata-shim"
[runtime]
internetworking_model="macvtap"

比较重要的参数有:
machine_type,机器类型,kata-container支持多种机器类型,x86上的pc、q35,ARM的virt,IBM Power的pseries。默认是pc。
internetworking_model,VM和container之间的连接方式,除了macvtap,也可以配置从bridge。但bridge不能工作在macvlan和ipvlan的场景下。
Proxy
默认使用virtio-serial和VM通信,内核版本高于4.8可以使用vsock,一种虚拟的套接字。VM可以运行多个容器进程。在使用virtio-serial的情况下,与每个进程相关联的I/O流需要在主机上多路复用和解复用。
Kata-proxy给多个kata-shim和kata-runtime客户端提供对kata-agent提供访问,它的主要作用是在每个kata-shim和kata-agent之间路由I/O流和信号。Kata-proxy连接到kata-agent的unix域套接字上,这个套接字是kata-proxy启动时kata-runtime提供的。
Shim
一个容器处理能够像docker的containerd-shim一样处理响应,前提是可以监控容器进程。runtime运行在宿主机上,不能直接监控运行在虚拟机里的进程,最多只能看到QEMU进程。所以对kata-container来说,kata-shim扮演了监控容器进程的角色。Kata-shim需要处理容器的所有I/O流,包括stdout、stdin和stderr,以及转发所有的要发送出去的信号。
Kata-shim还有其他功能:
通过一个UNIX域套接字连接到kata-proxy。这个套接字在kata-runtime启动kata-shim的时候,由kata-runtime传给kata-shim,同时带上了containerID和execID,两个ID用来识别shim管理的是哪个容器。
读取来自VM内部容器进程的输出流和错误流
使用SignalProcessRequest API转发从reaper到kata-proxy的信号
监控终端修改,并使用grpc TtyWinResize API转发到kata-proxy

命令实现
分别讲解下docker常用的create、start、exec、kill、delete命令在kata-contailer的实现。Docker的这些操作最终也是转化成kata-container相应的操作。
creat
执行docker create时,kata-runtime做了些什么?
1、创建一个沙盒,沙盒的作用是创建网络命名空间,启动虚拟机和shim进程
2、调用pre-start钩子,负责在主机网络命名空间和刚才创建的网络命名空间之间,创建veth pair
3、扫描网络空间的网络,在veth和vm的tap设备之间创建MACVTAP连接
4、通过创建好的tap设备,在网络命名空间启动vm
5、等待vm运行
6、启动kata-proxy,连接到VM。Kata-proxy进程代理所有和VM的通信。每个VM一个代理
7、通过Kata-proxy和kata-agent通信,配置VM内部的沙盒
8、依赖于OCI配置文件config.json,和kata-agent通信创建容器
9、启动kata-shim,会连接到kata-proxy提供的gRPC服务。Kata-shim会启动一些go协程并行地以阻塞方式调用ReadStdout()、ReadStderr()、WaitProcess()方法。ReadStdout()、ReadStderr()死循环运行直至容器退出。WaitProcess只在容器退出时调用,并返回退出原因。
 kata-container初探
Start
使用runc时,docker start就是在自己的命名空间里运行一个容器进程。Kata-container来说,kata-runtime主要的任务是让VM里的kata-agent启动容器。
1、通过kata-proxy和kata-agent通信,在VM里启动容器负载,比如启动的命令是Docker run –ti Ubuntu top,kata-shim的ReadStdOut会返回top的输出,WatiProcess()会继续阻塞直到top进程退出。
2、调用post-start钩子,1.0版本是个空函数
 kata-container初探
Exec
请求通过kata-proxy发送到kata-agent,在虚拟机的容器里,启动一个新的kata-shim进程。当你执行docker exec命令时通过ps就能发现多了一个shim进程。
2、这个新的kata-shim在原来的kata-shim的网络命名空间和PID命名空间里被创建,用于exec。
 kata-container初探
Kill
发送kill命令,kata-runtime发送一个UNIX信号给容器进程,kill发送终止信号,比如SIGKILL或者SIGTERM来终止容器进程。以前只是停止容器,对kata-runtime来说需要容器和虚拟机一块停止。
1、通过proxy,向kata-agent发送kill请求
2、等待kata-shim退出
3、如果kata-shim超时没有返回,则强制杀死容器进程,也就是向kata-agent发送SIGKILL信号。
4、等待kata-shim退出,还是超时就报错
5、和kata-agent通信,从VM中删除容器配置
6、和kata-agent通信,从VM中删除沙盒的配置
7、停止VM
8、删除网络命名空间里的所有网络配置,删除命名空间
9、执行post-stop钩子

Delete
删除所有容器相关的资源,运行的容器不能被删除,强制删除需要带上—force。
如果沙箱没有停止,但是特定的容器进程已经自己返回,那么kata-runtime将首先执行终止信号所需的大部分步骤。在此过程之后,或者如果沙箱已经停止,则KATA运行时将:
1、移除容器资源。每个文件保存在/var/{lib,run}/virtcontainers/sandboxes/<sandboxID>/<containerID>。
2、删除沙盒资源。每个文件保存在/var/{lib,run}/virtcontainers/sandboxes/<sandboxID>。
此时,与容器相关的所有内容都应该从主机系统中移除。


本文主要讲述kata-container的基本原理,后面再介绍kata-container的网络和存储相关知识以及在k8s里的应用。