Rebuild toàn bộ hạ tầng Linux MicroVM trên Apple Silicon: Câu chuyện từ Encore

21 tháng 8, 2026·7 phút đọc

Encore, nền tảng triển khai backend, đã xây dựng 'crackling' — một API microVM thống nhất giúp chạy cùng một hệ thống build dựa trên Firecracker trên cả Linux lẫn macOS (Apple Silicon) mà không cần máy ảo lồng nhau. Bài viết chia sẻ chi tiết về quá trình thay thế quy trình SSH cồng kềnh, những thách thức kỹ thuật với Apple Virtualization.framework và cách họ tối ưu hóa toàn bộ image pipeline để chạy native trên Mac.

Rebuild toàn bộ hạ tầng Linux MicroVM trên Apple Silicon: Câu chuyện từ Encore

Encore tái xây dựng toàn bộ hạ tầng Linux MicroVM để chạy native trên Apple Silicon

Encore, nền tảng tự động hóa backend, đã chính thức thay thế quy trình build từ xa đầy bất tiện bằng một hệ thống microVM thống nhất mang tên "crackling". Hệ thống này cho phép các kỹ sư chạy cùng một công cụ build dựa trên Firecracker — loại microVM từng chỉ hoạt động trên Linux — ngay trên chiếc MacBook Apple Silicon của họ, thông qua Apple Virtualization.framework. Với crackling, Encore không chỉ loại bỏ nhu cầu SSH vào máy chủ dùng chung mà còn tối ưu toàn bộ quy trình chuyển đổi Docker image thành rootfs có thể boot, mở ra trải nghiệm phát triển mượt mà như đúng cam kết "backend nên dễ dàng" của họ.

Vấn đề: Bốn năm build system "ở đâu đó"

Encore đã sử dụng Firecracker để cô lập mọi build sau khi triển khai từ giữa năm 2022. Firecracker loại bỏ phần cứng giả lập thừa thãi, chỉ giữ lại những gì kernel Linux cần, mang lại độ khởi động nhanh như container nhưng độ cô lập mạnh như máy ảo.

Tuy nhiên, có một vấn đề lớn: Firecracker dựa trên KVM, và KVM không tồn tại trên macOS. Trong khi đó, hầu hết kỹ sư của Encore đều phát triển trên Mac. Ngay cả một bản proof-of-concept dùng Apple's Virtualization.framework cũng bị đội ngũ upstream từ chối, vì họ không có kế hoạch hỗ trợ macOS.

Kết quả là trong suốt bốn năm, làm việc trên build system đồng nghĩa với việc bạn phải làm việc trên một máy chủ Linux ở data center, thông qua SSH.

Quy trình cũ: Một loạt script và SSH "không thể chạm vào breakpoint"

Quy trình cũ của Encore được mô tả là cồng kềnh và đầy thủ công:

  • Onboarding: Mỗi kỹ sư chạy một script để SSH vào máy build dùng chung với quyền root, tự tạo user, thêm vào nhóm kvmdocker, rồi copy VM images và hard-link binary firecracker vào thư mục cá nhân.
  • Đồng bộ mã: Họ cross-compile với GOOS=linux GOARCH=amd64, rồi rsync kết quả lên máy chủ.
  • Xử lý image: Đây là phần khó nhất. Họ phải tự viết công cụ để chuyển Docker layers thành block device mà Firecracker có thể boot. Script này dùng find để xử lý các whiteout marker, hardcode /etc/resolv.conf, rồi gọi mksquashfs — tất cả đều trên máy chủ từ xa.
  • Restart: Cần thêm một lệnh SSH thứ ba để kill container cũ và start container mới. Firecracker chạy trong Docker, nên họ phải dựng một bridge ảo tên docker0 bên trong container để gắn tap devices.

Vòng lặp này khiến các kỹ sư phải suy nghĩ kỹ trước khi thử nghiệm bất cứ điều gì mang tính khám phá. Đặt breakpoint cục bộ là điều không tưởng, còn đọc log thì phải tail file qua SSH. Họ muốn một thứ gì đó chạy ngay trên chiếc Mac họ đang ngồi.

Giải pháp: "crackling" — Một API, hai nền tảng

Encore đã xem xét các giải pháp có sẵn như Lima, Tart, podman với libkrun, hay thậm chí chạy KVM lồng nhau trên M3 (macOS 15). Nhưng tất cả đều dẫn đến việc tạo ra "một hệ thống build thứ hai, chỉ tồn tại trên laptop" — điều họ không muốn.

Vì vậy, họ xây dựng crackling: một daemon và CLI có khả năng boot OCI images thành microVM Linux trên cả hai nền tảng. Cụ thể:

  • Trên Linux: Vẫn dùng Firecracker làm backend.
  • Trên macOS: Dùng Apple Virtualization.framework (VZ).

Cả hai backend cùng tuân theo một trait MachineBackend với các phương thức start, shutdown, pause, resume, snapshot, wait, dispose, và connect_vsock. Việc lựa chọn backend được quyết định tĩnh tại thời điểm compile vì mỗi hệ điều hành chỉ có một backend khả dụng.

Xử lý rào cản threading của Apple VZ

Điểm kỹ thuật đau đầu nhất là VZVirtualMachine là !Send + !Sync, trong khi phần còn lại của daemon chạy trên tokio (vốn di chuyển future giữa các thread). Giải pháp của Encore là tạo một serial DispatchQueue toàn cục cho mọi hoạt động liên quan đến VM. Các closure dispatch lên queue này chỉ chứa dữ liệu Send, còn bản thân đối tượng VM không bao giờ rời khỏi queue. Nhờ vậy, compiler có thể chặn mọi capture không hợp lệ.

Họ cũng phải tách quá trình "lowering" từ MachineSpec thành VZVirtualMachineConfiguration thành hai pha: một pha tạo cấu trúc dữ liệu Send trên tokio, pha còn lại chuyển nó thành cấu trúc VZ trên queue.

Booting kernel và rootfs trên macOS

Không có KVM, không có quyền root, không thể loop mount — Encore phải tự viết lại toàn bộ image pipeline:

  • Giải nén kernel: Kernel arm64 thường là file EFI zboot (vmlinuz). Họ tự viết code để nhận diện chữ ký MZ và zimg, đọc header để lấy offset, kích thước và thuật toán nén. Việc đưa kernel nén vào Virtualization.framework sẽ gây lỗi "internal error" vô cùng khó hiểu — họ thậm chí đã mất cả buổi chiều để tái ký binary trước khi nhận ra vấn đề.
  • Áp dụng OCI layers: Họ xử lý hoàn toàn trong userspace, tôn trọng các whiteout entry .wh một cách "in-process", không cần pass cleanup. Họ cũng phải viết custom platform resolver vì resolver mặc định không bao giờ khớp với image linux/arm64 khi request từ Mac.
  • Tạo initramfs: Cần tạo archive cpio định dạng newc, nén bằng gzip, và bơm vào RAM. Họ dùng pure Rust để tạo cả hai lớp này. Cache được clone bằng clonefile trên APFS hoặc FICLONE reflink trên Linux, giúp tăng tốc đáng kể.

Agent trong guest và giao thức vsock

Mỗi VM chạy một agent tĩnh (static musl binary) lắng nghe trên AF_VSOCK. Agent này hỗ trợ:

  • exec với stdout/stderr được stream
  • Shell tương tác qua PTY
  • cp hai chiều
  • forward — biến một connection thành tunnel tới một port bên trong guest

"Agent dùng vsock cho control, để guest không cần cấu hình mạng thủ công hay SSH daemon. Outbound networking là một tùy chọn riêng, còn inbound chỉ có thể truy cập qua control-plane forward với token xác thực sinh ra tại thời điểm boot."

Một phát hiện đáng chú ý về Apple Virtualization.framework

Khi triển khai tính năng snapshot, Encore phát hiện một điều khá "bất công":

  • VZVirtualMachine.saveMachineStateToURLvalidateSaveRestoreSupport tồn tại công khai.
  • Validator trả về thành công, nhưng lệnh save lại fail với VZErrorInternal.
  • Lý do: Để save state, bạn cần entitlement com.apple.private.virtualization — thứ Apple không cấp cho bên thứ ba. Entitlement công khai com.apple.security.virtualization chỉ đủ để chạy VM, không đủ để save.

Họ gọi đây là một hành vi "lừa đảo" vì validator không kiểm tra entitlement thứ hai, khiến lập trình viên mất thời gian truy tìm nguyên nhân.

Kết quả và sau đó

Giờ đây, một kỹ sư Encore chỉ cần clone build system về máy, chạy nó trên laptop, và boot chính những OCI image dùng cho build và deploy của Encore qua cùng một agent và vsock path. Máy chủ dùng chung đã biến mất — cùng với script docker save pipe qua rsync và cây cầu docker0 dựng thủ công trong container đặc quyền.

Bạn có thể đặt breakpoint trong build system và chạm vào nó. Điều đó đã không thể thực hiện trong suốt bốn năm qua.

Với việc crackling trở thành một phần trong nỗ lực cải thiện trải nghiệm backend, Encore hy vọng sẽ tiếp tục mở rộng hạ tầng này, đưa toàn bộ vòng lặp phát triển — từ local dev đến production — trở nên mượt mà và tự động hơn cho cả con người lẫn agent.

Sơ đồ kiến trúc cracklingSơ đồ kiến trúc crackling

Sơ đồ minh họa quá trình crackling điều phối giữa Firecracker (Linux) và Apple Virtualization.framework (macOS).

So sánh quy trình cũ và mớiSo sánh quy trình cũ và mới

So sánh trực quan giữa quy trình SSH từ xa nhiều bước và quy trình native trên máy tính cá nhân.

Agent vsock bên trong guestAgent vsock bên trong guest

*Minh họa agent chạy trong guest VM, giao tiếp với daemon qua giao thức vsock. *

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗