AWS Lambda&Fargate 無服務底層技術是如何實現的

一、AWS Serverless 服務

近些年 AWS 非常推崇無服務器模式,自從2014年 Lambda 發佈之後,無服務器大受歡迎,隨之 2017 年推出 AWS Fargate 服務,應用於自家的容器服務平臺 ECS。在 2019 年,EKS 也相繼支持 AWS Fargate。

現在,更多的用戶使用無服務器計算來構建應用程序,AWS 旨在打造讓用戶無需擔心基礎設施的預置或管理問題。開發人員可以使用 AWS Fargate 將其代碼封裝爲無服務器容器,或使用 AWS Lambda 封裝爲無服務器函數。無服務器的低運營開銷特點,這將繼續對計算的未來發揮關鍵作用。

隨着用戶越來越廣泛採用無服務器技術,AWS 認識到現行虛擬化技術還未同步發展,以針對此類事件驅動性,有時又呈短暫性特點的工作負載進行優化。AWS 認爲需要構建特別針對無服務器計算設計的虛擬化技術。這種技術需要既能提供基於硬件虛擬化的虛擬機安全性邊界,同時又能保持容器和函數較小的封裝型號和敏捷性。

二、Firecracker 技術

2.1、簡介

image-20200222204400218

現在的技術環境下,容器具有快速啓動時間和高密度,VM 可以對硬件虛擬化,具有更好的安全性,並對工作負載具有更好的隔離性。容器和 VM 的特性現在還不可兼得。

AWS 開源了 Firecracker,一種利用 KVM 的新虛擬化技術,專門用於創建和管理多租戶容器以及基於函數的服務。你可以在幾分之一秒內在非虛擬化環境中啓動輕量級微虛擬機(microVM),充分利用傳統虛擬機提供的安全性和工作負載隔離,同時兼具容器的資源效率。

Firecracker 是一種採用基於 Linux 內核的虛擬機 (KVM) 技術的開源虛擬機監控程序(VMM)。Firecracker 允許您創建微型虛擬機,即 microVM。Firecracker 堅持精簡主義的設計原則,它僅包含運行安全、輕量的虛擬機所需的組件。在設計過程的各個環節,AWS 依據安全性、速度和效率要求來優化 Firecracker。例如,僅啓動相對較新的 Linux 內核,並且僅啓動使用特定配置選項集編譯的內核(內核編譯配置選項超過 1000 種)。此外,不支持任何類型的圖形卡或加速器,不支持硬件透傳,不支持(大多數)老舊設備。

Firecracker 啓動的內核配置極少,不依賴仿真 BIOS,不使用完整設備模式。唯一的設備是半虛擬化網卡和半虛擬化硬盤,以及單按鈕鍵盤(復位引腳在無電源管理設備時使用)。這種極簡的設備模式不僅有利於縮短開機時間(採用默認 microVM 型號的 i3.metal 實例開機時間 < 125 毫秒),同時也減少了***面,從而提高了安全性。請參閱有關 Firecracker 承諾支持以極低的開銷執行容器和無服務器工作負載的更多信息。

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 也同樣可行。所有硬件計算資源可以安全地超訂,從而最大化可以在主機上運行的工作負載數量。

2.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.3、Firecracker 的安全

  • 簡單客戶機模型:Firecracker 客戶端提供了一個非常簡單的虛擬化設備模型,以最小化***面:只有網絡設備,block I / O 設備,可編程定時器,KVM 時鐘,串行控制檯和一個不完全的 鍵盤(剛好足以讓 VM 重置)。
  • 進程監獄:使用 cgroups 和 seccomp BPF 對 Firecracker 進程進行監禁,並且可以訪問一個嚴格控制的小型系統調用列表。
  • 靜態鏈接:Firecracker 進程是靜態鏈接的,可以從進程監獄中啓動,以確保主機環境儘可能安全和乾淨。

2.4、Firecracker 的工作模式

2.4.1、與宿主機的關係

Firecracker 運行在 Linux 主機上,內核爲4.14或更新內核,並且使用 Linux guest OSs (從這一點來說,稱爲 guest)。 啓動該進程後,在發出 instanceart 命令之前,用戶與 Firecracker API 交互以配置 microVM。

AWS Lambda&Fargate 無服務底層技術是如何實現的

2.4.2、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.3、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.5、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。

三、Firecracker 入門

3.1、先決條件

Firecracker 入門 提供了有關如何下載 Firecracker 二進制代碼、以不同的選項啓動 Firecracker、從源進行構建以及運行集成測試等方面的詳細說明。您可以通過 Firecracker Jailer 在生產環境中運行 Firecracker。

下面我們來看如何在 AWS 雲上開始使用 Firecracker(這些步驟可以在任何裸機上使用):

使用 Ubuntu 18.04.1 創建一個 i3.metal 實例。

Firecracker 在 KVM 上構建並且需要 /dev/kvm 的讀/寫權限。登錄一個終端中的主機,然後設置該訪問權限:

sudo chmod 777 /dev/kvm

3.2、下載二進制包

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.3、運行 Firecracker

3.3.1、修改 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.2、設置啓動內核和根目錄

現在此 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.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.4、登錄到 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.4、爲 microVM 配置網絡

3.4.1、創建 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.2、爲 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.3、爲 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.4、清除網絡

當我們刪掉某個 microVM 的時候,可以把其相關網絡設備刪除。

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

這裏只是簡單的介紹了一下 Firecracker 的使用方法,關於生產環境的使用,請詳細查看官方 github 文檔的推薦。

參考文檔:

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 無服務底層技術是如何實現的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章