The Order of Triage, and Keeping Notes
한국어 원문으로 표시합니다.
한 줄 요약
장애 대응에서 실력 차이는 도구가 아니라 순서와 기록에서 난다. 순서가 있으면 같은 곳을 두 번 보지 않고, 기록이 있으면 다음 사람이 처음부터 시작하지 않는다.
왜 이게 필요했나
새벽 3시에 온 신고를 받으면 누구나 조급해진다. 조급하면 순서가 무너지고, 순서가 무너지면 "아까 확인했던가?" 라는 질문이 반복된다. 그래서 숙련자는 미리 정해 둔 순서를 기계적으로 따른다. 판단은 데이터를 모은 다음에 한다.
어떻게 동작하나
순서는 아래에서 위로 올라간다. 아래층이 깨졌으면 위층을 볼 필요가 없기 때문이다.
- 이름 —
getent hosts <이름>과dig +short <이름>을 나란히 실행한다. 두 결과가 다르면 그 차이가 곧 원인의 위치다. - 도달 —
ping -c 3 <IP>. 실패해도 곧바로 결론짓지 않는다. ICMP 차단일 수 있다. - 포트 —
nc -zv -w 2 <IP> <포트>. refused 인지 timeout 인지 반드시 구분해 적는다. 이 한 단어가 다음 조사 방향을 정한다. - 바인딩 — 대상 호스트에서
ss -ltnp | grep <포트>. Local Address 가127.0.0.1이면 거기서 끝이다. - 응답 —
curl -o /dev/null -s -w '...'. 상태 코드와 구간별 시간을 함께 본다.
각 단계에서 명령과 그 출력을 그대로 남긴다. "확인함" 이라고만 적힌 기록은 다음 사람에게 아무 가치가 없다. 반대로 명령과 출력이 붙어 있으면 다음 사람은 그 출력을 다시 읽고 다른 결론을 낼 수도 있다.
사후 보고서에는 최소한 이 다섯 가지가 있어야 한다.
| 항목 | 내용 |
|---|---|
| 증상 | 사용자가 실제로 본 것 (추측 아님) |
| 계층 | 어느 층에서 멈췄는가 |
| 원인 | 근거가 되는 명령 출력과 함께 |
| 조치 | 무엇을 어떻게 바꿨는가 |
| 재발 방지 | 같은 일이 다시 안 나게 하려면 |
계층별로 무엇을 두드리나
"안 된다" 를 좁히는 순서가 있습니다. 아래에서 위로 올라가면 한 단계마다 후보가 줄어듭니다.
| 층 | 확인 명령 | 여기서 실패하면 |
|---|---|---|
| 1. 이름 | getent hosts api.example.com |
DNS·/etc/hosts·검색 도메인 |
| 2. 경로 | ip route get 10.0.3.12 |
라우팅·기본 게이트웨이 |
| 3. 도달 | ping -c1 10.0.3.12 |
ICMP 가 막혔을 수도(실패해도 다음으로) |
| 4. 포트 | nc -zv 10.0.3.12 8080 또는 curl -v telnet://… |
방화벽·보안그룹·리스닝 안 함 |
| 5. 서비스 | curl -sv http://10.0.3.12:8080/healthz |
애플리케이션 |
3번에서 실패해도 멈추지 않는 것이 중요합니다. ICMP 는 흔히 막혀 있어 "ping 이 안 되니 네트워크 문제" 는 자주 틀립니다. 4번이 진짜 판정 입니다.
nc 의 결과는 세 가지로 갈리고 각각 뜻이 다릅니다.
- connected — 포트가 열려 있다. 문제는 5번 위에 있다.
- Connection refused — 패킷은 닿았고 아무도 안 듣고 있다. 서비스가 안 떴거나 다른 포트에 붙었다. 방화벽 문제가 아니다.
- timeout — 패킷이 사라졌다. 방화벽·보안그룹·라우팅 쪽이다.
이 셋을 구분하는 것만으로 조사 범위가 크게 갈립니다.
어디에 듣고 있는지 확인하기
Connection refused 가 나오면 서버 쪽에서 봅니다.
ss -ltnp | grep 8080
LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("app",pid=42,fd=3))
↑ 여기가 함정
127.0.0.1:8080 이면 자기 자신에서만 닿습니다. 컨테이너 안에서 curl localhost:8080 은 되는데 밖에서는 안 되는 전형적인 원인입니다. 0.0.0.0:8080
이나 [::]:8080 이어야 밖에서 붙습니다.
애플리케이션 설정에서 바인딩 주소를 고칩니다(--host 0.0.0.0, bind = "0.0.0.0").
포트 매핑을 아무리 고쳐도 이것이 틀리면 안 됩니다.
쿠버네티스에서 한 층 더
파드 사이가 안 될 때는 네트워크 정책을 먼저 의심합니다. 기본 차단(default deny) 이 걸린 네임스페이스에서는 정책에 적히지 않은 통신이 전부 timeout 입니다.
kubectl -n <ns> get networkpolicy
kubectl -n <ns> describe networkpolicy <이름> # from/to 를 읽는다
증상이 "가끔 된다" 면 정책이 아니라 엔드포인트 를 봅니다. 파드 셋 중 하나만 Ready 가 아니면 그 하나로 간 요청만 실패해, 밖에서는 간헐적 오류로 보입니다.
kubectl -n <ns> get endpoints <svc> # 주소가 몇 개 있나
현장에서 만나는 모습
원인이 하나라고 가정하는 것. 실제 장애는 원인이 둘 이상 겹쳐 있는 경우가 많다. 하나를 고치고 "안 낫네" 하고 다른 방향으로 가면 이미 고친 것까지 의심하게 된다. 그래서 각 층을 끝까지 확인하고 발견한 것을 모두 적어 두는 편이 결국 빠르다.
고친 뒤 검증을 안 하는 것. hosts 를 고쳤으면 getent 로 다시 확인하고, 바인딩을 고쳤으면 바깥 주소로 다시 두드려야 한다. 같은 명령으로 실패를 재현하고 성공을 확인하는 것이 조치의 마지막 단계다.
다음 실습에서 할 것
세 가지 결함이 동시에 걸린 장애를 받는다. 계층을 하나씩 좁혀 원인을 특정하고, 고치고, 정해진 형식으로 사후 보고서를 남긴다.