Istio 도입시 겪었던 Error 정리

Jisu·2025년 4월 24일

배경

사내에서 대규모 서비스 리뉴얼 작업을 진행하였고, 이에 따라 Infra에서도 고도화를 준비하게 되었다. 내가 맡은 파트는 istio의 도입인데 크게 3가지 이유로 도입을 진행하였다.

  1. MSA 환경에서의 in-cluster 통신 가시성 향상
    --> service간 의존 관계의 투명한 파악

  2. 손쉬운 Canary 배포 환경 준비

  3. Circuit Breaker, HTTP 헤더 삽입 등 애플리케이션 레벨에서 수행되던 여러 설정은 인프라 레벨에서 수행 가능

하지만 그 과정은 아주 녹록치 않았다 그래서 그 과정에서 만난 핵심 에러들을 소개한다. istio 도입하는 많은 분들도 비슷한 에러를 겪고있을것이라고 생각하고 참고가 되었으면 좋겠다!


Envoy Image Pull Rate Limit

일반적으로 네임스페이스별로 istio-injection 라벨을 걸어 해당 네임스페이스 내에 배포된 서비스들이 istio service mesh로 올라가게됩니다. 이 때 빠르게 side car container를 주입시키기 위해 deployment rolling update를 시킨다면 퍼블릭 이미지를 다운받기 위해 사용되는 NAT Gateway IP로 Rate Limit이 걸리게 되므로 주의하셔야합니다. ECR 등을 사용하여 별도 Private Registry 사용을 권장합니다.

이 글을 쓰는 시점에 익명 사용자는 6시간동안 100회 pull rate limit 정책이 명시되어있습니다.

https://docs.docker.com/docker-hub/usage/


Mutating Admission Webhook 사용을 위한 포트 개방

Webhook은 서버에서 특정 이벤트가 발생했을 때, 지정된 URL로 HTTP POST를 보내는 방식입니다.

Kubernetes API Server도 mutatingwebhookconfiguration 이라는 리소스를 등록하면 webhook을 사용할 수 있습니다. webhook 중에서도 k8s 리소스를 변형시키는데 사용되는 webhook을 MutatingAdmission Webhook이라고 합니다. 사용자가 Pod을 생성하면, Kubernetes API Server는 등록된 mutatingwebhookconfiguration에 따라 istiod의 15017 포트로 HTTP POST 요청을 보냅니다.
istiod는 이 요청을 받아 PodSpec에 Envoy 사이드카 컨테이너를 주입한 뒤, 수정된 PodSpec을 반환하고, 이를 기반으로 최종 Pod이 생성됩니다.

따라서 해당 eks node에는 control plane으로 부터 15017로 전달되는 트래픽에 대해서 개방되어야합니다.

참고) Ports used by Istio

https://istio.io/latest/docs/ops/deployment/application-requirements/

Pod 시작시 Network Error

side car가 주입된 경우, k8s Pod로 오고 가는 모든 패킷은 envoy container를 거치게 됩니다. (Inbound 패킷은 15006, Outbound 패킷은 15001 으로 리다이렉트)

https://istio.io/latest/docs/ops/deployment/application-requirements/

이 설정을 위해 파드 생성시, init container가 실행되며 iptable을 이용하여 네트워크 설정을 하게 됩니다. Pod내에 있는 컨테이너들은 같은 네트워크 네임스페이스를 공유하는 특성이 있으므로 애플리케이션 컨테이너도 같은 네트워크 규칙을 적용받게 됩니다.

규칙 설정 이후 Envoy side car 컨테이너가 시작되기까지 1~2초 정도 걸립니다. 만약 애플리케이션 컨테이너가 이 side car가 준비되기 전에 네트워크 통신을 시도하면 네트워크 설정은 side car 프록시 계층을 거치도록 설정은 되었으나, 프록시 컨테이너 (envoy)가 패킷을 받을 준비가 되지못했으므로 연결 에러가 발생할 수 있습니다.

따라서 이를 방지하기 위해 holdApplicationUntilProxyStarts: true 를 설정해야합니다.

이는 공식 문서의 Sidecar Injection Problems 에도 소개되어있습니다.

Pod or containers start with network issues if istio-proxy is not ready
https://istio.io/latest/docs/ops/common-problems/injection/


Pod 종료시 Network Error

istio sidecar는 sigterm을 받은 뒤 5초 이후 강제종료됩니다. 만약 애플리케이션 컨테이너가 종료되는데 5초 이상이 걸린다면 서비스 컨테이너보다 프록시 컨테이너가 빨리 종료되므로 5초 이후에는 네트워크 프록시 계층이 없어 네트워크 에러가 나게 됩니다. 이 또한 istio에서 terminationDrainDuration이라는 설정값으로 종료시간을 늘릴 수 있습니다.

하지만 좀 더 추천드리는 방식은 EXIT_ON_ZERO_ACTIVE_CONNECTIONS 을 설정하는 것으로 이를 통해 envoy의 tcp 연결이 0개가 될 때 까지 side car 종료를 지연시킬 수 있습니다.

실제로 istio-proxy 컨테이너에서 connection 연결을 끊기를 대기하는 모습을 볼 수 있습니다. 하지만 유의하실 것은 Pod에 설정된 GracefulShutdown이 되면 연결이 남아있어도 강제 종료가 되게 됩니다. 따라서 애플리케이션 단에서의 연결 종료와 Pod GracefulShutdown 설정이 적절히 조합되어야합니다.


후기

istio service mesh는 러닝커브가 높은것으로 알려진 기술이었다. 정리하고 보니 문제에 대한 각기 명쾌한 답이 있었지만 도입과정에서 connection error 같은 경우는 원인 파악에 시간이 생겨 개발팀과 약간의 갈등이 있기도 하였다.

하지만 협업 과정에서 원활히 풀어나갔으며 모든 기술이 그렇듯 익숙해지면 할만하다라는 생각이 들었다. 그리고 특히나 network 관련한 트러블 슈팅 능력이 많이 향상되었다고 느껴졌다.

그리고 확실히 MSA 가시성 향상과 더불어 쉬운 canary 배포는 정말 큰 강점이었다. 앞으로 circuit breaker 등 다양한 기능에 대해 실 적용을 추진해봐야겠다.

profile
기술 공유를 즐기는 Engineer 장지수입니다!

0개의 댓글