Anatomi Masalah: Bootloop pada Edge Device

Kegagalan pembaruan sistem operasi pada edge device sering kali berujung pada kondisi unrecoverable (bricked). Akar masalah umumnya mencakup kernel panic, inkompatibilitas Device Tree Blob (DTB), atau kegagalan systemd mencapai target kritis (seperti network.target atau target aplikasi utama). Ketika perangkat tidak memiliki akses fisik langsung, intervensi manual melalui UART console tidak memungkinkan.

Solusi standar industri untuk masalah ini adalah skema partisi asimetris/ganda (A/B) yang dikelola oleh update controller stateful. Kombinasi RAUC (Robust Auto-Update Controller), boot counter pada U-Boot, dan kernel/systemd hardware watchdog menjamin perangkat otomatis kembali ke slot sistem operasi yang berfungsi (fallback) jika build image baru mengalami kegagalan saat boot.

Arsitektur Partisi A/B

Penyusunan eMMC atau storage target harus memisahkan state runtime dari sistem read-only. Skema tipikal mencakup:

  • U-Boot Environment: Menyimpan variabel kontrol status boot, trial counter, dan slot aktif.
  • Slot A (Rootfs + Kernel): Read-only root filesystem produksi saat ini.
  • Slot B (Rootfs + Kernel): Read-only root filesystem target update.
  • Data Partition: Read-write (ext4/f2fs), persisten antar pembaruan, mount di /data atau /var.

Pola ini mencegah split-brain data dan memastikan rootfs dapat diverifikasi integritasnya menggunakan dm-verity jika diperlukan.

Konfigurasi RAUC: system.conf

RAUC membutuhkan konfigurasi deskriptif pada root filesystem di /etc/rauc/system.conf untuk mendefinisikan topologi slot dan antarmuka bootloader. File ini harus dipasang langsung melalui resep Yocto (rauc-conf) atau Buildroot package override.

[system]
compatible=acme-iot-gateway-v1
bootloader=uboot
mountprefix=/mnt/rauc

[keyring]
path=/etc/rauc/ca.cert.pem

[slot.rootfs.0]
device=/dev/mmcblk0p2
type=raw
bootname=A

[slot.rootfs.1]
device=/dev/mmcblk0p3
type=raw
bootname=B

Pengaturan bootname mengikat slot RAUC secara langsung ke variabel kontrol lingkungan U-Boot. Atribut compatible memvalidasi bahwa bundle update yang ditandatangani kriptografis memang ditujukan untuk varian hardware yang tepat.

Logika Fallback pada U-Boot

U-Boot bertanggung jawab melakukan tracking percobaan boot (boot attempt counting). RAUC menyediakan skrip standar integrasi U-Boot. Alur kerjanya mengandalkan tiga variabel utama: BOOT_ORDER, BOOT_A_LEFT, dan BOOT_B_LEFT.

Tambahkan logika berikut ke dalam skrip lingkungan boot U-Boot (boot.scr atau uEnv.txt):

test -n "${BOOT_ORDER}" || setenv BOOT_ORDER "A B"
test -n "${BOOT_A_LEFT}" || setenv BOOT_A_LEFT 3
test -n "${BOOT_B_LEFT}" || setenv BOOT_B_LEFT 3

setenv boot_target ""

for slot in ${BOOT_ORDER}; do
  if test "x${boot_target}" = "x"; then
    if test "x${slot}" = "xA"; then
      if test ${BOOT_A_LEFT} -gt 0; then
        setexpr BOOT_A_LEFT ${BOOT_A_LEFT} - 1
        setenv boot_target "A"
      fi
    fi
    if test "x${slot}" = "xB"; then
      if test ${BOOT_B_LEFT} -gt 0; then
        setexpr BOOT_B_LEFT ${BOOT_B_LEFT} - 1
        setenv boot_target "B"
      fi
    fi
  fi
done

saveenv

if test "x${boot_target}" = "xA"; then
  setenv bootargs "console=ttymxc0,115200 root=/dev/mmcblk0p2 ro rootwait"
  load mmc 0:2 ${kernel_addr_r} /boot/fitImage
  bootm ${kernel_addr_r}
elif test "x${boot_target}" = "xB"; then
  setenv bootargs "console=ttymxc0,115200 root=/dev/mmcblk0p3 ro rootwait"
  load mmc 0:3 ${kernel_addr_r} /boot/fitImage
  bootm ${kernel_addr_r}
else
  # Kedua slot gagal: Masuk ke emergency rescue recovery
  reset
fi

Setiap eksekusi boot mengurangi counter slot aktif. Jika nilai counter menyentuh 0 akibat bootloop yang terus-menerus mereset board, U-Boot beralih ke slot berikutnya pada urutan BOOT_ORDER.

Integrasi Hardware Watchdog & Healthcheck Service

Watchdog memastikan sistem me-reboot hardware jika kernel terhenti (hang) atau systemd gagal menyelesaikan inisialisasi user-space. Aktifkan integrasi watchdog pada /etc/systemd/system.conf:

RuntimeWatchdogSec=30s
RebootWatchdogSec=60s
ShutdownWatchdogSec=10m

Systemd secara berkala mengirim sinyal keep-alive (ping) ke /dev/watchdog. Jika user-space membeku sebelum mencapai stage stabil, watchdog hardware menarik jalur reset SoC.

Konfirmasi Boot Sukses (Mark-Good)

Slot yang baru di-deploy tidak boleh dinyatakan permanen sampai service bisnis berhasil berjalan dan memvalidasi integritas sistem. Buat service systemd satu kali jalan (oneshot) yang dieksekusi setelah service aplikasi aktif:

[Unit]
Description=RAUC Boot Validation and Mark-Good Service
After=network-online.target app-gateway.service
Wants=network-online.target
Requires=app-gateway.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/curl -s -f --connect-timeout 5 http://127.0.0.1:8080/healthz
ExecStart=/usr/bin/rauc status mark-good

[Install]
WantedBy=multi-user.target

Perintah rauc status mark-good memanggil antarmuka D-Bus RAUC untuk mereset variabel percobaan boot U-Boot (misal: mengembalikan BOOT_B_LEFT ke 3 dan menempatkan slot aktif di urutan pertama BOOT_ORDER).

Alur Postmortem: Diagnostik Bootloop

Saat rollback otomatis terjadi, perangkat berhasil kembali ke sistem operasi stabil, namun image bermasalah harus segera dianalisis tanpa menghilangkan status kegagalan.

1. Observasi Log via Pstore & Ramoops

Aktifkan modul kernel pstore dan ramoops di defconfig Yocto/Buildroot. Ramoops menyimpan buffer dmesg terakhir pada area RAM yang tidak terhapus selama warm reset:

mount -t pstore pstore /sys/fs/pstore
cat /sys/fs/pstore/console-ramoops-0

Log ini menunjukkan jejak kernel panic atau kegagalan hardware probe yang terjadi tepat sebelum watchdog mereset unit.

2. Persistent Telemetry & Journald

Simpan log systemd secara persisten pada partisi data dengan mengonfigurasi /etc/systemd/journald.conf:

[Journal]
Storage=persistent
MaxUse=50M

Arahkan mount point log ke storage persisten via bind mount atau symlink: /var/log/journal -> /data/journal. Service telemetri pada slot fallback dapat membaca log boot dari slot yang gagal dan mengunggahnya ke server observabilitas.

3. Root Cause Analysis: Image Drift

Penyebab umum kegagalan pada build Yocto/Buildroot meliputi:

  • Shared dynamic libraries mismatch: Kompilasi aplikasi terhadap versi glibc atau library vendor (seperti GPU/NPU runtime) yang berbeda dengan rootfs target.
  • Device Tree Drift: Kernel baru memerlukan entri node DTB yang tidak disediakan oleh bootloader lama yang tidak di-update.
  • Missing Kernel Modules: Driver storage atau network terkompilasi sebagai modul (.ko), namun initramfs gagal memuatnya tepat waktu sebelum rootfs pivot.

Pencegahan di Pipeline CI/CD

Rollback adalah mekanisme mitigasi darurat, bukan pengganti verifikasi rilis. Implementasikan dua kontrol mutlak pada CI/CD:

  1. Immutability Hash & dm-verity: Generate rootfs hash manifest selama proses build. Gunakan tool verifikasi bit-bake untuk memvalidasi bahwa artefact biner identik secara deterministik sebelum paket .bundle ditandatangani.
  2. Canary Rollout Strategy: Batasi rilis OTA berbasis batch (ring-based deployment). Terbitkan bundle update ke 1-5% perangkat non-kritis selama interval 24 jam. Monitor metrik fallback/rollback via telemetri sebelum mempromosikan artefak ke armada produksi yang lebih luas.