Cuộc gọi đánh thức lúc 2 giờ sáng: Tại sao Image thủ công lại thất bại
Đó là lúc 2:14 sáng khi thiết bị báo tin của tôi bắt đầu kêu liên hồi. Một instance quan trọng trong auto-scaling group của chúng tôi đã bị lỗi. Thông thường, đây không phải là vấn đề lớn, nhưng instance thay thế lại bị kẹt trong vòng lặp ‘Bootstrapping’. Nguyên nhân? Một mirror bên thứ ba của libssl-dev bị sập, và script user-data không thể hoàn tất việc cài đặt bản vá bảo mật. Chúng tôi đã mất 180 phút để vá lỗi thủ công cho một hệ điều hành mới tinh chỉ để đưa dịch vụ hoạt động trở lại.
Đêm đó đã dạy tôi một bài học xương máu: Bootstrapping tại thời điểm runtime là một canh bạc đầy rủi ro. Việc phụ thuộc vào apt-get install hoặc yum install trong quá trình scale-out sẽ tạo ra các phụ thuộc bên ngoài mà sớm muộn gì cũng sẽ gặp lỗi. Đây là lúc “Golden Image” phát huy tác dụng. Bằng cách đóng gói sẵn (pre-baking) các phụ thuộc, bản vá bảo mật và cấu hình vào một artifact duy nhất, bạn đảm bảo hạ tầng của mình có thể dự đoán được và mở rộng chỉ trong vài giây.
Trong thực tế, đây là một kỹ năng bắt buộc đối với kỹ sư hiện đại. Việc chuyển từ snapshot thủ công sang các pipeline tự động với HashiCorp Packer là sự khác biệt giữa một SysAdmin luôn căng thẳng và một DevOps Engineer chủ động.
Kiến trúc của một Pipeline bất biến
Packer hoạt động bằng cách khởi chạy một máy ảo tạm thời (gọi là ‘Builder’), chạy các script cấu hình (gọi là ‘Provisioners’), sau đó tắt máy ảo để lưu nó thành một image có thể tái sử dụng (gọi là ‘Artifact’).
Trước khi viết bất kỳ mã HCL (HashiCorp Configuration Language) nào, tôi thường phải dọn dẹp các cấu hình cũ. Nếu bạn đang chuyển đổi các dự án cũ, một công cụ Chuyển đổi YAML ↔ JSON là một công cụ tiết kiệm thời gian cực kỳ hiệu quả để chuyển đổi các định dạng sang cú pháp HCL2 hiện đại. Vì nó chạy hoàn toàn trong trình duyệt, bạn không phải lo lắng về việc logic hạ tầng nhạy cảm bị rò rỉ khỏi máy tính của mình.
Cài đặt Packer
Packer là một tệp thực thi duy nhất (single binary). Trên một node điều khiển Linux, việc cài đặt chỉ mất chưa đầy một phút thông qua kho lưu trữ chính thức:
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install packer
Kiểm tra phiên bản để xác nhận mọi thứ đã được thiết lập chính xác:
packer version
Cấu hình Golden Image đầu tiên của bạn
Hãy cùng xem xét hai trường hợp sử dụng tiêu chuẩn: AWS cho đám mây và Proxmox cho ảo hóa tại chỗ (on-premise). Packer hiện đại sử dụng các tệp .pkr.hcl. Chúng dễ đọc và bảo trì hơn nhiều so với định dạng JSON cũ.
1. Xây dựng một AWS AMI
Bạn sẽ cần một người dùng IAM có quyền AmazonEC2FullAccess (hoặc các quyền tạo AMI cụ thể). Template này xây dựng một image Ubuntu 22.04 đã được tối ưu bảo mật trong khoảng 8 phút.
packer {
required_plugins {
amazon = {
version = ">= 1.2.8"
source = "github.com/hashicorp/amazon"
}
}
}
source "amazon-ebs" "ubuntu-golden-image" {
ami_name = "golden-ubuntu-{{timestamp}}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"] # Canonical
}
ssh_username = "ubuntu"
}
build {
name = "production-builder"
sources = ["source.amazon-ebs.ubuntu-golden-image"]
provisioner "shell" {
inline = [
"sudo apt-get update",
"sudo apt-get upgrade -y",
"sudo apt-get install -y docker.io nginx",
"sudo systemctl enable nginx"
]
}
}
2. Xây dựng một Proxmox Template
Proxmox là lựa chọn hàng đầu cho các lab tại chỗ. Việc xây dựng một template ở đây yêu cầu một tệp ISO và quyền truy cập API. Khi thiết lập mạng cho các bản build này, tôi sử dụng Công cụ tính toán Subnet IP để phân chia một dải IP riêng biệt cho build bridge. Điều này ngăn các máy ảo build tạm thời chiếm dụng IP từ các VLAN production của bạn.
source "proxmox-iso" "proxmox-ubuntu" {
proxmox_url = "https://192.168.1.10:8006/api2/json"
username = "root@pam"
password = "mat-khau-cua-ban"
node = "pve-node-01"
iso_file = "local:iso/ubuntu-22.04-live-server-amd64.iso"
ssh_username = "admin"
ssh_password = "mat-khau-bao-mat"
network_adapters {
model = "virtio"
bridge = "vmbr0"
}
}
Xác minh và Giám sát
Tạo ra image mới chỉ là bước khởi đầu. Bạn phải đảm bảo nó hoạt động trước khi đưa vào môi trường production. Tôi tuân theo quy trình xác minh ba bước đơn giản:
- Xác thực (Validation): Chạy
packer validate .để phát hiện các lỗi cú pháp. Nếu bạn đang xử lý các biến lồng nhau phức tạp, một công cụ Định dạng JSON sẽ giúp phát hiện các dấu ngoặc bị thiếu hoặc cấu trúc sai định dạng ngay lập tức. - Kiểm tra (Inspection): Sử dụng
packer inspect .để kiểm tra kỹ xem các biến và builder nào đang hoạt động. - Kiểm thử tự động (Automated Testing): Tích hợp Packer vào GitHub Actions hoặc GitLab CI. Chỉ gắn thẻ một AMI là ‘Production-Ready’ nếu nó vượt qua bài kiểm tra
gosshoặcinspeccơ bản.
Việc gỡ lỗi các shell script bên trong khối provisioner có thể rất tẻ nhạt, đặc biệt là với các Regex phức tạp cho lệnh sed. Tôi sử dụng Công cụ kiểm tra Regex để xác minh các pattern của mình trước khi bắt đầu một bản build kéo dài 12 phút. Việc phải chờ đợi cả một chu kỳ chỉ để phát hiện một lỗi đánh máy trong regex là một tác nhân gây lãng phí năng suất cực lớn.
Lời kết
Tự động hóa các machine image giúp loại bỏ tình trạng ‘trôi dạt cấu hình’ (configuration drift) xảy ra khi các máy chủ được vá lỗi thủ công trong nhiều tháng. Mọi instance được khởi chạy từ Golden Image của bạn đều là một bản sao chính xác của bản trước đó. Điều này giúp việc xử lý sự cố trở nên dễ dàng hơn đáng kể.
Nếu bạn vẫn đang click chuột qua AWS Console để tạo AMI, hãy bắt đầu từ những việc nhỏ nhất. Hãy chuyển cấu hình OS phổ biến nhất của bạn vào một tệp Packer HCL và thực hiện bản build đầu tiên. Bản thân bạn lúc 2 giờ sáng sẽ cảm ơn chính mình khi sự cố tiếp theo xảy ra và hạ tầng của bạn có thể mở rộng lại chỉ trong vài giây chứ không phải vài giờ.

