Vấn đề thực tế: Ác mộng cài đặt VM thủ công khi cụm máy chủ phình to
Khoảng nửa năm trước, team mình nhận dự án dựng lại hạ tầng dịch vụ nội bộ kết hợp scale cụm Kubernetes trên Proxmox VE. Ban đầu, anh em vẫn làm theo thói quen cũ. Tải file ISO Ubuntu Server về storage, tạo VM trắng qua web GUI rồi bấm Next từng bước cài đặt. Sau đó mới đặt IP tĩnh, tạo user, add SSH key và cài thêm qemu-guest-agent. Hoàn tất mọi thứ, mình convert máy ảo thành Template để sau này clone ra dùng dần.
Mọi chuyện bắt đầu rối khi nhu cầu mở rộng tăng nhanh. Team phải dựng thêm 20-30 VM mỗi tuần cho cụm k3s và môi trường staging. Lúc này, bản template tạo từ 3 tháng trước đã thiếu hàng trăm bản vá kernel quan trọng.
Mỗi lần clone một VM mới, kỹ sư lại mất thêm 15-20 phút chạy apt update && apt upgrade, cài Docker, chỉnh timezone và logrotate. Đỉnh điểm là có lần một bạn dev clone máy nhưng quên start QEMU agent. Hệ thống Prometheus và Grafana tịt ngòi, không lấy được IP của host để thu thập metric.
Ở nhà, mình cũng dựng cụm homelab Proxmox nhỏ quản lý 12 VM và LXC container để thử nghiệm trước khi đưa lên production. Nhưng ngay cả trên homelab, việc snapshot hay tạo template bằng tay cũng cực kỳ phiền. Ổ cứng ZFS ngốn thêm cả trăm GB vô ích. Quan trọng nhất: không ai nhớ nổi bên trong template đã cài những package gì và quy trình này hoàn toàn nằm ngoài Git.
Tại sao VM template thủ công luôn dẫn đến Configuration Drift?
Sau vài tháng vận hành thực tế, mình rút ra ba điểm nghẽn lớn nhất của quy trình bấm tay:
- Thiếu tính tái lập (Lack of Reproducibility): Thao tác click chuột trên màn hình noVNC không để lại bất kỳ audit log nào. Bạn không thể biết chắc người làm template trước đó đã chọn phân vùng LVM ra sao, bật tắt service nào hay vô tình bỏ sót cấu hình bảo mật quan trọng.
- Configuration Drift (Lệch cấu hình): Template gốc bị đóng băng theo thời gian. Trong khi đó, các gói phần mềm, SSL cert và bản vá kernel bên ngoài liên tục thay đổi. Càng để lâu, khoảng cách giữa template và trạng thái mong muốn của production càng xa.
- Bỏ qua bước verify checksum bộ cài: Tải ISO từ nhiều mirror về server thường tiềm ẩn rủi ro file bị lỗi hoặc bị can thiệp. Tuy nhiên, thao tác kiểm tra SHA-256 hay bị anh em bỏ qua vì ngại SSH vào gõ lệnh dài.
Để verify nhanh bộ cài ISO trước khi đưa vào storage của Proxmox, mình hay dùng công cụ Hash Generator của ToolCraft. Điểm tiện lợi là thuật toán tính SHA-256 hoặc MD5 chạy 100% trên trình duyệt (client-side). File không bị tải lên bất kỳ server trung gian nào, rất an toàn khi cần kiểm tra các file nhạy cảm.
Các giải pháp tình thế và hạn chế thực tế
Trước khi chuyển hẳn sang công cụ chuyên dụng, team mình từng thử nghiệm hai hướng tiếp cận phổ biến:
1. Dùng Bash script chạy sau khi Clone VM
Ý tưởng ban đầu: giữ template thật nhẹ, clone xong thì SSH vào chạy một script dài ngoằng để cập nhật phần mềm. Hướng đi này giúp kéo được package mới nhất. Dù vậy, thời gian khởi tạo VM bị kéo dài tới 10-15 phút mỗi node. Nếu repo mirror gặp sự cố mạng hoặc tiến trình apt lock bị kẹt, cả pipeline tự động sẽ dừng hoạt động hoàn toàn.
2. Sử dụng Cloud-init độc lập trên Proxmox
Proxmox VE hỗ trợ Cloud-Init Drive rất mượt. Bạn có thể nạp sẵn SSH key, user và IP tĩnh. Dù vậy, Cloud-init chỉ đóng vai trò cấu hình trong lần boot đầu tiên (Day 1). Nó không sinh ra Golden Image có sẵn Docker engine, runtime đặc thù hay tùy biến kernel (như mở max open files, tinh chỉnh sysctl).
Giải pháp chuẩn: Tự động hóa Golden Image bằng HashiCorp Packer
Sau hơn 6 tháng áp dụng, HashiCorp Packer kết hợp plugin proxmox-iso đã giải quyết dứt điểm vấn đề này. Toàn bộ thông số VM được mô tả bằng code HCL2 sạch sẽ. Khi kích hoạt, Packer tự tạo VM tạm trên Proxmox, bơm file autoinstall qua HTTP server nội bộ, cài đặt phần mềm và đóng gói thành Template chỉ bằng một câu lệnh duy nhất.
Bước 1: Tạo API Token riêng trên Proxmox VE
Nhằm tuân thủ nguyên tắc đặc quyền tối thiểu (least privilege), hãy tạo riêng một API Token thay vì dùng trực tiếp tài khoản root:
# Tạo role cấp quyền chuyên biệt cho Packer
pveum role add PackerRole -privs "VM.Allocate VM.Clone VM.Config.CDROM VM.Config.CPU VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Monitor VM.Audit VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit"
# Tạo user và cấp token
pveum user add packer@pve
pveum user token add packer@pve packer-token -privsep=0
pveum aclmodify / -user packer@pve -role PackerRole
Bước 2: Viết file cấu hình Packer (HCL)
Tạo file ubuntu-2204.pkr.hcl trong thư mục dự án. File này định nghĩa cấu hình phần cứng, nguồn ISO và boot command gửi qua VNC:
packer {
required_plugins {
proxmox = {
version = ">= 1.1.3"
source = "github.com/hashicorp/proxmox"
}
}
}
variable "proxmox_api_url" {
type = string
default = "https://192.168.1.100:8006/api2/json"
}
variable "proxmox_api_token_id" {
type = string
default = "packer@pve!packer-token"
}
variable "proxmox_api_token_secret" {
type = string
sensitive = true
default = "YOUR_PROXMOX_API_SECRET"
}
source "proxmox-iso" "ubuntu-server" {
proxmox_url = var.proxmox_api_url
username = var.proxmox_api_token_id
token = var.proxmox_api_token_secret
insecure_skip_tls_verify = true
node = "pve-node1"
vm_id = 9000
vm_name = "ubuntu-2204-golden-template"
template_description = "Ubuntu 22.04 LTS Golden Image built by Packer"
iso_file = "local:iso/ubuntu-22.04.4-live-server-amd64.iso"
iso_storage_pool = "local"
unmount_iso = true
qemu_agent = true
cores = 2
memory = 2048
os = "l26"
scsi_controller = "virtio-scsi-pci"
disks {
disk_size = "20G"
storage_pool = "local-lvm"
type = "scsi"
}
network_adapters {
model = "virtio"
bridge = "vmbr0"
}
# Packer tự chạy webserver tạm để host file user-data
http_directory = "http"
boot_command = [
"<wait>c<wait>",
"linux /casper/vmlinuz --- autoinstall ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ <enter><wait>",
"initrd /casper/initrd <enter><wait>",
"boot<enter>"
]
boot_wait = "5s"
ssh_username = "sysadmin"
ssh_password = "SuperSecurePass123!"
ssh_timeout = "20m"
}
Lưu ý: Mật khẩu khai báo trong cấu hình autoinstall nên là chuỗi hash crypt SHA-512 thay vì plaintext. Để sinh nhanh mật khẩu phức tạp ban đầu trước khi hash bằng lệnh openssl passwd -6, mình hay dùng Password Generator của ToolCraft. Tiện ích này đo entropy mật khẩu ngay trên trình duyệt, không gửi secret qua internet nên rất tiện khi cần sinh mật khẩu ngẫu nhiên cho cụm máy mới.
Bước 3: Cấu hình Autoinstall Cloud-Init
Tạo file http/user-data. Ubuntu Server Subiquity sẽ đọc file này để tự động phân vùng ổ cứng, tạo tài khoản và cài đặt sẵn package:
#cloud-config
autoinstall:
version: 1
locale: en_US
keyboard:
layout: us
identity:
hostname: golden-image
username: sysadmin
password: "$6$rounds=4096$salt$hashedpasswordhere..."
ssh:
install-server: true
allow-pw: true
packages:
- qemu-guest-agent
- curl
- wget
- git
- htop
late-commands:
- systemctl enable qemu-guest-agent
- echo "sysadmin ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/sysadmin
Bước 4: Kích hoạt quy trình đóng gói tự động
Chỉ cần 3 lệnh trên máy quản trị để bắt đầu build template:
# Tải plugin Proxmox
packer init .
# Kiểm tra cú pháp file cấu hình
packer validate .
# Khởi chạy quá trình build tự động
packer build ubuntu-2204.pkr.hcl
Quá trình build diễn ra hoàn toàn tự động. Đầu tiên, Packer gọi API Proxmox để tạo VM tạm với ID 9000. Máy ảo khởi động từ ISO và nhận file autoinstall qua web server mini do chính Packer dựng. Sau khi Ubuntu cài xong, Packer SSH vào máy dọn dẹp log, reset machine-id và xóa cache apt. Cuối cùng, nó convert VM thành Template chuẩn và tắt máy.
Hiệu quả thực tế sau 6 tháng đưa vào Production
Quy trình đóng gói tự động bằng Packer đã thay đổi hoàn toàn cách team mình quản trị hạ tầng Proxmox:
- Thời gian khởi tạo VM rút ngắn từ 20 phút xuống 25 giây: Khi cần thêm node mới cho cluster, Terraform chỉ cần gọi lệnh clone từ VM ID 9000 với disk dạng linked clone. Máy ảo sẵn sàng nhận tải chỉ trong chưa đầy nửa phút.
- Cập nhật định kỳ qua CI/CD: Mình tạo GitHub Actions workflow chạy tự động vào 2h sáng Chủ nhật hàng tuần. Bản Golden Image trên Proxmox luôn chứa kernel và security patch mới nhất mà không tốn công gõ tay.
- Hạ tầng đồng nhất 100%: Cả máy chủ lab cá nhân lẫn 3 cụm Proxmox tại công ty đều dùng chung một repository HCL. Nhờ đó, lỗi lệch môi trường (environment drift) giữa dev và prod gần như biến mất hoàn toàn.
