Đang tải bài học…
Nội dung sẽ hiển thị khi tải xong.
Nội dung sẽ hiển thị khi tải xong.
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.
Dịch vụ kdc-logger ghi log vào /mnt/kdc-logs và liên tục crash. Ca trực trước thấy ổ đầy nên đã xóa file debug-trace.log rất lớn, nhưng df vẫn báo 100%. Thư mục archive/ chứa log audit phải giữ 90 ngày theo chính sách, không được xóa.
Nhiệm vụ: giải phóng dung lượng, đưa kdc-logger chạy lại, giữ nguyên archive/, và viết RCA.
Ổ đầy là một trong những sự cố production phổ biến nhất: database ngừng ghi, dịch vụ không tạo được file tạm, có khi không SSH vào được. Phản xạ "xóa file lớn nhất" thường sai: có thể xóa nhầm dữ liệu cần giữ, hoặc như ở đây, xóa xong mà dung lượng không được trả lại.
df và du, giải thích vì sao hai con số có thể khác nhau.Script tạo một filesystem 128 MB trên file loop, chỉ tồn tại tới lần reboot, nên không đụng tới ổ thật. Đọc kỹ script, lưu vào ~/break-disk-full.sh trên VM, chạy sudo bash ~/break-disk-full.sh.
#!/usr/bin/env bash
# KDC Break/Fix: disk full. 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 ổ loop /mnt/kdc-logs và làm đầy nó. Tiếp tục? [y/N] " answer
[[ $answer == y ]] || exit 1
img=/var/lib/kdc-logs.img
mnt=/mnt/kdc-logs
systemctl stop kdc-logger.service kdc-debug-trace.service 2>/dev/null || true
if mountpoint -q "$mnt"; then umount "$mnt"; fi
rm -f "$img"
truncate -s 128M "$img"
mkfs.ext4 -q -F -m 0 -L kdc-logs "$img"
install -d "$mnt"
mount -o loop "$img" "$mnt"
id -u kdc-logger &>/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin kdc-logger
install -d -m 755 "$mnt/archive"
for month in 07 08 09; do
head -c 10M /dev/zero > "$mnt/archive/audit-2026-$month.log"
done
install -o kdc-logger -g kdc-logger -m 644 /dev/null "$mnt/app.log"
install -d -m 755 /opt/kdc-logger
cat > /opt/kdc-logger/logger.py <<'PY'
import os
import sys
import time
from datetime import datetime
LOG_DIR = "/mnt/kdc-logs"
MIN_FREE = 5 * 1024 * 1024
with open(f"{LOG_DIR}/app.log", "a", buffering=1) as log:
while True:
disk = os.statvfs(LOG_DIR)
if disk.f_bavail * disk.f_frsize < MIN_FREE:
print(f"FATAL: less than 5 MiB free on {LOG_DIR}; stopping so no log line is lost", file=sys.stderr, flush=True)
sys.exit(1)
log.write(f"{datetime.now().isoformat()} INFO request handled\n")
time.sleep(1)
PY
cat > /opt/kdc-logger/debug_trace.py <<'PY'
import time
with open("/mnt/kdc-logs/debug-trace.log", "wb", buffering=0) as trace:
chunk = b"TRACE " * 174763
try:
while True:
trace.write(chunk)
except OSError:
pass
while True:
time.sleep(3600)
PY
systemd-run --unit=kdc-debug-trace --description="Debug trace started during an old incident" \
/usr/bin/python3 /opt/kdc-logger/debug_trace.py
for _ in $(seq 60); do
(( $(df --output=avail "$mnt" | tail -1) < 4096 )) && break
sleep 1
done
rm -f "$mnt/debug-trace.log"
cat > /etc/systemd/system/kdc-logger.service <<'UNIT'
[Unit]
Description=KDC demo logger
[Service]
User=kdc-logger
ExecStart=/usr/bin/python3 /opt/kdc-logger/logger.py
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now kdc-logger.service
echo "Đã tạo sự cố. Bắt đầu từ: systemctl status kdc-logger"
| Lệnh / tùy chọn trong script | Ý nghĩa |
|---|---|
mountpoint -q "$mnt" | Kiểm tra đường dẫn có là mountpoint; -q không in thông báo, dùng mã thoát trong if. |
truncate -s 128M "$img" | Đặt kích thước file image 128 MiB; file có thể là sparse file, chưa chiếm đủ dung lượng tương ứng. |
mkfs.ext4 -q -F -m 0 -L kdc-logs "$img" | -q giảm thông báo; -F cho phép format file thường; -m 0 không dành phần trăm block cho superuser; -L đặt label. Lệnh ghi filesystem mới vào file image lab. |
mount -o loop "$img" "$mnt" | -o nhận tùy chọn mount; loop dùng file image như thiết bị block qua loop device. |
head -c 10M /dev/zero | -c lấy số byte thay vì số dòng; tạo 10 MiB dữ liệu zero để làm file mẫu. |
install ... /dev/null "$mnt/app.log" | Tạo file rỗng từ nguồn /dev/null, đặt owner/group và quyền bằng các tùy chọn install. |
systemd-run --unit=... --description=... <lệnh> | Tạo unit tạm và chạy lệnh dưới systemd; hai tùy chọn đặt tên unit và mô tả. |
seq 60, break | Tạo dãy số 1–60 cho vòng chờ; break thoát vòng khi điều kiện đủ. |
df --output=avail | Chỉ lấy cột dung lượng khả dụng; trong môi trường GNU mặc định thông thường tính theo block 1 KiB. |
Script dùng image riêng /var/lib/kdc-logs.img để mô phỏng ổ đầy; không format ổ hệ điều hành. Khối Python ghi bằng <<'PY' là mã dịch vụ, không phải các lệnh shell để gõ từng dòng.
Bấm Kiểm tra kết quả một lần để thấy trạng thái xuất phát.
df) và theo tổng kích thước file nhìn thấy (du) có khớp nhau không?du -sh <thư-mục>: du cộng dung lượng của file còn nhìn thấy, -s in tổng thay vì từng thư mục, -h dùng đơn vị dễ đọc. df -h đo dung lượng filesystem, nên hai kết quả có thể khác.lsof +aL1 /mnt/kdc-logs: +L1 chọn file đang mở có link count nhỏ hơn 1, thường đã bị xóa tên; +a kết hợp điều kiện đó với filesystem được chỉ định. Lệnh giúp xem file đã xóa nhưng vẫn mở trên đúng filesystem lab.find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n': tìm symlink FD có đích khớp mẫu deleted. -lname xét nội dung symlink; -printf in đường dẫn %p, đích link %l, xuống dòng \n. Các dấu nháy giữ nguyên mẫu/định dạng.ps ... -p <PID>: chọn đúng PID; systemctl reset-failed xóa trạng thái failed và bộ đếm giới hạn khởi động lại, chưa tự start dịch vụ.Các lệnh xem trạng thái giúp xác định nguồn dung lượng; tự chọn cách sửa sau khi thu đủ evidence.
rm chỉ xóa tên file. Dữ liệu chỉ được giải phóng khi không còn ai mở file.df -h /mnt/kdc-logs, sudo du -sh /mnt/kdc-logs, sudo lsof +aL1 /mnt/kdc-logs. Không có lsof thì dùng sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n'.ps -o pid,unit,cmd -p <PID>. Dừng đúng unit đó. Sau đó kdc-logger có thể đã chạm giới hạn restart (start-limit-hit); dùng systemctl reset-failed trước khi start lại.Tạo ~/kdc-labs/rca/disk-full.md:
# RCA: /mnt/kdc-logs đầy, kdc-logger crash
## Triệu chứng
## Evidence
## Nguyên nhân gốc
## Cách sửa
## Phòng tránh
Trong Evidence, ghi lại con số df và du trước khi sửa và PID/unit giữ file. Trong Phòng tránh, nghĩ về: log rotation, giới hạn kích thước log debug, cảnh báo dung lượng trước khi đầy.
df -h /mnt/kdc-logs
ls -l /mnt/kdc-logs/archive
systemctl is-active kdc-logger
tail -3 /mnt/kdc-logs/app.log
df -h xem dung lượng filesystem chứa đường dẫn với đơn vị dễ đọc (-h). ls -l liệt kê file chi tiết; tail -3 đọc ba dòng log cuối. systemctl is-active xem trạng thái service.
Chọn server và bấm Kiểm tra kết quả.
: > file) rồi xử lý nguyên nhân; xóa thì phải khởi động lại tiến trình đang giữ file.logrotate hoặc giới hạn của journald (SystemMaxUse=) thay vì dọn tay.sudo systemctl stop kdc-debug-trace.service 2>/dev/null || true
sudo systemctl disable --now kdc-logger.service
if mountpoint -q /mnt/kdc-logs; then sudo umount /mnt/kdc-logs; fi
sudo rm -f /var/lib/kdc-logs.img /etc/systemd/system/kdc-logger.service
sudo rm -rf /opt/kdc-logger
sudo systemctl daemon-reload
sudo userdel kdc-logger
2>/dev/null bỏ stderr; || true cho phép tiếp tục khi lệnh dừng service phụ thất bại. mountpoint -q kiểm tra mountpoint bằng mã thoát, không in thông báo; if ...; then ...; fi chỉ unmount khi đang mount. 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.