Cơ Chế Chống Boot Loop & Máy Trạng Thái (Anti-Boot-Loop & State Machine)
Tài liệu này giải thích chi tiết nghịch lý cốt lõi trong mô hình Zero-Touch Provisioning (ZTP), nguyên lý hoạt động của máy trạng thái (State Machine) trong dự án, kỹ thuật nhường quyền điều khiển phần cứng (Hardware Handoff qua sanboot), và cơ chế khóa vòng lặp cài đặt vĩnh viễn thông qua Phone-Home Webhook.
1. Nghịch Lý Boot Loop Trong Cài Đặt Tự Động (The ZTP Boot Dilemma)
Để đạt được mục tiêu Zero-Touch Provisioning (ZTP) (cắm điện máy mới là tự động cài đặt hoàn chỉnh từ A đến Z mà không cần con người can thiệp vào bàn phím hay màn hình):
- Bắt buộc: Máy chủ (Bare-metal) hoặc máy ảo (VM) phải được cấu hình thứ tự khởi động trong BIOS/UEFI là Network Boot (PXE) ưu tiên số 1.
- Hệ quả nghịch lý: Sau khi hệ điều hành (Ubuntu, Talos...) cài đặt thành công 100% vào ổ cứng và thực hiện lệnh khởi động lại (
reboot), bo mạch chủ lại tiếp tục ưu tiên boot qua card mạng! - Thảm họa: Nếu máy chủ iPXE không có bộ nhớ nhận diện trạng thái, nó sẽ tiếp tục gửi kịch bản cài đặt OS. Máy tính sẽ bị format lại ổ đĩa và lọt vào vòng lặp cài đặt vô tận (Infinite Reinstall Loop)!
2. Kỹ Thuật Nhường Quyền Điều Khiển Phần Cứng (Hardware Handoff)
Khi Bun server xác định node đã hoàn tất cài đặt, nó không trả về menu cài đặt mà trả về kịch bản iPXE đặc biệt sau (định nghĩa tại [src/routes/ipxe.ts](file:///Users/timi/lab/lab-ipxe-os/src/routes/ipxe.ts)):
#!ipxe
echo ==========================================================
echo Node [k3s-single-node] (bc:24:11:00:24:33) is ALREADY INSTALLED.
echo Bypassing network installation. Booting local disk...
echo (To reinstall, trigger API: POST http://192.168.250.202:3000/api/reset?mac=bc:24:11:00:24:33)
echo ==========================================================
sleep 2
sanboot --no-describe --drive 0x80 || exit 12.1. Lệnh sanboot --no-describe --drive 0x80 hoạt động như thế nào?
0x80(Hệ thập lục phân) đại diện cho ổ cứng vật lý thứ nhất (First Hard Drive) trong kiến trúc BIOS chuẩn ngắtINT 13h.- Trong môi trường UEFI hiện đại, iPXE ánh xạ
0x80tới thiết bị lưu trữ cục bộ đầu tiên theo giao thức UEFI Block I/O Protocol. - Cờ
--no-describechỉ thị cho iPXE không tạo thêm các bảng mô tả thiết bị SAN ảo phức tạp trong bộ nhớ ACPI, giúp quá trình chuyển giao quyền điều khiển CPU sang Master Boot Record (MBR) hoặc EFI System Partition (ESP) trên ổ cứng diễn ra ngay lập tức mà không làm gián đoạn kernel boot.
2.2. Cơ chế cứu hộ dự phòng || exit 1
Nếu lệnh sanboot gặp sự cố (ví dụ: ổ cứng thứ nhất chưa có bootloader hợp lệ hoặc firmware UEFI của hãng không hỗ trợ ngắt chuyển tiếp iPXE):
- Lệnh
exit 1sẽ kết thúc chương trình thực thi của iPXE EFI Application (ipxe.efi). - Ngay khi iPXE thoát với mã lỗi khác 0, trình quản lý UEFI Boot Manager (NVRAM) của bo mạch chủ sẽ tự động chuyển tiếp sang mục ưu tiên khởi động kế tiếp trong danh sách (thông thường là mục
ubuntutrỏ vào\EFI\ubuntu\shimx64.efitrên ổ đĩa nội bộ).
2.3. Cơ chế bảo vệ thứ tự khởi động UEFI NVRAM (efibootmgr late-command)
Trên các hệ thống Bare-metal hiện đại (như bo mạch chủ Intel Gen 12+ LGA1700 H610/B660/B760 hoặc AMD AM5), quá trình cài đặt OS mặc định sẽ gọi grub-install, và công cụ này tự ý chèn ubuntu lên vị trí số 1 của biến BootOrder trong NVRAM. Điều này khiến máy tính ở các lần reboot sau nhảy thẳng vào ổ cứng mà không qua iPXE nữa.
Để bảo toàn mô hình ZTP, dự án tích hợp script efibootmgr tự động trong late-commands của Ubuntu Autoinstall ([src/providers/ubuntu/profiles/index.ts](file:///Users/timi/lab/lab-ipxe-os/src/providers/ubuntu/profiles/index.ts)):
- Tìm mã
BootIDcủa card mạng (IPv4/PXE/Network). - Sắp xếp lại
BootOrder, đưa card mạng về vị trí ưu tiên #1, và giữubuntuở vị trí #2. - Lợi ích kép:
- Khi iPXE Server online: Node luôn boot vào iPXE để Server quyết định (re-install hoặc chạy
sanboot). - Khi iPXE Server offline / Rút dây mạng: BIOS tự động fallback sang mục #2 (
ubuntutrên SSD), đảm bảo hệ thống không bao giờ bị gián đoạn.
- Khi iPXE Server online: Node luôn boot vào iPXE để Server quyết định (re-install hoặc chạy
3. Kiến Trúc State Machine Của Bun Server
Toàn bộ logic quản lý trạng thái cài đặt được tập trung trong lớp StateManager tại [src/core/state.ts](file:///Users/timi/lab/lab-ipxe-os/src/core/state.ts).
3.1. Cấu Trúc Bảng hosts trong data/state.db (SQLite)
Trạng thái vòng đời và cấu hình máy chủ được lưu trữ bền vững (persistent) trong cơ sở dữ liệu SQLite chuẩn ACID (PRAGMA journal_mode = WAL):
SELECT mac, hostname, os, status, ip, installed_at, updated_at FROM hosts;Ví dụ một bản ghi hoàn tất cài đặt:
{
"mac": "bc:24:11:00:24:33",
"hostname": "k3s-single-node",
"os": "ubuntu",
"status": "INSTALLED",
"ip": "192.168.250.33",
"installed_at": "2026-09-14T07:25:39.124Z",
"updated_at": "2026-09-14T07:25:39.124Z"
}3.2. Chu Kỳ Chuyển Đổi Trạng Thái (State Transitions)
[ UNCONFIGURED / NEW_NODE ]
│
▼ (Tạo qua Web UI "+ Add Node", REST API, hoặc Seed từ hosts.yaml)
[ REGISTERED (PENDING) ]
│
▼ (Client kéo boot.ipxe & bắt đầu tải Kernel/Initrd)
[ PROVISIONING ]
│
▼ (Subiquity / Combustion hoàn thành cài đặt -> Gửi Webhook Phone-Home)
[ INSTALLED ] ◄── (Khóa chặn Boot Loop vĩnh viễn)
│
├── (Mỗi lần Reboot sau đó: Thực thi sanboot boot ổ cứng)
│
▼ (Quản trị viên muốn cài lại: Bấm nút "Reset" trên UI hoặc gọi API Reset)
[ PENDING ] ──> Cho phép cài đặt lại từ đầu mà không mất cấu hình máy!4. Cơ Chế Phone-Home Webhook
Quá trình "xác nhận hoàn tất" diễn ra tự động 100% từ chính bên trong máy tính vừa được cài đặt.
Tại thời điểm Subiquity hoàn thành việc ghi dữ liệu vào ổ cứng, nó kích hoạt danh sách lệnh late-commands bên trong chroot của máy đích (định nghĩa tại [src/providers/ubuntu/profiles/index.ts](file:///Users/timi/lab/lab-ipxe-os/src/providers/ubuntu/profiles/index.ts)):
curtin in-target --target=/target -- curl -s -X POST \
"http://192.168.250.202:3000/api/installed?mac=bc%3A24%3A11%3A00%3A24%3A33&hostname=k3s-single-node&os=ubuntu"Khi máy chủ Bun nhận được request tại route /api/installed ([src/routes/api.ts](file:///Users/timi/lab/lab-ipxe-os/src/routes/api.ts)):
- Chuẩn hóa địa chỉ MAC (chuyển chữ thường, thay
-bằng:, bỏ prefix0x). - Cập nhật record trong
data/state.dbchuyển trạng thái sangINSTALLEDvà ghi nhận thời điểminstalled_at. - Trả về mã phản hồi HTTP
200 OK. - Kể từ thời khắc này, mọi truy vấn iPXE từ địa chỉ MAC này sẽ chỉ nhận được lệnh
sanboot 0x80.
5. Quy Trình Cài Đặt Lại Máy (Re-installation Workflow)
Khi bạn muốn cài đặt lại hệ điều hành cho một máy đã được đánh dấu INSTALLED, bạn có 4 cách linh hoạt:
Cách 1: Bấm nút "Reset" trên Web UI Dashboard (Nhanh nhất)
Tại trang chủ http://localhost:3000/, bấm nút Reset tương ứng với hàng của máy đó:
- Trạng thái ngay lập tức chuyển thành
PENDING(hiển thị màu xanh dương nhạt). - Toàn bộ cấu hình mạng, profile, ổ đĩa của node vẫn được bảo toàn nguyên vẹn trong SQLite.
Cách 2: Gọi API Quản Trị Reset qua cURL
Gửi lệnh HTTP POST tới endpoint /api/reset:
curl -X POST "http://192.168.250.202:3000/api/reset?mac=bc:24:11:00:24:33"Kết quả: Máy chủ cập nhật status của node về PENDING trong data/state.db. Lần khởi động tiếp theo, máy sẽ lại hiện menu cài đặt.
Cách 3: Bật cờ force_install qua Web UI Edit hoặc REST API
Bấm nút Edit trên Dashboard hoặc gọi PUT /api/hosts/:mac với "force_install": true.
Cách 4: Nạp URL Boot kèm tham số ?force=true
Trong iPXE CLI hoặc trên Router:
chain --autofree http://192.168.250.202:3000/boot.ipxe?mac=${net0/mac}&force=true6. Xử Lý Các Kịch Bản Ngoại Lệ (Edge Cases)
| Tình Huống Ngoại Lệ | Hành Vi Của Hệ Thống | Giải Pháp Xử Lý |
|---|---|---|
| Mất điện hoặc lỗi mạng giữa chừng khi đang cài đặt | Vì lỗi xảy ra TRƯỚC bước late-commands, webhook chưa được kích hoạt -> Node vẫn ở trạng thái PROVISIONING hoặc PENDING. Khi có điện lại, máy sẽ tự động khởi động lại quá trình cài đặt từ đầu một cách an toàn. | Hệ thống tự phục hồi tự động, không cần thao tác thủ công. |
| Webhook thất bại do Router bị nghẽn gói | Cờ || true trong late-command đảm bảo quá trình cài đặt của Subiquity không bị dừng đột ngột. Tuy nhiên lần boot sau máy sẽ bị cài lại. | Kiểm tra firewall/ACL giữa subnet máy đích và cổng 3000 của Bun Server. |
| Máy chủ Bun bị restart hoặc sập nguồn | bun:sqlite hoạt động ở chế độ Write-Ahead Logging (WAL) đảm bảo tính toàn vẹn dữ liệu (ACID). Khi server khởi động lại, trạng thái node được giữ nguyên vẹn. | Không bị mất trạng thái của các node đã cài. |
7. Khuyến Nghị Bảo Mật Cho Môi Trường Mạng (Security Hardening)
- Giới hạn dải mạng truy cập API:
- Các Endpoint quản trị và bảo mật như
/api/installed,/api/reset,/api/hosts, và/api/kubeconfigchỉ nên cho phép các IP thuộc mạng nội bộ Homelab/Data Center (192.168.250.0/24) truy cập. Tuyệt đối không mở cổng 3000 ra Internet công cộng mà không có reverse proxy xác thực.
- Các Endpoint quản trị và bảo mật như
- Khóa State bằng API Token (Khuyến nghị cho Enterprise):
- Có thể bổ sung thêm biến môi trường
ADMIN_API_TOKENvào file.env. - Các lệnh
/api/reset,/api/hosts, hoặc/api/installedbắt buộc phải kèm HeaderAuthorization: Bearer <TOKEN>để ngăn chặn việc người dùng trái phép gửi request giả mạo địa chỉ MAC làm gián đoạn máy chủ.
- Có thể bổ sung thêm biến môi trường