Break/Fix: dịch vụ lỗi khi boot
Tạo sự cố trong phạm vi lab của bài, thu bằng chứng, sửa rồi kiểm tra.
Tình huống
Sau đợt reboot bảo trì, giám sát báo kdc-worker không chạy. Đồng nghiệp viết unit này nói "đã enable rồi mà". Hàng đợi kdc-queue vẫn chạy bình thường.
Nhiệm vụ: đưa kdc-worker chạy được và tự chạy khi boot, chứng minh bằng một lần reboot, và viết RCA.
Vì sao cần học
Dịch vụ lỗi khi boot thường không ai thấy tới khi người dùng báo. systemd ghi rất rõ lý do, nhưng phải biết tìm ở đâu: systemctl --failed, mã lỗi trong status, log của lần boot, và systemd-analyze verify để bắt lỗi unit trước khi reboot.
Mục tiêu
- Liệt kê unit lỗi và đọc mã lỗi (
status=203/EXEC, dependency failed) của systemd. - Đọc log của lần boot hiện tại và lần trước (
journalctl -b,-b -1). - Kiểm tra unit file bằng
systemd-analyze verifytrước khi áp dụng. - Hiểu
Requires=,After=và cách một dependency hỏng làm dịch vụ không khởi động.
Điều kiện tiên quyết
- Bài Vận hành web service bằng systemd và Đọc log và cấu hình journald, logrotate (journal bền vững để xem log của lần boot trước).
Tạo sự cố
Đọc kỹ script, lưu vào ~/break-boot.sh trên VM, chạy sudo bash ~/break-boot.sh, rồi reboot VM.
#!/usr/bin/env bash
# KDC Break/Fix: boot failure. Chỉ chạy trên VM lab có /etc/kdc-lab.
set -euo pipefail
[[ $EUID -eq 0 ]] || { echo "Chạy bằng sudo." >&2; exit 1; }
grep -qs '^KDC-LAB' /etc/kdc-lab || { echo "Không thấy marker /etc/kdc-lab; script chỉ chạy trên máy lab." >&2; exit 1; }
read -r -p "Script sẽ tạo kdc-queue và kdc-worker với unit lỗi. Tiếp tục? [y/N] " answer
[[ $answer == y ]] || exit 1
install -d -m 755 /opt/kdc-worker
cat > /opt/kdc-worker/queue.sh <<'SH'
#!/usr/bin/bash
while :; do sleep 60; done
SH
cat > /opt/kdc-worker/worker.sh <<'SH'
#!/usr/bin/bash
while :; do date --iso-8601=seconds > "$STATE_DIRECTORY/heartbeat"; sleep 10; done
SH
chmod 755 /opt/kdc-worker/queue.sh
chmod 644 /opt/kdc-worker/worker.sh
cat > /etc/systemd/system/kdc-queue.service <<'UNIT'
[Unit]
Description=KDC demo queue
[Service]
ExecStart=/opt/kdc-worker/queue.sh
[Install]
WantedBy=multi-user.target
UNIT
cat > /etc/systemd/system/kdc-worker.service <<'UNIT'
[Unit]
Description=KDC demo worker
Requires=kdc-queu.service
After=kdc-queue.service
[Service]
StateDirectory=kdc-worker
ExecStart=/opt/kdc-worker/worker.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable kdc-queue.service kdc-worker.service
echo "Đã cài dịch vụ. Giờ hãy reboot: sudo systemctl reboot"
Giải thích lệnh và tham số
systemctl enable chỉ cấu hình chạy khi boot; không có --now nên chưa khởi chạy unit ngay. chmod 644 cho đọc nhưng không có quyền thực thi; chmod 755 có quyền thực thi. Đây là giá trị script cố ý đặt để tạo tình huống cho bạn điều tra, không phải hướng dẫn sửa dịch vụ thật.
Sau khi đăng nhập lại, bật lại tunnel và agent, rồi bấm Kiểm tra kết quả một lần để thấy trạng thái xuất phát.
Điều tra
- Symptom: unit nào đang lỗi sau boot?
- Scope: chỉ
kdc-worker, hay cả những gì nó phụ thuộc? - Layer: systemd từ chối khởi động vì dependency, hay tiến trình được khởi động rồi chết?
- Evidence: đọc chính xác thông báo lỗi; mỗi lần sửa xong, lỗi có thể đổi sang lỗi khác.
- Fix: sửa unit, kiểm tra bằng
systemd-analyze verify,daemon-reload, start, rồi reboot để chứng minh.
Đọc các công cụ điều tra
systemctl --failed liệt kê unit đang failed. journalctl -b -u <unit> chỉ lấy log unit trong lần boot hiện tại; -b -1 chọn lần boot trước. systemd-analyze verify <file-unit> kiểm tra unit, dependency và một số lỗi của lệnh khởi chạy mà chưa start service. ls -l xem file executable có quyền x hay không. Requires= và After= là thuộc tính trong file unit, không phải tùy chọn của journalctl.
Gợi ý (chỉ mở khi bế tắc)
- Mức 1, hướng nhìn: có hai lỗi: một trong unit file, một trên chính file chương trình.
- Mức 2, công cụ:
systemctl --failed,systemctl status kdc-worker,journalctl -b -u kdc-worker,sudo systemd-analyze verify /etc/systemd/system/kdc-worker.service,ls -l /opt/kdc-worker. - Mức 3, một bước: đọc kỹ tên unit trong dòng
Requires=. Sau khi sửa,status=203/EXECnghĩa là systemd không thực thi được file trongExecStart.
Viết RCA
Tạo ~/kdc-labs/rca/boot-failure.md:
# RCA: kdc-worker không chạy sau reboot
## Triệu chứng
## Evidence
## Nguyên nhân gốc
## Cách sửa
## Phòng tránh
Trong Phòng tránh, đề xuất một bước kiểm tra tự động chạy trước khi unit mới được đưa lên server.
Tự kiểm tra (Verification)
Sau lần reboot cuối:
systemctl --failed
systemctl is-active kdc-queue kdc-worker
sudo cat /var/lib/kdc-worker/heartbeat
Giải thích lệnh và tham số
systemctl --failed liệt kê unit đang ở trạng thái failed. is-active xem trạng thái hai service; cat đọc heartbeat đã ghi.
Chọn server và bấm Kiểm tra kết quả.
Ghi chú production
Requires=làm dịch vụ dừng theo dependency;Wants=thì không.After=chỉ quy định thứ tự, không kéo dependency vào. Hai loại thường đi cùng nhau.- Chạy
systemd-analyze verifytrong CI cho mọi unit file trước khi triển khai. Module 07 (Ansible) có thể làm bước này tự động. systemctl --failednên là một kiểm tra của monitoring sau mỗi lần reboot.
Dọn dẹp
sudo systemctl disable --now kdc-worker.service kdc-queue.service
sudo rm -f /etc/systemd/system/kdc-worker.service /etc/systemd/system/kdc-queue.service
sudo systemctl daemon-reload
sudo systemctl reset-failed
sudo rm -rf /opt/kdc-worker /var/lib/kdc-worker
Giải thích lệnh và tham số
systemctl disable --now bỏ cấu hình tự chạy khi boot và dừng service ngay. daemon-reload yêu cầu systemd đọc lại unit file sau khi sửa/xóa. rm -f xóa file và không hỏi xác nhận; -r thêm xóa đệ quy thư mục cùng nội dung, nên -rf gộp hai tùy chọn này. systemctl reset-failed xóa trạng thái lỗi đã ghi nhận và bộ đếm giới hạn khởi động lại; không tự khởi chạy service.