Skip to content

최신 CNI를 이르게 도입한 대가 — Cilium 버그로 요청이 조용히 사라졌고, Calico로 내려왔음 ​

  • 내부/외부 HTTP 통신이 아주 가끔 실패하는데, 받는 쪽 애플리케이션 로그에는 요청이 들어온 흔적조차 없던 장애입니다.
  • 결론부터 쓰면 우리 설정 문제가 아니라 Cilium에 공식적으로 리포트돼 있던 버그였고, 패치를 기다리는 대신 Calico로 내려왔습니다.
  • K8s 버전 업그레이드 장애 회고와 같은 클러스터 이야기예요. 그 글이 "어떻게 복구했나"라면, 이 글은 "왜 결국 Cilium을 걷어냈나"입니다. (두 사건의 정확한 선후 관계는 [확인 필요])

개요 ​

Cilium을 고른 이유는 분명했습니다. eBPF 기반의 성능, 그리고 최신 기술을 이르게 들여놓는 것 자체의 값어치요. 그때 판단으로는 맞는 선택이었다고 생각합니다.

이 클러스터는 매니지드 K8s였고, 서비스 간 통신이 큰 JSON을 주고받는 구조였습니다. 그래서 요청 하나가 실패하는 게 "재시도하면 되죠"로 끝나지 않았어요. 실패율 자체는 낮았는데 구조상 치명적이었습니다.

원인 특정까지 오래 걸렸고, 결국 근본 수정이 아니라 우회로 끝냈습니다. 그 판단이 맞았는지는 지금도 확신이 없어서, 그것까지 그대로 남깁니다.

한 줄 결론: 업스트림에 알려진 정책 드랍 버그를 밟았고, 패치 대기 대신 검증된 CNI로 내려왔음 ​

증상 — 내부·외부 HTTP 요청이 간헐적으로 실패함. 보내는 쪽은 연결 실패로 뜨는데, 받는 쪽 웹 앱에는 요청이 들어온 기록 자체가 없음. 양쪽 다 자기 잘못이 아니라고 말하는 상태였음.

원인 — Cilium이 정책을 판정할 때 쓰는 identity가 제때 안 잡히거나 유실되면, 정상 트래픽이 정책 미매칭으로 분류돼 거부 응답 없이 버려짐. 애플리케이션 로그·LB 로그·방화벽 로그 어디에도 안 남는 이유가 이거였음.

결정적이었던 건 — 이게 우리 정책을 잘못 쓴 게 아니라 업스트림에 리포트된 버그 계열이었다는 것. 우리가 고쳐서 될 문제가 아니라는 게 확인되면서 선택지가 "패치 대기 vs 교체" 둘로 줄었음.

해결 — Calico(iptables 데이터패스)로 CNI를 내림. 성능과 최신성을 성숙도와 맞바꿨음.

대가 — L7 정책을 포기하고 L3/L4만 남았음. iptables는 서비스·엔드포인트 수에 비례해 룰이 늘고 갱신이 느려짐. 알고 받은 손해였음.

남는 인사이트 한 줄 — 최신 기술을 이르게 도입한다는 건, 남들이 아직 안 밟은 버그를 우리가 먼저 밟겠다는 뜻임. 그 자체는 나쁜 선택이 아님. 다만 얼리어답터 비용은 "버그를 만날 확률"이 아니라 "만났을 때 그게 버그인 줄 알아채는 데 걸리는 시간"으로 청구됨. 우리는 관측 도구를 안 켜둔 채로 그 청구서를 받았음.


증상: 양쪽 다 자기 잘못이 아니라고 말하는 상태 ​

보내는 쪽과 받는 쪽의 진술이 정면으로 어긋났음.

  • 보내는 쪽: 요청을 보냈고 연결 실패로 끝났다고 기록함
  • 받는 쪽 웹 앱: 그런 요청이 들어온 적 없음. 액세스 로그에 아예 안 찍힘

둘 다 거짓말을 안 하고 있는 상황임. 요청이 나간 건 맞고, 도착 안 한 것도 맞음. 그럼 나간 뒤 도착하기 전 구간에서 사라진 것임.

빈도는 낮았음. [확인 필요 — 실패율 몇 % 였는지, 하루 몇 건이었는지] 재실행하면 대체로 통과해서 처음엔 애플리케이션 타임아웃을 의심했음.

간헐적이라는 게 이 장애의 제일 고약한 부분이었음. 재현이 안 되니 가설을 세워도 검증에 시간이 걸리고, 그 사이에 "그냥 재시도 붙이자"는 결론으로 흘러가기 쉬움. 실제로 그렇게 넘어갈 뻔했음.

애플리케이션이 아니라고 판단한 근거 ​

설정상 나올 수 없는 시점에 끊겼음.

  • 커넥션 풀 설정, 타임아웃 값, 재시도 로직을 먼저 확인함 [확인 필요 — 실제 확인한 항목과 값]
  • 애플리케이션 로그에는 "정상 요청 후 응답 없이 끊김"으로 남음
  • 요청은 나갔는데 응답이 안 온 거라 그 사이 구간, 즉 네트워크를 봐야 한다고 판단함

여기서 하나 짚어둠. 애플리케이션 타임아웃과 네트워크 드랍은 로그 모양이 비슷하게 생겼음. 둘 다 "응답이 안 왔다"로 끝남. 구분하는 기준은 로그 문구가 아니라 설정값과 실제 끊긴 시점이 맞느냐임. 타임아웃 10초로 걸어놨는데 3초에 끊겼으면 그건 애플리케이션이 끊은 게 아님.

관측: 로그가 없는 게 단서였음 ​

TCP 덤프, LB 로그, 방화벽 로그를 봤음. [확인 필요 — 실제로 어느 구간에서 떴는지, Hubble을 썼는지 안 썼는지]

여기서 방향이 잡혔음. 정상적인 거절은 흔적을 남김.

  • 방화벽이 막으면 방화벽 로그에 남음
  • LB가 끊으면 LB 로그에 남음
  • 애플리케이션이 거절하면 액세스 로그에 남음
  • TCP 레벨에서 거절되면 RST가 돌아오고, 보내는 쪽이 "connection refused"로 받음

근데 이번 건은 어디에도 안 남고, RST도 안 오고, 그냥 조용히 없어졌음. 이 조합을 만들 수 있는 건 목록이 짧음. 커널이나 데이터패스에서 판정 후 버리는 경우임.

이때부터 CNI를 봤음.

원인: silent drop은 "안 보내진 것"이 아니라 "지워진 것"임 ​

Cilium의 정책 판정에 걸리지 않은 트래픽이 거부 응답 없이 버려지고 있었음.

Cilium이 정책을 판정하는 방식이 iptables 기반 CNI와 다름. 여기가 핵심임.

  • Cilium은 IP가 아니라 파드 라벨에서 파생된 identity 단위로 정책을 판정함
  • 정책에 매칭되지 않는 트래픽은 drop임. TCP RST도, ICMP unreachable도 안 보냄
  • 그래서 보내는 쪽은 응답을 영원히 기다리다 타임아웃으로 끝나고, 받는 쪽은 애초에 패킷을 못 봤으니 로그가 없음

이게 "둘 다 황당한" 상태의 정체였음. 통신이 거절된 게 아니라 존재가 지워진 거라, 양쪽 어느 로그에도 사건이 기록되지 않음.

그리고 이 드랍은 정보가 없는 게 아니라 다른 데 있음. Cilium은 드랍 이벤트를 자체적으로 갖고 있고, cilium monitor --type drop이나 Hubble로 보면 어떤 identity에서 어떤 identity로 가는 패킷이 어떤 이유로 버려졌는지 나옴. 우리는 그걸 안 켜둔 상태로 장애를 맞았음. 그래서 며칠이 걸렸음.

관측 도구를 장애 나고 켜는 것과 켜져 있는 상태로 장애를 맞는 것은 완전히 다른 얘기임.

우리 정책이 틀린 게 아니었음 — 업스트림에 이미 올라와 있던 버그였음 ​

이 장애의 분기점은 "우리가 고칠 수 있는 문제인가"였음. 정책을 잘못 쓴 거라면 정책만 고치면 되고, CNI를 갈아엎을 이유가 없음.

논리적으로 먼저 걸러진 게 있었음. 정책 내용 자체가 잘못됐다면 CNI를 바꿔도 똑같이 드랍됐어야 함 — Calico도 정책에 안 걸리는 트래픽은 RST 없이 버림. Calico로 바꾸고 증상이 사라졌다는 사실이, 원인을 정책 내용이 아니라 Cilium이 그 정책을 데이터패스에 밀어 넣는 구간으로 좁혀줌.

그리고 실제로 그 구간의 버그는 업스트림에 리포트돼 있음. 이 글을 정리하면서 다시 찾아본 것들임.

이슈영향 버전내용
#35993 Dropped packets due to Deny policy on pod startupv1.14, v1.15, v1.16.xcilium-operator 재시작 등으로 파드 라벨을 못 가져오면 엔드포인트에 기본 deny가 걸린 채로 남음. CNI 프로비저닝이 끝나도 안 풀림
#33772 Traffic drop due to local identity changev1.14.12CNP 삭제 후 해제된 identity를 계속 참조해 reserved:world로 안 떨어지고 policy denied
#37711 Policy denied happening for no reasonv1.16.x, v1.17.0정책 변경이 없는데 identity가 스스로 사라지고 그 출발지 트래픽이 드랍됨. 재현 불가·비결정적
#14775 Cilium seems to lose identitiesv1.8, v1.9.1파드가 identity와 엔드포인트를 잃고 플로우가 드랍됨

세 가지가 눈에 띔.

  • 네 건 모두 증상이 같음 — Policy denied 드랍, 정책은 멀쩡한데 identity 쪽이 어긋남
  • 워크어라운드도 같음 — cilium 에이전트 재시작. 앞 글에서 서포트 엔지니어가 cilium 재시작으로 라우팅을 살린 것과 겹침
  • 버전을 가리지 않음 — 1.8부터 1.17까지 계열이 이어짐. 특정 릴리즈의 실수라기보다 identity 라이프사이클이라는 설계 지점 자체가 어려운 것에 가까워 보임

앞 글에 남은 우리 구성이 cilium v1.14.4인데, #35993이 v1.14를 영향 버전으로 명시하고 있음. 증상도 "간헐적", "특정 파드만", "재시작하면 풀림"으로 우리 것과 겹침. 다만 우리 건이 정확히 이 이슈였다고 단정하진 못함 — 당시 cilium monitor나 Hubble 로그를 안 남겨놨기 때문임. [확인 필요 — 당시 티켓이나 슬랙에 드랍 로그가 남아 있는지]

왜 간헐적이었나 ​

위 이슈들이 이 질문에 답을 줌. 트리거가 전부 "상태가 바뀌는 순간"임.

  • 파드가 새로 뜨는데 라벨 조회가 늦으면 → 기본 deny가 걸린 채로 남음 (#35993)
  • 정책이 지워지면서 identity가 해제되는데 참조가 남으면 → 엉뚱한 판정 (#33772)
  • identity가 이유 없이 삭제되면 → 그 출발지만 드랍 (#37711)

정책 판정 자체는 결정적(deterministic)이라 "정책이 틀렸으면 항상 실패"가 자연스러움. 근데 실제로는 간헐적이었음. 판정이 틀린 게 아니라, 판정에 쓰이는 입력(identity)이 특정 타이밍에만 어긋났기 때문임.

"간헐적"이라는 단어가 붙으면 정적인 설정이 아니라 상태 전이 구간을 먼저 의심하는 게 맞는 것 같음. 이번 건에서 제일 값이 큰 감각이었음.

참고로 초기 메모에는 "DNS resolve 실패"와 "eBPF kube-proxy replacement 버그"도 원인 후보로 적혀 있었음. 앞 글(K8s 버전 업그레이드 장애 회고)에서 이 클러스터는 KubeProxyReplacement=False(kube-proxy 병용)로 확인됐으므로, kube-proxy replacement 경로는 원인이 아님. DNS 쪽은 앞 글에서 다룬 별개 증상이었을 가능성이 큰데, 지금 기억으로 배제 근거를 확정하진 못함. 가르는 기준은 하나임 — 애플리케이션이 남긴 에러가 이름 해석 실패(UnknownHostException 류)였는지, 연결 실패·타임아웃이었는지. 후자였으면 DNS는 아님. [확인 필요]

조치: 패치를 기다리지 않고 한 세대 내려온 이유 ​

성능 이점보다 안정성이 우선인 워크로드였고, 패치 일정에 우리 일정을 걸 수 없었음.

두 가지를 놓고 봤음.

Cilium 패치 대기Calico로 내려오기
언제 끝나나릴리즈 일정에 종속우리가 정함
실패 시 되돌리기원래 상태 유지다시 갈아엎어야 함
남는 기능L7 정책·eBPF 성능 유지L3/L4만
확실성이 증상이 잡힌다는 보장 없음데이터패스 자체가 바뀜

마지막 줄이 결정적이었음. 업스트림 이슈들을 보면 닫힌 이슈인데도 근본 원인이 특정 안 된 채로 끝난 게 있고(#37711은 "재현 불가"로 남음), 제시된 워크어라운드가 전부 에이전트 재시작임. 재시작은 조치가 아니라 증상 리셋임.

즉 패치를 기다리는 건 "다음 릴리즈가 우리 증상을 잡는다"는 전제에 일정을 거는 것인데, 이슈 목록 자체가 그 전제를 보장해주지 않았음. 반면 CNI를 통째로 바꾸면 원인이 뭐였든 그 구간이 사라짐.

큰 JSON을 주고받는 구조라 요청 하나의 실패 비용이 컸고, 그래서 "빠른 데이터패스"보다 "예측 가능한 데이터패스"를 골랐음.

전환은 [확인 필요 — 노드 순차 교체였는지 / 신규 노드풀 만들고 워크로드 이관이었는지, 무중단이었는지, 롤백 계획을 뭘로 잡았는지] 방식으로 진행했음.

바꾸면서 포기한 것 ​

정직하게 손해도 적어둠. Calico가 Cilium보다 좋아서 고른 게 아님.

L7 정책을 잃었음. Cilium은 CNI 자체가 HTTP 메서드·경로 단위 정책을 지원함. Calico도 L7이 아예 안 되는 건 아닌데, Istio + Dikastes 사이드카를 얹어야 가능함 — CNI 하나로 끝나던 걸 서비스 메시까지 들여야 하는 구조가 됨. 우리는 그때 L7 정책을 실제로 쓰고 있었는지부터가 애매했음. 그래서 잃는 게 크지 않다고 판단했는데, 거꾸로 보면 안 쓰는 기능을 이유로 이 CNI를 골라놨던 것임.

iptables는 룰이 늘어나면 느려짐. 다만 여기는 흔히 말하는 것보다 정확히 짚을 필요가 있음. 쿠버네티스 공식 문서가 짚는 병목은 패킷당 탐색보다 룰 갱신 시간 쪽임 — 서비스·엔드포인트 하나당 룰이 몇 개씩 생기고, 파드가 뜨고 지는 때마다 커널 룰셋을 다시 써야 해서 수만 개 규모에서 동기화가 오래 걸림. eBPF는 커널에 프로그램을 붙이고 해시맵으로 조회해서 갱신 비용과 탐색 비용을 둘 다 줄임. 우리 규모에서는 체감할 수준이 아니라고 봤지만 [확인 필요 — 전환 전후 지연 비교를 실제로 재봤는지], 규모가 커지면 다시 볼 항목임.

이건 해결이라기보다 트레이드오프를 갈아탄 것에 가까움. 성능과 최신성을 주고 예측 가능성을 샀음.

그래서 무엇을 남길 것인가 ​

가장 중요한 것부터.

얼리어답터 비용은 "버그를 만날 확률"이 아니라 "버그인 줄 알아채는 시간"으로 청구됨 ​

최신 CNI를 이르게 도입한 것 자체는 지금도 나쁜 선택이었다고 생각 안 함. 성능 이점은 실재했고, 그 경험이 팀에 남았음. 다시 골라도 비슷하게 골랐을 것 같음.

문제는 값을 치른 방식이었음. 우리가 실제로 잃은 건 "버그를 만났다"가 아니라 "그게 버그인 줄 알기까지 걸린 시간"임. 그 며칠 동안 애플리케이션 코드를 뒤졌고, 커넥션 풀 설정을 의심했고, 재시도 로직을 검토했음. 전부 우리 잘못이라는 전제 위에서 움직인 시간이었음.

성숙한 기술을 쓸 때는 이 전제가 대체로 맞음. 나온 지 오래된 스택에서 이상한 게 나오면 십중팔구 내가 잘못 쓴 것임. 근데 최신 기술에서는 이 전제의 적중률이 떨어짐. 도입 시점을 앞당긴다는 건 "내 잘못이 아닐 확률"을 높이는 일인데, 진단 습관은 여전히 "내 잘못부터 의심"에 맞춰져 있었음.

그래서 얼리어답터를 하려면 세트로 필요한 게 있음.

  • 업스트림 이슈 트래커를 진단 도구로 취급 — 이 글 쓰면서 검색 몇 번으로 #35993, #33772, #37711이 나왔음. 그때 안 찾아봤음. 증상 키워드(Policy denied + intermittent)로 검색하는 건 5분이면 되는 일인데, 그 5분을 며칠 뒤에 썼음
  • 관측 도구는 도입과 동시에 — Hubble은 Cilium을 고를 때 같이 켰어야 함. 최신 기술을 고르는 값에 관측 비용이 포함돼 있다고 봐야 함
  • 되돌아갈 경로를 미리 확보 — 우리는 결국 되돌아왔는데, 그 경로를 장애 중에 설계했음

정리하면 "최신 기술을 쓸 수 있느냐"가 아니라 "최신 기술이 배신했을 때 그걸 빨리 알아챌 수 있느냐"가 도입 기준이어야 했던 것 같음.

애플리케이션 로그에 안 남는 실패는 데이터패스부터 봄 ​

"어느 로그에도 안 남는다"를 정보 부족이 아니라 단서로 취급함. 방화벽·LB·애플리케이션은 막을 때 흔적을 남김. 흔적 없이 사라지는 건 그 아래에서 판정 후 버려진 것임.

다음에 같은 증상을 만나면 순서를 이렇게 잡을 것 같음.

  1. 보내는 쪽·받는 쪽 로그의 진술이 어긋나는지 확인 (어긋나면 중간 구간 확정)
  2. 끊긴 시점이 애플리케이션 타임아웃 설정값과 맞는지 확인 (안 맞으면 애플리케이션 아님)
  3. RST가 돌아왔는지 확인 (RST 없이 타임아웃이면 silent drop 의심)
  4. CNI 드랍 관측 (cilium monitor --type drop / Hubble / Calico는 iptables 카운터)
  5. 그다음에 tcpdump

이번엔 3번을 건너뛰고 5번부터 갔음.

CNI 드랍 관측을 상시로 켜둠 ​

장애 나고 켜는 관측 도구는 절반의 값어치임. 드랍은 이미 일어났고 카운터는 리셋돼 있음. 간헐적 장애일수록 이게 치명적임 — 켜둔 다음에 다시 발생하기를 기다려야 함.

Hubble을 미리 붙여놨으면 며칠이 몇 시간이었을 것 같음. 이게 이 장애에서 제일 값비싼 교훈임.

CNI 선택 기준은 "성능"이 아니라 "그 기능을 실제로 쓰는가"임 ​

기능이 많은 CNI는 판정 지점이 많은 CNI이기도 함. Cilium의 L7 정책과 eBPF 데이터패스는 기능인 동시에 실패 지점임. 안 쓰는 기능이면 그 실패 지점만 떠안는 것임.

그래서 다음에 CNI를 고를 때 물어볼 것은 이 순서인 것 같음.

  • L7 단위 정책이 실제로 필요한가 (아니면 L3/L4로 충분한가)
  • 서비스 개수가 iptables가 버거워질 규모인가
  • 문제가 생겼을 때 팀이 그 데이터패스를 디버깅할 수 있는가

세 번째가 제일 중요한데 보통 제일 늦게 물어봄. 우리도 그랬음.

NetworkPolicy는 강제 적용 전에 관측부터 함 ​

정책을 default deny로 조이기 전에, 먼저 드랍 이벤트만 관측하면서 어떤 트래픽이 걸리는지 보는 단계가 있어야 했음. 지금 구성으로는 정책이 트래픽을 막는 순간을 사후에만 알 수 있었음. [확인 필요 — 당시 default deny 정책이 걸려 있었는지]

정직하게 남기는 아쉬운 점 ​

  • 업스트림 이슈를 그때 안 찾아봤음. 이 글 쓰면서 검색 몇 번으로 나온 것들을, 장애 중에는 우리 코드 뒤지느라 안 봤음. 제일 싸고 제일 늦게 한 검증이었음
  • 원인을 우리 손으로 확정하지 않고 우회로 덮었음. Calico로 바꾸니 증상이 사라졌지만, 증상이 사라진 것과 원인을 안 것은 다른 얘기임. 업스트림 이슈로 정황은 맞췄어도 우리 클러스터에서 그걸 관측한 기록은 없음
  • 관측 도구를 안 켜둔 상태로 간헐적 장애를 맞았음. 이게 시간의 대부분을 먹었음
  • 전환 전후 지연·처리량을 안 재놨음. 트레이드오프를 골랐다고 말하려면 잃은 쪽 숫자도 있어야 하는데 없음

아직 다 정리된 건 아니에요. 우리 건이 정확히 어느 이슈였는지는 당시 로그가 없어서 확정이 어렵고, 비슷한 구성을 다시 만들면 그때 재현해보려고 합니다.

최신 CNI를 이르게 쓰고 계시다면 관측 도구를 도입과 같은 날에 켜는 것, 그리고 이상하면 우리 코드보다 이슈 트래커를 먼저 여는 것 두 개만 가져가셔도 충분할 것 같습니다. 규모나 구성이 다르시면 참고용으로만 보시면 좋겠어요.


부록: 예상 질문과 답변 뼈대 ​

면접에서 이 경험을 설명할 일이 있어서 같이 정리해뒀음. [ ] 안은 본인 기억으로 채워야 하는 칸임.

"CNI 이슈, 자세히 설명해주세요" ​

① 증상

내부·외부 HTTP 통신이 간헐적으로 실패했습니다. 전체가 아니라 [N%] 정도였고 재실행하면 통과하는 경우가 있어서, 처음엔 애플리케이션 타임아웃으로 의심했습니다.

② 애플리케이션이 아니라고 판단한 근거

[커넥션 풀 설정 / 타임아웃 값 / 재시도 로직]을 먼저 확인했는데 설정상 나올 수 없는 시점에 끊겼습니다. 애플리케이션 로그에는 정상 요청 후 응답 없이 끊긴 것으로 남았고, 받는 쪽에는 요청 기록 자체가 없었습니다. 요청은 나갔는데 도착은 안 했으니 그 사이 구간을 봐야 한다고 판단했습니다.

③ 관측 방법

[tcpdump로 양쪽 패킷 비교 / LB·방화벽 로그 대조]를 했습니다. 어디서도 거절 기록이 없고 RST도 안 왔습니다. 거절이 아니라 드랍이라는 게 여기서 확정됐습니다.

④ 근본 원인

Cilium은 IP가 아니라 파드 라벨에서 파생된 identity로 정책을 판정하는데, 그 identity가 제때 안 잡히거나 유실되면 정상 트래픽이 정책 미매칭으로 분류돼 드랍됩니다. 정책 내용이 틀린 게 아니라 정책을 데이터패스에 반영하는 구간의 문제였고, 업스트림에 같은 계열로 리포트된 이슈들이 있었습니다. 저희가 쓰던 v1.14 라인도 영향 버전에 포함돼 있었습니다.

⑤ 조치

패치 대기와 CNI 교체를 놓고 봤는데, 이슈 목록을 보니 근본 원인이 특정 안 된 채 닫힌 건도 있고 제시된 워크어라운드가 에이전트 재시작뿐이었습니다. 다음 릴리즈가 이걸 잡는다는 보장이 없다고 판단해서, 성숙도가 높은 Calico로 내렸습니다. [노드 순차 교체 / 신규 노드풀 이관] 방식으로 진행했고 [롤백 계획 / 검증 절차]를 준비했습니다.

⑥ 재발 방지

[드랍 관측 상시화 / 커넥션 지표 알람 / 장애 회고 문서화]로, 같은 증상이 재발하면 애플리케이션이 아니라 네트워크 계층을 먼저 의심할 수 있게 했습니다.

꼬리 질문 ​

질문답변 방향
애초에 왜 Cilium을 골랐나요변명하지 말고 이유를 그대로 말한다. "eBPF 성능과 최신 기술 도입 자체의 값어치를 봤고, 지금도 그 판단이 틀렸다고 생각하진 않습니다. 다만 최신 기술을 이르게 쓰면 버그를 우리가 먼저 밟는다는 걸 도입 비용에 안 넣었던 게 문제였습니다"
eBPF와 iptables 차이가 뭔가요iptables는 서비스·엔드포인트 수에 비례해 룰이 선형으로 늘어남. 공식 문서가 짚는 병목은 패킷당 탐색보다 룰 갱신 시간 쪽 — 엔드포인트가 바뀔 때마다 커널 룰셋을 다시 써서 수만 개 규모면 동기화가 느려짐. eBPF는 커널에 프로그램을 붙이고 해시맵으로 조회해 갱신·탐색 비용을 둘 다 줄이고, kube-proxy를 대체할 수 있음. Cilium은 XDP로 NIC 단계에서 경로를 단축하기도 함
왜 Cilium 패치를 안 기다렸나요트레이드오프로 답한다. "업스트림 이슈에 근본 원인 미특정 건이 있었고 워크어라운드가 재시작뿐이라, 패치 일정에 우리 일정을 걸 수 없었습니다. 신규 클러스터였거나 재현 환경이 있었다면 Cilium을 유지하고 패치를 기다렸을 겁니다"
그럼 정책을 고치면 되는 거 아닌가요이게 제일 날카로운 질문임. "정책 내용이 문제였다면 Calico로 바꿔도 똑같이 드랍됐어야 합니다. Calico도 미매칭 트래픽은 RST 없이 버리니까요. CNI를 바꾸고 증상이 사라졌다는 게, 원인이 정책 내용이 아니라 그걸 반영하는 구간이었다는 근거입니다"
전환 중 무중단은 어떻게 했나요노드 단위 순차 교체 + PDB로 최소 가용 파드 보장 + 노드마다 검증 후 다음 노드
L7 정책을 잃은 건 괜찮았나요당시 L7 정책을 실제로 쓰고 있지 않아 손실이 작다고 판단함. 다만 안 쓰는 기능을 이유로 그 CNI를 골라놨다는 점은 선택 기준의 문제였음
지금 다시 한다면"증상 키워드로 업스트림 이슈를 먼저 검색했을 겁니다. 그리고 Hubble로 드랍을 봤을 거예요. 그때는 우리 코드부터 뒤졌는데, 그 순서가 며칠을 만들었습니다"

부록: 진단에 썼던 것 ​

거절인지 드랍인지 가르기 ​

sh
# RST가 오는가 (오면 거절, 안 오고 타임아웃이면 드랍 의심)
sudo tcpdump -i any -nn "host <상대IP> and tcp[tcpflags] & tcp-rst != 0"

# 3-way handshake가 완성되는가 — SYN만 나가고 SYN-ACK가 없으면 중간에서 사라진 것
sudo tcpdump -i any -nn "host <상대IP> and (tcp[tcpflags] & (tcp-syn|tcp-ack) != 0)"

# 커넥션 추적 상태 — SYN_SENT에서 멈춰 있으면 상대까지 못 감
sudo conntrack -L | grep <상대IP>

CNI 드랍 관측 (Cilium) ​

sh
# 드랍 이벤트만 실시간으로 — 왜 버려졌는지(reason)가 같이 나옴
kubectl exec -n kube-system <cilium-파드> -c cilium-agent -- \
  cilium monitor --type drop

# 정책 판정 결과 확인 — 엔드포인트별로 어떤 identity를 허용 중인지
kubectl exec -n kube-system <cilium-파드> -c cilium-agent -- cilium endpoint list
kubectl exec -n kube-system <cilium-파드> -c cilium-agent -- cilium policy get

# Hubble이 있으면 (미리 켜둬야 값이 있음)
hubble observe --verdict DROPPED --last 100

전환 후 검증 (Calico) ​

sh
# 파드가 전부 새 CNI로 올라왔는지 (IP 대역·인터페이스 확인)
kubectl get pods -A -o wide
calicoctl node status                   # BGP 피어 상태

# 드랍 카운터 — 룰별로 몇 개 버렸는지 숫자로 보임
sudo iptables -L -n -v | grep -i drop

참고 ​