Firecracker’da FreeBSD
(usenix.org)- AWS Lambda için Linux odaklı bir microVM olan Firecracker VMM üzerinde FreeBSD 14 çekirdeğini başlatma çalışması, asgari sanallaştırma ortamlarının işletim sistemi başlatma yolundaki gizli varsayımları ve darboğazları nasıl ortaya çıkardığına bir örnektir
- İlk boot, PVH boot mode’daki ELF Note biçimi farkları, Xen’e özgü hypercall’lar ve Firecracker’ın bellek yerleşimi farkları nedeniyle engellendi; FreeBSD’nin PVH kodunda yapılan değişikliklerle çözüldü
- Firecracker ACPI sağlamadığından CPU ve interrupt bilgilerini alma yolu değişti; Linux’un MPTable işleme hatasına uyum sağlamak için
MPTABLE_LINUX_BUG_COMPATseçeneği eklendi - Seri konsol ve Virtio aygıtlarını bağlama sürecinde UART davranışı, çekirdek komut satırı ayrıştırması ve hizalanmamış disk I/O kısıtları ortaya çıktı; FreeBSD
hw.broken_txfifo, FIFO boşaltma çevresinden dolaşma çözümü vebusdmatabanlı bounce işlemesini uyguladı - Commit edilmemiş yamalar dahil edildiğinde, 1 CPU ve 128 MB RAM’li bir VM’de FreeBSD çekirdeği 20 ms’nin altında boot edebiliyor; kalan işler PVH desteğinin birleştirilmesi, Xen kodunun ayrılması, daha küçük çekirdek yapılandırması ve Firecracker’ın FreeBSD’ye port edilmesinin değerlendirilmesi
Firecracker’a FreeBSD koymaya çalışma nedeni
- Firecracker, AWS Lambda gibi serverless çalıştırma ortamları için Linux KVM üzerinde düşük ek yükle microVM’ler oluşturan ve yöneten bir VMM’dir
- FreeBSD portlama çalışması Haziran 2022’de başladı
- Motivasyon, FreeBSD ile Firecracker’ın sınırlarını birlikte görmekti
- FreeBSD boot hızını iyileştirme çalışmalarını sürdürürken minimal hypervisor üzerinde ne kadar hızlanabileceğini görmek istiyordu
- FreeBSD’yi yeni bir platforma port etmek, hem FreeBSD’deki hem de ilgili platformdaki hataları ortaya çıkarır
- AWS Lambda şu anda yalnızca Linux destekliyor; Lambda’nın FreeBSD’yi benimseyip benimsememesinden bağımsız olarak FreeBSD’nin Firecracker’ı desteklemesi gerekli bir ön koşuldur
- Firecracker’ın kendisi ilginç bir platform olduğundan gerçekten çalışıp çalışmadığını görmek istendi
Çekirdeği çalıştırmaya kadarki ilk engel
- Firecracker başlangıçta Linux çekirdeği çalıştırmak için tasarlanmıştı; ancak 2020’de
linuxbootdışında PVH boot mode desteği ekleyen bir yama vardı - FreeBSD, Xen üzerinde PVH boot’u desteklediği için aynı yol Firecracker’da denendi
- İlk sorun, Firecracker’ın FreeBSD çekirdeğini belleğe yükledikten sonra kernel entry point’i bulamamasıydı
- PVH boot protokolü bu değeri ELF Note içinde saklar
- ELF Note’ta
PT_NOTEveSHT_NOTEvardır; FreeBSD, Firecracker’ın aradığı biçimi sağlamıyordu - FreeBSD çekirdek linker script’inde yapılan küçük bir değişiklikle Firecracker’ın FreeBSD çekirdeğini çalıştırmaya başlaması sağlandı
- Çekirdek çalışması yaklaşık 1 mikrosaniye sonra yeniden durdu
İlk hata ayıklama ve Xen bağımlılıklarını kaldırma
- Çekirdek debugger’ı ve seri konsol başlatılmadan önce çekirdek ölürse FreeBSD’nin hata ayıklama özellikleri pek işe yaramıyordu
- Firecracker sürecinin verdiği tek bilgi, FreeBSD guest’in triple-fault verdiğiydi
- Çekirdek başlangıç kodunun ortasına
hltkomutları eklenerek çökme konumunu daraltan bir “kernel bisection” yapıldıhltnoktasına ulaşılırsa Firecracker çalışmaya devam eder, ancak host CPU kullanımı %0 olur- Firecracker sonlanırsa ilgili noktadan önce çöktüğü anlaşılabiliyordu
- İlk neden bir Xen hypercall idi
- FreeBSD’nin PVH giriş noktası aslında Xen’de boot etmek için yazılmış koddur ve Xen içinde çalıştığını varsayıyordu
- Firecracker’ın kullandığı KVM, Xen hypercall’ları sağlamadığından çağrı yapıldığında VM çöküyordu
- Başta Xen hypercall’ları yorum satırına alındı; daha sonra
CPUIDiçinde Xen imzası kontrol edildikten sonra çağrılacak şekilde düzeltildi
- Fiziksel bellek haritasını sorgulamak, Xen hypercall’ının üstlendiği zorunlu bir işlevdi
- PVH version 1’den itibaren bellek haritası işaretçisi
start_infosayfası üzerinden aktarılır - FreeBSD, Xen hypercall’ı yerine PVH version 1 bellek haritasını kullanacak şekilde değiştirildi
- PVH version 1’den itibaren bellek haritası işaretçisi
- Firecracker ile Xen’in bellek yerleşimi farkı da sorun çıkardı
- Xen önce çekirdeği yükler, ardından
start_infosayfasını sona yerleştirir - Firecracker
start_infosayfasını sabit bir düşük adrese koyar ve sonra çekirdeği yükler - FreeBSD PVH kodu,
start_infohemen arkasındaki alanı scratch space olarak varsayıyordu; Firecracker’da bu, ilk çekirdek yığınını ezdi - Hypervisor’ın başlattığı tüm bellek bölgelerinden sonra scratch space ayıracak şekilde düzeltilerek çözüldü
- Xen önce çekirdeği yükler, ardından
ACPI yokluğu ve MPTable uyumluluğu
- x86’da FreeBSD normalde disk, ağ adaptörü, CPU ve interrupt controller bilgilerini ACPI üzerinden alır
- Firecracker bilinçli olarak minimal bir uygulamayı seçtiği için ACPI sağlamaz
- FreeBSD bunun yerine eski Intel MultiProcessor Specification’ın MPTable yapısını kullanabilir
GENERICçekirdek yapılandırmasına varsayılan olarak dahil değildir- Firecracker için hafif çekirdek yapılandırmasında
device mptableeklenerek kullanılabildi
- Firecracker’ın sunduğu MPTable standart değildi; Linux’un kabul ettiği davranışa göre ayarlanmıştı
- Linux’ta MPTable’ı bulma ve ayrıştırma biçiminde hatalar vardı
- Firecracker, Linux boot etmeyi hedefleyerek tasarlandığından Linux’un desteklediği standart dışı yerleşimi sunar
- Standartlara uygun bağımsız bir uygulama olan FreeBSD, yanlış yerleştirilmiş MPTable’ı bulamadı; bulsa bile geçersiz MPTable’ı ayrıştıramadı
- FreeBSD’ye
options MPTABLE_LINUX_BUG_COMPATçekirdek seçeneği eklendi- Linux’un MPTable işlemesiyle bug-for-bug uyumluluk gerektiğinde kullanılır
- Bu seçenekle Firecracker’da FreeBSD boot süreci daha da ilerledi
Seri konsol ve Virtio aygıt desteği
- Firecracker’ın sağladığı az sayıdaki emüle aygıttan biri seri porttur
- Tipik yapılandırmada Firecracker sürecinin standart girdisi ve çıktısı, VM’in seri port girdisi ve çıktısı olur
- FreeBSD çekirdeği, root diski çekirdek imajına dahil edilmiş halde boot etti ve çekirdek konsol çıktısı okunabiliyordu
- Kullanıcı alanı boot’una geçilince konsol çıktısı 16 karakterde durdu
- Eski QEMU UART hatasıyla aynı belirtideydi
- UART’ın transmit FIFO’su boşaldığında interrupt gelmediği için FreeBSD 16 byte’tan sonra daha fazla yazamıyordu
- FreeBSD çekirdeğinin mevcut geçici çözümü olan
hw.broken_txfifo="1", çekirdek ortam değişkeni olarak derlenerek çözüldü
- Konsol girdisi de çalışmıyordu
- Firecracker, emüle UART’ın receive FIFO’sunun dolu olduğuna karar verdiği için konsolu okumuyordu
- FreeBSD, UART başlatması sırasında FIFO boyutunu ölçmek için receive FIFO’yu çöp değerlerle doldurup FIFO Control Register üzerinden boşaltıyordu
- Firecracker FIFO Control Register’ı uygulamadığından FIFO sürekli dolu kaldı
- FreeBSD, FIFO boşaltma sonrasında
LSR_RXRDYkalırsa karakterleri tek tek okuyup atarak FIFO’yu boşaltacak şekilde düzeltildi
- Disk ve ağ kullanmak için Virtio block/network aygıtları gerekiyordu
- Firecracker bunları
mmioaygıtları olarak sunar - FreeBSD Firecracker çekirdek yapılandırmasına
device virtio_mmioeklendi
- Firecracker bunları
- FreeBSD aslında
mmioaygıtlarını FDT üzerinden keşfetmeyi bekliyordu; Firecracker ise çekirdek komut satırınavirtio_mmio.device=4K@0x1001e000:5gibi yönergeler aktarıyordu- FreeBSD, bu yönergeleri ayrıştırıp
virtio_mmioaygıt düğümleri oluşturan kod ekledi - Aygıt düğümü oluşunca FreeBSD’nin mevcut device probe süreci Virtio aygıt türünü belirleyip uygun sürücüyü bağlar
- FreeBSD, bu yönergeleri ayrıştırıp
- Birden fazla Virtio aygıtı olduğunda çekirdek komut satırı ayrıştırma sorunu yaşandı
- Firecracker, Linux tarzında birden çok
key=valueçifti geçirir - FreeBSD çekirdek komut satırını ortam değişkenleri olarak ayrıştırdığı için aynı ada sahip iki
virtio_mmio.device=varsa yalnızca biri kalır - İlk çekirdek ortam ayrıştırma kodu, yinelenen değişkenlere numara suffix’i ekleyerek
virtio_mmio.device=vevirtio_mmio.device_1=gibi koruyacak şekilde düzeltildi
- Firecracker, Linux tarzında birden çok
- Anormal kapanıştan sonraki boot’ta
fsckçalışınca çekirdek paniği oluştufsck, FreeBSD’de sayfa hizalı olmayan disk I/O üreten nadir durumlardan biridir- Firecracker’ın Virtio uygulaması yalnızca tek veri tamponu alır; sayfa sınırını aşan tamponu birden çok segmente bölen yaygın Virtio yöntemini desteklemez
- FreeBSD Virtio block sürücüsü
busdmakullanacak şekilde değiştirildi; hizalanmamış istekler geçici tampon üzerinden bounce işlenerek Firecracker kısıtlarına uyduruldu
Firecracker’ın ortaya çıkardığı boot optimizasyonları
- FreeBSD Firecracker’da çalışmaya başlayınca boot süresi ve bellek kullanımını azaltılabilecek noktalar belirginleşti
- 128 MB RAM’li VM’de sistem belleğinin neredeyse yarısı
wireddurumundaydı ve süreçler sık sık sonlanıyordu- İnceleme sonucunda
busdma’nın bounce page’ler için 32 MB ayırdığı görüldü - Firecracker kısıtları nedeniyle her disk I/O için en fazla tek bir 4 KB bounce page gerekiyordu
- Az sayıda I/O segmenti destekleyen aygıtlar için bounce page rezervasyonunu sınırlayan yamayla bellek kullanımı 512 KB’ye düştü
- İnceleme sonucunda
- Çekirdek rastgele sayı üreteci optimizasyonu boot süresini azalttı
- VM’lerde donanım aygıtı tabanlı entropi etkili olmayabilir
- x86’daki
RDRANDyedek entropi kaynağı olarak kullanılıyordu; ancak istek başına entropi miktarı azdı ve yalnızca her 100 ms’de bir istek yapılıyordu - Fortuna rastgele sayı üretecini tamamen seed etmeye yetecek kadar istekte bulunacak şekilde değiştirilerek 2,3 saniye kazanıldı
- Host ID işlemesi de hızlandı
- Genelde boot loader, BIOS veya UEFI bilgilerine dayanarak
smbios.system.uuiddeğerini ayarlar - Firecracker’da boot loader olmadığından ID sağlanmıyordu
- Donanım hatalı ID sağlarsa uyarıdan sonra 2 saniye bekleyen, ID hiç yoksa sessiz ve hızlı ilerleyen bir davranışa dönüştürüldü
- Genelde boot loader, BIOS veya UEFI bilgilerine dayanarak
- IPv6 DAD bekleme koşulu daraltıldı
- FreeBSD, ağ arayüzünde IPv6 etkinse Duplicate Address Detection’ı bekliyordu
- loopback arayüzünde IPv6 her zaman etkindi
- Yalnızca loopback dışındaki arayüzlerde IPv6 varsa DAD bekleyecek şekilde değiştirilerek 2 saniye kazanıldı
- Yeniden başlatma ve kapatma sürecindeki sabit bekleme süreleri kaldırıldı
- Yeniden başlatma sırasında
Rebooting...mesajından sonraprintftamamlanması ve okuma süresi için 1 saniye bekleyen davranışkern.reboot_wait_timesysctl’ine dönüştürüldü; varsayılan değer 0’dır - Kapatma veya yeniden başlatma sırasında BSP’nin diğer CPU’lardan durma sinyali aldıktan sonra ek 1 saniye beklemesi de kaldırıldı
- Yeniden başlatma sırasında
- Boot flame chart’ını analiz etmek için TSLOG kullanıldı
- Firecracker’ın minimal ortamı az gürültülü olduğu için kalan darboğazları görmek kolaydı
- VM çalıştırma çok hızlı olduğundan yeni çekirdek derleme, çalıştırma ve flame chart oluşturma çoğu zaman 30 saniyenin altında mümkün oluyordu
- TSLOG analiziyle milisaniye ölçeğinde birkaç darboğaz azaltıldı
lapic_initiçindeki 100000 tekrarlı kalibrasyon döngüsü 1000’e düşürülerek 10 ms kazanıldıns8250_drain’in her karakterdeDELAYçağırdığı kısım,LSR_RXRDYkontrolünden sonra yalnızca gerektiğinde gecikecek şekilde değiştirilerek 27 ms kazanıldı- Firecracker’ın TSC ve local APIC clock frekanslarını bildiren CPUID leaf’ini uygulamasıyla 20 ms kazanıldı
kern.nswbufdeğerini her zaman 256 yapmak yerine32 * mp_ncpusbiçimine çevirmek, 1 CPU’lu VM’de 5 ms kazandırdımi_startupiçindeki bubblesort’u quicksort’a çevirmek 2 ms kazandırabilir; 22 Ağustos 2023 itibarıyla henüz commit edilmemiştirvm_mem’in tüm fiziksel belleğinvm_pageyapılarını hemen başlatması yerine lazy initialization’a geçirilmesi 2 ms kazandırabilir; aynı tarih itibarıyla henüz commit edilmemiştir- Firecracker’ın guest memory
mmapçağrısınaMAP_POPULATEeklemek, ilk sayfa erişiminde Linux’un sayfa yapıları oluşturma maliyetini azaltarak 2 ms kazandırabilir; aynı tarih itibarıyla henüz commit edilmemiştir
Mevcut durum ve kalan işler
- FreeBSD, Firecracker’da boot ediyor ve çok hızlı çalışıyor
- FreeBSD ve Firecracker’ın commit edilmemiş yamaları dahil edildiğinde, 1 CPU ve 128 MB RAM’li VM’de FreeBSD çekirdeği 20 ms’nin altında boot edebilir
- Kalan işler PVH desteğinin düzenlenmesi ve çekirdek yapılandırmasının küçültülmesine odaklanıyor
- Yukarıda belirtilen yamaların commit edilmesi gerekiyor
- PVH boot mode desteği Firecracker mainline’a birleştirilmeli
- PVH booting kodu Xen desteğiyle iç içe olduğundan ayrıştırılmalı
- FreeBSD arm64 çekirdeği şu anda PCI veya ACPI desteği olmadan derlenemiyor; hatalı bağımlılıklar kaldırılırsa FreeBSD/Firecracker çekirdeği daha küçük hale getirilebilir
- Intel GPU için bellek rezervasyonunun gerekli olup olmadığını kontrol etmeye 25 µs harcandığından, daha küçük bir çekirdek yapılandırması boot süresini birkaç mikrosaniye daha azaltabilir
- Daha uzun vadede Firecracker’ı FreeBSD üzerinde çalışacak şekilde port etme olasılığı da var
- Firecracker, Linux KVM kullanımını varsayarak yazılmıştır
- FreeBSD’nin bhyve hypervisor çekirdek kısmını kullanacak hale getirilememesi için temel bir neden olmadığı düşünülüyor
- Denemek için FreeBSD 14.0 çekirdeği amd64
FIRECRACKERçekirdek yapılandırmasıyla derlenebilir ve Firecracker projesininfeature/pvhbranch’i kullanılabilir- Bu branch artık yoksa kodun mainline Firecracker ağacına birleştirildiği anlamına gelir
1 yorum
Hacker News görüşleri
Firecracker VM’in basit bir Linux container teknolojisi değil, tam teşekküllü bir sanal makine olduğunu pek bilmiyordum
İlk bakışta verimsiz gelebilir ama fly.io gibi gerçek kullanım örneklerine bakınca mikro VM’lerin çok küçük olup yine de yeterince güçlü olması şaşırtıcı
KVM ve asgari donanım desteği sayesinde (PCI, ACPI yok vb.) Firecracker kaynak kodu oldukça sade ve uzman olmayanlar için de nispeten okunabilir
Firecracker’ın varlık nedeni tam da bu
Yazıda verilen ACPI bunun bir örneği. Yine de çekirdeği değil donanımı sanallaştırdığı doğru; başlangıcı o kadar hızlı ki çoğu kullanıcı sıradan containerd’yi firecracker-containerd ile değiştirse farkı hissetmez gibi görünüyor
Firecracker dışında crosvm, cloud-hypervisor, Kata’nın Dragonball’u gibi birçok mikro VM şu anda KVM üzerinde geliştiriliyor
Programlama dillerine yeni bir hedef uygulamak bana o kadar zor görünmediğinden, WASI/WASM benzeri işletim sistemi benzeri bir hedef oluşturup desteklenen dillere PR göndermekle ek yükün büyük kısmı azaltılabilir gibi geliyor. En zor kısım muhtemelen Linux kullanıcı alanını yeterince doğru taklit etmek olacaktır; yüzey alanı çok geniş olduğu için işletim sistemi benzeri bir hedef oluşturma yolu aksine en iyi seçenek gibi görünüyor
Colin’in yamaları FreeBSD ve Firecracker’a girerse çekirdeğin toplam önyükleme süresi 20 ms’nin altına inecek
Gerçekten inanması güç bir çağda yaşıyoruz
Kısa bir aramayla bazı sayılar bulunuyor ama bunlar birkaç yıl öncesine ait; önyükleme süresini ölçme yöntemleri aynı mı ya da “önyükleme süresi” tanımı aynı mı belirsiz, bu yüzden karşılaştırılabilir mi emin değilim
Bu, Colin’in birkaç gün önce yayımlanan son BSDCan sunumu
https://youtu.be/MT3cdeuRTzs?si=l6baNriUjcvy0ZOE
BSDCan sunumundan sonra FreeBSD Journal “güzel bir sunumdu, bunu yazıya dönüştürebilir misin?” diye sordu; FreeBSD Journal yazısı çıktıktan sonra da ;login: yeniden yayımlayıp yayımlayamayacağını sordu
qemu’da firecracker’dan esinlenen microvm var
https://qemu.readthedocs.io/en/latest/system/i386/microvm.ht...
Elbette bazıları FreeBSD hata düzeltmesi olduğu için kaçınılmaz olarak gerekli
1 saniyelik beklemelerin önemli bir kısmının aslında şart olmadığının ortaya çıkması ilginç
Hatalı makine UUID’si yüzünden sistem durduğunda gerçekten anlamlı bir işlem yapan kaç sistem yöneticisi vardı acaba
Buna karşılık “kullanıcıya yeniden başlatılacağını yazdır, konsolu okuyabilmesi için 1 saniye bekle ve sonra yeniden başlat” tarafı biraz farklı
Ukalalık gibi duyulmasını istemem ama Firecracker instance gibi şeylerin hangi kullanım senaryolarına uygun olduğunu merak ediyorum
FreeBSD’yi kolokasyon sunucularından kişisel PC’lere kadar her yerde kullanıyorum ve geliştiriciden çok eski usul bir Unix yöneticisiyim. Bare-metal’i tercih ederim ama işletim sistemine katkı sağlayan geleceğin teknolojilerini memnuniyetle karşılarım. Yine de Lambda veya Firecracker gibi moda terimleri duysam da gerçekte nerede kullanıldıklarını pek bilmiyorum. Docker ve container’ları anlıyorum, k8s’i ise ancak zar zor anlıyorum; sonuçta bir VM açıp gerektiğinde kullanmak varken, neden VM’i açıp hemen yok etmek gerekir bilmiyorum. Tamamen bulut deneyimi veya maliyet azaltma amacıyla mı?
Böylece compute plane’deki herhangi bir düğüm herhangi bir uygulama trafiğini işleyebilir. Bir uygulama, trafik desenlerindeki değişime göre plane’deki boş compute kaynaklarını dinamik olarak tüketecek şekilde büyüyebilir ve trafik işlemediğinde kaynak kullanmaz. Compute plane’in kapasitesini artırmak, daha fazla düğümü çevrimiçi hale getirmek demektir. Büyük ölçekli çok sayıda dağıtımı yönetmek dışında belirgin bir kullanım senaryosu aklıma gelmiyor; “ölçek” gerektirmeyen ortamlarda ise bu, sağlayıcı sınırlarının altında gizli kalacak bir teknoloji
API’nin sık kullanılmadığı ama çağrıldığında hızlı yanıt vermesi gereken bir servis işletiyorsanız Lambda veya benzeri bir yaklaşım iyi uyar. Gerçekte cep telefonu uygulamalarına yönelik API’lerin önemli bir kısmı bu kategoriye girer ve bu API çağrılarına yanıt vermek için zamanın %99’unda boşta duran bir makineyi sürekli ayakta tutmak istemezsiniz
Çoğu bunu yapmaz çünkü harcanacak çaba tasarruftan daha büyüktür; yine de potansiyel vardır. Lambda ve Firecracker gibi şeyler bunu çok daha kolay hale getiriyor
AWS’nin de ARM macOS’un da iç içe sanallaştırmayı desteklememesi üzücü
Destekleselerdi Firecracker tabanlı teknolojiler geliştirmek ve dağıtmak çok daha kolay olurdu
Aslında her instance türünde sanallaştırma mümkün, ama donanım hızlandırmasından yararlanabilenlerin yalnızca .metal instance’lar olduğunu biliyorum
Firecracker etkileyici, ama dokümante edilmesi gereken çok sayıda istisnai durum var
Colin Percival’ın bunu paylaşmasına gerçekten minnettarım. Özellikle “alçaktaki meyveler toplandıktan sonra” ifadesini seviyorum; Colin için bu, özel bus_dma yamaları anlamına geliyor. Artık herkes “1 CPU ve 128 MB RAM ile FreeBSD çekirdeğinin 20 ms’den kısa sürede açılması”ndan ücretsiz olarak yararlanabiliyor. k8s kümelerine ya da çok sayıda Docker kullanmaya alışkın DevOps için bu gerçekten şaşırtıcı
Firecracker’ı biraz kurcaladım; açılış süresi vaat edildiği gibi, ama kullanım deneyimi epey zorlu
Örneğin açılışı başarıp sevindikten sonra, ağ yapılandırmasını halletmek için bir de uzun bir öğreticiyi takip etmeniz gerektiğini öğrenince hevesim kaçtı
Tek bir binary indirip çalıştırınca hem web arayüzü hem API ayağa kalksa, hızlıca yapılandırılabilse ve gerekenleri kendisi indiriverse gerçekten harika olurdu
“1 CPU ve 128 MB RAM’e sahip bir sanal makinede FreeBSD çekirdeği 20 ms’den kısa sürede açılabiliyor”
Aman Tanrım, VM olmadan gerçek donanımda aynı şeyi nasıl başarabiliriz ki ;)
Yavaş olan geri kalan her şey. Örneğin benim makinemde
Startup finished in 14.552s (firmware) + 2.885s (loader) + 741ms (kernel) + 23.116s (initrd) + 11.191s (userspace) = 52.488s