K8s Networking - 04. calico
Calico가 BGP로 Pod를 잇는 법 — 그리고 WireGuard가 가져온 변화
한 클러스터가 두 데이터센터에 걸쳐 있었다. 트래픽이 노드 간에 평문_으로 흘렀다. 보안 팀이 "Pod 통신을 암호화하라"고 요구했다. 팀은 Calico의 WireGuard 모드를 켰다 — 노드 간 Pod 트래픽이 커널 수준에서 암호화됐다. 코드 한 줄 안 고치고. 이것이 Calico를 *네트워크 플러그인 이상으로 쓰는 사례다.
이 글이 푸는 것은: Calico가 03장의 두 접근(오버레이/언더레이)을 BGP와 IPIP/VXLAN 모드로 어떻게 구체화하고, WireGuard로 암호화를 어떻게 덧붙이는가다. 그리고 왜 Calico가 "CNI 하나"가 아니라 "CNI + 정책 엔진" 두 역할인지.
03장의 연장선에서 Calico 보기 — 두 모드와 정책
03장에서 CNI의 두 근본 접근을 봤다 — 오버레이(캡슐화)와 언더레이(직접 라우팅). Calico는 그 두 접근을 모두 모드로 제공하면서, 거기에 한 가지를 더 얹는다: 고급 네트워크 정책.
flowchart TD
CAL["Calico"] --> DP["데이터플레인 (CNI)<br/>IPAM + 라우팅"]
CAL --> PE["정책 엔진<br/>NetworkPolicy + CRD(고급)"]
DP --> M1["모드: BGP / IPIP / VXLAN<br/>+ WireGuard(암호화)"]
PE --> L["L3/L4/L7 격리"]
이 "데이터플레인 모드"와 "정책"이 _독립_이라는 게 Calico의 핵심 설계다. 데이터플레인은 VXLAN으로, 정책은 CRD 고급 모드로 — 각각 따로 고른다. 그래서 "Calico 깔았다"가 아니라 "어느 모드로"까지 봐야 한다. 이 글은 데이터플레인에 집중하고, 정책은 07장에서.
BGP 모드 — 03장의 언더레이를 Calico가 구현하는 법
03장에서 언더레이는 "물리 라우터에게 Pod 대역을 가르쳐준다"였다. Calico는 이걸 BGP(Border Gateway Protocol)로 구현한다 — 각 노드가 BGP로 이웃(다른 노드 또는 TOR 라우터)에게 "내 노드엔 10.244.1.0/24 Pod 대역이 있다"고 광고하면, 모든 노드가 _모든 Pod 대역으로 가는 경로_를 학습한다. (Calico docs - Networking)
flowchart LR
N1["노드1<br/>10.244.1.0/24"] -. "BGP 광고<br/>나는 10.244.1.0/24를 가짐" .-> N2["노드2<br/>10.244.2.0/24"]
N1 -->|"Pod 패킷 그대로"| R["물리 라우터/스위치"]
R --> N2
캡슐화 없이 Pod 패킷이 그대로 전달되므로, 성능·가시성이 좋다. tcpdump로 패킷을 보면 Pod IP가 그대로 보인다 — 디버깅이 쉽다. CPU 오버헤드도 없다(캡슐화/캡슐해제 연산이 없으니까).
제약: 물리 네트워크가 BGP를 지원·허용해야 한다. 클라우드 VPC는 보통 노드 간 BGP를 막거나 제한한다(클라우드 라우터는 사용자 정의 라우팅을 허용하지 않음). 그래서 클라우드에선 BGP 대신 IPIP/VXLAN 모드로 간다. 온프렘 베어메탈이나 자체 데이터센터에서 BGP가 빛을 발한다.
BGP 토폴로지 — 대규모에서 피어가 폭증한다
BGP 모드가 대규모에서 부딪히는 벽은 _토폴로지_다. 가장 단순한 구성은 full mesh — 모든 노드가 모든 노드와 BGP 피어를 맺는다. 노드 N개면 피어 연결이 N×(N-1)/2개. 노드 100개면 ~5000개의 피어, 노드 1000개면 비현실적이다. (Calico docs - BGP route reflectors)
그래서 대규모에선 route reflector(RR) 패턴을 쓴다 — 몇 개의 노드(또는 전용 RR)가 중계 역할을 맡는다. 모든 노드가 RR하고만 피어를 맺고, RR이 라우팅 정보를 모아 전파. 피어 수가 선형으로 줄어든다.
이 토폴로지 설계가 "BGP 모드를 대규모에서 쓸 수 있는가"의 핵심이다. full mesh는 소규모(수십 노드)까지. 그 이상은 RR 또는 아예 VXLAN으로. 이 결정을 안 하면 노드 추가 시 BGP 피어가 폭증해 통신이 불가능해진다.
IPIP / VXLAN 모드 — 03장의 오버레이를 Calico가 구현하는 법
BGP가 안 되는 환경(클라우드 등)에서는 03장의 오버레이(캡슐화)로 돌아간다. Calico는 두 캡슐화 형식을 지원한다:
- IPIP(IP-in-IP): Pod 패킷을 추가 IP 헤더 하나로 감쌈. 단순하지만 일부 클라우드(AWS)가 지원하지 않는다.
- VXLAN: Pod 패킷을 UDP로 감쌈. 범용. 대부분의 클라우드에서 동작.
BGP 모드: [Pod IP 헤더][페이로드]
IPIP: [노드 IP 헤더][Pod IP 헤더][페이로드]
VXLAN: [노드 IP][UDP][VXLAN][Pod 이더넷][페이로드]
캡슐화 모드는 어디서든 동작하지만 오버헤드가 있다. Calico 모드 선택의 기준은 단순하다 — "물리 네트워크가 BGP를 허용하는가?" 허용하면 BGP(성능·가시성), 아니면 캡슐화(범용성).
WireGuard 모드 — 라우팅 위에 암호화를 얹다
도입의 사례로 돌아가자. 보안 팀이 "Pod 통신을 암호화하라"고 했다. 전통적 해법은 애플리케이션에 mTLS를 넣거나 서비스 메시를 까는 것이었는데, 둘 다 코드나 인프라 변경이 크다. Calico는 WireGuard(커널 수준의 가벼운 VPN)를 데이터플레인 위에 얹어, 노드 간 Pod 트래픽을 코드 변경 없이 암호화한다. (Calico docs - WireGuard 암호화)
중요한 점: WireGuard는 BGP/VXLAN 모드와 함께 쓴다. "BGP로 라우팅하되 WireGuard로 암호화" — 라우팅 모드를 바꾸지 않고 암호화만 덧붙이는 계층.
- 장: 코드 변경 없이 Pod 통신 암호화. 커널 수준이라 빠르다. 규정(PCI-DSS, HIPAA 등)의 "전송 구간 암호화" 요구를 충족.
- 단: 노드 간에만 암호화. 같은 노드 안 Pod 통신은 암호화되지 않는다(로컬 브리지를 거치므로). WireGuard 커널 모듈 의존.
# Calico WireGuard 활성화 (Calico 설치 후, felixConfiguration)
kubectl patch felixConfiguration default --type='merge' -p '{"spec":{"wireguardEnabled":true}}'
정확한 활성화 명령/지원 버전은 Calico docs에서 실측. 1.36 호환 Calico 버전 명시 필요.
WireGuard가 IPsec 같은 기존 암호화 대비 가벼운 이유: 단순한 현대 암호학(ChaCha20-Poly1305) + 커널 통합. (WireGuard) 성능 손실이 적으면서 규정을 충족할 수 있어, Calico가 IPsec 대신 WireGuard를 택했다.
IPAM — 왜 블록 기반인가, 라우팅 집약를 위해
왜 Calico IPAM이 블록 기반*일까? *라우팅 집약 때문이다. BGP 모드에서 노드 1000개가 각자 자기 Pod IP를 개별적으로 광고하면 라우팅 테이블이 폭발한다. Calico는 각 노드에 CIDR 블록(예: /24)을 할당하고, 그 블록에서 Pod IP를 준다 — 블록이 가득 차면 새 블록을 요청. Calico는 IP 풀(IPPool CRD)로 전체 대역과 블록 크기를 관리한다. (Calico docs - IPAM)
이 블록 설계가 _라우팅 집약_을 가능하게 한다. 각 노드가 /24 블록 하나만 BGP로 광고하므로, 노드 1000개여도 라우팅 테이블이 /24 단위 1000줄로 줄어든다 — Pod별 라우팅이 아니라 블록별. 03장의 host-local IPAM보다 정교한 블록 관리가 BGP 모드의 전제다.
블록 모델이 만드는 흥미로운 특성: Pod가 같은 노드에서 재시작되면 _같은 IP 블록_에서 IP를 받을 확률이 높다(블록이 노드에 _affinity_를 갖기 때문). 이것이 어느 정도의 IP "안정성"을 준다(완전한 고정은 아님). 반면 Pod가 다른 노드로 재스케줄되면 다른 블록의 IP를 받는다. 완전한 IP 고정이 필요하면 StatefulSet이 별도로 필요하다.
아키텍처 — felix, typha, bird가 각각 무슨 일을 하나
Calico는 여러 컴포넌트로 이루어진다. 각자 무슨 일을 하는지, 왜 필요한지 보자.
flowchart TD
APIS["kube-apiserver"] --> TC["typha<br/>(스케일, 중개)"]
TC --> F1["felix (노드1)<br/>라우팅/iptables 규칙"]
TC --> F2["felix (노드2)"]
F1 --> BIRD1["bird (BGP 데몬, 노드1)"]
F2 --> BIRD2["bird (BGP 데몬, 노드2)"]
BIRD1 <-. BGP 피어 .-> BIRD2
- felix: 각 노드의 에이전트. 라우팅/iptables/정책 규칙을 커널에 깐다. 데이터플레인을 실제로 프로그래밍하는 주체.
- bird(선택): BGP 데몬. 노드 간 BGP 피어링. felix가 라우팅 정보를 bird에게 넘기면 bird가 BGP로 광고.
- typha(대규모): felix가 apiserver를 직접 watch하지 않게 중개해 apiserver 부하를 감소. (Calico 아키텍처)
- kube-controllers: 클러스터 수준 컨트롤러(IPAM 등).
typha의 역할을 03장 관점에서 보면 명확하다 — felix N개가 각자 apiserver를 watch하면 apiserver 부하가 N배. typha가 한 번 watch해 felix들에게 중개하면 apiserver 부하가 1배. 대규모 클러스터(수백 노드 이상)의 필수 컴포넌트. 이것이 "CNI도 규모 대응 설계가 필요하다"는 사례다.
Calico eBPF 모드 — kube-proxy까지 대체하는 옵션
여기까지 Calico의 데이터플레인은 iptables 기반이었다. Calico는 eBPF 데이터플레인 모드도 지원한다 — iptables 대신 eBPF로 Service 라우팅·정책을 처리. 이점은 05장 Cilium과 같은 맥락이다: 대규모에서 iptables 병목(규칙 순차 탐색)을 회피한다. (Calico docs - eBPF dataplane)
이것이 "Calico는 iptables, Cilium은 eBPF"라는 단순화가 틀린 이유다. Calico도 eBPF 모드가 있어, iptables의 Calico와 eBPF의 Calico는 다른 데이터플레인_이다. 차이가 있다면 Cilium은 eBPF를 기본/주력으로 하는 반면, Calico는 iptables가 기본이고 eBPF가 옵션이라는 점. 어느 쪽이든 "_현재 모드"가 데이터플레인의 성격을 결정한다.
BGP graceful restart — 노드 재부팅 중에 라우팅이 끊기면
BGP 모드에서 한 노드가 재부팅되면 — 그 노드의 BGP 세션이 끊기고, 다른 노드들이 "10.244.1.0/24로 가는 경로가 사라졌다"고 판단해 트래픽을 드롭한다. BGP graceful restart가 이 찰나를 완화한다:
- 노드가 BGP 세션을 의도적으로 끊을 때 "잠시 후 돌아온다"고 알린다.
- 다른 노드들이 일정 시간 그 경로를 유지한다(즉시 철회하지 않는다).
- 재부팅 후 세션이 복구되면 경로가 다시 활성화된다.
이것이 "유지보수 중 트래픽 손실 최소화"의 BGP 메커니즘이다. graceful restart가 없으면 노드 재부팅 찰나에 그 노드의 Pod로 향하던 트래픽이 드롭된다. Calico BGP 모드의 운영 품질에 영향을 주는 설정.
Calico 배포 방식 — operator vs manifest
Calico 설치에 두 방식이 있다:
- Tigera operator: Calico 전용 operator가 Calico 구성 요소를 관리. 선언적(
InstallationCRD). 업그레이드/설정 변경이 operator 경유. 권장. - 직접 manifest: YAML apply로 Calico 구성 요소를 직접 배포. 단순하지만 업그레이드/설정 변경이 수동.
operator가 권장되는 이유: Calico가 felix/typha/bird 등 여러 구성 요소 + IPPool/BGPConfiguration 등 CRD로 이루어져, operator가 이 _전체_를 일관되게 관리. 직접 manifest는 컴포넌트 간 버전 불일치 위험이 있다.
직접 확인하기 (CNI 교체 클러스터 필요)
기본 kind는 kindnetd CNI. Calico 테스트는
disableDefaultCNI: truekind config로 클러스터를 만든 뒤 Calico를 설치.k8s-verify스킬 참조.
# Calico 설치 후
kubectl get pods -n calico-system -o wide
kubectl get ippool -o yaml | grep -E 'cidr|ipipMode|vxlanMode'
확인할 것: IPPool의 ipipMode/vxlanMode/bgp 설정이 현재 모드를 알려준다.
# 노드 라우팅 테이블에서 Pod 대역 확인
docker exec <node> ip route | grep -E '10.244|tunl0|vxlan'
확인할 것: BGP 모드면 Pod 대역이 직접 경로로, IPIP/VXLAN이면 tunl0/vxlan.calico 인터페이스로 나타난다.
흔히 묻는 것, 흔히 틀리는 것
| 오해 | 정정 |
|---|---|
| "Calico는 항상 BGP다" | 모드에 따라 BGP/IPIP/VXLAN. 클라우드는 보통 VXLAN |
| "WireGuard 모드가 BGP를 대체한다" | 같이 쓴다. BGP로 라우팅 + WireGuard로 암호화 |
| "Calico는 CNI만 한다" | 정책 엔진도 |
| "IPIP와 VXLAN은 같다" | IPIP=IP헤더 1개, VXLAN=UDP+이더넷. 클라우드 호환성 다름 |
| "Calico IPAM은 동적 할당이다" | 블록 기반. 노드마다 블록 할당(라우팅 집약 목적) |
| "BGP는 클라우드에서 쓴다" | 반대. 온프렘 베어메탈에서 빛남. 클라우드는 VXLAN |
| "typha는 선택이라 안 써도 된다" | 소규모 생략 가능하나 수백 노드 이상에선 필수(apiserver 부하) |
| "WireGuard는 같은 노드 Pod도 암호화" | 아님. 노드 간만. 같은 노드는 로컬 브리지(평문) |
| "Calico는 iptables 고정이다" | eBPF 모드도 지원. 현재 모드가 데이터플레인 성격을 결정 |
요약 — 이 글의 결론
- Calico는 03장의 두 접근을 모두 구체화 — BGP(언더레이)와 IPIP/VXLAN(오버레이)을 모드로. 거기에 고급 정책을 독립적으로 얹는다.
- BGP 모드가 Calico 시그니처. Pod 대역을 물리 라우팅(캡슐화 없음, 성능/가시성 좋음). 단 BGP 지원 네트워크 필요 — 온프렘 빛, 클라우드 제약.
- BGP 토폴로지가 대규모 관건 — full mesh(소규모) vs route reflector(대규모). 토폴로지 설계 없이 노드 추가하면 BGP 피어 폭증.
- IPIP/VXLAN 모드로 클라우드에서도 동작(캡슐화). 어디서든 되지만 오버헤드.
- WireGuard 모드가 코드 변경 없이 Pod 통신 암호화(규정 충족). 라우팅 모드와 함께 쓴다. 노드 간에만. IPsec 대비 가벼운 현대 암호학.
- 블록 기반 IPAM이 라우팅 집약(노드당 /24 광고)을 가능하게 한다. BGP 모드의 전제.
- felix(노드 에이전트, 커널 프로그래밍) + typha(대규모 apiserver 중개) + bird(BGP)가 아키텍처 핵심. typha가 03장 list-watch 부하를 회피하는 수단.
- eBPF 모드도 지원 — iptables 병목 회피. "Calico=iptables" 단순화는 틀림.
생각해 볼 문제
- AWS VPC에서 Calico를 BGP 모드로 설정했다. 왜 Pod 통신이 안 될 가능성이 높은가?
- WireGuard로 노드 간 Pod 트래픽을 암호화했다. 같은 노드의 두 Pod 통신은 암호화되는가? 왜?
- Calico IPAM 블록 크기를 /24로 잡았다. 노드에 Pod가 256개 넘게 필요하면?
- tcpdump로 노드 인터페이스를 잡았다. VXLAN 모드에선 Pod IP가 보이는가? IPIP에선?
- typha 없이 노드 500개 클러스터에서 Calico를 돌리면 생기는 문제는?
- 노드 1000개 클러스터에서 Calico BGP를 full mesh로 짰다. 피어 연결 수는? 왜 비현실적인가?
- Calico 정책(CRD)이 K8s 기본 NetworkPolicy보다 강력한 점을 한 가지 짚어 보라.
- 데이터플레인 모드(VXLAN)와 정책 모드(CRD 고급)를 독립적으로 선택하는 게 왜 유용한가?
참고
- Calico docs - Networking - 접근 2026-07-13 (BGP/IPIP/VXLAN 모드)
- Calico docs - WireGuard 암호화 - 접근 2026-07-13
- Calico docs - IPAM - 접근 2026-07-13 (블록 기반)
- Calico docs - BGP route reflectors - 접근 2026-07-13 (대규모 토폴로지)
- Calico docs - eBPF dataplane - 접근 2026-07-13
- Calico 아키텍처 - felix/typha - 접근 2026-07-13
- WireGuard - 접근 2026-07-13 (현대 암호학, 커널 통합)
'Tech Artifacts > K8s Networking' 카테고리의 다른 글
| K8s Networking - 06. network-policy (0) | 2026.07.14 |
|---|---|
| K8s Networking - 05. cilium ebpf (0) | 2026.07.14 |
| K8s Networking - 03. cni model (0) | 2026.07.14 |
| K8s Networking - 02. coredns (0) | 2026.07.14 |
| K8s Networking - 01. service kube-proxy (0) | 2026.07.13 |