쿠버네티스 네트워킹은 “Pod에 IP를 하나씩 준다”에서 시작해,
CNI로 연결을 자동화하고, Service/kube-proxy로 VIP(가상 IP)를 구현하고,
DNS로 이름 기반 통신을 만들고, Ingress로 L7 진입점을 정리,
마지막으로 Gateway API로 멀티테넌시/표준화된 라우팅 모델을 완성합니다.
0) 전체 큰 그림
쿠버네티스 네트워킹을 기능별로 나누면 이렇게입니다.
- Pod 네트워킹(데이터 플레인)
- Pod마다 고유 IP
- Pod ↔ Pod (같은 노드/다른 노드) 통신 보장
- NAT 없이 “Pod IP 그대로” 통신
- CNI + IPAM(자동화/주소 관리)
- Pod 생성/삭제 시 네트워크 연결 작업을 자동으로 수행
- IP 중복 없이 할당/회수
- Service 네트워킹(kube-proxy)
- Service IP(ClusterIP)는 “실재하는 인터페이스 IP”가 아니라 가상 VIP
- kube-proxy가 iptables/ipvs 규칙을 만들어 Service → Pod로 바꿔치기(DNAT)
- 클러스터 DNS(CoreDNS)
service.namespace.svc.cluster.local같은 규칙으로 이름 해석- Pod는 기본적으로 “이름=PodName” 레코드가 아니라, 옵션에 따라 “IP 기반 레코드”
- Ingress(L7 진입점)
- 외부 트래픽을 HTTP(S) 기준으로 서비스들에 라우팅
- TLS/경로 기반 분기/리라이트 등
- Gateway API(차세대 표준 라우팅 + 멀티테넌시)
- GatewayClass/Gateway/Route로 역할 분리
- annotation 의존을 줄이고, 표준 스펙으로 고급 라우팅 제공
1) Pod 네트워킹: “Pod마다 IP 하나”를 어떻게 현실로 만들까?
쿠버네티스가 기대하는 Pod 네트워킹 요구사항은 단순하지만 강력합니다.
- 모든 Pod는 고유한 IP를 가져야 한다.
- 같은 노드의 Pod끼리 Pod IP로 통신 가능해야 한다.
- 다른 노드의 Pod끼리도 Pod IP로 통신 가능해야 한다.
- 그리고 가능하면 NAT 없이 이 조건을 만족하라.
쿠버네티스는 “이걸 어떻게 구현할지”는 직접 제공하지 않고, 요구사항만 제시합니다. (그래서 CNI 플러그인들이 존재)
1.1 노드 내부: 네트워크 네임스페이스 + veth + bridge
컨테이너(=Pod)가 만들어지면, Linux 관점에서는 보통 이런 형태가 됩니다.
- Pod마다 네트워크 네임스페이스(netns) 생성
- 호스트와 Pod netns 사이를 veth pair(가상 케이블)로 연결
- 호스트 쪽 veth들을 bridge에 붙여 L2 네트워크를 구성
- Pod netns 안쪽 veth에 IP를 주고, default route를 bridge 쪽 게이트웨이로 설정
개념적으로는 이런 그림입니다.
[Pod(netns)] veth0 -- veth-host ----(bridge cni0 같은)---- (host)
IP: 10.244.1.2/24 GW: 10.244.1.1
네임스페이스 ping 문제에서 중요한 포인트: IP 설정할 때 NETMASK(/24 등) 를 제대로 주지 않으면 라우팅/ARP가 꼬일 수 있습니다.
예:ip -n red addr add 192.168.1.10/24 dev veth-red
또한 실습 환경에서 통신이 안 되면, FirewallD/iptables 정책이 네임스페이스 트래픽을 막는 경우가 많습니다.
1.2 노드 간: 라우팅(또는 오버레이)로 “10.244.0.0/16”을 하나로 묶기
노드마다 Pod CIDR을 따로 준다면 예를 들어:
- Node1:
10.244.1.0/24 - Node2:
10.244.2.0/24 - Node3:
10.244.3.0/24
이때 Node1의 Pod(10.244.1.2)가 Node2의 Pod(10.244.2.2)로 가려면,
Node1이 “10.244.2.0/24는 Node2로 가라”는 라우팅 정보를 알아야 합니다.
단순한 방식은 각 노드에 static route를 넣는 것:
# Node1에서: 10.244.2.0/24는 Node2(192.168.1.12)로
ip route add 10.244.2.0/24 via 192.168.1.12
하지만 노드/Pod가 수백/수천이면, 이 방식은 라우팅 테이블이 커지고 운영이 불가능해집니다.
그래서 실제 CNI 솔루션들은 보통:
- 라우팅을 자동으로 전파(BGP 등)하거나
- 오버레이(캡슐화) 로 “노드 간 네트워크를 하나처럼” 보이게 합니다.
2) CNI: 이 모든 과정을 누가 “자동으로” 해주나?
여기서 CNI(Container Network Interface)가 등장합니다.
- 쿠버네티스(정확히는 노드의 런타임/에이전트)가
- “Pod 만들었으니 네트워크 연결해라”를 표준 방식으로 플러그인에게 요청할 수 있게 만든 규격
2.1 왜 kubelet runtime endpoint 질문이 중요했나?
실습에서 자주 나오는 질문:
“Inspect the kubelet service and identify the container runtime endpoint value…”
이게 중요한 이유는:
- CNI 플러그인을 실제로 실행하는 주체는 “컨테이너 런타임” 계층이기 때문입니다.
- kubelet은 CRI를 통해 containerd/cri-o 같은 런타임에게 “컨테이너 만들기”를 시키고,
- 런타임은 설정된 CNI를 통해 “네트워크 붙이기(Add)”를 호출합니다.
즉, runtime endpoint는 “내 클러스터가 실제로 어떤 런타임을 통해 Pod 생성/네트워크 구성을 트리거하는지”를 확인하는 열쇠입니다.
트러블슈팅할 때도 런타임이 바뀌면 CNI 동작 지점과 로그/설정 위치가 달라질 수 있습니다.
2.2 “이 클러스터는 어떤 CNI 플러그인을 쓰나?”가 중요한 이유
CNI 플러그인은 곧 Pod-to-Pod 연결 방식(라우팅/오버레이/IPAM/NetworkPolicy 지원 여부) 를 결정합니다.
확인 루틴은 다음이 실무적으로 가장 빠릅니다.
# 1) 설치된 CNI(대부분 DaemonSet)
kubectl get pods -A | grep -E "calico|cilium|flannel|weave|antrea"
# 2) 노드에서 CNI 설정 파일(환경에 따라 접근 방식 다름)
ls /etc/cni/net.d/
ls /opt/cni/bin/
그리고 CNI 설정 파일(/etc/cni/net.d/*.conf 또는 *.conflist)에서
- 어떤 plugin(type)이 사용되는지,
- IPAM이 host-local인지, dhcp인지,
- 어떤 CIDR을 쓰는지 확인합니다.
여러 파일이 있으면 “알파벳 순으로” 선택되는 케이스가 실습/환경에 따라 존재할 수 있으니, 실제로는 conflist 우선/설정 방식은 배포 도구에 따라 확인이 필요합니다.
3) IPAM: Pod IP는 누가, 어디서 관리하나?
Pod IP 관리의 책임은 “쿠버네티스”가 아니라 CNI 플러그인(또는 그 IPAM 플러그인) 입니다.
강의의 핵심 포인트:
- “IP 중복 없이 할당/회수”만 잘 되면 Kubernetes는 방식에 크게 관여하지 않음
- 로컬 파일로 IP 사용 현황을 관리할 수도 있고,
- CNI가 제공하는 IPAM 플러그인(host-local, dhcp 등)에게 위임할 수도 있음
3.1 host-local IPAM의 핵심
- 노드 로컬에서 IP 풀을 관리(파일 기반)
- 노드가 관리하는 Pod들에 대해 “중복 없는 IP 할당”을 보장
CNI config의 iPam 섹션에서 보통 이런 형태가 등장합니다.
{
"ipam": {
"type": "host-local",
"subnet": "10.244.1.0/24",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
4) Weave 같은 오버레이 CNI는 라우팅 문제를 어떻게 풀까?
우리가 수동으로 했던 방식은 “각 노드 라우팅 테이블에 모든 Pod CIDR을 등록”하는 방식이었고,
큰 규모에서 비현실적입니다.
Weave Net(예시 CNI)의 설명 흐름은 다음과 같습니다.
- 각 노드에 Weave peer(에이전트) 를 배치(보통 DaemonSet)
- peer들이 서로 통신하며 토폴로지를 공유(다른 노드의 Pod IP 정보 인지)
- Pod 간 트래픽이 다른 노드로 가야 하면,
- 패킷을 캡슐화(overlay) 해서 노드 간 네트워크로 보내고
- 목적지 노드에서 디캡슐화 후 해당 Pod로 전달
이 방식의 장점:
- 외부 라우터/노드 라우팅 테이블에 “Pod CIDR 전체”를 직접 관리하지 않아도 됨
- 노드 수가 늘어나도 비교적 확장 가능
5) NetworkPolicy: flannel은 안 된다던데, 다른 건?
핵심만 정리하면:
- NetworkPolicy는 “Kubernetes 리소스”지만, 실제로 enforced(차단/허용)를 수행하는 건 CNI 구현체입니다.
- 그래서 CNI가 NetworkPolicy를 구현하지 않으면, YAML을 써도 “동작하지 않는 것처럼” 보입니다.
실무적으로는:
- Calico, Cilium 같은 CNI는 NetworkPolicy(또는 확장 정책)를 적극 지원하는 편
- flannel은 전통적으로 “기본 네트워킹 제공”에 초점이고, NetworkPolicy는 별도 조합이 필요하거나 제한이 있는 구성들이 흔합니다.
결론:
- “보안/격리/제로트러스트”가 중요하면, CNI 선택 기준에 NetworkPolicy 지원을 반드시 포함해야 합니다.
6) Service 네트워킹: Service IP는 “실존”하는가?
이 파트는 쿠버네티스 네트워킹에서 가장 오해가 많은 지점입니다.
6.1 Service는 Pod처럼 “어딘가에 떠 있는 서버”가 아니다
- Pod는 netns/인터페이스/IP가 “실제”로 존재
- Service는 클러스터에 “오브젝트”로 존재하지만,
- Service IP에 대응되는 “프로세스/네임스페이스/인터페이스”는 없습니다.
그럼에도 Service IP로 접속이 되는 이유는?
6.2 kube-proxy가 “규칙을 깔아두기” 때문이다
kube-proxy는 Service가 생성/변경되면,
각 노드에 포워딩 규칙(iptables/ipvs 등) 을 설치합니다.
바꿔치기(DNAT)는 왜 하나?
Service의 핵심 목적은:
- Pod는 늘었다 줄었다 하고 IP도 바뀔 수 있음
- 그런데 클라이언트(다른 Pod)는 “DB”를 언제나 같은 주소로 접근하고 싶음
그래서 쿠버네티스는:
- Service IP(고정된 VIP) 를 클라이언트에게 주고,
- 실제 백엔드 Pod로는 kube-proxy가 설치한 규칙을 통해 목적지 주소를 바꿔치기 합니다.
예시 개념:
- Client →
10.103.132.104:3306(Service VIP) - 커널 iptables NAT 규칙에 의해
- 실제로는 →
10.244.1.2:3306(Pod IP) 로 전달
“실제 라우팅 주체가 프록시인가?”
iptables 모드 기준으로 정확히 말하면:
- kube-proxy가 매 요청을 “중간에서 프록시”하는 게 아니라
- kube-proxy는 커널에 규칙을 프로그래밍하고,
- 실제 패킷 포워딩/변환(DNAT)은 리눅스 커널(netfilter/iptables) 이 수행합니다.
즉:
- 제어면(control plane): kube-proxy(규칙 생성/삭제)
- 데이터면(data plane): 커널(규칙 적용, 실제 패킷 처리)
7) DNS: 같은 네임스페이스면 짧게, 다른 네임스페이스면 길게
DNS 파트에서 핵심 질문이 이거였습니다.
같은 네임스페이스면
web-server
다른 네임스페이스면web-server.apps
그 뒤의.svc.cluster.local은 언제 붙이냐?
정리하면:
7.1 기본 FQDN 규칙
Service의 정규 FQDN은 보통:
service-name.namespace.svc.cluster.local
예:
web-service.default.svc.cluster.localweb-service.apps.svc.cluster.local
7.2 왜 같은 네임스페이스면 짧게 되나?
Pod의 /etc/resolv.conf에는 보통 search 도메인이 들어갑니다.
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
그래서 같은 네임스페이스에서 web-service만 쳐도,
DNS가 자동으로 뒤를 붙여가며 질의합니다.
7.3 다른 네임스페이스면 web-service.apps가 필요한 이유
다른 네임스페이스의 서비스는 search 첫 후보로 안 잡히므로,
최소한 namespace까지는 명시해야 충돌 없이 정확히 찾습니다.
7.4 .svc.cluster.local은 “다른 노드/다른 클러스터라서” 붙이는 게 아니다
.svc.cluster.local은 클러스터 내부 DNS의 루트 도메인 관례(기본값)입니다.- 노드가 달라도 같은 클러스터면 동일 규칙.
- “다른 클러스터”는 애초에 DNS 영역이 다르거나 네트워크가 분리된 케이스가 대부분이라, 단순히 suffix를 붙인다고 해결되는 개념이 아닙니다.
7.5 CoreDNS 구현: kube-dns vs coredns 둘 다 있는 건가?
네 출력에서 관찰된 전형적 패턴:
- Pod는
coredns-...가 실제로 떠 있음(Deployment) - Service 이름은
kube-dns로 존재함(ClusterIP: 53/UDP,TCP)
즉,
- DNS 서버 구현체는 CoreDNS Pod
- kube-dns는 그 CoreDNS를 가리키는 Service 이름(호환 관례)
Pod 입장에서는 /etc/resolv.conf의 nameserver가 kube-dns Service IP를 가리키고,
그 트래픽이 CoreDNS Pod로 전달됩니다.
8) Ingress: 서비스와 뭐가 다르고, 왜 필요한가?
Service(NodePort/LoadBalancer)만으로도 외부 노출은 가능합니다.
하지만 운영 요구사항이 올라가면 급격히 복잡해집니다.
- 포트 숨기기(80/443)
- URL 경로 기반 라우팅(
/watch는 video,/wear는 apparel) - 도메인 기반 라우팅(
watch.my-online-store.com) - TLS(HTTPS) 중앙 처리
- 서비스 늘어날 때마다 LB를 늘리고 비용 증가 문제
Ingress는 이를 “클러스터 안에서”, “Kubernetes 리소스로”, “한 번의 외부 진입점으로” 정리합니다.
8.1 Ingress의 구성요소 2개
- Ingress Controller(nginx, traefik, HAProxy, …)
- Ingress Resource(규칙: host/path/backend)
Ingress 리소스만 만들고 컨트롤러가 없으면 동작하지 않습니다.
8.2 rewrite-target(리라이트)이 왜 필요했나?
실습에서 가장 흔한 함정:
- 사용자는
/watch로 들어오고 싶어서 Ingress에/watch → watch-service를 설정 - 그런데 백엔드 앱은
/watch라는 path를 모르고/만 제공
rewrite-target 없이 동작하면:
/watch요청이 백엔드에/watch로 그대로 전달 → 404
그래서 Ingress에서:
/watch로 들어온 요청을 백엔드에는/로 바꿔서 전달해야 합니다.
NGINX Ingress에서는 대표적으로:
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
9) 네임스페이스 운영: Ingress를 쓰면 더 중요해진다
Ingress를 도입하면 결국 host/path를 누가 소유하느냐가 운영의 핵심이 됩니다.
권장 구조(현실적인 운영 패턴):
- 인프라(컨트롤러) 전용 네임스페이스:
ingress-nginx - 앱 네임스페이스:
prod-store,prod-video(환경+도메인 조합 추천) - Ingress 규칙은 보통:
- 각 팀이 소유하는 서비스 네임스페이스에 두는 편이 RBAC/운영이 깔끔
- 단, “한 도메인/한 Ingress에 다수 팀이 얽히는 구조”라면 중앙 조율 정책 필요
TLS Secret은 네임스페이스 스코프이므로,
Ingress와 인증서 관리 전략(cert-manager 등)을 함께 설계해야 합니다.
10) Gateway API: Ingress의 한계를 “역할 분리 + 표준 스펙”으로 해결
Ingress의 대표적인 약점:
- 멀티테넌시: 여러 팀이 하나의 Ingress 리소스를 같이 편집해야 충돌
- 고급 기능: 컨트롤러별 annotation으로 흩어지고, 쿠버네티스가 검증 불가
- HTTP 위주: TCP/UDP/gRPC 등 확장 표현이 제한적
Gateway API는 이를 공식 프로젝트로 해결하려고 합니다.
10.1 3개의 오브젝트로 “3개의 페르소나” 분리
- GatewayClass: 인프라 제공자(어떤 컨트롤러/구현체를 쓸지)
- Gateway: 클러스터 운영자(리스너/포트/허용 라우트 범위)
- Route(HTTPRoute/TCPRoute/…): 앱 개발자(서비스별 라우팅 규칙)
예: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx
spec:
controllerName: nginx.org/gateway-controller
예: Gateway(Listener + allowedRoutes)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: nginx-gateway
namespace: default
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
예: HTTPRoute(경로 라우팅)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: basic-route
namespace: default
spec:
parentRefs:
- name: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /app
backendRefs:
- name: my-app
port: 80
10.2 Gateway API의 핵심 장점: annotation 없이 “스펙으로” 표현
- HTTP→HTTPS 리다이렉트:
RequestRedirect - Path rewrite:
URLRewrite - 헤더 조작:
RequestHeaderModifier/ResponseHeaderModifier - 트래픽 분할:
backendRefs.weight - 미러링:
RequestMirror
예: 트래픽 분할 80/20
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: traffic-split
spec:
parentRefs:
- name: nginx-gateway
rules:
- backendRefs:
- name: v1-service
port: 80
weight: 80
- name: v2-service
port: 80
weight: 20
이렇게 하면 “어디로 어떻게 보내는지”가 YAML만 봐도 드러나고,
컨트롤러가 달라져도(지원 범위 내라면) 일관되게 적용되도록 설계되었습니다.
10.3 L4/L7 확장
Ingress는 주로 HTTP 중심이지만,
Gateway API는 TCP/UDP/TLS/gRPC 같은 라우트 모델을 확장 가능한 형태로 제공합니다(컨트롤러 구현/지원 범위에 따라 다름).
11) 실전 점검/트러블슈팅 체크리스트
Pod 네트워크/CNI
kubectl get pods -A | grep -E "calico|cilium|flannel|weave|antrea"
ls /etc/cni/net.d/
ls /opt/cni/bin/
Service/kube-proxy (iptables 확인)
kubectl -n kube-system get pods | grep kube-proxy
# 노드에서:
iptables -t nat -L -n | grep <service-name>
DNS(CoreDNS/kube-dns)
kubectl -n kube-system get deploy,pod,svc | grep -E "coredns|kube-dns"
kubectl exec -it <pod> -- cat /etc/resolv.conf
kubectl exec -it <pod> -- nslookup web-service
Ingress
kubectl get ingress -A
kubectl describe ingress <name> -n <ns>
kubectl logs -n ingress-nginx deploy/<controller-deploy>
Gateway API
kubectl get crd | grep gateway.networking.k8s.io
kubectl get gatewayclass
kubectl get gateway -A
kubectl get httproute -A
kubectl describe gateway <name> -n <ns>
kubectl describe httproute <name> -n <ns>
12) 결론: 무엇부터 확실히 잡아야 하나?
네트워킹을 “순서대로” 제대로 이해하려면 이 순서가 가장 안정적입니다.
- Pod 네트워크 요구사항(Pod IP 고유 + Pod-to-Pod 전 구간 통신)
- CNI가 Pod 생성 시 네트워크를 어떻게 붙이는지(Add/Del)
- IPAM이 IP 중복을 어떻게 막는지
- Service VIP가 ‘실체 없음’에도 되는 이유(kube-proxy가 규칙 설치 → 커널 DNAT)
- DNS가 짧은 이름을 어떻게 FQDN으로 확장하는지(search domain)
- Ingress가 L7 진입점에서 운영 복잡도를 어떻게 줄이는지(TLS/라우팅/리라이트)
- Gateway API가 멀티테넌시/표준화/확장성을 어떻게 해결하는지
원하면, 이 총정리 글을 기반으로 (1) 실습용 미니 랩 시나리오(flannel 환경에서 어디까지 되는지, NetworkPolicy를 쓰려면 CNI를 무엇으로 바꿔야 하는지 포함)와 (2) 운영 표준 템플릿(네임스페이스/권한/RBAC/allowedRoutes/TLS 전략)을 “회사에서 그대로 쓰는 문서” 스타일로 추가 확장해줄 수 있습니다.
'CKA' 카테고리의 다른 글
| Design Kubernetes - Choosing Infrastructure (0) | 2026.01.06 |
|---|---|
| Design Kubernetes (0) | 2026.01.06 |
| Network - Gateway API (0) | 2026.01.05 |
| Network - Ingress (1) | 2026.01.05 |
| Network - Service Networking (0) | 2026.01.05 |