使用firecracker创建虚拟机和配置firecracker作为kata后端的过程

news/2026/1/24 23:37:04/文章来源:https://www.cnblogs.com/peacemaple/p/19527842

参考资料

  • 如何在 AWS EC2 实例上通过“伪”嵌套虚拟化方案运行 Firecracker
  • How to run Firecracker without KVM on cloud VMs
  • 为AI Agent构建安全沙箱基础架构:在Amazon EKS上部署Kata Containers的最佳实践
  • https://github.com/xzy0223/eks-kata-containers
  • https://github.com/kata-containers/kata-containers/blob/main/docs/how-to/how-to-use-kata-containers-with-firecracker.md

Firecracker虚拟化相关问题

Firecracker可以实现启动microvm的需求,是否可以运行在m5类型的实例上,和bear metal相比有哪些区别?

  • 普通的虚拟化 m5 实例(如 m5.large, m5.xlarge)无法运行 Firecracker,因为 AWS 的普通虚拟化实例不支持嵌套虚拟化(Nested Virtualization),即无法提供 /dev/kvm。必须使用 m5.metal(裸金属)实例
  • Firecracker 强依赖于 Linux 的 KVM (Kernel-based Virtual Machine) 技术。要运行 KVM,CPU 必须暴露硬件虚拟化扩展(Intel VT-x 或 AMD-V)。对于普通的m5实例,AWS 目前在这些普通的 Guest OS 中屏蔽了硬件虚拟化指令集(VMX flags)

Firecracker使用KVM创建虚拟机如何体现?

  • KVM 负责的 CPU 和内存虚拟化(利用硬件指令集),而 Firecracker 负责KVM 并处理 KVM 处理不了的 I/O 设备模拟。
  • Firecracker 本身是一个运行在 Linux 用户态的进程(Binary),它无法直接操作 CPU 硬件的虚拟化功能(如 Intel VT-x 或 AMD-V)。Firecracker 启动时会打开 /dev/kvm 这个设备文件,通过 ioctl() 系统调用向 KVM 发送指令创建虚拟机(在内核里给我开立一个独立的虚拟化上下文(Context),并给我一个文件句柄(Handle)来管理它)
  • 当内核收到 KVM_CREATE_VM 指令时,分配 struct kvm 结构体,代表一个虚拟机的核心数据结构。初始化 MMU(内存管理单元)上下文,确保这个 VM 里的操作系统将来在访问它认为的“物理地址”时,KVM 能通过这套硬件加速的页表,正确地将其翻译成宿主机的真实物理内存地址。此后KVM 把这个新创建的 struct kvm 关联到发起调用的 Firecracker 进程(当 Firecracker 进程被杀掉时,这个虚拟机相关的内核资源也会被自动清理掉)
  • KVM 负责“配置”进程相关的独立的上下文VMCS (Virtual Machine Control Structure)(告诉 CPU 哪些指令需要拦截),而 CPU 硬件负责在运行时“监控”并在遇到这些指令时“触发” VM Exit

如果是x86平台,运行 KVM为什么要求CPU 必须暴露硬件虚拟化扩展Intel VT-x?

  • 传统的 x86 架构有 4 个特权级别(Ring 0 到 Ring 3)。虚拟机里的操作系统(Guest OS)也认为自己是内核,它必须运行在 Ring 0 才能执行特权指令(如修改页表 CR3 寄存器)。但是,宿主机(Host OS)已经占据了物理硬件的 Ring 0,绝不能把真正的 Ring 0 让给 Guest OS,否则宿主机就失去控制权了。

  • 在 Intel VT-x 出现之前(如早期的 VMware Workstation),为了解决上述矛盾,虚拟化软件必须使用非常复杂的软件技术。

    • 强行把 Guest OS 挪到 Ring 1 运行。当 Guest OS 在 Ring 1 试图执行一条特权指令(例如“关中断”)时,CPU 会报错(抛出异常),因为只有 Ring 0 能做这个。虚拟化软件(VMM)捕获这个错误,然后模拟这条指令的效果,再告诉 Guest OS “你执行成功了”。
    • 但是x86 指令集中有一部分指令是 “敏感但非特权” 的。意思是,这些指令如果不运行在 Ring 0,它不会报错,而是会静默失败或者表现出不同的行为(例如读取 CS 寄存器)。 这就导致 VMM 无法捕获这些行为,Guest OS 会莫名其妙崩溃。
    • 因此VMM 必须在指令执行前扫描并动态修改二进制代码(Binary Translation),这极大地牺牲了性能,且实现极其复杂。
  • KVM 利用 Intel VT-x 来抛弃复杂的软件模拟。引入了两个维度的操作,

    • VMX Root Operation:宿主机(Host)运行的模式,宿主机运行在 VMX Root 的 Ring 0
    • VMX Non-Root Operation:虚拟机(Guest)运行的模式,Guest OS 运行在 VMX Non-Root 的 Ring 0
    • Guest OS 以为自己在 Ring 0,它执行特权指令时,CPU 硬件会自动判断
      • 如果是普通指令,直接在硬件执行(速度极快,接近原生)。
      • 如果是敏感指令(如涉及硬件控制),CPU 会强制暂停 Guest OS,触发 VM Exit,将控制权交还给 Host(KVM)。
    • KVM的作用是配置好VMCS (Virtual Machine Control Structure),如果 Guest 使用这些寄存器就Exit
  • KVM出现后CPU 的虚拟化交给 CPU 硬件(VT-x)做,内存的虚拟化交给 CPU 硬件(EPT)做。KVM只负责在 Host 和 Guest 之间切换状态。

如果CPU会判断是否需要触发vm exit,那么要KVM来做什么?需要理解VM Entry/Exit 的生命周期循环

  • 这里有两个角色需要认识

    • KVM (软件/内核模块)的角色,决定虚拟机配置,决定在这个时间片虚拟机能够执行什么,当VM Exit时负责模拟结果
    • CPU (硬件/VT-x)负责极速切换上下文,按照VMCS切换环境执行指令
  • KVM 提前配置好 VMCS,然后命令”CPU 进入虚拟机模式

  • 在让 CPU 运行虚拟机之前,KVM 会通过指令向内存中的 VMCS (Virtual Machine Control Structure) 结构体填入数据

  • KVM 准备好后,执行一条汇编指令 VMLAUNCH(或 VMRESUME)。此时 KVM 暂停工作,CPU 硬件接管一切。 CPU 读取 VMCS,瞬间保存 Host 寄存器,加载 Guest 寄存器,切换到 Non-Root 模式,虚拟机运行。

  • 虚拟机执行普通加法指令时CPU 直接执行。 虚拟机执行类似写串口时 CPU 硬件警报,CPU 查阅 VMCS 发现这条指令被标记为需拦截

  • 硬件自动切换 (VM Exit)

    • CPU 暂停 Guest 执行。

    • CPU 把 Guest 当前的寄存器状态、指令指针(停在哪一行)自动保存进 VMCS。

    • CPU 读取 VMCS 里的“Exit Reason”(退出原因),写上:EXIT_REASON_IO_INSTRUCTION

    • CPU 加载 Host 的寄存器状态,切换回 Root 模式。

    • CPU 将控制权交还给 KVM 代码(即刚才 VMLAUNCH 指令的下一行)

  • KVM 读取 VMCS 里的 Exit Reason,发现是“写串口”。KVM(或者交给 QEMU/Firecracker)在软件层面模拟这个操作。比如把字符打印到宿主机的文件里。

  • KVM 修改 VMCS 中的 Guest RIP(指令指针)(假装刚才那条指令执行成功了)。KVM 再次执行 VMRESUME,回到VM Entry。再次KVM 暂停工作,CPU 硬件接管一切。CPU 读取 VMCS,瞬间保存 Host 寄存器,加载 Guest 寄存器,切换到 Non-Root 模式

  • 从架构设计的角度来看,Hypervisor (KVM + Firecracker/QEMU) 对于 Guest OS 的角色,几乎完全等同于 Kernel 对于应用程序(User App)的角色

以发送网络包为例,如果KVM负责真正的工作,这个动作是通过宿主机的内核协议栈完成的吗,客户机的的内核如何工作和感知到这个动作呢?

  • 如果每次发包都要触发 VM Exit(Guest -> Host)并进行完整寄存器模拟,性能会非常差。 Virtio 的核心思想是:宿主机和客户机商量好一块共享内存(Shared Memory),大家直接往里面填数据,减少上下文切换。这块共享内存区域被称为 Virtqueue (虚拟队列)
  • 当发送网络请求时,Guest 内核的TCP/IP 协议栈处理数据,封装成以太网帧。Guest 网卡驱动 (virtio-net)将数据包的内存地址,填入 Virtqueue (共享内存环形缓冲区) 的“可用环”这一步是纯内存操作,不会触发 VM Exit。
  • Guest 驱动执行一条特殊的 I/O 指令(如 PIO 写特定端口,或 MMIO 写特定内存地址)。CPU 捕获到这个敏感指令,触发 VM Exit。CPU 暂停 Guest,切换回 Host (KVM)。
  • KVM (Kernel)看到 Exit Reason 是“I/O 写”,识别出这是属于 virtio-net 设备的通知。KVM 通过 ioeventfd 机制唤醒在用户态睡眠的 Firecracker 进程。
  • Firecracker (User Space)被唤醒后,去读取 Virtqueue (共享内存),看到了 Guest 刚才填入的数据包地址。Firecracker 宿主机上打开了一个特殊的字符设备文件,叫做 TAP 设备(例如 /dev/tap0)。Firecracker 调用宿主机的 write() 系统调用,把从共享内存里拿到的数据,写入这个 TAP 文件。
  • Host 内核的TAP 驱动收到数据,会把这串数据伪装成从一根网线接收到的以太网帧。这个帧进入宿主机的网络协议栈(Network Stack)。宿主机内核根据路由表、iptables/nftables 规则、网桥配置(Bridge)进行处理。最后通过宿主机的物理网卡 (NIC) 发送出去。
  • Firecracker 完成 write() 操作后,知道包已经交给宿主机内核了。Firecracker通知 KVM给那个虚拟机发中断。KVM 设置 VMCS 中的中断注入字段。下次 CPU 进入虚拟机时,硬件会自动跳转到 Guest OS 的中断处理函数。Guest 驱动收到中断,读取 Virtqueue 的Used Ring,回收内存。

vm进程和host中的Firecracker进程指的是一个同进程吗?Firecracker 进程其实一直在两个身份之间极其快速地来回切换。

  • 当 VM Exit 发生前Firecracker进程在运行虚拟机的 Linux Guest Kernel。
  • 当 VM Exit 发生时,CPU 从 Guest OS 跳回了 Host OS,回到了 Firecracker 进程的代码空间。变为一个普通的、正在执行 Rust 代码的 Linux 进程
  • 在这个过程中发生了4次CPU 特权级或运行模式的变更,但是这4 次切换自始至终都是在同一个 Firecracker 线程上下文中发生的

对比QEMU和Firecracker的区别?

  • QEMU模拟各种硬件,而Firecracker只支持 Virtio但是速度快
  • 例如磁盘模拟,Virtio让虚拟机以为自己有一块独立的硬盘,但实际上只是在宿主机上读写一个普通的文件。QEMU (全模拟 IDE/SATA 模式)会努力模拟一个真实的硬盘控制器(比如 Intel PIIX3 IDE 控制器)。它会模拟寄存器状态、模拟中断行为,甚至有些模拟器还会模拟磁盘旋转的延迟。Firecracker (Virtio 模式)Guest 直接把数据给它直接写文件。
特性 Firecracker QEMU
本质 用户态进程 (Rust) 用户态进程 (C语言)
CPU 虚拟化 必须依赖 KVM (硬件加速) KVM (首选) 或 TCG (纯软件模拟)
设备模型 仅支持 Virtio (网络/磁盘/键盘) 模拟真实硬件 (E1000网卡, USB, 显卡, 声卡) + Virtio
主板模拟 无 (MicroVM) 完整 (i440fx / Q35 / ACPI)
启动方式 直接跳转 Kernel 完整的 BIOS -> Bootloader -> Kernel 流程
典型用途 Lambda/Serverless, 容器隔离 运行 Windows, 传统 VPS, 跨架构模拟

EC2实例启动Firecracker虚拟机

启动metal实例,检查kvm设备

ls -l /dev/kvm

获取二进制文件

wget https://github.com/firecracker-microvm/firecracker/releases/download/v1.14.1/firecracker-v1.14.1-x86_64.tgz
tar -xzvf firecracker-v1.14.1-x86_64.tgzmv firecracker-v1.14.1-x86_64 firecracker
chmod +x firecracker
sudo mv firecracker /usr/local/bin/

准备 Kernel 和 RootFS,Firecracker需要一个未压缩的 Linux 内核 (vmlinux) 和一个根文件系统 (rootfs)

  • vmlinux.bin内核在编译时剔除了所有不必要的驱动(没有 USB、没有显卡、没有蓝牙、没有复杂的电源管理),必须开启 Virtio 相关的驱动(VIRTIO_NET, VIRTIO_BLK)。
  • bionic.rootfs.ext4内部是单纯的磁盘镜像文件Ubuntu 18.04 (代号 Bionic) 的用户态文件。
ARCH="$(uname -m)"
wget https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/${ARCH}/kernels/vmlinux.bin
wget https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/${ARCH}/rootfs/bionic.rootfs.ext4

启动 Firecracker 进程,Firecracker 启动后是一个运行在后台的进程,它监听一个 Unix Socket 等待指令

$ rm -f /tmp/Firecracker.socket
$ firecracker --api-sock /tmp/Firecracker.socket
2026-01-24T12:08:42.663881877 [anonymous-instance:main] Running Firecracker v1.14.1
2026-01-24T12:08:42.664033537 [anonymous-instance:main] Listening on API socket ("/tmp/Firecracker.socket").
2026-01-24T12:08:42.664338924 [anonymous-instance:fc_api] API server started.

在另一个shell中配置并启动MicroVM,设置内核和rootfs

curl --unix-socket /tmp/Firecracker.socket -i \-X PUT 'http://localhost/boot-source'   \-H 'Accept: application/json'           \-H 'Content-Type: application/json'     \-d "{\"kernel_image_path\": \"vmlinux.bin\",\"boot_args\": \"console=ttyS0 reboot=k panic=1 pci=off\"}"curl --unix-socket /tmp/Firecracker.socket -i \-X PUT 'http://localhost/drives/rootfs' \-H 'Accept: application/json'           \-H 'Content-Type: application/json'     \-d "{\"drive_id\": \"rootfs\",\"path_on_host\": \"bionic.rootfs.ext4\",\"is_root_device\": true,\"is_read_only\": false}"

启动虚拟机

curl --unix-socket /tmp/Firecracker.socket -i \-X PUT 'http://localhost/actions'       \-H  'Accept: application/json'          \-H  'Content-Type: application/json'    \-d "{\"action_type\": \"InstanceStart\"}"

启动完毕

image-20260124201241260

关闭虚拟机

curl --unix-socket /tmp/firecracker.socket -i \-X PUT 'http://localhost/actions' \-H  'Accept: application/json' \-H  'Content-Type: application/json' \-d '{ "action_type": "SendCtrlAltDel" }'

自定义Firecracker内核和rootfs

如何定制内核?

  • 下载 Linux Kernel 源码
  • 下载 Firecracker 官方提供的 MicroVM Kernel Config
  • 编译:make vmlinux
wget https://mirrors.aliyun.com/linux-kernel/v6.x/linux-6.1.13.tar.xz
tar -xf linux-6.1.13.tar.xz# https://github.com/firecracker-microvm/firecracker/blob/main/resources/guest_configs/microvm-kernel-ci-x86_64-6.1.config
mv microvm-kernel-ci-x86_64-6.1.config .configapt update && apt install -y gcc make libssl-dev bc flex bison libelf-dev pkg-configmake -j$(nproc) vmlinux

那么如何获取Rootfs?把 Docker 镜像转化为 ext4 文件

dd if=/dev/zero of=rootfs.ext4 bs=1M count=500
mkfs.ext4 rootfs.ext4mkdir /tmp/my-rootfs
sudo mount rootfs.ext4 /tmp/my-rootfsdocker run -d --name firecracker-rootfs public.ecr.aws/docker/library/alpine:latest tail -f /dev/nulldocker exec firecracker-rootfs apk add --no-cache openrc util-linux
docker export firecracker-rootfs | sudo tar -xf - -C /tmp/my-rootfsdocker rm -f firecracker-rootfs# 配置串口登录
sudo sh -c 'echo "ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100" >> /tmp/my-rootfs/etc/inittab'# 配置 DNS
sudo sh -c 'echo "nameserver 8.8.8.8" > /tmp/my-rootfs/etc/resolv.conf'sudo umount /tmp/my-rootfs

启动vm

curl --unix-socket /tmp/firecracker.socket -i \-X PUT 'http://localhost/boot-source'   \-d "{\"kernel_image_path\": \"/root/kernal6.1.13/vmlinux\",\"boot_args\": \"console=ttyS0 reboot=k panic=1 pci=off root=/dev/vda rw init=/sbin/init random.trust_cpu=on\"}"curl --unix-socket /tmp/firecracker.socket -i \-X PUT 'http://localhost/drives/rootfs' \-d "{\"drive_id\": \"rootfs\",\"path_on_host\": \"/root/kernal6.1.13/rootfs.ext4\",\"is_root_device\": true,\"is_read_only\": false}"curl --unix-socket /tmp/firecracker.socket -i \-X PUT 'http://localhost/actions' \-d "{ \"action_type\": \"InstanceStart\" }"

一直报错找不到设备。unknown-block(0,0):这意味着内核试图挂载文件系统,但找不到你指定的设备(root=/dev/vda)。here are the available partitions: 为空:这证明内核在启动时,完全没有检测到任何硬盘。

[    0.126580] VFS: Cannot open root device "vda" or unknown-block(0,0): error -6
[    0.127120] Please append a correct "root=" boot option; here are the available partitions:
[    0.127769] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    0.128379] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.1.13 #4

检查发现编译配置开启了ACPI 。Firecracker 在 x86_64 下通常不提供完整的 ACPI 表(除非使用特定的引导加载程序流程,但你使用的是直连 vmlinux)。当内核开启 ACPI 支持时,它会优先尝试通过 ACPI 表来枚举硬件设备。当它找不到预期的 ACPI 信息时,往往会放弃后续的设备扫描,或者与 virtio_mmio 的命令行参数发现机制发生冲突。关闭ACPI,重新编译

./scripts/config --file .config --disable ACPI

启动成功,忘记设置密码了,修改如下

sudo mount rootfs.ext4 /tmp/my-rootfs
sudo chroot /tmp/my-rootfs /bin/shpasswd
exitsudo umount /tmp/my-rootfs

登录成功,查看磁盘大小

~# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root               452.0M     16.7M    400.2M   4% /
devtmpfs                 51.2M         0     51.2M   0% /dev
tmpfs                    21.4M     12.0K     21.4M   0% /run

image-20260124214855513

配置网络,在宿主机执行

  • tap0 的作用是充当 VM 和宿主机之间的虚拟网线插口

  • VM 内部的 Alpine 认为 eth0 是真正的网卡,于是它把数据封装成以太网帧(比如发给网关 MAC 地址)

  • Firecracker 进程截获了 VM 发出的这些帧,通过文件描述符(tap0)把数据直接写入宿主机的 /dev/net/tun 文件。

  • 宿主机内核内核看到数据从 tap0 出来,就像看到一张物理网卡收到了数据一样。因为配置了 iptables NAT,宿主机把这个包的源 IP 改成宿主机的 IP,发给路由器。

# 1. 创建 tap0 设备
sudo ip tuntap add dev tap0 mode tap
sudo ip addr add 172.16.0.1/24 dev tap0
sudo ip link set tap0 up# 2. 开启内核转发
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"# 3. 配置 IPTables NAT (让 VM 能够伪装宿主机 IP 上网)
HOST_IFACE=$(ip route show default | awk '/default/ {print $5}')
echo "Using host interface: $HOST_IFACE"sudo iptables -t nat -A POSTROUTING -o $HOST_IFACE -j MASQUERADE
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i tap0 -o $HOST_IFACE -j ACCEPT

在指定kernel和rootfs之后,执行为vm添加网络配置。随后启动vm

curl --unix-socket /tmp/firecracker.socket -i \-X PUT 'http://localhost/network-interfaces/eth0' \-d "{\"iface_id\": \"eth0\",\"guest_mac\": \"AA:FC:00:00:00:01\",\"host_dev_name\": \"tap0\"}"

guest os中执行如下命令配置网络

# 赋予 IP (跟宿主机 tap0 在同网段)
ip addr add 172.16.0.2/24 dev eth0ip link set eth0 up
ip route add default via 172.16.0.1

随后测试连接成功

(none):~# ping bing.com
PING bing.com (150.171.27.10): 56 data bytes
64 bytes from 150.171.27.10: seq=0 ttl=96 time=81.811 ms

或者可以通过如下配置启动,命令为firecracker --api-sock /tmp/firecracker.socket --config-file config.json

{"boot-source": {"kernel_image_path": "/root/kernal6.1.13/vmlinux","boot_args": "console=ttyS0 reboot=k panic=1 root=/dev/vda"},"drives": [{"drive_id": "rootfs","path_on_host": "/root/kernal6.1.13/rootfs.ext4","is_root_device": true,"is_read_only": false}],"machine-config": {"vcpu_count": 2,"mem_size_mib": 512}
}

kata使用Firecracker后端一些问题

基于 EBS 的 Loop 设备配置 (EBS-based)的场景下,需要使用标准的 EBS 作为后端存储。通过在 Linux 系统中创建一个大文件并将其映射为 Loop 设备,进而构建 Device Mapper Thin Pool 供 Kata Containers 使用。

那么为什么kata需要底层存储呢?

  • 在普通的 Docker 或 Kubernetes 容器中,通常通常直接使用宿主机的 OverlayFS 文件系统。而在Kata Containers + Firecracker的场景下,必须配置专门的底层存储(如 Device Mapper Thin Pool),因为每一个 Pod 实际上都是MicroVM,无法像普通进程那样直接、高效地读取宿主机的文件目录。
  • Loop设备是Linux内核提供的一种虚拟块设备,它可以将普通文件映射为块设备
  • 为了让虚拟机能启动并运行容器镜像,需要使用devmapper把容器镜像文件伪装成一块虚拟硬盘(块设备,Block Device)插给虚拟机。
  • Thin Pool允许多个虚拟机共享同一份基础数据(只读的 Base Image),当某个 Agent 需要写数据时只会为它分配那一小块新产生的空间。即只占用实际存储数据所需的空间,而不是预先分配的空间。

kata vm启动不需要内核吗,为什么只需要配置镜像就可以?

  • Docker 容器镜像里面只有用户空间的文件。启动时直接借用宿主机(物理机)的内核来运行这些程序。而启动Kata 容器时,Kata 会从宿主机的特定目录加载一个预先编译好的、极度精简的 Linux 内核。把你的容器镜像(通过 Thin Pool 变成的块设备)挂载给上面那个内核,作为它的 根文件系统 (Rootfs)。这个 Guest Kernel 是特制的,它裁掉了 USB、蓝牙、声卡等驱动

  • 当 Kubernetes 通知 Kata 启动一个容器时,Kata 的组件(containerd-shim-kata-v2)会去读取自己的配置文件(通常在 /etc/kata-containers/configuration.toml),找到默认的内核路径/usr/share/kata-containers/vmlinux.container

  • Kata 启动 Firecracker 进程,并通过 Unix Socket 接口通知Firecracker 。

  • Firecracker 收到 Kata 的指令(通过 HTTP over Unix Socket 的 /boot-source 接口)后将内核文件的二进制代码,直接映射(mmap)或者是拷贝到属于这个虚拟机的内存空间里(Guest Memory),并设置好虚拟 CPU 的寄存器(Instruction Pointer),指向内核代码的入口点。

  • Firecracker 没有BIOS和GRUB,自己做完了Bootloader 的工作并进入内核代码。

EKS集群的环境配置步骤

测试环境为EKS1.33和al2023优化AMI,磁盘大小100GB

创建loop设备和Thin Pool

# 安装工具
dnf install -y bc device-mapper lvm2
# 创建目录
mkdir -p /var/lib/containerd/io.containerd.snapshotter.v1.devmapper
cd /var/lib/containerd/io.containerd.snapshotter.v1.devmapper
# 创建小容量稀疏文件
touch data meta
truncate -s 75G data
truncate -s 5G meta
# 挂载 Loop 设备
DATA_DEV=$(losetup --find --show data)
META_DEV=$(losetup --find --show meta)
# 创建 Thin Pool
SECTOR_SIZE=512
DATA_SIZE="$(blockdev --getsize64 -q ${DATA_DEV})"
LENGTH=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}")
# 创建名为 'devpool' 的池
dmsetup create devpool --table "0 ${LENGTH} thin-pool ${META_DEV} ${DATA_DEV} 128 32768"
# 验证
dmsetup ls

(恢复)使用如下命令删掉节点中存储设备并释放空间

dmsetup remove devpool
losetup -d /dev/loopX 
losetup -d /dev/loopY
rm /var/lib/containerd/io.containerd.snapshotter.v1.devmapper/data
rm /var/lib/containerd/io.containerd.snapshotter.v1.devmapper/meta

配置containerd的devmapper插件

cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
cat >> /etc/containerd/config.toml << 'EOF'
[plugins."io.containerd.snapshotter.v1.devmapper"]pool_name = "devpool"root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.devmapper"base_image_size = "30GB"discard_blocks = true
EOFsystemctl restart containerd
ctr plugins ls | grep devmapper
# io.containerd.snapshotter.v1              devmapper                linux/amd64    ok

安装kata运行时

参考https://github.com/kata-containers/kata-containers/blob/main/tools/packaging/kata-deploy/helm-chart/README.md

export VERSION=$(curl -sSL https://api.github.com/repos/kata-containers/kata-containers/releases/latest | jq .tag_name | tr -d '"')
export CHART="oci://ghcr.io/kata-containers/kata-deploy-charts/kata-deploy"
helm install kata-deploy "${CHART}" --version "${VERSION}"

kata-deploy具体做了什么?

  • 把运行 Kata 容器所需的所有核心组件(已经被打包在 kata-deploy 的镜像里),复制到宿主机的 /opt/kata/ 目录下,包括

    • Hypervisor,Firecracker

    • Guest Kernel,虚拟机启动时用的 Linux 内核文件(vmlinux)

    • Rootfs 镜像虚拟机启动时的微型系统盘(initrd/image)

    • Containerd Shim,containerd-shim-kata-v2`,这是 containerd 和 Kata 虚拟机之间的通信接口

    # cd /opt/kata/
    # tree -L 3
    .
    ├── VERSION
    ├── bin
    │   ├── cloud-hypervisor
    │   ├── containerd-shim-kata-v2
    │   ├── Firecracker
    │   ├── jailer
    │   ├── kata-collect-data.sh
    │   ├── kata-monitor
    │   ├── kata-runtime
    │   ├── qemu-system-x86_64
    │   ├── qemu-system-x86_64-snp-experimental
    │   └── qemu-system-x86_64-tdx-experimental
    ├── containerd
    │   └── config.d
    │       └── kata-deploy.toml
    ├── include
    │   ├── fdt.h
    │   ├── libfdt.h
    │   └── libfdt_env.h
    ├── lib
    │   ├── kata-qemu
    │   │   ├── libfdt.a
    │   │   └── pkgconfig
    │   ├── kata-qemu-snp-experimental
    │   │   ├── libfdt.a
    │   │   └── pkgconfig
    │   └── kata-qemu-tdx-experimental
    │       ├── libfdt.a
    │       └── pkgconfig
    ├── libexec
    │   ├── nydusd
    │   └── virtiofsd
    ├── runtime-rs
    │   └── bin
    │       └── containerd-shim-kata-v2
    ├── share
    │   ├── bash-completion
    │   │   └── completions
    │   ├── defaults
    │   │   └── kata-containers
    │   ├── kata-containers
    │   │   ├── config-6.12.47-176-dragonball-experimental
    │   │   ├── config-6.18.5-176
    │   │   ├── config-6.18.5-176-confidential
    │   │   ├── config-6.18.5-176-nvidia-gpu
    │   │   ├── config-6.18.5-176-nvidia-gpu-confidential
    │   │   ├── kata-alpine-3.22.initrd
    │   │   ├── kata-cbl-mariner-3.0-mariner.image
    │   │   ├── kata-containers-confidential.img -> kata-ubuntu-noble-confidential.image
    │   │   ├── kata-containers-initrd-confidential.img -> kata-ubuntu-noble-confidential.initrd
    │   │   ├── kata-containers-initrd-nvidia-gpu-confidential.img -> kata-ubuntu-noble-nvidia-gpu-confidential-590.48.01.initrd
    │   │   ├── kata-containers-initrd-nvidia-gpu.img -> kata-ubuntu-noble-nvidia-gpu-590.48.01.initrd
    │   │   ├── kata-containers-initrd.img -> kata-alpine-3.22.initrd
    │   │   ├── kata-containers-mariner.img -> kata-cbl-mariner-3.0-mariner.image
    │   │   ├── kata-containers-nvidia-gpu-confidential.img -> kata-ubuntu-noble-nvidia-gpu-confidential-590.48.01.image
    │   │   ├── kata-containers-nvidia-gpu.img -> kata-ubuntu-noble-nvidia-gpu-590.48.01.image
    │   │   ├── kata-containers.img -> kata-ubuntu-noble.image
    │   │   ├── kata-ubuntu-noble-confidential.image
    │   │   ├── kata-ubuntu-noble-confidential.initrd
    │   │   ├── kata-ubuntu-noble-nvidia-gpu-590.48.01.image
    │   │   ├── kata-ubuntu-noble-nvidia-gpu-590.48.01.initrd
    │   │   ├── kata-ubuntu-noble-nvidia-gpu-confidential-590.48.01.image
    │   │   ├── kata-ubuntu-noble-nvidia-gpu-confidential-590.48.01.initrd
    │   │   ├── kata-ubuntu-noble.image
    │   │   ├── root_hash.txt
    │   │   ├── vmlinux-6.12.47-176-dragonball-experimental
    │   │   ├── vmlinux-6.18.5-176
    │   │   ├── vmlinux-6.18.5-176-confidential
    │   │   ├── vmlinux-6.18.5-176-nvidia-gpu
    │   │   ├── vmlinux-6.18.5-176-nvidia-gpu-confidential
    │   │   ├── vmlinux-confidential.container -> vmlinux-6.18.5-176-confidential
    │   │   ├── vmlinux-dragonball-experimental.container -> vmlinux-6.12.47-176-dragonball-experimental
    │   │   ├── vmlinux-nvidia-gpu-confidential.container -> vmlinux-6.18.5-176-nvidia-gpu-confidential
    │   │   ├── vmlinux-nvidia-gpu.container -> vmlinux-6.18.5-176-nvidia-gpu
    │   │   ├── vmlinux.container -> vmlinux-6.18.5-176
    │   │   ├── vmlinuz-6.12.47-176-dragonball-experimental
    │   │   ├── vmlinuz-6.18.5-176
    │   │   ├── vmlinuz-6.18.5-176-confidential
    │   │   ├── vmlinuz-6.18.5-176-nvidia-gpu
    │   │   ├── vmlinuz-6.18.5-176-nvidia-gpu-confidential
    │   │   ├── vmlinuz-confidential.container -> vmlinuz-6.18.5-176-confidential
    │   │   ├── vmlinuz-dragonball-experimental.container -> vmlinuz-6.12.47-176-dragonball-experimental
    │   │   ├── vmlinuz-nvidia-gpu-confidential.container -> vmlinuz-6.18.5-176-nvidia-gpu-confidential
    │   │   ├── vmlinuz-nvidia-gpu.container -> vmlinuz-6.18.5-176-nvidia-gpu
    │   │   └── vmlinuz.container -> vmlinuz-6.18.5-176
    │   ├── kata-qemu
    │   │   └── qemu
    │   ├── kata-qemu-snp-experimental
    │   │   └── qemu
    │   ├── kata-qemu-tdx-experimental
    │   │   └── qemu
    │   └── ovmf
    │       ├── AMDSEV.fd
    │       ├── OVMF.fd
    │       └── OVMF.inteltdx.fd
    └── versions.yaml
    
  • 读取宿主机的 /etc/containerd/config.toml,并往里面注入 Kata 的配置。只管注入 Runtime,不影响 Devmapper 存储配置。例如

    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes][plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-fc]runtime_type = "io.containerd.kata.v2"# 这里会指向 Firecracker 的具体配置文件options = { ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration-fc.toml" }
    
  • 向 Kubernetes API Server 注册RuntimeClass,结果如下

    image-20260124175133962

  • 给Node 打上一个标签katacontainers.io/kata-runtime=true

kata-deploy运行日志如下

Action:installEnvironment variables passed to this scriptNODE_NAME: ip-192-168-6-172.cn-north-1.compute.internalDEBUG: falseSHIMS_X86_64: clh cloud-hypervisor dragonball fc qemu qemu-coco-dev qemu-coco-dev-runtime-rs qemu-nvidia-gpu qemu-nvidia-gpu-snp qemu-nvidia-gpu-tdx qemu-runtime-rs qemu-snp qemu-tdxSHIMS_AARCH64: clh cloud-hypervisor dragonball fc qemu qemu-cca qemu-nvidia-gpuSHIMS_S390X: qemu qemu-coco-dev qemu-coco-dev-runtime-rs qemu-runtime-rs qemu-se qemu-se-runtime-rsSHIMS_PPC64LE: qemuDEFAULT_SHIM_X86_64: qemuDEFAULT_SHIM_AARCH64: qemuDEFAULT_SHIM_S390X: qemuDEFAULT_SHIM_PPC64LE: qemuALLOWED_HYPERVISOR_ANNOTATIONS_X86_64:ALLOWED_HYPERVISOR_ANNOTATIONS_AARCH64:ALLOWED_HYPERVISOR_ANNOTATIONS_S390X:ALLOWED_HYPERVISOR_ANNOTATIONS_PPC64LE:SNAPSHOTTER_HANDLER_MAPPING_X86_64: fc:devmapper,qemu-coco-dev:nydus,qemu-coco-dev-runtime-rs:nydus,qemu-snp:nydus,qemu-tdx:nydusSNAPSHOTTER_HANDLER_MAPPING_AARCH64: fc:devmapper,qemu-cca:nydusSNAPSHOTTER_HANDLER_MAPPING_S390X: qemu-coco-dev:nydus,qemu-coco-dev-runtime-rs:nydus,qemu-se:nydus,qemu-se-runtime-rs:nydusSNAPSHOTTER_HANDLER_MAPPING_PPC64LE:AGENT_HTTPS_PROXY:AGENT_NO_PROXY:PULL_TYPE_MAPPING_X86_64: qemu-coco-dev:guest-pull,qemu-coco-dev-runtime-rs:guest-pull,qemu-nvidia-gpu-snp:guest-pull,qemu-nvidia-gpu-tdx:guest-pull,qemu-snp:guest-pull,qemu-tdx:guest-pullPULL_TYPE_MAPPING_AARCH64: qemu-cca:guest-pullPULL_TYPE_MAPPING_S390X: qemu-coco-dev:guest-pull,qemu-coco-dev-runtime-rs:guest-pull,qemu-se:guest-pull,qemu-se-runtime-rs:guest-pullPULL_TYPE_MAPPING_PPC64LE:INSTALLATION_PREFIX:MULTI_INSTALL_SUFFIX:HELM_POST_DELETE_HOOK: falseEXPERIMENTAL_SETUP_SNAPSHOTTER:EXPERIMENTAL_FORCE_GUEST_PULL_X86_64: qemu-nvidia-gpu-snp,qemu-nvidia-gpu-tdxEXPERIMENTAL_FORCE_GUEST_PULL_AARCH64:EXPERIMENTAL_FORCE_GUEST_PULL_S390X:EXPERIMENTAL_FORCE_GUEST_PULL_PPC64LE:
Validating the snapshotter-handler mapping: "fc:devmapper,qemu-coco-dev:nydus,qemu-coco-dev-runtime-rs:nydus,qemu-snp:nydus,qemu-tdx:nydus"
Using containerd drop-in files: true
copying kata artifacts onto host
WARN: Distro amzn 2023 does not support TDX and the TDX related runtime classes will not work in your cluster!
WARN: Distro amzn 2023 does not support TDX and the TDX related runtime classes will not work in your cluster!
Add Kata Containers as a supported runtime for containerd
node/ip-192-168-6-172.cn-north-1.compute.internal labeled

在节点上检查一下containerd的配置文件,引入了/opt/kata/containerd/config.d/kata-deploy.toml

# cat /etc/containerd/config.toml
version = 3
root = "/var/lib/containerd"
state = "/run/containerd"
imports = ["/opt/kata/containerd/config.d/kata-deploy.toml"]

部署使用kata运行时的负载

apiVersion: apps/v1
kind: Deployment
metadata:name: redis-deployment 
spec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:runtimeClassName: kata-fccontainers:- name: redis-containerimage: public.ecr.aws/docker/library/redis:latestimagePullPolicy: IfNotPresentports:- containerPort: 6379

当调度到非预期实例时候的报错

Warning  FailedCreatePodSandBox  41s   kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to start sandbox "9afc683fd428c1ec0fb688835ae52d819b73abcc65cff897802124014ba4ea93": failed to
create containerd task: failed to create shim task: Failed to connect to Firecrackerinstance (timeout 10s)

调度到metal节点报错,表明之前使用overlayfs 下载过镜像,后来配置了 devmapper,挂载了新的存储池,切换到 devmapper 或者重建 thin-pool 时,底层的数据找不到了

Warning  Failed     40s (x53 over 15m)  kubelet            Error: failed to create containerd container: error unpacking image: apply layer error for "public.ecr.aws/docker/library/redis:latest": failed to extract layer sha
256:e0e6002570470d87b99366522e2deadfd07fd6abb0c481198c1e336f9117e5a6: failed to get reader from content store: content digest sha256:c02d17997ce3d2c82e082235ea0b5152d06ee659c4e2fabcf1e0079312f1bcde: not found                 

清理containerd并重启

systemctl stop kubelet
systemctl stop containerd
rm -rf /var/lib/containerd
systemctl start containerd
systemctl start kubelet

此后经过手动拉取镜像部署运行正常。那么如何确认pod使用的kata和Firecracker?

# 宿主机内核
# uname -r
6.12.63-84.121.amzn2023.x86_64# pod内核
# uname -r
6.18.5

查看Firecracker进程如下

image-20260124190223807

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1211522.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025防火材料深度解析,带你了解防火涂料的多样应用,油性防火涂料/膨胀型防火涂料,防火涂料订制厂家电话

近年来,随着建筑、工业、交通等多个领域的快速发展,防火安全问题日益凸显,防火涂料作为一种重要的防火材料,其市场需求也在不断增长。然而,当前市场上防火涂料品牌众多,产品质量参差不齐,采购方在选择时往往面临…

大数据领域:数据价值挖掘的挑战与机遇

大数据领域&#xff1a;数据价值挖掘的挑战与机遇 关键词&#xff1a;大数据、数据价值挖掘、挑战、机遇、机器学习、数据质量、隐私保护 摘要&#xff1a;本文深入探讨大数据领域中数据价值挖掘面临的挑战与蕴含的机遇。开篇阐述大数据时代背景及数据价值挖掘概念的发展轨迹…

LeetCode 383 赎金信

文章目录摘要描述题解答案题解代码分析1. 字符计数的方法2. 统计 magazine 中的字符3. 检查 ransomNote 中的字符4. 为什么这样能解决问题&#xff1f;5. 优化&#xff1a;提前返回示例测试及结果示例 1&#xff1a;ransomNote "a", magazine "b"示例 2&…

Java 实战 - 字符编码问题解决方案

网罗开发&#xff08;小红书、快手、视频号同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

LLMs之ISC:《Enhancing LLM Planning Capabilities through Intrinsic Self-Critique》翻译与解读

LLMs之ISC&#xff1a;《Enhancing LLM Planning Capabilities through Intrinsic Self-Critique》翻译与解读 导读&#xff1a;本文提出并验证了一种结构化的“内在自我批评”迭代方法—内在自检推动LLM规划能力跃升—通过让模型逐步生成计划、逐条检验动作前置条件并把历史失…

干货大集合!AI应用架构师构建AI系统性能监控平台全攻略

干货大集合&#xff01;AI应用架构师构建AI系统性能监控平台全攻略 关键词 AI系统性能监控、可观测性三支柱、Metrics设计、分布式追踪、模型漂移检测、Prometheus&Grafana、根因分析 摘要 当你花费数月搭建的AI推荐系统突然因为推理延迟飙升导致用户流失&#xff0c;或…

AI原生应用领域边缘推理:实现实时智能决策的关键

AI原生应用领域边缘推理&#xff1a;实现实时智能决策的关键关键词&#xff1a;AI原生应用、边缘推理、实时智能决策、边缘计算、云计算摘要&#xff1a;本文深入探讨了AI原生应用领域中边缘推理这一实现实时智能决策的关键技术。首先介绍了相关背景&#xff0c;包括目的、预期…

2025网文新手必看避坑指南:新人逆袭SOP|投稿指南+AI写小说工具合集

我是你们的老朋友。在圈子里摸爬滚打了这么久&#xff0c;太懂那种感觉了——想写小说赚点零花钱&#xff0c;脑洞有了&#xff0c;打开文档却憋不出半个字&#xff1b;或者辛辛苦苦写了三万字&#xff0c;投给编辑&#xff0c;结果连个水花都没有。 说实话&#xff0c;现在的网…

盘点10个顶级写小说软件!ai写小说效率提升10倍,一个人顶一个编辑部!

也想在知乎、番茄或是晋江一书封神&#xff1f;作为一名在知乎摸爬滚打多年、坐拥百万粉丝的自媒体博主&#xff0c;我太了解写小说的那种痛苦了。&#x1f4da; 每天坐在电脑前&#xff0c;对着空白文档发呆&#xff0c;明明脑子里有个惊天动地的故事&#xff0c;一落笔却是“…

有哪些免费好用的AI写小说软件?盘点2026年AI写作10大辅助工具

一、AI辅助创作已成网文圈“隐形刚需” 现在的网文圈有一个心照不宣的秘密&#xff1a;虽然大家嘴上都在骂AI&#xff0c;但私底下偷偷用写小说软件辅助的人越来越多了。 据行业内部观察&#xff0c;2025年起&#xff0c;完全拒绝AI辅助的“纯手工”作者正在面临巨大的产能焦虑…

2026新手指南:盘点5款好用的写小说软件,第一款简直是“日更救星”!

很多刚入行的朋友常问我&#xff1a;“为什么我有那么多惊天动地的脑洞&#xff0c;可一打开文档就大脑一片空白&#xff1f;” 其实&#xff0c;99%的新人作者不是没天赋&#xff0c;而是顾虑太多。脑子里的设定堪比史诗巨作&#xff0c;手底下的字数却尴尬地停在第一行。这就…

从零开始写网文:2026年最强小说软件生成器深度横评与避坑指南

很多新人作者问我&#xff1a;“大神&#xff0c;为什么我设定做得比《三体》还宏大&#xff0c;可一动笔就觉得干巴巴的&#xff1f;” 其实问题很简单&#xff1a;你的脑子在天上飞&#xff0c;手却在地上爬。对于新手来说&#xff0c;最痛苦的不是没有创意&#xff0c;而是…

探索未来智能记忆系统 - MemU

MemU: 前沿智能记忆系统 在当今人工智能和大语言模型&#xff08;LLMs&#xff09;快速发展的背景下&#xff0c;MemU应运而生。它是一个功能强大的智能记忆框架&#xff0c;旨在为LLM和AI智能体提供后端支持&#xff0c;能够处理多模态输入&#xff08;包括对话、文档、图像等…

[特殊字符] 提升你编码效率的超级助手:Awesome GitHub Copilot

&#x1f916; 让你的GitHub Copilot焕然一新 — Awesome GitHub Copilot Customizations 在开发过程中&#xff0c;GitHub Copilot凭借其出色的辅助编码功能&#xff0c;已经成为了许多开发者的得力助手。今天&#xff0c;我们将介绍一个为GitHub Copilot提供强大定制功能的项…

【心电信号ECG】QRS波和峰值的检测(从噪声和清晰信号中获得心跳)附Matlab代码和报告

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#…

2026年市面上评价好的一体板加工厂怎么选,仿石漆保温装饰一体板/保温装饰一体板,一体板厂家哪家权威

外墙装饰一体板作为建筑节能领域的核心材料,直接影响建筑外立面的美观性、耐久性及节能效率。随着绿色建筑标准升级,市场对高品质一体板的需求持续攀升,如何从众多厂家中筛选出技术领先、服务完善、性价比突出的合作…

攻防世界ics-06

1.观察题目拿到题目随便乱点看看有没有什么地方可以跳转的发现报表中心可以跳转看看能不能找到跳转点用sqlmap发现不行 用bp试试看发现在get请求中的id 2.使用bp进行爆破选中这段送入intruder中添加payload先小范围尝试…

微软开源 VibeVoice:90 分钟播客级语音合成技术解析

一个改变语音合成的技术突破 你有没有想过,输入一段对话脚本,AI 就能生成两个人自然交谈 90 分钟的播客音频——不是机械的电子音,而是有停顿、有情感、能互动的真实对话。 微软刚开源的 VibeVoice 做到了。它解决了…

高德地图 API Key 获取指南

概述 高德地图开放平台为开发者提供丰富的地图服务 API&#xff0c;包括地图展示、定位、搜索、路线规划等功能。获取 API Key 是使用高德地图服务的第一步。一、准备工作 1. 注册账号访问官网&#xff1a;https://lbs.amap.com/注册开发者账号&#xff1a; 点击右上角"注…

best work

on the boundary of laws. people dont want to touch them, will be poorer, called left; but on the boundary, its capitalism.