Đ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-poller gọi health check của API tại http://api.kdc.lab:8095/health mỗi 3 giây. Sau đợt "chuyển API sang máy mới" tuần trước, log tràn ngập health check failed. Đội API khẳng định API vẫn chạy ngay trên máy này.
Nhiệm vụ: làm kdc-poller gọi được API, không sửa mã nguồn hay unit của poller, và viết RCA.
"It's always DNS" là câu đùa quen thuộc của người vận hành, vì lỗi phân giải tên trông giống lỗi mạng, lỗi firewall hoặc lỗi ứng dụng. Kỹ năng then chốt là kiểm tra tên được phân giải theo đúng đường ứng dụng dùng, không theo công cụ bạn quen tay.
getent hosts, hiểu vì sao dig có thể cho kết quả khác./etc/nsswitch.conf và quy tắc dòng đầu tiên thắng trong /etc/hosts.Đọc kỹ script, lưu vào ~/break-dns.sh trên VM, chạy sudo bash ~/break-dns.sh.
#!/usr/bin/env bash
# KDC Break/Fix: DNS. 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-api-v2, kdc-poller và sửa /etc/hosts. Tiếp tục? [y/N] " answer
[[ $answer == y ]] || exit 1
for name in kdc-api-v2 kdc-poller; do
id -u "$name" &>/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin "$name"
done
install -d -m 755 /opt/kdc-dns
cat > /opt/kdc-dns/api.py <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
class Health(BaseHTTPRequestHandler):
def do_GET(self):
body = b"ok\n"
self.send_response(200 if self.path == "/health" else 404)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
HTTPServer(("127.0.0.1", 8095), Health).serve_forever()
PY
cat > /opt/kdc-dns/poller.sh <<'SH'
#!/usr/bin/bash
while :; do
if curl -fsS --max-time 2 "http://${API_HOST}:8095/health" >/dev/null; then
date --iso-8601=seconds > "$STATE_DIRECTORY/last-ok"
else
echo "health check to ${API_HOST} failed" >&2
fi
sleep 3
done
SH
chmod 755 /opt/kdc-dns/poller.sh
cat > /etc/systemd/system/kdc-api-v2.service <<'UNIT'
[Unit]
Description=KDC API v2
[Service]
User=kdc-api-v2
ExecStart=/usr/bin/python3 /opt/kdc-dns/api.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
UNIT
cat > /etc/systemd/system/kdc-poller.service <<'UNIT'
[Unit]
Description=KDC health poller
[Service]
User=kdc-poller
Environment=API_HOST=api.kdc.lab
StateDirectory=kdc-poller
ExecStart=/opt/kdc-dns/poller.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
UNIT
# Ghi đè tại chỗ để giữ nguyên inode và SELinux label của /etc/hosts.
grep -v 'api\.kdc\.lab' /etc/hosts > /tmp/kdc-hosts || true
cat /tmp/kdc-hosts > /etc/hosts && rm -f /tmp/kdc-hosts
echo '10.255.255.1 api.kdc.lab # API cũ, đã chuyển đi' >> /etc/hosts
rm -rf /var/lib/kdc-poller
systemctl daemon-reload
systemctl enable --now kdc-api-v2.service kdc-poller.service
echo "Đã tạo sự cố. Bắt đầu từ: journalctl -u kdc-poller -f"
curl -fsS --max-time 2 <URL> gộp -f (trả lỗi khi HTTP báo lỗi từ 400), -s (ẩn progress), -S (vẫn in lỗi khi dùng silent); --max-time 2 giới hạn toàn bộ lần gọi ở 2 giây. grep -v 'api\.kdc\.lab' giữ các dòng không khớp tên này; \. trong regex là dấu chấm thật. Script dùng kết quả đó để ghi lại /etc/hosts tại chỗ rồi thêm dòng mẫu gây sự cố.
>/dev/null bỏ nội dung phản hồi curl nhưng vẫn dùng được mã thoát trong if; >&2 gửi thông báo lỗi tới stderr. sleep 3 chờ giữa các lần kiểm tra. Đây là script tạo sự cố đã có xác nhận, không chạy từng dòng cấu hình bằng tay.
Bấm Kiểm tra kết quả một lần để thấy trạng thái xuất phát.
api.kdc.lab được phân giải ra đâu, từ nguồn nào?curl -v <URL> in chi tiết kết nối/request/response để xác định điểm lỗi; -v ở curl là verbose. getent hosts <tên> dùng cơ chế phân giải của hệ điều hành, còn dig <tên> và nslookup <tên> hỏi DNS server, thường không đọc /etc/hosts. grep -n kdc.lab /etc/hosts thêm số dòng (-n) để dễ tìm vị trí cấu hình. resolvectl flush-caches xóa cache của systemd-resolved khi dịch vụ này đang được sử dụng; không cần chạy nếu máy không dùng nó.
curl -v http://127.0.0.1:8095/health, getent hosts api.kdc.lab, grep hosts /etc/nsswitch.conf, grep -n kdc.lab /etc/hosts./etc/hosts, dòng đầu tiên khớp tên sẽ thắng. Thêm dòng đúng ở cuối file không có tác dụng khi dòng cũ vẫn còn.Tạo ~/kdc-labs/rca/dns.md:
# RCA: kdc-poller timeout khi gọi api.kdc.lab
## Triệu chứng
## Evidence
## Nguyên nhân gốc
## Cách sửa
## Phòng tránh
Trong Phòng tránh, nghĩ về: ai được sửa /etc/hosts, vì sao nên dùng DNS nội bộ, và TTL/cache ảnh hưởng thế nào khi đổi bản ghi DNS thật.
getent hosts api.kdc.lab
journalctl -u kdc-poller -n 5 --no-pager
sudo cat /var/lib/kdc-poller/last-ok
journalctl -u kdc-poller lọc log theo unit (-u); -n 5 lấy năm dòng gần nhất, --no-pager in trực tiếp ra terminal. getent hosts tra cứu tên theo cấu hình hệ thống; cat đọc marker lần thành công.
Chọn server và bấm Kiểm tra kết quả.
dig và nslookup chỉ hỏi DNS server, bỏ qua /etc/hosts và cache cục bộ. Ứng dụng dùng thư viện hệ thống, nên getent hosts mới phản ánh đúng.systemd-resolved hoặc nscd, kết quả có thể bị cache; xóa cache sau khi sửa (resolvectl flush-caches).sudo systemctl disable --now kdc-poller.service kdc-api-v2.service
sudo rm -f /etc/systemd/system/kdc-poller.service /etc/systemd/system/kdc-api-v2.service
sudo systemctl daemon-reload
sudo sed -i '/api\.kdc\.lab/d' /etc/hosts
sudo rm -rf /opt/kdc-dns /var/lib/kdc-poller
sudo userdel kdc-poller; sudo userdel kdc-api-v2
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 /etc/hosts tại chỗ; /api\.kdc\.lab/d xóa dòng khớp hostname lab. userdel xóa các tài khoản lab.