From 7bfeaf885cce2b1d9288dd55866b35b72dce6472 Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Thu, 20 Aug 2026 23:14:20 +1000 Subject: [PATCH] fix: give LB microVM initramfs headroom by bumping sys.micro to 256 MiB (#850) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ELBv2 LB microVM boots with -m 128 (sys.micro). After kernel reservations the 37.7 MiB initramfs — 45% of it the Go 1.27 lb-agent — leaves under 512 KiB of headroom, so the guest panics with 'Initramfs unpacking failed' before init and lb-agent never heartbeats. Bump sys.micro to 256 MiB so the initramfs unpacks with margin, and add an uncompressed-initramfs gate to build-microvm-image.sh (the compressed gate was blind to the guest-RAM footprint) so a future bump fails the build loudly instead of panicking in production. --- scripts/build-microvm-image.sh | 17 +++++++++++++++++ spinifex/instancetypes/definitions.go | 4 ++-- spinifex/instancetypes/generate_test.go | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/scripts/build-microvm-image.sh b/scripts/build-microvm-image.sh index 8ad01f319..d092cf704 100755 --- a/scripts/build-microvm-image.sh +++ b/scripts/build-microvm-image.sh @@ -334,5 +334,22 @@ if [ "$total_bytes" -gt "$max_bytes" ]; then exit 1 fi echo "[build-microvm-image] artifact size gate: PASS (${total_mib} MiB / ${ARTIFACT_MAX_MiB} MiB)" + +# --- Guest-RAM initramfs gate (uncompressed) --- +# The kernel unpacks the whole initramfs into RAM before init, so the +# UNCOMPRESSED size — not the gzip artifact — sets the sys.micro memory floor. +# Over budget => "Initramfs unpacking failed" panic before userspace. +UNCOMPRESSED_MAX_MiB="${MICROVM_INITRAMFS_UNCOMPRESSED_MAX_MiB:-96}" +uncompressed_bytes=$(zcat "$INITRAMFS_OUT" | wc -c) +uncompressed_mib=$(( (uncompressed_bytes + 1048575) / 1048576 )) +umax_bytes=$(( UNCOMPRESSED_MAX_MiB * 1024 * 1024 )) +if [ "$uncompressed_bytes" -gt "$umax_bytes" ]; then + echo "ERROR: uncompressed initramfs ${uncompressed_mib} MiB exceeds ${UNCOMPRESSED_MAX_MiB} MiB guest-RAM gate" >&2 + echo " The LB microVM unpacks this into its 256 MiB guest RAM; a larger" >&2 + echo " footprint panics the kernel before init. Slim the initramfs, or raise" >&2 + echo " sys.micro memory AND MICROVM_INITRAMFS_UNCOMPRESSED_MAX_MiB together." >&2 + exit 1 +fi +echo "[build-microvm-image] initramfs guest-RAM gate: PASS (${uncompressed_mib} MiB / ${UNCOMPRESSED_MAX_MiB} MiB uncompressed)" echo "" echo "[build-microvm-image] done." diff --git a/spinifex/instancetypes/definitions.go b/spinifex/instancetypes/definitions.go index 4d625c4f3..e655981a3 100644 --- a/spinifex/instancetypes/definitions.go +++ b/spinifex/instancetypes/definitions.go @@ -310,8 +310,8 @@ var p5eSizes = []instanceSize{ // systemSizes defines internal-only instance types for system VMs (LB, NAT GW, etc.). // These are registered in the type map for allocation but excluded from DescribeInstanceTypes. var systemSizes = []instanceSize{ - {"micro", 1, 0.125}, // 1 vCPU, 128 MB — ELBv2 LB microVMs - {"medium", 2, 4}, // 2 vCPU, 4 GB — EKS k3s control-plane VMs + {"micro", 1, 0.25}, // 1 vCPU, 256 MB — ELBv2 LB microVMs (initramfs unpack headroom) + {"medium", 2, 4}, // 2 vCPU, 4 GB — EKS k3s control-plane VMs } // instanceFamilyDefs lists all supported instance families. Excluded families require diff --git a/spinifex/instancetypes/generate_test.go b/spinifex/instancetypes/generate_test.go index d4d408409..d963b3612 100644 --- a/spinifex/instancetypes/generate_test.go +++ b/spinifex/instancetypes/generate_test.go @@ -82,7 +82,7 @@ func TestGenerateSystemTypes(t *testing.T) { sysMicro, ok := types["sys.micro"] require.True(t, ok, "sys.micro must exist") assert.Equal(t, int64(1), *sysMicro.VCpuInfo.DefaultVCpus, "sys.micro should have 1 vCPU") - assert.Equal(t, int64(128), *sysMicro.MemoryInfo.SizeInMiB, "sys.micro should have 128 MiB") + assert.Equal(t, int64(256), *sysMicro.MemoryInfo.SizeInMiB, "sys.micro should have 256 MiB") assert.False(t, *sysMicro.BurstablePerformanceSupported, "sys.micro should not be burstable") sysMedium, ok := types["sys.medium"]