- Published on
EKS AWS Load Balancer Controller 500 Webhook 타임아웃 해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
EKS에서 Ingress(또는 Service type=LoadBalancer)를 적용하는 순간 아래와 같은 에러로 배포가 멈추는 경우가 있습니다.
Internal error occurred: failed calling webhook "mservice.elbv2.k8s.aws": ...context deadline exceededwebhook call failed: the server is currently unable to handle the request (500)
이 문제는 겉으로는 “AWS Load Balancer Controller(ALBC) webhook 500/timeout”이지만, 실제로는 (1) API Server → webhook 서비스 네트워크 경로, (2) webhook TLS 인증서/CA 번들, (3) 컨트롤러/웹훅 파드 상태(리소스/스케줄링), (4) DNS/엔드포인트 불일치 중 하나가 깨져서 발생합니다. 이 글에서는 원인별로 빠르게 분해하고, 재현 가능한 진단 커맨드와 함께 확실히 복구하는 절차를 정리합니다.
> 참고: ALBC 권한 문제(403)와는 결이 다릅니다. IAM/IRSA 권한으로 인한 오류라면 아래 글을 먼저 확인하세요. > - EKS에서 AWS Load Balancer Controller 403 해결법
1) 증상 패턴으로 원인 범위 좁히기
1.1 kubectl apply 시점에 바로 실패한다
Ingress를 생성/수정하는 순간 바로 실패하면 대부분 Validating/Mutating Webhook 호출 실패입니다.
확인 포인트:
- 에러 메시지에
failed calling webhook/context deadline exceeded - 대상 webhook 이름이
*.elbv2.k8s.aws또는*.k8s.aws계열
1.2 컨트롤러 로그에 webhook 관련 로그가 없다
API Server가 webhook에 도달하지 못한 경우(네트워크/DNS/서비스 엔드포인트 문제) 컨트롤러 로그가 조용한 경우가 많습니다.
반대로, 컨트롤러 로그에 x509/tls/certificate가 보이면 TLS/CA 번들 문제일 확률이 높습니다.
2) 가장 먼저 확인할 것: webhook 서비스/엔드포인트
ALBC는 보통 kube-system 네임스페이스에 설치되며, webhook 서비스는 대개 다음 형태입니다.
aws-load-balancer-webhook-service
다음 명령으로 서비스와 엔드포인트가 살아있는지 확인합니다.
kubectl -n kube-system get svc | grep -E "aws-load-balancer|webhook"
kubectl -n kube-system get endpoints aws-load-balancer-webhook-service -o yaml
kubectl -n kube-system get pods -l app.kubernetes.io/name=aws-load-balancer-controller -o wide
2.1 endpoints가 비어있으면(=Ready 파드가 없음)
원인 후보:
- 컨트롤러 파드가 CrashLoop
- readiness probe 실패
- 노드 스케줄링 실패(리소스 부족/taint)
바로 아래를 확인합니다.
kubectl -n kube-system describe pod -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl -n kube-system logs -l app.kubernetes.io/name=aws-load-balancer-controller --tail=200
리소스 부족으로 OOM/재시작이 반복되면 webhook 호출이 타임아웃으로 터질 수 있습니다. OOM/메모리 이슈가 의심되면 아래 글의 체크리스트도 함께 보세요.
3) API Server → webhook 네트워크 경로 점검(가장 흔한 타임아웃 원인)
EKS에서 webhook은 클러스터 내부 서비스로 호출됩니다. 즉, API Server(컨트롤 플레인)가 워커 노드의 Pod/Service IP로 접근할 수 있어야 합니다.
타임아웃(context deadline exceeded)이 주로 의미하는 것:
- 컨트롤 플레인 → 워커 노드 보안그룹/네트워크 ACL에서 443(또는 webhook 포트) 차단
- 프라이빗 클러스터/엔드포인트 설정과 보안그룹 규칙 불일치
- CNI/네트워크 정책(칼리코 등)로 kube-system webhook 트래픽 차단
3.1 보안그룹(Cluster SG ↔ Node SG) 인바운드 확인
EKS는 컨트롤 플레인이 노드로 들어오는 트래픽이 필요합니다. 일반적으로 **노드 SG에 클러스터 SG에서의 인바운드(443/10250/웹훅 포트 등)**가 허용되어야 합니다.
- ALBC webhook 서비스는 보통 443(TLS)로 노출됩니다.
- 실제로는 Service → Pod로 NAT되며, 노드로 인입이 필요합니다.
검증 방법(간접):
- 같은 클러스터에서 다른 webhook(예: cert-manager)이 정상인데 ALBC만 안 되면 SG보다는 서비스/인증서 쪽 가능성 증가
- 모든 webhook이 죽는다면 네트워크/SG 가능성 증가
3.2 NetworkPolicy 사용 시 kube-system 예외 허용
NetworkPolicy가 활성화된 클러스터에서는 kube-system의 webhook 서비스로 들어오는 트래픽이 차단될 수 있습니다.
다음으로 네임스페이스에 정책이 있는지 확인합니다.
kubectl -n kube-system get networkpolicy
kubectl get networkpolicy -A | head
정책이 있다면, 최소한 API Server에서 들어오는 트래픽을 허용하거나(환경에 따라 소스 CIDR/네임스페이스 셀렉터로) kube-system의 webhook 파드에 대한 인바운드를 열어야 합니다.
4) TLS/x509/CA 번들 문제(500 또는 인증서 에러로 표출)
webhook은 TLS로 동작하고, ValidatingWebhookConfiguration/MutatingWebhookConfiguration에 caBundle이 정확히 들어가야 합니다. 이 값이 깨지면 다음과 같은 에러가 납니다.
x509: certificate signed by unknown authoritytls: bad certificate- 또는 API Server가 내부적으로 500으로 처리
4.1 webhook configuration 확인
kubectl get validatingwebhookconfigurations | grep -E "load-balancer|elbv2|aws"
kubectl get mutatingwebhookconfigurations | grep -E "load-balancer|elbv2|aws"
kubectl get validatingwebhookconfiguration aws-load-balancer-webhook -o yaml | sed -n '1,200p'
확인할 것:
clientConfig.service.name/namespace가 실제 서비스와 일치하는지clientConfig.caBundle이 비어있거나 너무 짧지 않은지
4.2 cert-manager와의 충돌/재발급 이슈
ALBC는 설치 방식에 따라 자체적으로 cert를 관리하거나(헬름 차트 훅) cert-manager를 쓰기도 합니다. 인증서가 꼬이면 caBundle과 실제 서버 인증서가 불일치할 수 있습니다.
빠른 복구 전략(권장): 헬름으로 재설치/업그레이드하여 웹훅 인증서를 재생성
helm repo add eks https://aws.github.io/eks-charts
helm repo update
# values는 환경에 맞게 조정
helm upgrade --install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<YOUR_CLUSTER_NAME> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
> 이미 운영 중이라면, 무작정 삭제보다는 먼저 kubectl get ... -o yaml로 현재 설정을 백업하세요.
5) DNS/서비스 이름 불일치(의외로 자주 발생)
webhook configuration은 서비스 이름을 하드코딩합니다. 설치/커스터마이징 과정에서 서비스 이름이 바뀌었거나 네임스페이스가 다르면 API Server는 엉뚱한 대상으로 호출하다 실패합니다.
5.1 service 참조가 일치하는지 교차검증
# 실제 서비스
kubectl -n kube-system get svc aws-load-balancer-webhook-service -o wide
# webhook이 참조하는 서비스
kubectl get validatingwebhookconfiguration aws-load-balancer-webhook \
-o jsonpath='{.webhooks[0].clientConfig.service.namespace}{"/"}{.webhooks[0].clientConfig.service.name}{"\n"}'
불일치하면:
- 올바른 릴리스/차트로 재설치(가장 안전)
- 또는 webhook configuration을 수동 수정(권장도 낮음: 업그레이드 시 덮어씌워짐)
6) 컨트롤러 파드가 살아도 webhook이 느린 경우(타임아웃)
파드가 Ready인데도 타임아웃이 나면 “느려서”가 아니라 보통 다음입니다.
- 노드의 conntrack/iptables 문제
- CoreDNS 장애로 서비스 디스커버리 지연
- 컨트롤러 파드 CPU throttling 심각 → TLS 핸드셰이크/응답 지연
6.1 리소스 제한/스로틀링 확인
kubectl -n kube-system top pod -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl -n kube-system describe pod -l app.kubernetes.io/name=aws-load-balancer-controller | sed -n '/Limits:/,/Conditions:/p'
CPU limit이 너무 낮으면(예: 100m) webhook 처리 순간에 지연이 커질 수 있습니다. 운영 환경에서는 여유 있게 잡는 편이 안전합니다.
헬름 values 예시:
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
적용:
helm upgrade aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
-f values.yaml
7) 실전 트러블슈팅 플로우(10분 컷)
아래 순서대로 보면 대부분 10~15분 내로 원인에 도달합니다.
- 이벤트/에러 원문 확보
kubectl apply -f ingress.yaml
kubectl get events -A --sort-by=.lastTimestamp | tail -n 50
- webhook 서비스/엔드포인트
kubectl -n kube-system get svc aws-load-balancer-webhook-service
kubectl -n kube-system get endpoints aws-load-balancer-webhook-service
- 컨트롤러 파드 상태/로그
kubectl -n kube-system get pods -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl -n kube-system logs -l app.kubernetes.io/name=aws-load-balancer-controller --tail=200
- webhook configuration의 service/caBundle 확인
kubectl get validatingwebhookconfiguration aws-load-balancer-webhook -o yaml | sed -n '1,220p'
- 네트워크(보안그룹/NetworkPolicy) 의심 시
- kube-system NetworkPolicy 존재 여부
- 최근 SG 변경/노드 교체/클러스터 엔드포인트 설정 변경 여부 확인
- 마지막 수단: 헬름 재설치로 웹훅 인증서/구성 재생성
(운영 영향 최소화 위해 점진적으로 수행)
8) 재발 방지 체크리스트
- ALBC 업그레이드 시 헬름 차트/컨트롤러 버전 호환성 확인
kube-system에 NetworkPolicy를 도입했다면 webhook 트래픽 예외 규칙 포함- 노드/클러스터 SG를 IaC로 관리하고, “컨트롤 플레인 → 노드” 인바운드 규칙을 변경 이력과 함께 고정
- 컨트롤러에 과도하게 낮은 CPU limit을 주지 말 것(웹훅은 짧지만 burst가 있음)
- IRSA/권한 문제는 별도로 분리 진단(403/AccessDenied는 다른 축)
IRSA 자체가 꼬여서 컨트롤러가 정상 동작하지 못하는 경우도 있으니, AccessDenied 류가 보이면 아래 글로 함께 점검하세요.
결론
EKS에서 AWS Load Balancer Controller의 500 webhook timeout은 “컨트롤러가 문제”라기보다 API Server가 webhook 서비스에 도달하지 못하거나(TCP 경로), TLS/CA 번들이 불일치하거나, 엔드포인트가 비어있는 상태에서 발생하는 경우가 대부분입니다.
가장 효과적인 접근은 (1) endpoints가 비었는지부터 확인하고, (2) webhook configuration의 서비스 참조와 caBundle을 검증한 뒤, (3) NetworkPolicy/보안그룹으로 컨트롤 플레인의 인바운드가 막히지 않았는지 점검하는 것입니다. 이 3가지만 체계적으로 보면 “원인 불명 webhook 500”은 거의 사라집니다.