
사내에서 쿠버네티스 기반의 개발 환경을 구축하던 중, 예상치 못한 네트워크 문제를 마주한 적이 있습니다.
Pod에서 외부 DB 서버로의 통신이 이루어지지 않았습니다.
당시, 필요한 포트는 열려 있었고, 서비스도 정상적으로 기동 중이었으며, 도커 컨테이너도 문제없이 돌아가고 있었습니다.
문제를 좁혀보기 위해 양쪽에서 tcpdump를 통해 패킷을 확인해보았습니다.
아래는 그 당시 패킷을 캡처했던 화면입니다.

이 화면을 봤을 때, 저는 문제의 원인을 전혀 눈치채지 못했습니다.
오히려 “패킷은 잘 나가고 있는데 왜 안 들어가지?”라는 생각만 했고, 결국 문제 해결은 꽤 오래 걸렸습니다.
그때는 알지 못했습니다...
어느 인터페이스를 통해 나가고 있는가였다는 사실을 고려하지 못했다는 사실을요..
이번 글에서는 이때 알게 된 NIC(Network Interface Card)라는 개념과,
방화벽 설정에서 NIC가 어떤 영향을 주는지를 하나씩 풀어보려 합니다.
NIC는 "Network Interface Card"의 약자입니다.
여기서 Network Interface는 컴퓨터가 네트워크와 데이터를 주고받기 위한 논리적인 연결을 의미하고,
Card는 그 기능을 실제로 수행하는 물리적(또는 가상) 장치를 뜻합니다.
즉, NIC는 네트워크 통신을 위한 인터페이스와 이를 담당하는 장치를 아우르는 개념입니다.
"Network Interface"는 운영체제나 네트워크 스택 입장에서,
외부 네트워크와 통신하기 위한 논리적 통로입니다.
우리가 흔히 쓰는 curl, ping, ssh 같은 명령어들이
모두 이 네트워크 인터페이스를 통해 데이터를 송수신합니다.
실제 하드웨어일 수도 있고, 소프트웨어적으로 만들어진 가상 인터페이스일 수도 있습니다.
어떤 경우든 OS는 각 인터페이스마다 고유한 이름과 설정(IP, MTU 등)을 가지고 관리합니다.
위와 같이 각 인터페이스에는 MAC 주소(ether), 할당된 IP 주소(inet, inet6), 상태(status) 등이 포함됩니다.
IP와 Ports는 패킷의 목적지에 대한 주소일 뿐,
실제로 어떤 경로로 데이터를 보낼지, 어디서 받을지를 담당하는 것은 네트워크 인터페이스입니다.
ifconfig로 NIC를 확인해보자.macOS나 Linux 환경에서는 ifconfig 명령어를 통해 NIC 목록을 확인할 수 있습니다.
아래는 실제 macOS에서 확인한 NIC 중 일부입니다:
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether d6:17:d2:17:46:ff
inet6 fe80::c7b:25c0:92e4:da3b%en0 prefixlen 64 secured scopeid 0xb
inet 192.168.0.13 netmask 0xffffff00 broadcast 192.168.0.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
...
위에 출력된 lo0, en0 외에도 다양한 인터페이스가 존재하며,
각 인터페이스의 특징과 용도는 다음과 같이 정리해볼 수 있습니다:
| 인터페이스 | 간단 설명 | 구분 | 생성 조건 | 할당된 IP |
|---|---|---|---|---|
lo0 | 루프백 인터페이스 (자기 자신과 통신) | 가상 | 기본 포함 | 127.0.0.1 |
en0 | 활성화된 유선/무선 NIC (실제 통신) | 물리 | 기본 포함 | 192.168.0.13 |
bridge0 | 여러 NIC를 묶는 가상 브리지 | 가상 | 사용자 활동 시 생성 | (없음) |
awdl0 | AirDrop 등 Apple 기기 간 통신 | 가상 | 기본 포함 | fe80::b853:1ff:fe04:16af |
utun0 | 가상 터널 인터페이스 (VPN 등) | 가상 | VPN 시 생성 | fe80::df7d:86bc:82fc:7dc6 |
서버에는 종종 여러 개의 NIC가 붙어 있습니다.
예를 들어:
ens160은 외부망과 연결된 인터페이스 ens224는 내부망에 연결된 인터페이스처럼 각각 다른 네트워크에 연결되어 있을 수 있습니다.
이런 상황에서 서버가 어떤 NIC를 통해 패킷을 내보내느냐는 매우 중요한 문제가 됩니다.
같은 포트가 열려 있어도, 방화벽이 특정 NIC를 막고 있다면 통신이 되지 않을 수 있습니다.
앞서 본 패킷을 다시 봐볼까요?

IP와 포트는 정상적으로 보이고,
Flags [S]도 찍혀 있으니
“패킷이 잘 나가고 있네”라고 생각하기 쉬운 화면입니다.
하지만 NIC에 대해서 공부한 지금, 이상한 점이 보입니다.
외부 DB 서버에 보내야 하는 패킷이지만,
이 화면에는 실제 외부로 나가는 NIC가 등장하지 않습니다.
NIC를 기준으로 패킷을 다시 바라보게 되면서,
저는 문제의 원인이 DB 서버가 아니라 클러스터 전체의 외부 통신 차단일 수도 있다는
가정을 세우게 되었습니다.
그래서 DB 서버가 아닌, 전혀 다른 외부 IP인 8.8.8.8로 ping을 시도했습니다.
테스트는 netshoot pod에서 수행했습니다.
결과는 동일했습니다. 응답이 없었고,
ping 응답 메시지에는 Packet Filtered라는 문구가 포함되어 있었습니다.
이 부분에서 저는 방화벽에 의해 막혔을 가능성을 의심했고,
이에 관한 로그를 확인해보기 위해 /var/log/kern.log를 보았습니다.
기본적으로 firewalld 에 의해 걸러지는 패킷들에 대한 로그를 찍고 있지 않기 때문에
firewall-cmd --set-log-denied=all
를 하고 보았습니다. (로그를 모두 본 뒤에는 off 로 설정)
거기에는 다음과 같은 로그가 찍히고 있었습니다:
Apr 7 08:45:19 worker kernel: [12868.221898] "filter_FWD_public_REJECT:
"IN=cni0 OUT=enp2s0 PHYSIN=vethe05661cb
MAC=36:50:69:84:9b:2c:4e:65:15:1d:9d:92:08:00 SRC=10.244.2.2
DST=192.168.150.131 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=28423 DF PROTO=TCP
SPT=51670 DPT=8629 WINDOW=64860 RES=0x00 SYN URGP=0
이 로그를 통해 cni0 인터페이스에서 들어온 패킷이 enp2s0를 통해 나가려다,
방화벽(firewalld)에 의해 차단된 상황을 확인할 수 있었습니다.
결국, 해결책은 단순했습니다.
firewalld 설정에서 해당 NIC (enp2s0)를 허용 인터페이스로 추가한 것입니다.
enp2s0에 해당하는 인터페이스는 각 환경에 따라 다를 수 있습니다. 만약 비슷한 방법으로 문제해결을 시도하신다면 먼저 NIC 를 확인하시면 좋을 것 같아요!
firewall-cmd --zone=public --add-interface=enp2s0
위의 설정을 반영한 후 다시 ping을 시도하자,
외부 통신은 정상적으로 이루어졌고
문제의 DB 서버와도 연결이 가능해졌습니다.
이번 경험을 통해 네트워크에 대해 한층 더 깊이있게 알게 되었습니다. 개발자에게 기본 CS 지식이 얼마나 중요한지도 또 한번 몸소 체험할 수 있는 기회이기도 했어요! 😄
사실 문제 원인을 파악하는데 NIC 관점으로 보기까지 여러 시도를 했었어요. 하지만 문제의 원인을 정확히 짚자 해결은 정말 순식간이었던거 같아요!
위에서는 언급하지 않았지만 적절한 질문의 중요성도 느낄 수 있었어요. 원인 파악에 진전이 없을 때 패킷캡쳐를 보여주며 질문을 했었는데 바로 네트워크 인터페이스를 집어서 얘기하시더라구요! 이 덕에 문제 해결도 할 수 있었고 제가 앞으로 문제를 바라보는 시각도 넓힐 수 있게 되었습니다!