간단한 트러블슈팅 경험 공유를 위해 작성하였다.

문제 발생

문득 예전에 겪었던 한 가지 네트워크 이슈가 떠올랐다. 작은 웹 서비스 아키텍처를 구성하던 중, 특정 인스턴스에서만 DB 연결이 되지 않는 이상한 현상이 발생했던 상황이었다.

image.png

구성 자체는 단순했다. 하나의 VPC 내부에 퍼블릭 역할의 서브넷과 Private DB 서브넷이 존재했고, 여러 인스턴스 중 단 한 개의 인스턴스에서만 DB 연결 시 타임아웃이 발생했다. 흥미로운 점은 다른 인스턴스에서는 동일한 DB로의 연결이 모두 정상적이었다는 것이다.

image.png

처음에는 흔히 그렇듯 보안그룹이나 ACL 설정을 의심했다. 하지만 관련 포트는 이미 모두 오픈된 상태였고, 다른 인스턴스에서 접속이 되는 이상 단순 네트워크 정책 문제일 가능성은 낮아 보였다. 오히려 이 시점부터는 “클라우드 제품 문제라기보다 해당 인스턴스 내부에서 무언가 이상하게 동작하고 있겠다”는 생각이 강하게 들었다.

문제 해결 시도

수사의 기본은 사건 현장에서 가까운 것부터 하나씩 짚어보는 것 아니겠는가.

1) 기본 아키텍처 점검

우선 VPC, 서브넷, 라우팅, IAM 계열 설정 등을 전체적으로 점검했다. 특별히 이상한 부분은 발견되지 않았다.

2) 보안그룹 및 라우팅 테이블 점검

문제가 발생한 인스턴스와 DB 간의 보안그룹 설정도 확인했다.

  • 인스턴스 outbound 허용

  • DB inbound 허용

  • 포트 정상

  • ACL 기본값

모두 문제 없었다.

VPC 레벨 라우팅도 정상적으로 구성되어 있었고, 다른 인스턴스들이 동일한 DB에 접근 가능한 만큼 인프라 자체 문제일 가능성은 점점 낮아졌다.

3) DB 자체 설정 점검

DB 엔드포인트, 파라미터 그룹 등도 함께 살펴봤지만 특이사항은 없었다.

무엇보다 특정 인스턴스 한 대에서만 연결이 실패한다는 점이 계속 마음에 걸렸다.

상황 정리

트러블슈팅을 하다 보면 종종 이런 상황을 마주하게 된다. 분명 네트워크는 살아있고, 보안 정책도 맞고, DB도 정상인데, 유독 한 대만 말을 듣지 않는다. 이럴 때는 점점 “인프라”보다 “머신 내부”를 의심하게 된다. 비유하자면 이런 느낌이다. 건물 전체 수도는 정상이고, 모든 층에서 물이 잘 나오는데, 유독 303호만 수도가 안 나온다. 배관도 정상이고 물탱크도 정상인데, 딱 한 집만 문제인 상황. 그렇다면 이제는 건물 전체보다 303호 내부를 의심해봐야 한다.

패킷 분석

다시 상황으로 돌아와서, 이쯤되니 문제의 인스턴스에서 무슨 일이 일어나고 있는지 궁금해졌다.

tcpdump -i eth0 -n host <TDB IP>

먼저 일단 인스턴스에 접속해서 패킷을 들여다보았다.

$ tcpdump -i eth0 -n host 10.0.2.100
10:21:00.686502 IP 10.0.1.10.ssh > <TDB IP>.5432: Flags [S], seq 4839923, win 29200, length 0

SYN패킷 요청은 있으나 응답 패킷이 없었다.

이번엔 문제의 인스턴스가 아닌 다른 인스턴스에서 패킷 모니터링을 해보니 응답이 정상적으로 오는 것을 확인했다. 해당 인스턴스내 에서 누군가 패킷을 가로채는 느낌이 들어 시스템 내부 라우팅 테이블을 확인해보니 의심가는 부분이 있었다.

$ route -n
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.1.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 docker0
10.0.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
10.0.1.1 0.0.0.0 255.255.255.0 U 0 0 0 eth0
10.0.1.2 0.0.0.0 255.255.255.0 U 0 0 0 eth0
10.0.2.0 0.0.0.0 255.255.192.0 U 0 0 0 br-3887aidc

시스템 라우팅 테이블에서 도커 브릿지가 보였다. 잡았다 요놈..

문제 해결

원인은 머신 내부에 생성된 Docker bridge network였다. 도커 브릿지가 사용 중이던 대역이 DB가 위치한 Private 대역과 겹치면서, DB로 향해야 할 트래픽이 잘못된 브릿지 인터페이스로 라우팅되고 있었던 것이다. 즉 패킷은 정상적으로 SYN을 보내고 있었지만, 실제로는 목적지 DB까지 도달하지 못하고 로컬 Docker bridge 내부에서 길을 잃고 있었다. 문제 원인을 확인한 뒤 브릿지 네트워크 대역을 변경했고, 이후 DB 연결은 정상적으로 복구되었다.

마치며

특히 Docker bridge, VPN interface, tun/tap, local route 같은 요소들은 의외로 조용히 트래픽을 가로채는 경우가 많다. 그리고 tcpdump 한 줄은, 복잡한 추측보다 훨씬 빠르게 진실에 가까워지게 만들어준다.

끝.