Greenboot trên Fedora IoT và CoreOS: Tự động kiểm tra sức khỏe và rollback khi update lỗi

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

Tháng trước mình update kernel trên một cái Raspberry Pi chạy Fedora IoT — và máy không boot lên được nữa. Không có màn hình, không có bàn phím, chỉ là một hộp đen nhỏ nằm góc phòng. Phải SSH từ máy khác vào rescue mode mới fix được. Đó là lần đầu mình thực sự hiểu tại sao Greenboot tồn tại.

Bối cảnh & Tại sao cần Greenboot

Fedora IoT và CoreOS đều dùng hệ thống file immutable dựa trên rpm-ostree — mỗi lần update tạo ra một “deployment” mới, hệ thống cũ vẫn còn nguyên. Về lý thuyết, nếu update lỗi, bạn chỉ cần boot vào deployment cũ. Nhưng trên thiết bị headless không màn hình không bàn phím, ai sẽ phát hiện ra lỗi đó và tự động kéo về bản cũ?

Đó là việc của Greenboot.

Về cơ bản, Greenboot là một framework nhỏ tích hợp với systemd. Nó chạy các script kiểm tra sức khỏe ngay sau mỗi lần boot — nếu bất kỳ script nào trong thư mục required.d fail, Greenboot đánh dấu boot hiện tại là thất bại. Sau 3 lần thất bại liên tiếp, rpm-ostree tự động rollback về deployment trước đó, không cần người can thiệp.

Mình dùng Fedora làm máy development chính được 2 năm. Update thất bại trên laptop thì khó chịu, nhưng vẫn sửa được. Với thiết bị headless cắm ở góc phòng hoặc server đặt tại data center cách xa hàng trăm kilomet thì câu chuyện hoàn toàn khác. Greenboot đặc biệt cần thiết khi:

  • Thiết bị ở xa, không có access vật lý (VPS, edge device, Raspberry Pi)
  • Hệ thống cần uptime cao — downtime 30 phút chờ fix thủ công là quá đắt
  • Bạn bật rpm-ostreed-automatic hoặc zincati để update tự động không giám sát

Cài đặt Greenboot

Trên Fedora IoT và CoreOS, Greenboot thường đã được cài sẵn. Kiểm tra nhanh:

rpm -q greenboot
# greenboot-0.15.0-4.fc40.noarch

Nếu chưa có, vì filesystem là immutable nên phải dùng rpm-ostree thay vì dnf:

# Fedora IoT / CoreOS
sudo rpm-ostree install greenboot greenboot-default-health-checks

# Reboot để apply
sudo systemctl reboot

Trên Fedora Workstation/Server thông thường:

sudo dnf install greenboot greenboot-default-health-checks

Sau khi cài, enable và khởi động 2 service chính:

sudo systemctl enable --now greenboot-healthcheck.service
sudo systemctl enable --now greenboot-status.service

# Kiểm tra trạng thái
sudo systemctl status greenboot-healthcheck.service

Cấu hình chi tiết

Greenboot đọc health check scripts từ hai thư mục chính:

  • /etc/greenboot/check/required.d/ — Script bắt buộc phải pass. Fail → hệ thống bị đánh dấu unhealthy
  • /etc/greenboot/check/wanted.d/ — Script không bắt buộc. Fail → chỉ log warning, không kích hoạt rollback

Tùy vào kết quả health check, Greenboot còn chạy hai thư mục hook:

  • /etc/greenboot/green.d/ — Chạy khi tất cả check đều pass
  • /etc/greenboot/red.d/ — Chạy khi có check fail, trước khi reboot để rollback

Script kiểm tra kết nối mạng

Exit code 0 = healthy, khác 0 = fail. Quy tắc này đơn giản nhưng cần nhớ — Greenboot không đọc output text, chỉ nhìn vào exit code của script. Mình hay bắt đầu với network check vì đây là thứ dễ bị ảnh hưởng nhất sau kernel update:

sudo nano /etc/greenboot/check/required.d/01-check-network.sh
#!/bin/bash
# Kiểm tra kết nối mạng sau boot

TIMEOUT=30
TARGET="8.8.8.8"

echo "Checking network connectivity..."

for i in $(seq 1 $TIMEOUT); do
    if ping -c 1 -W 1 "$TARGET" &>/dev/null; then
        echo "Network OK after ${i}s"
        exit 0
    fi
    sleep 1
done

echo "ERROR: Network unreachable after ${TIMEOUT}s"
exit 1
sudo chmod +x /etc/greenboot/check/required.d/01-check-network.sh

Prefix số trong tên file (01-, 10-, 99-) kiểm soát thứ tự chạy. Đặt network check ở 01- vì nhiều check khác phụ thuộc vào mạng — không có nghĩa gì khi test API endpoint nếu network chưa lên.

Script kiểm tra service quan trọng

sudo nano /etc/greenboot/check/required.d/10-check-services.sh
#!/bin/bash
# Kiểm tra các service bắt buộc phải chạy

REQUIRED_SERVICES=("sshd" "NetworkManager")

for svc in "${REQUIRED_SERVICES[@]}"; do
    if ! systemctl is-active --quiet "$svc"; then
        echo "ERROR: Service $svc is not running"
        systemctl status "$svc" --no-pager
        exit 1
    fi
    echo "OK: $svc is active"
done

exit 0
sudo chmod +x /etc/greenboot/check/required.d/10-check-services.sh

Gửi thông báo Telegram khi boot thành công

Với thiết bị remote, biết chính xác lúc nào máy boot xong rất tiện — thay vì phải mở terminal ping thủ công. Hook trong green.d chạy sau khi tất cả health check pass, nên đây là thời điểm lý tưởng để gửi tín hiệu “tôi sống rồi”:

sudo nano /etc/greenboot/green.d/99-notify-success.sh
#!/bin/bash
HOSTNAME=$(hostname)
TOKEN="your-bot-token"
CHAT_ID="your-chat-id"

MESSAGE="✅ ${HOSTNAME} boot thành công lúc $(date '+%Y-%m-%d %H:%M')"

curl -s -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
    -d "chat_id=${CHAT_ID}&text=${MESSAGE}" &>/dev/null

exit 0

Gửi cảnh báo trước khi rollback

sudo nano /etc/greenboot/red.d/99-notify-failure.sh
#!/bin/bash
HOSTNAME=$(hostname)
TOKEN="your-bot-token"
CHAT_ID="your-chat-id"
BOOT_COUNTER=$(cat /run/greenboot/boot_counter 2>/dev/null || echo "unknown")

MESSAGE="⚠️ ${HOSTNAME}: Boot health check FAILED (attempt ${BOOT_COUNTER}/3). Preparing rollback..."

curl -s -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
    -d "chat_id=${CHAT_ID}&text=${MESSAGE}" &>/dev/null

exit 0

Kiểm tra & Monitoring

Chạy health check thủ công không cần reboot

# Chạy toàn bộ health check ngay lập tức
sudo systemctl start greenboot-healthcheck.service

# Xem kết quả
sudo systemctl status greenboot-healthcheck.service

# Log chi tiết từng script
sudo journalctl -u greenboot-healthcheck.service -n 50 --no-pager

Xem trạng thái deployment và boot counter

# Boot counter hiện tại (tăng mỗi lần fail, reset về 0 khi pass)
sudo grub2-editenv - list | grep boot_counter

# Xem tất cả deployments
rpm-ostree status

# Output mẫu:
# ● fedora:fedora/40/x86_64/iot
#                    Version: 40.20240601.0 (current)
#   fedora:fedora/40/x86_64/iot
#                    Version: 40.20240501.0 (rollback target)

Test rollback bằng script giả lỗi

Trước khi tin tưởng Greenboot với thiết bị thật, mình luôn test thủ công. Cách nhanh nhất là tạo một script fail có chủ đích, reboot 3 lần, và xem hệ thống có tự rollback đúng không:

# Tạo script fail có chủ đích
sudo bash -c 'cat > /etc/greenboot/check/required.d/99-test-failure.sh << EOF
#!/bin/bash
echo "Simulated failure for testing"
exit 1
EOF'
sudo chmod +x /etc/greenboot/check/required.d/99-test-failure.sh

# Reboot và quan sát
sudo systemctl reboot

Sau 3 lần boot fail liên tiếp, hệ thống tự rollback về deployment cũ. Nhớ xóa script test sau khi kiểm tra xong bằng sudo rm /etc/greenboot/check/required.d/99-test-failure.sh.

Tích hợp với Zincati trên CoreOS

Trên CoreOS, Zincati lo việc tải và áp dụng update tự động. Ghép với Greenboot, bạn có một vòng lặp hoàn chỉnh không cần người giám sát: update lúc 2 giờ sáng, sáng dậy hoặc máy đang chạy bản mới ổn định, hoặc đã tự rollback về bản cũ rồi.

sudo mkdir -p /etc/zincati/config.d
sudo nano /etc/zincati/config.d/55-updates-strategy.toml
[updates]
strategy = "periodic"

[[updates.periodic.window]]
days = [ "Mon", "Wed", "Fri" ]
start_time = "02:00"
length_minutes = 60

Thứ 2, 4, 6 lúc 2 giờ sáng — tránh cuối tuần để còn người trực nếu có gì bất thường. Nếu update gây lỗi, Greenboot phát hiện ngay lần boot tiếp theo và rollback xong trước khi trời sáng.

Theo dõi log realtime

# Theo dõi tất cả Greenboot services
sudo journalctl -fu "greenboot*"

# Chỉ xem 1 giờ gần nhất
sudo journalctl -u "greenboot*" --since "1 hour ago" --no-pager

Sau khi setup xong, mình để Fedora IoT trên Raspberry Pi tự update mấy tháng không cần đụng vào. Có 1 lần kernel update bị lỗi driver WiFi, Greenboot phát hiện ngay (script check network fail), rollback tự động, và mình nhận thông báo Telegram lúc sáng sớm. Không mất downtime, không phải mò vào rescue mode như hồi trước nữa.

Share: