Break/Fix: mọi thứ biến mất sau reboot
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
Một đồng nghiệp dựng dịch vụ kdc-report bằng tay và báo "đã chạy". Tuần sau, máy được reboot trong đợt vá bảo mật định kỳ. Từ đó http://127.0.0.1:8090/ không trả lời.
Nhiệm vụ: đưa dịch vụ chạy lại, bảo đảm nó tự chạy sau mọi lần reboot, chứng minh bằng một lần reboot thật, và viết RCA.
Vì sao cần học
Cấu hình chỉ tồn tại trong bộ nhớ là cái bẫy kinh điển: mount bằng tay, systemctl start mà quên enable, IP đặt bằng ip addr, rule firewall chỉ ở runtime. Mọi thứ trông đúng cho tới lần reboot tiếp theo, thường đúng lúc không ai nhớ đã làm gì. Đề RHCSA chấm bài sau khi reboot máy vì lý do này.
Mục tiêu
- Phân biệt trạng thái runtime với cấu hình persistent.
- Đọc log của lần boot hiện tại (
journalctl -b) và lần trước (-b -1). - Khai báo mount tmpfs trong fstab và enable dịch vụ.
- Kiểm chứng bằng reboot, không bằng niềm tin.
Điều kiện tiên quyết
- Bài Vận hành web service bằng systemd và Thêm ổ dữ liệu bằng LVM và fstab.
Tạo sự cố
Đọc kỹ script, lưu vào ~/break-reboot.sh trên VM, chạy sudo bash ~/break-reboot.sh.
#!/usr/bin/env bash
# KDC Break/Fix: lost after reboot. 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ẽ dựng dịch vụ kdc-report theo cách đồng nghiệp đã làm. Tiếp tục? [y/N] " answer
[[ $answer == y ]] || exit 1
id -u kdc-report &>/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin kdc-report
install -d -m 755 /opt/kdc-report /mnt/kdc-cache
cat > /opt/kdc-report/report.py <<'PY'
import os
import sys
from http.server import BaseHTTPRequestHandler, HTTPServer
CACHE = "/mnt/kdc-cache"
if not os.path.ismount(CACHE):
print(f"FATAL: {CACHE} is not a mount point; refusing to write cache to the root filesystem", file=sys.stderr, flush=True)
sys.exit(1)
class Report(BaseHTTPRequestHandler):
def do_GET(self):
body = b"kdc-report ok\n"
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
print("kdc-report listening on 127.0.0.1:8090", flush=True)
HTTPServer(("127.0.0.1", 8090), Report).serve_forever()
PY
cat > /etc/systemd/system/kdc-report.service <<'UNIT'
[Unit]
Description=KDC demo report
[Service]
User=kdc-report
ExecStart=/usr/bin/python3 /opt/kdc-report/report.py
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
if ! mountpoint -q /mnt/kdc-cache; then mount -t tmpfs -o size=16m,mode=0755 tmpfs /mnt/kdc-cache; fi
systemctl start kdc-report.service
sleep 1
curl -s http://127.0.0.1:8090/ || true
echo "Dịch vụ đang chạy. Giờ hãy reboot: sudo systemctl reboot"
Giải thích lệnh và tham số
if ! mountpoint -q ... thực hiện nhánh khi đường dẫn chưa là mountpoint; ! đảo kết quả kiểm tra. mount -t tmpfs -o size=16m,mode=0755 tmpfs /mnt/kdc-cache: -t chọn filesystem tmpfs, -o nhận danh sách tùy chọn cách nhau bằng dấu phẩy, size=16m giới hạn kích thước, mode=0755 đặt quyền thư mục gốc của mount. Tmpfs lưu dữ liệu trong bộ nhớ ảo và nội dung mất khi unmount/reboot; lệnh mount runtime chưa tạo khai báo tự mount lúc boot.
systemctl start chỉ chạy service bây giờ; khác enable cấu hình chạy khi boot. Script cố ý dùng thao tác runtime để bạn đối chiếu trạng thái trước/sau reboot.
Sau khi script in kdc-report ok, reboot VM. Sau khi đăng nhập lại, bật lại tunnel và agent, rồi bắt đầu điều tra.
Điều tra
- Symptom: sau reboot, client nhận lỗi gì?
- Scope: dịch vụ không chạy, hay chạy mà không phục vụ?
- Layer: systemd có được yêu cầu khởi động dịch vụ khi boot không? Nếu bạn tự start, nó có chạy được không?
- Evidence: log nói gì về điều kiện mà dịch vụ cần? Điều kiện đó trước reboot được tạo ra bằng cách nào?
- Fix: biến mọi thứ thành persistent, reboot, kiểm tra lại.
Đọc các công cụ điều tra
is-enabled hỏi cấu hình tự chạy, status xem trạng thái hiện tại, journalctl ... -b xem log lần boot hiện tại. findmnt <mountpoint> hỏi filesystem đang gắn thực tế; grep ... /etc/fstab xem khai báo để boot sau. Dòng fstab là cấu hình có 6 trường, không phải lệnh shell. sysctl -w <tên>=<giá-trị> được nhắc ở ghi chú production là sửa tham số kernel runtime; chưa lưu file cấu hình để áp lại khi boot.
Gợi ý (chỉ mở khi bế tắc)
- Mức 1, hướng nhìn: có hai thứ đồng nghiệp làm bằng tay, chỉ tồn tại tới lần reboot.
- Mức 2, công cụ:
systemctl is-enabled kdc-report,systemctl status kdc-report,journalctl -u kdc-report -b,findmnt /mnt/kdc-cache,grep kdc /etc/fstab. - Mức 3, một bước: dòng fstab cho tmpfs có dạng
tmpfs /mnt/kdc-cache tmpfs size=16m,mode=0755 0 0. Chạysystemctl daemon-reload,findmnt --verifyvàmount -atrước khi reboot.
Viết RCA
Tạo ~/kdc-labs/rca/lost-after-reboot.md:
# RCA: kdc-report ngừng sau reboot bảo trì
## Triệu chứng
## Evidence
## Nguyên nhân gốc
## Cách sửa
## Phòng tránh
Phần Phòng tránh nên đề xuất cách bắt lỗi này trước đợt reboot tiếp theo, ví dụ checklist sau thay đổi hoặc reboot thử trên môi trường staging. Module 07 (Ansible) sẽ cho một câu trả lời tốt hơn.
Tự kiểm tra (Verification)
Sau lần reboot cuối:
systemctl is-enabled kdc-report
findmnt /mnt/kdc-cache
curl -s http://127.0.0.1:8090/
Giải thích lệnh và tham số
systemctl is-enabled xem cấu hình tự chạy khi boot; findmnt xem filesystem đang mount. curl -s lấy phản hồi HTTP và ẩn thanh tiến độ.
Chọn server và bấm Kiểm tra kết quả.
Ghi chú production
- Thêm
RequiresMountsFor=/mnt/kdc-cachevào[Unit]để systemd tự sắp thứ tự và chỉ start dịch vụ khi mount đã sẵn sàng. Sau khi sửa unit,daemon-reloadvà reboot lại để chứng minh. - Danh sách những thứ chỉ có ở runtime cần nhớ:
mount,systemctl start,ip addr add,sysctl -w,firewall-cmdkhông có--permanent,setenforce.
Dọn dẹp
sudo systemctl disable --now kdc-report.service
sudo sed -i '\|/mnt/kdc-cache|d' /etc/fstab
sudo systemctl daemon-reload
sudo umount /mnt/kdc-cache
sudo rm -rf /opt/kdc-report /etc/systemd/system/kdc-report.service
sudo systemctl daemon-reload
sudo userdel kdc-report
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. sed -i sửa fstab tại chỗ; biểu thức có hậu tố d xóa dòng khớp mountpoint lab. umount tháo filesystem, userdel xóa tài khoản lab.