爆竹:在不到一秒钟的时间内启动虚拟机

2021-01-24 03:31:48

你好!过去一周我花了整整一个时间来弄清楚如何使用鞭炮,到目前为止,我真的很喜欢。

最初,当我了解到发布Firecracker时,我以为它只是供云提供商使用的工具–我知道AWS Fargate和https://fly.ioused了,但我不认为这是我可以直接使用的工具自用。

但是事实证明,Firecracker的使用相对简单(或者至少与运行VM的其他任何东西一样简单),文档和示例都非常清楚,您绝对不需要成为acloud提供者即可使用它,并且如广告所示,它启动虚拟机的速度非常快!

因此,我想从更DIY的“我只想运行一些VM”的角度来撰写有关使用Firecracker的文章。

首先,我会说说我的用途,然后讲解我从中学到的一些知识。

我正在开发一种游戏,通过给他们一个要解决的问题和一个解决该问题的虚拟机来帮助人们学习命令行工具,就像aCTF一样。它基本上仍然只存在于我的计算机上,但是我已经使用了一段时间。

这是我目前正在处理的难题之一的屏幕截图。这是关于使用setfacl设置文件扩展属性。

我基本上想为该项目使用虚拟机而不是容器,因为我想模仿用户具有root访问权限的真实生产机器–我希望人们能够设置sysctls,使用nsenter,制定iptables规则,使用ip配置联网,运行性能,基本上是任何事情。

我希望人们能够在难题上单击“开始”并立即启动虚拟机。最初,我每次都启动DigitalOcean VM,但是启动它们大约要花一分钟的时间,每次都让我非常不耐烦,而且我认为人们不得不等待一分钟并不是一种可以接受的用户体验。

我也尝试过使用qemu,但出于我不完全了解的原因,使用qemu启动aVM也很慢-似乎至少需要20秒。

从接收Firecracker InstanceStart API调用到Linux来宾用户空间/ sbin / init进程的开始要花费< = 125毫秒。

到目前为止,我一直在使用Firecracker启动相对较大的VM(将systemd作为初始系统运行的Ubuntu VM),它们可能需要2-3秒才能启动。我没有进行过仔细的测量,因为说实在的5秒钟足够快,而且我也不介意以任何方式额外花费200毫秒。

我在这篇文章的开头说过,鞭炮非常容易上手。这是如何做。

Firecracker的入门说明确实很不错(它们很有效!),但是它分成了很多步骤,我想用1个Shell脚本看到您必须一起做的所有事情。因此,我编写了一个简短的Shell脚本,可用于启动Firecracker VM,并提供了一些有关如何使用它的快速说明。

尝试将这样的脚本运行在鞭炮周围时,我要做的第一件事。基本上有3个步骤:

第2步:以root身份运行此脚本(如果爆竹二进制文件不在root的PATH中,则可能需要用鞭炮二进制文件的路径编辑最后一行)

我还把这个脚本放在了要点上:firecracker-hello-world.sh。这里的IP地址是任意选择的。大多数脚本只是编写JSON文件。

设置-eu#下载内核和文件系统映像[-e hello-vmlinux.bin] || wget https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin [-e hello-rootfs.ext4] || wget -O hello-rootfs.ext4 https://github.com/firecracker-microvm/firecracker-demo/raw/master/xenial.rootfs.ext4 [-e hello-id_rsa] || wget -O hello-id_rsa https://raw.githubusercontent.com/firecracker-microvm/firecracker-demo/ec271b1e5ffc55bd0bf0632d5260e96ed54b5c0c/xenial.rootfs.id_rsaTAP_DEV="fc-88-tap0" argsMASK_LONG =" 255.255.255.252" MASK_SHORT =" / 30" FC_IP =" 169.254.0.21" TAP_IP =" 169.254.0.22" FC_MAC =" 02:FC:00:00:00:05" KERNEL_BOOT_ARGS =" ro console = ttyS0 noapic reboot = k panic = 1 pci = off nomodules random.trust_cpu = on" KERNEL_BOOT_ARGS =" $ {KERNEL_BOOT_ARGS} ip = $ {FC_IP} :: $$ TAP_IP:$ {MASK_LONG} :: eth0:off"#为Firecracker VM设置了Tap网络接口,以使用户IP链接del& #34; $ TAP_DEV" 2> / dev / null || trueip tuntap add dev" $ TAP_DEV"模式tapsysctl -w net.ipv4.conf。$ {TAP_DEV} .proxy_arp = 1> / dev / nullsysctl -w net.ipv6.conf。$ {TAP_DEV} .disable_ipv6 = 1> / dev / nullip addr add" $ {TAP_IP} $ {MASK_SHORT}" dev" $ TAP_DEV" ip链接集dev" $ TAP_DEV" #创建一个配置文件cat<< EOF> vmconfig.json {" boot-source&#34 ;: {" kernel_image_path&#34 ;:" hello-vmlinux.bin&#34 ;," boot_args&#34 ;:&#34 ; $ KERNEL_BOOT_ARGS" }," drives&#34 ;: [{" drive_id&#34 ;:" rootfs&#34 ;," path_on_host&#34 ;:" hello-rootfs.ext4&# 34 ;," is_root_device&#34 ;: true," is_read_only&#34 ;: false}]," network-interfaces&#34 ;: [{" iface_id&#34 ;:& #34; eth0&#34 ;," guest_mac&#34 ;:" $ FC_MAC&#34 ;," host_dev_name&#34 ;:" $ TAP_DEV" }]," machine-config":{" vcpu_count":2," mem_size_mib":1024," ht_enabled":false}} EOF #启动firecrackerfirecracker --no-api --config-file vmconfig.json

您还可以使用脚本下载的SSH密钥像这样通过SSH进入虚拟机:

您可能会注意到,如果在此VM上运行ping 8.8.8.8,则无法正常工作:它无法连接到外部互联网。我想我实际上是要使用这样的设置来解决人们不需要连接互联网的难题。

该脚本中的联网命令和rootfs映像来自firecracker-demo存储库,我发现它非常有用。

我希望能够从Docker容器SSH到他们(因为我在docker-compose中运行游戏的网络服务器)

在努力弄清楚如何使它工作之前,我努力地了解了Linux桥是什么以及它如何工作了大约一天。这是对先前脚本firecracker-hello-world-docker-bridge.sh的略微修改,该脚本在Docker桥上运行Firecracker VM

您可以像这样以root用户身份和SSH身份运行到生成的虚拟机(IP不同,因为它必须在Docker子网中)。

有一个额外的sudo brctl addif docker0 $ TAP_DEV将虚拟机的网络接口添加到Docker桥

它将内核启动参数中的网关更改为Docker桥网络接口的IP(172.17.0.1)

我的猜测是,大多数人可能不想使用Docker桥接器,如果您只是希望VM能够连接到外部互联网,我认为最好的方法是创建一个新的桥接器。

在我的应用程序中,我实际上正在使用一个名为firecracker0的网桥,这是我制作的一个由docker组成的网络。以这种方式使用由Docker管理的网桥有点粗略,但是现在它可以正常工作,所以除非我找到更好的方法,否则我会继续这样做。

这个“ hello world”的例子很好,但是您可能会说–好的,我如何构建自己的图像?

制作一个Linux内核。我想要一个5.8内核,所以我使用了爆竹文档中的说明来创建自己的映像以编译Linux内核,并且它们起作用了。我对此感到有些害怕,因为我以前从未以某种方式编译过Linux内核,但是按照说明进行操作才可以第一次使用。我以为itwo应该超级慢,但是从头开始编译实际上只花了不到10分钟的时间。

使用VM文件系统中所需的所有文件制作ext4文件系统映像。

这是我整理文件系统的方法。最初,我尝试下载Ubuntu的焦点云映像并使用dd提取根分区,但是我无法使其正常运行。

相反,我按照Firecracker文档的建议进行了操作,并构建了一个Dockercontainer并将容器的内容复制到文件系统映像中。

这是我使用的Dockerfile的大致样子:(我尚未测试此确切的Dockerfile,但我认为它应该可以工作)。主要的事情是您必须安装某种初始化系统,因为默认的ubuntu:20.04映像没有附带一个,因为您不需要在容器中安装一个。由于容器是供交互使用的,因此我也尽量减少恢复手册页。

来自ubuntu:20.04RUN apt-get updateRUN apt-get install -y init openssh-serverRUN是| Unminimize#复制一些SSH密钥并安装我想要的其他程序

这是我用来从Docker容器创建文件系统映像的基本Shell脚本。我以root身份运行整个程序,但从技术上讲,您只需要以root身份运行mount。

IMG_ID = $(docker build -q。)CONTAINER_ID = $(docker run -td $ IMG_ID /bin/bash)MOUNTDIR=mntFS=mycontainer.ext4mkdir $ MOUNTDIRqemu-img create -f raw $ FS 800Mmkfs.ext4 $ FSmount $ FS $ docker cp $ CONTAINER_ID:/ $ MOUNTDIRumount $ MOUNTDIR

我仍然不太确定我会喜欢这种使用Docker容器创建VM映像的方法的感觉–我觉得有点奇怪,但到目前为止一切正常。

我认为大多数使用Firecracker的人都使用比systemd更为轻便的init系统,并且绝对没有必要使用systemd,但我认为我现在会坚持使用systemd,因为我希望它看起来像是一个正常生产的Linux系统,并且我使用的生产服务器已经使用systemd。

好的,这就是创建图像的全部内容。让我们再谈谈配置Firecracker。

创建一个API套接字并向该API套接字编写指令(就像他们在其入门指南中说明的那样)

我真的很喜欢配置文件方法来进行一些初始实验,因为我发现能够一次查看所有内容变得更容易。但是,当将Firecracker与现实生活中的实际应用程序集成时,我发现使用该API更容易。

我想要一个可以从Ruby on Railsserver调用的HTTP服务来启动新的VM,并在完成后停止它们。

界面如下所示-您给它一个根映像和一个内核,它返回一个ID和VM的IP地址。所有文件路径都只是我机器上的本地路径。

然后是删除虚拟机的样子(我可能会在以后使用DELETE方法使它更像REST-y :))

最初我不确定如何使用Firecracker套接字API来实现此接口,但是后来我发现有一个Go SDK!这使生成正确的JSON变得更容易,因为存在许多结构,编译器会告诉我是否在字段名称中输入了错字。

到目前为止,我基本上是通过复制和修改Go命令行工具firectl的代码来编写所有代码的。我编写自己的工具直接使用firectl的原因是,我希望拥有一个可以启动和停止许多不同VM的HTTP API。

我发现firectl代码和Go SDK非常容易理解,因此在这里我不再赘述。

如果您有兴趣,可以查看我目前用于管理Firecracker VM的HTTP服务的要点,该服务杂乱无章,漏洞百出,不适合我以外的任何人使用。它确实成功启动了VM,但这是重要的第一步!!!

我遇到的另一个问题是:“好的,我将在生产中运行这些Firecracker VM?”在云中运行虚拟机的有趣之处在于,云实例已经是虚拟机。在VM内运行VM称为“嵌套虚拟化”,并非所有云提供商都支持它-例如,AWS不支持。

现在,我正在使用DigitalOcean,很高兴看到DigitalOceandoes即使在最小的Droplet上也支持嵌套虚拟化–我尝试从上面运行“ hello world” Firecracker脚本,它确实起作用了!

我认为GCP也支持嵌套虚拟化,但我还没有尝试过。官方的Firecracker文档建议在AWS上使用金属实例,这可能是因为Firecracker是由AWS制造的。

我不知道使用嵌套虚拟化对性能有何影响,但我想我会发现的!

我应该说Firecracker使用KVM,所以它只能在Linux上运行。我不知道是否有一种方法可以在Mac上以类似的快速方式启动VM,也许有,或者KVM有什么特别之处吗?我不了解KVM的运作方式。

目前,我没有使用jailer,这是Firecracker的另一部分,它通过添加一些seccomp-BPF规则和其他内容来帮助进一步隔离Firecracker VM。也许我应该! firectl使用jailer,因此复制执行该操作的代码非常容易。

我仍然不完全理解为什么鞭炮快(或者为什么qemu慢)。这篇LWNarticle指出,这是因为Firecracker仿真的设备比qemu少,但是我不确切知道哪些设备使qemu的启动速度变慢。

我不知道是否可以在Firecracker中运行图形应用程序,似乎可能不是因为它是为服务器而设计的,但是可能吗? 我不确定在每月5美元的DigitalOcean小滴上一次可以运行多少个Firecracker VM,我需要做一些实验。