14. 상황별 진단 플레이북
앞의 장들이 도구라면, 이 장은 어떤 순서로 꺼내 쓰는가다
이 장에서 처음 나오는 말3개
MTTRMean Time To Recovery- 장애가 나서 복구되기까지의 평균 시간. 원인 규명보다 복구가 먼저라는 원칙이 여기서 나온다 — 증거를 남기고 서비스를 살린 뒤 원인을 판다.
이머전시 모드emergency mode- 부팅 중 치명적 문제(대개
/etc/fstab오류)로 systemd가 최소 셸만 띄운 상태. 네트워크가 없어 콘솔 접근이 필수다. recovery mode- GRUB 메뉴에서 고를 수 있는 복구 부팅. root 셸·파일시스템 검사·네트워크 활성화 같은 메뉴를 준다 — 물리/가상 콘솔이 있어야 쓸 수 있다.
접속 직후 30초 점검
섹션 제목: “접속 직후 30초 점검”무슨 신고를 받았든 이 다섯 줄을 먼저 친다. 여기서 이미 답이 나오는 경우가 많다.
uptime # load average, 그리고 얼마 전에 재부팅됐는지df -h | grep -v tmpfs # 꽉 찬 파일시스템free -h # availablesystemctl --failed # 실패한 유닛journalctl -p err -b --no-pager | tail -20 # 이번 부팅의 오류1. “서버가 느려요”
섹션 제목: “1. “서버가 느려요””-
어느 자원인지 가른다
터미널 창 uptime # load를 코어 수(nproc)와 비교vmstat 1 5us/sy높음 → CPU ·wa높음 → 디스크 ·si/so있음 → 메모리 ·st높음 → 하이퍼바이저에 뺏기는 중(4장) -
범인 프로세스를 찾는다
터미널 창 ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -10ps -eo pid,user,rss,%mem,cmd --sort=-rss | head -10sudo iotop -o # I/O가 원인일 때 -
자원이 아니라 대기라면 — CPU도 디스크도 한가한데 느리다면 네트워크나 외부 의존이다
터미널 창 ss -s # 소켓 수, TIME-WAIT 폭증 여부curl -o /dev/null -s -w 'dns=%{time_namelookup} conn=%{time_connect} total=%{time_total}\n' https://외부API/8장의 시간 분해가 여기서 다시 쓰인다.
-
최근에 뭐가 바뀌었는지 본다 — 대개 여기에 답이 있다
터미널 창 grep -E "install|upgrade" /var/log/apt/history.log | tail -20sudo find /etc -mtime -3 -type f -ls
2. “디스크가 찼어요”
섹션 제목: “2. “디스크가 찼어요””-
df -h— 어느 파일시스템인가. 그리고df -i— inode는 아닌가(3장) -
sudo du -xh --max-depth=1 /경로 | sort -rh | head로 층을 내려간다 (또는sudo ncdu -x /) -
du합계와df사용량이 다르면sudo lsof +L1— 삭제됐는데 열려 있는 파일 -
흔한 범인 넷을 순서대로 확인한다
터미널 창 journalctl --disk-usage # 저널 (상한이 기본으로 없다 — 6장)sudo du -sh /var/log/* | sort -rh | headdocker system df # 도커 이미지·볼륨·빌드 캐시sudo du -sh /var/cache/apt /var/lib/snapd/snaps -
급하면 안전한 것부터 비운다
터미널 창 sudo journalctl --vacuum-time=7dsudo apt clean && sudo apt autoremove --purgedocker system prune # 내용을 확인하고 실행한다
rm 대신 truncate -s 0 을 쓰는 습관이 3번을 예방한다.
3. “서비스가 안 떠요”
섹션 제목: “3. “서비스가 안 떠요””-
상태와 로그를 나란히
터미널 창 systemctl status myappjournalctl -u myapp -b --no-pager | tail -50 -
설정 문법 검사 — 있는 것은 반드시 쓴다
터미널 창 sudo nginx -t ; sudo sshd -t ; sudo netplan try -
포트 충돌 —
Address already in use터미널 창 sudo ss -tulpn | grep :8080 -
권한 —
Permission denied터미널 창 namei -l /opt/myapp/config.yml # 경로 각 단계의 권한 (10장)sudo journalctl -k | grep -i apparmor # AppArmor 차단 (13장) -
설정이 진짜 적용됐는지
터미널 창 systemctl cat myapp # 원본 + drop-in 합본sudo tr '\0' '\n' < /proc/$(systemctl show -p MainPID --value myapp)/environ -
재시작 루프라면 —
Restart=always가 실패를 감추고 있을 수 있다터미널 창 systemctl show myapp -p NRestartsjournalctl -u myapp --since "10 min ago" | grep -c "Started"
4. “SSH 접속이 안 돼요”
섹션 제목: “4. “SSH 접속이 안 돼요””먼저 접속하는 쪽에서 층을 가른다(8장).
| 클라이언트에서 본 증상 | 뜻 | 다음 |
|---|---|---|
ssh: connect … Connection refused | 패킷은 도착. sshd가 안 떠 있다 | 콘솔로 systemctl status ssh |
| 응답 없이 타임아웃 | 경로/방화벽에서 버려지는 중 | ufw · 보안그룹 · 라우팅 |
Permission denied (publickey) | 접속은 됨. 인증 실패 | 서버의 auth.log |
| 비밀번호를 물어봄 (키를 넣었는데) | 키가 거부됨 | ~/.ssh 권한(700/600) |
Connection reset 직후 끊김 | fail2ban 밴 또는 MaxStartups | fail2ban-client status sshd |
서버 쪽에 (콘솔이나 다른 경로로) 들어갈 수 있다면 —
systemctl status sshsudo ss -tulpn | grep sshdsudo sshd -t # 설정 문법 — 여기서 실패하면 sshd가 안 뜬다sudo journalctl -u ssh -n 50sudo tail -50 /var/log/auth.logsudo fail2ban-client status sshd # 내 IP가 밴됐나5. “부팅이 안 돼요”
섹션 제목: “5. “부팅이 안 돼요””콘솔(물리·IPMI·하이퍼바이저 화면)이 필요하다. SSH로는 할 수 있는 것이 없다.
| 화면 | 원인 | 대처 |
|---|---|---|
| GRUB 메뉴도 안 나옴 | 부트로더·디스크 | 펌웨어 부팅 순서, 복구 미디어 |
emergency mode 셸 | 대개 /etc/fstab 오류 | journalctl -xb, fstab 수정 후 mount -a. 예방은 nofail(3장) |
| 특정 유닛에서 멈춤 | 서비스가 시작을 붙잡는 중 | systemd-analyze critical-chain, 해당 유닛 disable/mask |
| 2분씩 멈췄다 진행 | network-online.target 대기 | 5장 |
| 파일시스템 오류 | 비정상 종료 | recovery mode → fsck -f /dev/… (반드시 언마운트 상태에서) |
부팅에 성공한 뒤 원인은 직전 부팅 로그에서 찾는다 — journalctl -b -1 -e.
6. “메모리가 부족해요”
섹션 제목: “6. “메모리가 부족해요””free -h # available만 본다 (2장)ps -eo pid,user,rss,%mem,cmd --sort=-rss | headsudo journalctl -k | grep -i -E "out of memory|killed process"swapon --show ; vmstat 1 5 # 스왑을 쓰고 있나systemctl show myapp -p MemoryMax -p MemoryCurrent프로세스가 흔적 없이 사라졌다면 OOM killer다(4장).
근본 대처는 셋 — 메모리 증설, 앱의 힙 상한 조정,
유닛에 MemoryMax=를 걸어 한 프로세스가 서버 전체를 흔들지 못하게 하기.
7. “왜 이렇게 됐는지 모르겠어요”
섹션 제목: “7. “왜 이렇게 됐는지 모르겠어요””변경 이력을 훑는 순서다(11장).
last -F -a | head -20 # 누가 들어왔나sudo grep COMMAND /var/log/auth.log | tail -50 # 무슨 sudo 명령을 썼나grep -E "install|remove|upgrade" /var/log/apt/history.log | tail -20sudo find /etc -mtime -3 -type f -ls # 최근 바뀐 설정 파일journalctl --since "3 days ago" | grep -iE "Started|Stopped|Failed" | tail -40last reboot | head대응의 순서 — 복구가 먼저다
섹션 제목: “대응의 순서 — 복구가 먼저다”재시작하면 증거가 사라진다. 재시작 전에 30초만 써서 상태를 남긴다.
TS=$(date +%F-%H%M){ date; uptime; free -h; df -hT; ps auxf; ss -tulpn; systemctl --failed; } \ | sudo tee /var/tmp/snapshot-$TS.txtsudo journalctl -b --no-pager > /var/tmp/journal-$TS.log14장 요약
섹션 제목: “14장 요약”- 접속 직후
uptime·df -h·free -h·systemctl --failed·journalctl -p err -b - 느림은
vmstat 1로 CPU / 디스크(wa) / 메모리(si·so) / steal 을 가르는 것부터 - 디스크는
df -h→df -i→du -x→lsof +L1 - 서비스는
status+journalctl -u -b+ 문법 검사기(-t) + 포트 충돌 - SSH는 클라이언트에서 refused / timeout / publickey 를 먼저 가른다
- 부팅 실패는 콘솔이 필요하다 —
emergency mode면 fstab을 먼저 의심 - 복구 전에 스냅숏을 남긴다 — 재시작은 증거를 지운다