Istio 일반적인 에러 및 해결 방법
지원 버전: Istio 1.28 마지막 업데이트: 2026년 2월 19일
이 문서는 Istio를 사용할 때 가장 자주 발생하는 에러와 해결 방법을 정리합니다.
목차
- 파드 종료 시 연결 에러
- Sidecar 주입 문제
- mTLS 연결 실패
- VirtualService 라우팅 실패
- Gateway 설정 문제
- 메모리 및 성능 문제
- 인증서 만료
- DNS 해석 실패
- Envoy 초기화 타임아웃
- 디버깅 도구
파드 종료 시 연결 에러
문제 설명
파드가 종료될 때 Envoy Sidecar가 애플리케이션보다 먼저 종료되어 연결 에러가 발생합니다.
증상:
Connection reset by peer
Broken pipe
EOF
HTTP 503 Service Unavailable발생 원인
근본 원인:
- Envoy와 애플리케이션이 동시에 SIGTERM을 받음
- Envoy가 애플리케이션보다 빨리 종료
- 애플리케이션은 아직 요청을 처리 중이지만 Envoy가 이미 종료되어 연결 실패
해결 방법
방법 1: Envoy Proxy preStop Hook 설정 (권장)
Istio Proxy 컨테이너에 preStop Hook을 설정하여 활성 연결이 모두 종료될 때까지 대기하도록 합니다.
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
metadata:
annotations:
# Envoy가 활성 연결 종료까지 대기
proxy.istio.io/config: |
terminationDrainDuration: 30s
spec:
terminationGracePeriodSeconds: 60
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080동작 방식:
방법 2: Pod Annotation으로 Envoy 종료 동작 제어
Pod 단위로 Envoy의 종료 동작을 세밀하게 제어할 수 있습니다.
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
metadata:
annotations:
# Envoy가 애플리케이션 시작까지 대기
proxy.istio.io/config: |
holdApplicationUntilProxyStarts: true
terminationDrainDuration: 30s
# Envoy 종료 타임아웃
sidecar.istio.io/terminationGracePeriodSeconds: "60"
spec:
terminationGracePeriodSeconds: 60
containers:
- name: myapp
image: myapp:latest설정 설명:
holdApplicationUntilProxyStarts: true: 애플리케이션보다 Envoy가 먼저 시작terminationDrainDuration: 30s: Envoy 종료 시 30초 동안 드레인terminationGracePeriodSeconds: 60: 전체 파드 종료 유예 시간
방법 3: 전역 설정 (IstioOperator)
클러스터 전체에 일관된 종료 정책을 적용합니다.
yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-controlplane
spec:
meshConfig:
defaultConfig:
terminationDrainDuration: 30s
holdApplicationUntilProxyStarts: true
values:
global:
proxy:
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- |
# Envoy 드레인 시작
curl -X POST http://localhost:15000/drain_listeners?graceful
# 활성 연결 대기
while [ $(netstat -plunt | grep tcp | grep -v TIME_WAIT | wc -l | xargs) -ne 0 ]; do
sleep 1;
done권장 설정:
terminationDrainDuration: 30초 (활성 연결 드레인 시간)terminationGracePeriodSeconds: 60초 (SIGKILL 전 유예 시간)- Envoy가 활성 연결을 확인하고 graceful shutdown 수행
검증 방법
bash
# 1. 파드 종료 중 로그 확인
kubectl logs -f <pod-name> -c istio-proxy --previous
# 2. 종료 시 연결 상태 확인
kubectl exec <pod-name> -c istio-proxy -- netstat -an | grep ESTABLISHED
# 3. 종료 이벤트 확인
kubectl get events --field-selector involvedObject.name=<pod-name>모범 사례
yaml
# 권장 설정 템플릿
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
metadata:
annotations:
# Envoy 종료 동작 제어
proxy.istio.io/config: |
holdApplicationUntilProxyStarts: true
terminationDrainDuration: 30s
spec:
terminationGracePeriodSeconds: 60
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 5
successThreshold: 1
failureThreshold: 3
# 선택사항: 애플리케이션 graceful shutdown
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- |
# Readiness 비활성화 (optional)
touch /tmp/not-ready
# 애플리케이션 요청 완료 대기
sleep 5체크리스트:
- ✅ Envoy terminationDrainDuration 설정 (가장 중요!)
- ✅ holdApplicationUntilProxyStarts: true (시작 순서 보장)
- ✅ terminationGracePeriodSeconds 충분히 설정 (최소 60초)
- ✅ ReadinessProbe 설정 (종료 시 빠르게 unhealthy 전환)
- ✅ 애플리케이션 graceful shutdown 구현 (선택사항)
- ✅ 모니터링 및 로깅 설정
핵심:
- ❌ 애플리케이션 컨테이너에 sleep을 추가하지 마세요!
- ✅ Envoy가 드레인 모드로 graceful shutdown하도록 설정하세요.
Sidecar 주입 문제
문제 1: Sidecar가 주입되지 않음
증상:
bash
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].name}'
# 출력: myapp (istio-proxy가 없음)원인 및 해결:
1. Namespace 레이블 누락
bash
# 확인
kubectl get namespace <namespace> --show-labels
# 해결
kubectl label namespace <namespace> istio-injection=enabled2. Pod Annotation으로 주입 비활성화됨
yaml
# 잘못된 설정
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/inject: "false" # ← 주입 비활성화해결:
yaml
# 올바른 설정
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/inject: "true"3. Istio Sidecar Injector 동작 확인
bash
# Sidecar injector webhook 확인
kubectl get mutatingwebhookconfigurations
# Istio injector 로그 확인
kubectl logs -n istio-system -l app=sidecar-injector문제 2: Sidecar 리소스 부족
증상:
OOMKilled
CrashLoopBackOff
Error: container has runAsNonRoot and image has non-numeric user해결:
yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/proxyCPU: "200m"
sidecar.istio.io/proxyMemory: "256Mi"
sidecar.istio.io/proxyCPULimit: "1000m"
sidecar.istio.io/proxyMemoryLimit: "512Mi"
spec:
containers:
- name: myapp
image: myapp:latestmTLS 연결 실패
문제 설명
증상:
upstream connect error or disconnect/reset before headers
503 Service Unavailable
SSL routines:OPENSSL_internal:WRONG_VERSION_NUMBER원인 1: PeerAuthentication 모드 불일치
해결:
yaml
# 네임스페이스 전체에 일관된 mTLS 정책 적용
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT # 모든 서비스 STRICT 모드원인 2: DestinationRule과 PeerAuthentication 충돌
yaml
# ❌ 잘못된 예
---
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
trafficPolicy:
tls:
mode: DISABLE # ← 충돌!해결:
yaml
# ✅ 올바른 예
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
trafficPolicy:
tls:
mode: ISTIO_MUTUAL # PeerAuthentication과 일치디버깅 명령어
bash
# 1. mTLS 상태 확인
istioctl x describe pod <pod-name> -n <namespace>
# 2. PeerAuthentication 정책 확인
kubectl get peerauthentication -A
# 3. DestinationRule TLS 설정 확인
kubectl get destinationrule -A -o yaml | grep -A 5 "tls:"
# 4. Envoy 클러스터 TLS 설정 확인
istioctl proxy-config clusters <pod-name> -n <namespace> --fqdn <service-name>VirtualService 라우팅 실패
문제 1: 트래픽이 라우팅되지 않음
증상:
404 Not Found
default backend - 404원인 및 해결:
잘못된 host 매칭
yaml
# ❌ 잘못된 예
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp.example.com # ← DNS 이름
http:
- route:
- destination:
host: myapp # ← Kubernetes Service 이름해결:
yaml
# ✅ 올바른 예
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
namespace: default
spec:
hosts:
- myapp # Kubernetes Service 이름과 정확히 일치
- myapp.default.svc.cluster.local # FQDN도 추가
http:
- route:
- destination:
host: myapp문제 2: Subset not found
증상:
no healthy upstream
subset not found원인:
yaml
# VirtualService는 있지만 DestinationRule이 없음
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
spec:
http:
- route:
- destination:
host: myapp
subset: v1 # ← Subset이 정의되지 않음해결:
yaml
# DestinationRule 추가
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2디버깅
bash
# 1. VirtualService 검증
istioctl analyze -n <namespace>
# 2. 라우팅 규칙 확인
istioctl proxy-config routes <pod-name> -n <namespace>
# 3. VirtualService 상태 확인
kubectl get virtualservice <name> -n <namespace> -o yamlGateway 설정 문제
문제 1: Gateway에 트래픽이 도달하지 않음
증상:
bash
curl: (7) Failed to connect to example.com port 443: Connection refused원인 및 해결:
1. Gateway Service 확인
bash
# Gateway Service 상태 확인
kubectl get svc -n istio-system istio-ingressgateway
# External IP 확인
kubectl get svc -n istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'2. Gateway와 VirtualService 연결 확인
yaml
# ❌ 잘못된 예
---
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: myapp-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "example.com"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- "example.com"
gateways:
- my-gateway # ← Gateway 이름 오타!해결:
yaml
# ✅ 올바른 예
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- "example.com"
gateways:
- myapp-gateway # Gateway 이름과 정확히 일치문제 2: HTTPS 인증서 오류
증상:
SSL certificate problem: self signed certificate해결:
yaml
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: myapp-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: myapp-tls-secret # ← Secret 이름 정확히 지정
hosts:
- "example.com"bash
# TLS Secret 생성
kubectl create secret tls myapp-tls-secret \
--cert=path/to/cert.pem \
--key=path/to/key.pem \
-n istio-system메모리 및 성능 문제
문제 1: Envoy 메모리 사용량 증가
증상:
OOMKilled
Memory usage > 1GB per pod원인:
- 너무 많은 리스너/클러스터 생성
- 큰 ConfigMap/Secret
- 메모리 누수
해결:
yaml
# Sidecar 리소스로 범위 제한
apiVersion: networking.istio.io/v1
kind: Sidecar
metadata:
name: default
namespace: default
spec:
egress:
- hosts:
- "./*" # 같은 네임스페이스만
- "istio-system/*" # istio-system만yaml
# Envoy 리소스 제한
apiVersion: v1
kind: Pod
metadata:
annotations:
sidecar.istio.io/proxyMemory: "512Mi"
sidecar.istio.io/proxyMemoryLimit: "1Gi"문제 2: 높은 지연 시간
증상:
- P99 latency > 1초
- Timeout 에러 빈번
해결:
yaml
# VirtualService에 timeout 설정
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: myapp
spec:
http:
- route:
- destination:
host: myapp
timeout: 5s # 전체 요청 타임아웃
retries:
attempts: 3
perTryTimeout: 2s # 각 재시도 타임아웃인증서 만료
문제 설명
증상:
x509: certificate has expired
SSL handshake failed원인:
- Istio CA 인증서 만료 (기본 10년)
- 워크로드 인증서 만료 (기본 24시간, 자동 갱신)
해결:
bash
# 1. CA 인증서 확인
kubectl get secret istio-ca-secret -n istio-system -o jsonpath='{.data.ca-cert\.pem}' | base64 -d | openssl x509 -noout -dates
# 2. 워크로드 인증서 확인
istioctl proxy-config secret <pod-name> -n <namespace>
# 3. CA 인증서 재생성
istioctl x ca rootDNS 해석 실패
문제 설명
증상:
no such host
DNS resolution failed해결:
yaml
# ServiceEntry로 외부 서비스 등록
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-api
spec:
hosts:
- api.example.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNSEnvoy 초기화 타임아웃
문제 설명
증상:
waiting for Envoy proxy to be ready
Readiness probe failed해결:
yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
proxy.istio.io/config: |
holdApplicationUntilProxyStarts: true
spec:
containers:
- name: myapp
image: myapp:latest
readinessProbe:
initialDelaySeconds: 10 # Envoy 초기화 대기디버깅 도구
istioctl 명령어
bash
# 1. 파드 상태 분석
istioctl x describe pod <pod-name> -n <namespace>
# 2. 구성 검증
istioctl analyze -A
# 3. Envoy 설정 확인
istioctl proxy-config all <pod-name> -n <namespace>
# 4. Envoy 로그 레벨 변경
istioctl proxy-config log <pod-name> --level debug
# 5. 버그 리포트 생성
istioctl bug-reportEnvoy Admin API
bash
# Envoy admin 포트로 포워딩
kubectl port-forward <pod-name> 15000:15000
# 1. 클러스터 상태 확인
curl localhost:15000/clusters
# 2. 통계 확인
curl localhost:15000/stats/prometheus
# 3. 설정 덤프
curl localhost:15000/config_dump
# 4. 로깅 레벨 변경
curl -X POST localhost:15000/logging?level=debug일반적인 로그 확인
bash
# 애플리케이션 로그
kubectl logs <pod-name> -c <container-name>
# Envoy 로그
kubectl logs <pod-name> -c istio-proxy
# 이전 컨테이너 로그 (재시작된 경우)
kubectl logs <pod-name> -c istio-proxy --previous
# 실시간 로그
kubectl logs -f <pod-name> -c istio-proxy참고 자료
공식 문서
관련 문서
마지막 업데이트: 2025년 11월 27일