AWS Lambda&Fargate 无服务底层技术是如何实现的

1、AWS Serverless 服务

近些年 AWS 很是推崇无服务器模式,自从2014年 Lambda 发布以后,无服务器大受欢迎,随之 2017 年推出 AWS Fargate 服务,应用于自家的容器服务平台 ECS。在 2019 年,EKS 也相继支持 AWS Fargate。 node

如今,更多的用户使用无服务器计算来构建应用程序,AWS 旨在打造让用户无需担忧基础设施的预置或管理问题。开发人员可使用 AWS Fargate 将其代码封装为无服务器容器,或使用 AWS Lambda 封装为无服务器函数。无服务器的低运营开销特色,这将继续对计算的将来发挥关键做用。linux

随着用户愈来愈普遍采用无服务器技术,AWS 认识到现行虚拟化技术还未同步发展,以针对此类事件驱动性,有时又呈短暂性特色的工做负载进行优化。AWS 认为须要构建特别针对无服务器计算设计的虚拟化技术。这种技术须要既能提供基于硬件虚拟化的虚拟机安全性边界,同时又能保持容器和函数较小的封装型号和敏捷性。git

2、Firecracker 技术

2.一、简介

image-20200222204400218

如今的技术环境下,容器具备快速启动时间和高密度,VM 能够对硬件虚拟化,具备更好的安全性,并对工做负载具备更好的隔离性。容器和 VM 的特性如今还不可兼得。github

AWS 开源了 Firecracker,一种利用 KVM 的新虚拟化技术,专门用于建立和管理多租户容器以及基于函数的服务。你能够在几分之一秒内在非虚拟化环境中启动轻量级微虚拟机(microVM),充分利用传统虚拟机提供的安全性和工做负载隔离,同时兼具容器的资源效率。编程

Firecracker 是一种采用基于 Linux 内核的虚拟机 (KVM) 技术的开源虚拟机监控程序(VMM)。Firecracker 容许您建立微型虚拟机,即 microVM。Firecracker 坚持精简主义的设计原则,它仅包含运行安全、轻量的虚拟机所需的组件。在设计过程的各个环节,AWS 依据安全性、速度和效率要求来优化 Firecracker。例如,仅启动相对较新的 Linux 内核,而且仅启动使用特定配置选项集编译的内核(内核编译配置选项超过 1000 种)。此外,不支持任何类型的图形卡或加速器,不支持硬件透传,不支持(大多数)老旧设备。json

Firecracker 启动的内核配置极少,不依赖仿真 BIOS,不使用完整设备模式。惟一的设备是半虚拟化网卡和半虚拟化硬盘,以及单按钮键盘(复位引脚在无电源管理设备时使用)。这种极简的设备模式不只有利于缩短开机时间(采用默认 microVM 型号的 i3.metal 实例开机时间 < 125 毫秒),同时也减小了***面,从而提升了安全性。请参阅有关 Firecracker 承诺支持以极低的开销执行容器和无服务器工做负载的更多信息。api

2017 年秋,AWS 决定以 Rust 语言来编写 Firecracker,这是一种很是先进的编程语言,可保证线程和内存安全,防止缓存溢出以及可能致使安全性漏洞的许多其余类型的内存安全问题。请访问 Firecracker 设计以了解有关 Firecracker VMM 功能和架构的更多详细信息。缓存

因为设备模型极简,内核加载过程也简单,能够实现小于 125 ms 的启动时间和更少的内存占用。Firecracker 目前支持 Intel CPU,并将于 2019 年开始支持 AMD 和 ARM,还将与 containerd 等流行的容器运行时集成。Firecracker 支持内核版本为 4.14 及更高版本的 Linux 主机和客户机操做系统。安全

Firecracker microVM 提升了效率和利用率,内存开销极低,每 microVM 的内存开销 < 5MiB。这意味着用户能够将数千个 microVM 封装到一个虚拟机中。可使用进程中速率限制器来实现对网络和存储资源的共享方式的精细控制,即便跨数千个 microVM 也一样可行。全部硬件计算资源能够安全地超订,从而最大化能够在主机上运行的工做负载数量。bash

2.二、Firecracker 的优点

AWS 依据以下开放源项目的指导信条开发了 Firecracker。

  • 内置安全性:AWS 提供了支持多租户工做负载而且不会被客户错误禁用的计算安全性屏障。客户工做负载被认为既神圣(不可侵犯)又邪恶(应当拒之门外)。
  • 高性能:能够在短至 125 毫秒内启动 microVM(在 2019 年能够更快),使其成为众多工做负载类型的理想选择,包括瞬态或短时间工做负载。
  • 轻量虚拟化:重视瞬时性或无状态的工做负载,而非长时间运行或持续性的工做负载。Firecracker 的硬件资源开销是明确且又保障的。
  • 久经沙场:Firecracker 通过了不少测试,已经为包括 AWS Lambda 和 AWS Fargate 在内的多个高容量 AWS 服务提供支持。
  • 低开销:Firecracker 每一个 microVM 消耗大约 5 MiB 的内存。你能够在同一实例上运行数千个具备不一样 vCPU 和内存配置的安全 VM。
  • 功能极简主义:不会构建非咱们的任务所明确要求的功能。每一个功能仅实施一项。
  • 计算超订:Firecracker 向来宾开放的全部硬件计算资源均可以安全地超订。
  • 开源:Firecracker 是一个开源项目。AWS 已经准备好审核并接受拉取请求。

2.三、Firecracker 的安全

  • 简单客户机模型:Firecracker 客户端提供了一个很是简单的虚拟化设备模型,以最小化***面:只有网络设备,block I / O 设备,可编程定时器,KVM 时钟,串行控制台和一个不彻底的 键盘(恰好足以让 VM 重置)。
  • 进程监狱:使用 cgroups 和 seccomp BPF 对 Firecracker 进程进行监禁,而且能够访问一个严格控制的小型系统调用列表。
  • 静态连接:Firecracker 进程是静态连接的,能够从进程监狱中启动,以确保主机环境尽量安全和干净。

2.四、Firecracker 的工做模式

2.4.一、与宿主机的关系

Firecracker 运行在 Linux 主机上,内核为4.14或更新内核,而且使用 Linux guest OSs (从这一点来讲,称为 guest)。 启动该进程后,在发出 instanceart 命令以前,用户与 Firecracker API 交互以配置 microVM。

AWS Lambda&Fargate 无服务底层技术是如何实现的

2.4.二、Firecracker 内部架构

每一个 Firecracker 进程封装一个且只有一个 microVM。 该进程运行如下线程: API、 VMM 和 vCPU。 Api 线程负责 Firecracker 的 API 服务器和相关的控制平面。 它永远不会在虚拟机的快速路径上。 Vmm 线程公开机器模型、最小遗留设备模型、 microVM 元数据服务(MMDS)和 VirtIO 设备仿真 Net 和 Block 设备,并提供 i / o 速率限制。 除此以外,还有一个或多个 vCPU 线程(每一个客户 CPU 核心一个)。 它们是经过 KVM 建立的,并运行 KVM run 主循环。 它们在设备模型上执行同步 i / o 和存储器映射输入输出操做。

img

2.4.三、Firecracker如何工做

image-20200222212646652

Firecracker 在用户空间中运行,使用基于 Linux 内核的虚拟机(KVM)来建立 microVM。每一个 microVM 的快速启动时间和低内存开销使你可将数千个 microVM 打包到同一台机器上。这意味着每一个函数或容器组均可以使用虚拟机屏障进行封装,从而使不一样用户的工做负载能在同一台计算机上运行,而无需在安全性和效率之间进行权衡。Firecracker 是 QEMU 的替代品,QEMU 是一个成熟的 VMM,具备通用和普遍的功能集,能够托管各类客户操做系统。

能够经过 RESTful API 控制 Firecracker 进程,RESTful API 能够启用常见操做:例如配置 vCPU 数量或启动计算机。Firecracker 提供内置速率限制器,可精确控制同一台计算机上数千个 microVM 使用的网络和存储资源。你能够经过 Firecracker API 建立和配置速率限制器,并灵活定义速率限制器来支持突发状况或特定带宽 / 操做限制。Firecracker 还提供元数据服务,可在主机和客户机操做系统之间安全地共享配置信息。元数据服务可使用 Firecracker API 设置。

Firecracker 如今还不能在 Kubernetes、Docker 或 Kata Container 上使用。Kata Container 是一个符合 OCI 标准的容器运行时,在基于 QEMU 的虚拟机中执行容器。Firecracker 是 QEMU 的云原生替代品,专门用于安全高效地运行容器,这是 Firecracker 和 Kata Container 以及 QEMU 之间的区别。

2.五、AWS Lambda&Fargate 实现

AWS Lambda 利用 Firecracker 做为沙箱环境的配置与运行基础,AWS 会在沙箱环境之上执行客户代码。因为Firecracker所配置的安全微虚拟机可以以最小体积实现快速配置,所以可以在不牺牲安全性水平的前提下带来出色性能。如此一来,AWS 将可以在物理硬件之上实现高资源利用率——包括对为Lambda分配及运行工做负载的具体方式进行优化,并根据活动/空闲时段以及内存利用率等因素对工做负载加以混合。

在此以前,Fargate Tasks 包含一个或者多个运行于专用 EC2 虚拟机当中的 Docker 容器,旨在确保任务间相互隔离。这些任务如今能够在 Firecracker 微虚拟机上执行,这使得 AWS 可以立足 EC2 裸机实例对 Fargate 运行时层进行更快、更高效地配置,同时在不影响任务内核级隔离能力的前提下提升工做负载密度。随着时间的推移,这还使 AWS 得以继续在运行时层内实现创新,为客户提供更好的性能表现,同时保持高安全性水平并下降运行无服务器容器架构的整体成本。

Firecracker目前运行在英特尔处理器之上,并将在2019年年内实现对 AMD 以及 ARM 处理器的支持。

用户能够在 AWS .metal 实例上运行 Firecracker,同时也可将其运行在任何其它裸机服务器之上,具体包括内部环境以及开发人员的笔记本电脑。

Firecracker 还将启用目前极具人气的容器运行时(例如 containerd )将容器做为微虚拟机进行管理。如此一来,用户的 Docker 与容器编排框架(例如 Kubernetes )将可以使用 Firecracker。

3、Firecracker 入门

3.一、先决条件

Firecracker 入门 提供了有关如何下载 Firecracker 二进制代码、以不一样的选项启动 Firecracker、从源进行构建以及运行集成测试等方面的详细说明。您能够经过 Firecracker Jailer 在生产环境中运行 Firecracker。

下面咱们来看如何在 AWS 云上开始使用 Firecracker(这些步骤能够在任何裸机上使用):

使用 Ubuntu 18.04.1 建立一个 i3.metal 实例。

Firecracker 在 KVM 上构建而且须要 /dev/kvm 的读/写权限。登陆一个终端中的主机,而后设置该访问权限:

sudo chmod 777 /dev/kvm

3.二、下载二进制包

Firecracker 二进制不依赖任何库,You can just download the latest binary from our release page, and run it on your x86_64 or aarch64 Linux machine.

wget https://github.com/firecracker-microvm/firecracker/releases/download/v0.21.0/firecracker-v0.21.0-x86_64
chmod +x firecracker-v0.21.0-x86_64
./firecracker-v0.21.0-x86_64 --api-sock /tmp/firecracker.sock

咱们经过 ps -ef 查看到 firecracker 的进程为 3501,而后查看一下其占用内存状况,发现为启动前只占用 4kb 内存。

# cat /proc/3501/status|grep VmRSS
VmRSS:         4 kB

3.三、运行 Firecracker

3.3.一、修改 vcpu 和 内存

如今咱们启动了一个 microVM,每一个 microVM 均可以使用 REST API 来访问。在另外一个终端中查询 microVM:

# curl --unix-socket /tmp/firecracker.sock "http://localhost/machine-config"
{ "vcpu_count": 1, "mem_size_mib": 128,  "ht_enabled": false,  "cpu_template": "Uninitialized" }

这将启动一个 VMM 进程并等待 microVM 配置。默认状况下,每一个 microVM 将分配一个 vCPU 和 128MiB 内存,若是须要修改 vCPU 和内存大小,能够向 microVM API 发送下面的请求:

curl --unix-socket /tmp/firecracker.sock -i  \
    -X PUT 'http://localhost/machine-config' \
    -H 'Accept: application/json'            \
    -H 'Content-Type: application/json'      \
    -d '{
        "vcpu_count": 2,
        "mem_size_mib": 4096,
        "ht_enabled": false
    }'

3.3.二、设置启动内核和根目录

如今此 microVM 须要使用解压后的 Linux 内核二进制代码和将用做根文件系统的 ext4 文件系统来进行配置。

下载示例内核和 rootfs:

curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin
curl -fsSL -o hello-rootfs.ext4 https://s3.amazonaws.com/spec.ccfc.min/img/hello/fsfiles/hello-rootfs.ext4

设置来宾内核:

curl --unix-socket /tmp/firecracker.sock -i \
    -X PUT 'http://localhost/boot-source'   \
    -H 'Accept: application/json'           \
    -H 'Content-Type: application/json'     \
    -d '{ 
        "kernel_image_path": "./hello-vmlinux.bin", 
        "boot_args": "console=ttyS0 reboot=k panic=1 pci=off" 
    }'

返回以下内容:

HTTP/1.1 204 
Server: Firecracker API
Connection: keep-alive

而后设置根文件系统:

curl --unix-socket /tmp/firecracker.sock -i \
    -X PUT 'http://localhost/drives/rootfs' \
    -H 'Accept: application/json'           \
    -H 'Content-Type: application/json'     \
    -d '{ 
        "drive_id": "rootfs",
        "path_on_host": "./hello-rootfs.ext4",
        "is_root_device": true,
        "is_read_only": false
    }'

3.3.三、启动 microVM

配置好内核和根文件系统后,将会启动来宾虚拟机:

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

第一个终端如今将显示一个序列 TTY,提示您登陆到来宾虚拟机,咱们切换到第一个终端能够看到 microVM 的整个启动过程,咱们经过启动过程能够看到,启动完成大约须要 150ms,我贴在下面:

[    0.000000] Linux version 4.14.55-84.37.amzn2.x86_64 (mockbuild@ip-10-0-1-79) (gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)) #1 SMP Wed Jul 25 18:47:15 UTC 2018
[    0.000000] Command line: console=ttyS0 reboot=k panic=1 pci=off root=/dev/vda rw virtio_mmio.device=4K@0xd0000000:5
[    0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[    0.000000] x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256
[    0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007ffffff] usable
[    0.000000] NX (Execute Disable) protection: active
[    0.000000] DMI not present or invalid.
[    0.000000] Hypervisor detected: KVM
[    0.000000] tsc: Using PIT calibration value
[    0.000000] e820: last_pfn = 0x8000 max_arch_pfn = 0x400000000
[    0.000000] MTRR: Disabled
[    0.000000] x86/PAT: MTRRs disabled, skipping PAT initialization too.
[    0.000000] CPU MTRRs all blank - virtualized system.
[    0.000000] x86/PAT: Configuration [0-7]: WB  WT  UC- UC  WB  WT  UC- UC  
[    0.000000] found SMP MP-table at [mem 0x0009fc00-0x0009fc0f] mapped at [ffffffffff200c00]
[    0.000000] Scanning 1 areas for low memory corruption
[    0.000000] Using GB pages for direct mapping
[    0.000000] No NUMA configuration found
[    0.000000] Faking a node at [mem 0x0000000000000000-0x0000000007ffffff]
[    0.000000] NODE_DATA(0) allocated [mem 0x07fde000-0x07ffffff]
[    0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00
[    0.000000] kvm-clock: cpu 0, msr 0:7fdc001, primary cpu clock
[    0.000000] kvm-clock: using sched offset of 125681660769 cycles
[    0.000000] clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000000001000-0x0000000000ffffff]
[    0.000000]   DMA32    [mem 0x0000000001000000-0x0000000007ffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000001000-0x000000000009efff]
[    0.000000]   node   0: [mem 0x0000000000100000-0x0000000007ffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000001000-0x0000000007ffffff]
[    0.000000] Intel MultiProcessor Specification v1.4
[    0.000000] MPTABLE: OEM ID: FC      
[    0.000000] MPTABLE: Product ID: 000000000000
[    0.000000] MPTABLE: APIC at: 0xFEE00000
[    0.000000] Processor #0 (Bootup-CPU)
[    0.000000] IOAPIC[0]: apic_id 2, version 17, address 0xfec00000, GSI 0-23
[    0.000000] Processors: 1
[    0.000000] smpboot: Allowing 1 CPUs, 0 hotplug CPUs
[    0.000000] PM: Registered nosave memory: [mem 0x00000000-0x00000fff]
[    0.000000] PM: Registered nosave memory: [mem 0x0009f000-0x000fffff]
[    0.000000] e820: [mem 0x08000000-0xffffffff] available for PCI devices
[    0.000000] Booting paravirtualized kernel on KVM
[    0.000000] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645519600211568 ns
[    0.000000] random: get_random_bytes called from start_kernel+0x94/0x486 with crng_init=0
[    0.000000] setup_percpu: NR_CPUS:128 nr_cpumask_bits:128 nr_cpu_ids:1 nr_node_ids:1
[    0.000000] percpu: Embedded 41 pages/cpu @ffff880007c00000 s128728 r8192 d31016 u2097152
[    0.000000] KVM setup async PF for cpu 0
[    0.000000] kvm-stealtime: cpu 0, msr 7c15040
[    0.000000] PV qspinlock hash table entries: 256 (order: 0, 4096 bytes)
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 32137
[    0.000000] Policy zone: DMA32
[    0.000000] Kernel command line: console=ttyS0 reboot=k panic=1 pci=off root=/dev/vda rw virtio_mmio.device=4K@0xd0000000:5
[    0.000000] PID hash table entries: 512 (order: 0, 4096 bytes)
[    0.000000] Memory: 111064K/130680K available (8204K kernel code, 622K rwdata, 1464K rodata, 1268K init, 2820K bss, 19616K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] Kernel/User page tables isolation: enabled
[    0.004000] Hierarchical RCU implementation.
[    0.004000]  RCU restricting CPUs from NR_CPUS=128 to nr_cpu_ids=1.
[    0.004000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
[    0.004000] NR_IRQS: 4352, nr_irqs: 48, preallocated irqs: 16
[    0.004000] Console: colour dummy device 80x25
[    0.004000] console [ttyS0] enabled
[    0.004000] tsc: Detected 2299.998 MHz processor
[    0.004000] Calibrating delay loop (skipped) preset value.. 4599.99 BogoMIPS (lpj=9199992)
[    0.004000] pid_max: default: 32768 minimum: 301
[    0.004000] Security Framework initialized
[    0.004000] SELinux:  Initializing.
[    0.004187] Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
[    0.005499] Inode-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.006697] Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
[    0.008013] Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
[    0.009671] Last level iTLB entries: 4KB 64, 2MB 8, 4MB 8
[    0.010636] Last level dTLB entries: 4KB 64, 2MB 0, 4MB 0, 1GB 4
[    0.012005] Spectre V2 : Mitigation: Full generic retpoline
[    0.012987] Speculative Store Bypass: Vulnerable
[    0.025015] Freeing SMP alternatives memory: 28K
[    0.026799] smpboot: Max logical packages: 1
[    0.027795] x2apic enabled
[    0.028005] Switched APIC routing to physical x2apic.
[    0.030291] ..TIMER: vector=0x30 apic1=0 pin1=0 apic2=-1 pin2=-1
[    0.031291] smpboot: CPU0: Intel(R) Xeon(R) Processor @ 2.30GHz (family: 0x6, model: 0x4f, stepping: 0x1)
[    0.032000] Performance Events: unsupported p6 CPU model 79 no PMU driver, software events only.
[    0.032000] Hierarchical SRCU implementation.
[    0.032093] smp: Bringing up secondary CPUs ...
[    0.032817] smp: Brought up 1 node, 1 CPU
[    0.033456] smpboot: Total of 1 processors activated (4599.99 BogoMIPS)
[    0.034834] devtmpfs: initialized
[    0.035417] x86/mm: Memory block size: 128MB
[    0.036178] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.037685] futex hash table entries: 256 (order: 2, 16384 bytes)
[    0.038868] NET: Registered protocol family 16
[    0.039717] cpuidle: using governor ladder
[    0.040006] cpuidle: using governor menu
[    0.044665] HugeTLB registered 1.00 GiB page size, pre-allocated 0 pages
[    0.045744] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[    0.046973] dmi: Firmware registration failed.
[    0.047770] NetLabel: Initializing
[    0.048026] NetLabel:  domain hash size = 128
[    0.048731] NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO
[    0.049639] NetLabel:  unlabeled traffic allowed by default
[    0.050631] clocksource: Switched to clocksource kvm-clock
[    0.051521] VFS: Disk quotas dquot_6.6.0
[    0.051521] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    0.053231] NET: Registered protocol family 2
[    0.054036] TCP established hash table entries: 1024 (order: 1, 8192 bytes)
[    0.055137] TCP bind hash table entries: 1024 (order: 2, 16384 bytes)
[    0.056156] TCP: Hash tables configured (established 1024 bind 1024)
[    0.057164] UDP hash table entries: 256 (order: 1, 8192 bytes)
[    0.058077] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[    0.059067] NET: Registered protocol family 1
[    0.060338] virtio-mmio: Registering device virtio-mmio.0 at 0xd0000000-0xd0000fff, IRQ 5.
[    0.061666] platform rtc_cmos: registered platform RTC device (no PNP device found)
[    0.063021] Scanning for low memory corruption every 60 seconds
[    0.064162] audit: initializing netlink subsys (disabled)
[    0.065238] Initialise system trusted keyrings
[    0.065946] Key type blacklist registered
[    0.066623] audit: type=2000 audit(1582381251.667:1): state=initialized audit_enabled=0 res=1
[    0.067999] workingset: timestamp_bits=36 max_order=15 bucket_order=0
[    0.070284] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.073661] Key type asymmetric registered
[    0.074318] Asymmetric key parser 'x509' registered
[    0.075091] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
[    0.076319] io scheduler noop registered (default)
[    0.077122] io scheduler cfq registered
[    0.077799] virtio-mmio virtio-mmio.0: Failed to enable 64-bit or 32-bit DMA.  Trying to continue, but this might not work.
[    0.079660] Serial: 8250/16550 driver, 1 ports, IRQ sharing disabled
[    0.102677] serial8250: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a U6_16550A
[    0.105548] loop: module loaded
[    0.106732] tun: Universal TUN/TAP device driver, 1.6
[    0.107583] hidraw: raw HID events driver (C) Jiri Kosina
[    0.108489] nf_conntrack version 0.5.0 (1024 buckets, 4096 max)
[    0.109523] ip_tables: (C) 2000-2006 Netfilter Core Team
[    0.110405] Initializing XFRM netlink socket
[    0.111154] NET: Registered protocol family 10
[    0.112326] Segment Routing with IPv6
[    0.112931] NET: Registered protocol family 17
[    0.113638] Bridge firewalling registered
[    0.114325] sched_clock: Marking stable (112005721, 0)->(211417276, -99411555)
[    0.115605] registered taskstats version 1
[    0.116270] Loading compiled-in X.509 certificates
[    0.117814] Loaded X.509 cert 'Build time autogenerated kernel key: 3472798b31ba23b86c1c5c7236c9c91723ae5ee9'
[    0.119392] zswap: default zpool zbud not available
[    0.120179] zswap: pool creation failed
[    0.120924] Key type encrypted registered
[    0.123818] EXT4-fs (vda): recovery complete
[    0.124608] EXT4-fs (vda): mounted filesystem with ordered data mode. Opts: (null)
[    0.125761] VFS: Mounted root (ext4 filesystem) on device 254:0.
[    0.126874] devtmpfs: mounted
[    0.128116] Freeing unused kernel memory: 1268K
[    0.136083] Write protecting the kernel read-only data: 12288k
[    0.138147] Freeing unused kernel memory: 2016K
[    0.140430] Freeing unused kernel memory: 584K
OpenRC init version 0.35.5.87b1ff59c1 starting
Starting sysinit runlevel

   OpenRC 0.35.5.87b1ff59c1 is starting up Linux 4.14.55-84.37.amzn2.x86_64 (x86_64)

 * Mounting /proc ...
 [ ok ]
 * Mounting /run ...
 * /run/openrc: creating directory
 * /run/lock: creating directory
 * /run/lock: correcting owner
 * Caching service dependencies ...
Service `hwdrivers' needs non existent service `dev'
 [ ok ]
Starting boot runlevel
 * Remounting devtmpfs on /dev ...
 [ ok ]
 * Mounting /dev/mqueue ...
 [ ok ]
 * Mounting /dev/pts ...
 [ ok ]
 * Mounting /dev/shm ...
 [ ok ]
 * Setting hostname ...
 [ ok ]
 * Checking local filesystems  ...
 [ ok ]
 * Remounting filesystems ...
 [ ok[    0.292620] random: fast init done
 ]
 * Mounting local filesystems ...
 [ ok ]
 * Loading modules ...
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
 [ ok ]
 * Mounting misc binary format filesystem ...
 [ ok ]
 * Mounting /sys ...
 [ ok ]
 * Mounting security filesystem ...
 [ ok ]
 * Mounting debug filesystem ...
 [ ok ]
 * Mounting SELinux filesystem ...
 [ ok ]
 * Mounting persistent storage (pstore) filesystem ...
 [ ok ]
Starting default runlevel
[    1.088040] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x212733415c7, max_idle_ns: 440795236380 ns

Welcome to Alpine Linux 3.8
Kernel 4.14.55-84.37.amzn2.x86_64 on an x86_64 (ttyS0)

localhost login:

3.3.四、登陆到 microVM

使用 root 和密码 root 登陆以查看来宾虚拟机的终端:

Welcome to Alpine Linux 3.8
Kernel 4.14.55-84.37.amzn2.x86_64 on an x86_64 (ttyS0)

localhost login: root
Password: 
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <http://wiki.alpinelinux.org>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

login[855]: root login on 'ttyS0'
localhost:~#

您可使用 ls / 查看文件系统:

localhost:~# ls /
bin         home        media       root        srv         usr
dev         lib         mnt         run         sys         var
etc         lost+found  proc        sbin        tmp

这时,咱们再查看一下其占用内存占用 36MB。

# cat /proc/3501/status|grep VmRSS
VmRSS:     36996 kB

使用 reboot 命令终止 microVM。为了权衡效率,Firecracker 目前并未实施来宾电源管理。相反,reboot 命令会发出一个键盘复位操做以做为关机开关。

建立基本的 microVM 后,您能够添加网络接口、更多的驱动器以及继续配置 microVM。

须要在您的裸机实例上建立上千个 microVMs?

for ((i=0; i<1000; i++)); do
    ./firecracker-v0.21.0-x86_64 --api-sock /tmp/firecracker-$i.sock &
done

多个 microVM 能够配置同一个共享根文件系统,而后为每一个 microVM 分配本身的读/写份额。

3.四、为 microVM 配置网络

3.4.一、建立 tap 设备

目前建立的 microVM 没有网络或者其余 I/O,如今咱们为其配置网络,咱们首先在宿主机上面为其添加一个 tap0 设备。

sudo ip tuntap add tap0 mode tap

microVM 须要访问公网,咱们这里使用 NAT,这里须要配置 iptables,首先把 iptables 规则清除,以避免引发其余问题,我这里的宿主机网络接口名称为enp4s0

sudo ip addr add 172.16.0.1/24 dev tap0
sudo ip link set tap0 up
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo iptables -t nat -A POSTROUTING -o enp4s0 -j MASQUERADE
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i tap0 -o enp4s0 -j ACCEPT

如今咱们能够查看建立的 tap0:

root@ip-172-31-20-74:~# ifconfig tap0
tap0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.16.0.1  netmask 255.255.255.0  broadcast 0.0.0.0
        ether fe:2d:e3:ba:09:ae  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

若是咱们一台物理机要启动多个 microVM,咱们须要为每一个 microVM 建立 tap# 设备,为每一个 tap 设备设置 iptables NAT 规则。

3.4.二、为 microVM 配置 tap

在 microVM 启动以前,咱们经过 microVM API 为其配置网络接口。

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

3.4.三、为 microVM 配置 IP

咱们登陆到 microVM 中,为其网络接口 eth0 配置 IP:

ip addr add 172.16.0.2/24 dev eth0
ip link set eth0 up
ip route add default via 172.16.0.1 dev eth0

查看网络状况。

localhost:~# ifconfig
eth0      Link encap:Ethernet  HWaddr AA:FC:00:00:00:01  
          inet addr:172.16.0.2  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::a8fc:ff:fe00:1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:516 (516.0 B)

localhost:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=47 time=1.491 ms
64 bytes from 8.8.8.8: seq=1 ttl=47 time=1.118 ms
64 bytes from 8.8.8.8: seq=2 ttl=47 time=1.136 ms

3.4.四、清除网络

当咱们删掉某个 microVM 的时候,能够把其相关网络设备删除。

sudo ip link del tap0
sudo iptables -F
sudo sh -c "echo 0 > /proc/sys/net/ipv4/ip_forward"

这里只是简单的介绍了一下 Firecracker 的使用方法,关于生产环境的使用,请详细查看官方 github 文档的推荐。

4、应用

4.一、成本

让咱们直面这样的现实:云服务(IaaS)比拥有本身的基础架构更昂贵(若是你想要按需扩展你的基础架构)。一样的道理,没必要关心配置、管理和扩展服务器是要须要付出代价。若是你的应用十分简单,云服务并非最优解。

Fargate实好,可是其价格几乎是等配置EC2实例的价格的 4 倍(例如t2.medium)这让咱们很难抉择,让咱们期待它可以降价。

image-20200305235810459

4.二、我应该将全部ECS任务都切换到Fargate吗?

固然不是。如上所述,在某些状况下,您的成本将增长三倍以上,因此在它们下降成本以前,您可能最好使用标准EC2实例。

可是,在如下状况下,Fargate可能对您更有益:

  • 若是您没法很好地伸缩你的ECS任务,会致使大量空闲的CPU或内存,而使用Fargate,您只需为在任务中定义的资源付费
  • 对于按需或按定时计划运行的任务,并不须要一直运行着的EC2实例。使用Fargate,您只需在任务运行时付款。
  • 适用于有内存和/或CPU使用率峰值的任务。这仅仅是由于使用Fargate能够在这类状况下节省您配置和管理的时间。

参考文档:

https://aws.amazon.com/cn/blogs/china/firecracker-lightweight-virtualization-for-serverless-computing/

https://github.com/firecracker-microvm/firecracker/blob/master/docs/jailer.md

https://firecracker-microvm.github.io/

欢迎你们扫码关注,获取更多信息

AWS Lambda&Fargate 无服务底层技术是如何实现的

相关文章
相关标签/搜索