Skip to content

Advanced 퀴즈

지원 버전: Istio 1.28.0 EKS 버전: 1.34 (Kubernetes 1.28+) 마지막 업데이트: 2026년 2월 19일

이 퀴즈는 Istio의 고급 기능에 대한 이해도를 테스트합니다.

객관식 문제 (1-5번)

문제 1: Ambient Mode vs Sidecar Mode

Istio Ambient Mode의 가장 큰 장점은?

A. 더 많은 기능 제공
B. 리소스 사용량 대폭 감소
C. 더 빠른 설치 속도
D. 더 나은 보안

정답 및 해설

정답: B

Ambient Mode의 가장 큰 장점은 리소스 사용량이 98% 이상 감소한다는 것입니다.

해설:

Sidecar Mode vs Ambient Mode 비교:

항목Sidecar ModeAmbient Mode개선
메모리50MB × Pod 수ztunnel + waypoint만98%+ 감소
CPU0.1 vCPU × Pod 수ztunnel + waypoint만98%+ 감소
Pod 재시작필요불필요운영 간소화
배포 속도느림 (Sidecar 주입)빠름5-10배 향상

1000개 Pod 규모에서 리소스 비교:

Sidecar Mode:
- 메모리: 1000 × 50MB = 50GB
- CPU: 1000 × 0.1 vCPU = 100 vCPU

Ambient Mode (10개 노드):
- 메모리: (10 × 50MB) + 200MB = 700MB
- CPU: (10 × 0.1 vCPU) + 0.5 vCPU = 1.5 vCPU

절감률: 98.6% (메모리), 98.5% (CPU)

Ambient Mode 아키텍처:

두 노드의 파드가 각 노드의 ztunnel L4 프록시로 연결되고, 두 ztunnel이 mTLS로 직접 통신하며 필요할 때만 선택적으로 waypoint L7 프록시를 거치는 Istio 앰비언트 메시 구조를 보여준다.

Ambient Mode 활성화:

bash
# Ambient Mode로 Istio 설치
istioctl install --set profile=ambient -y

# Namespace를 Ambient Mode에 추가
kubectl label namespace default istio.io/dataplane-mode=ambient

# 확인
kubectl get pods -n istio-system | grep ztunnel

각 옵션 분석:

  • A (X): 기능은 Sidecar와 동일 (일부 고급 기능은 waypoint 필요)
  • B (O): 리소스 사용량이 98% 이상 감소
  • C (X): 설치 속도는 부차적 이점
  • D (X): 보안 수준은 동일 (mTLS, AuthorizationPolicy 모두 지원)

참고 자료:


문제 2: Multi-cluster Mesh

Istio Multi-cluster Mesh에서 클러스터 간 서비스 검색을 담당하는 것은?

A. Istiod
B. CoreDNS
C. East-West Gateway
D. Service Entry

정답 및 해설

정답: A

Istiod는 멀티 클러스터 환경에서 모든 클러스터의 서비스 정보를 수집하고 배포합니다.

해설:

Multi-cluster Mesh 아키텍처:

하나의 Primary Istiod가 두 클러스터의 서비스 검색을 총괄하고, 각 클러스터의 Istiod가 자기 클러스터의 서비스 정보를 수집하며 두 클러스터의 파드가 크로스 클러스터로 통신하는 공유 컨트롤 플레인 구조를 보여준다.

Istiod의 역할:

  1. 서비스 검색 (Service Discovery):
    • 모든 클러스터의 Kubernetes Service 수집
    • 통합된 서비스 레지스트리 유지
    • Envoy에 엔드포인트 정보 배포
  2. 구성 배포:
    • VirtualService, DestinationRule을 모든 클러스터에 배포
    • Cross-cluster 라우팅 규칙 관리
  3. 인증서 관리:
    • 모든 클러스터의 mTLS 인증서 발급
    • Root CA를 공유하여 신뢰 체인 구축

Multi-cluster 설정 예시:

yaml
# Primary 클러스터 설정
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      meshID: mesh1
      multiCluster:
        clusterName: cluster1
      network: network1

---
# Remote 클러스터에서 Primary 접근
apiVersion: v1
kind: Secret
metadata:
  name: istio-remote-secret-cluster2
  namespace: istio-system
  annotations:
    networking.istio.io/cluster: cluster2
type: Opaque
data:
  kubeconfig: <base64-encoded-kubeconfig>

각 옵션 분석:

  • A (O): Istiod가 모든 클러스터의 서비스 정보를 수집하고 배포
  • B (X): CoreDNS는 클러스터 내부 DNS만 담당
  • C (X): East-West Gateway는 트래픽 라우팅만 담당 (서비스 검색 아님)
  • D (X): ServiceEntry는 외부 서비스를 수동으로 등록하는 리소스

참고 자료:


문제 3: EnvoyFilter 사용 목적

EnvoyFilter를 사용하는 주요 목적은?

A. Kubernetes Service 생성
B. VirtualService 자동 생성
C. Envoy 프록시 동작 커스터마이징
D. Istiod 구성 변경

정답 및 해설

정답: C

EnvoyFilter는 Envoy 프록시의 동작을 세밀하게 커스터마이징하기 위한 고급 리소스입니다.

해설:

EnvoyFilter 사용 사례:

  1. 커스텀 헤더 추가:
yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: add-custom-header
  namespace: default
spec:
  workloadSelector:
    labels:
      app: reviews
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_OUTBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.lua
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
          inline_code: |
            function envoy_on_request(request_handle)
              request_handle:headers():add("x-custom-header", "my-value")
            end
  1. Wasm 확장 통합:
yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: wasm-filter
spec:
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.wasm
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
          config:
            vm_config:
              runtime: "envoy.wasm.runtime.v8"
              code:
                local:
                  filename: "/etc/istio/extensions/auth_filter.wasm"
  1. Rate Limiting 통합:
yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: rate-limit-filter
spec:
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.ratelimit
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
          domain: productpage-ratelimit
          rate_limit_service:
            grpc_service:
              envoy_grpc:
                cluster_name: rate_limit_cluster

EnvoyFilter 적용 범위:

yaml
spec:
  # 전체 메시에 적용
  workloadSelector: {}

  # 특정 워크로드에만 적용
  workloadSelector:
    labels:
      app: reviews
      version: v2

  # 특정 네임스페이스에만 적용
  # (metadata.namespace로 제어)

주의사항:

⚠️ EnvoyFilter는 매우 강력하지만 위험합니다:

  • Envoy 내부 구조에 대한 깊은 이해 필요
  • Istio 버전 업그레이드 시 호환성 문제 가능
  • 잘못된 구성으로 전체 메시 장애 가능

모범 사례:

  1. 가능하면 VirtualService, DestinationRule 사용
  2. EnvoyFilter는 최후의 수단으로만 사용
  3. 테스트 환경에서 충분히 검증
  4. workloadSelector로 범위 제한

각 옵션 분석:

  • A (X): Kubernetes Service 생성은 kubectl로 수행
  • B (X): VirtualService는 수동으로 생성
  • C (O): Envoy 프록시의 동작을 세밀하게 커스터마이징
  • D (X): Istiod 구성은 IstioOperator로 변경

참고 자료:


문제 4: Sidecar Injection

Istio에서 자동 Sidecar 주입을 비활성화하는 방법은?

A. Namespace에서 istio-injection=enabled 레이블 제거
B. Pod에 sidecar.istio.io/inject="false" annotation 추가
C. Istiod 재시작
D. A와 B 모두 가능

정답 및 해설

정답: D

Namespace 레벨과 Pod 레벨 모두에서 Sidecar 주입을 제어할 수 있습니다.

해설:

Sidecar 주입 제어 방법:

1. Namespace 레벨 (A - O):

bash
# Sidecar 주입 활성화
kubectl label namespace default istio-injection=enabled

# Sidecar 주입 비활성화
kubectl label namespace default istio-injection-

# 또는 레이블 변경
kubectl label namespace default istio-injection=disabled --overwrite

2. Pod 레벨 (B - O):

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "false"  # Sidecar 주입 비활성화
    spec:
      containers:
      - name: myapp
        image: myapp:latest

Sidecar 주입 우선순위:

Pod annotation > Namespace label > 기본값

예시:
1. Namespace: istio-injection=enabled
   Pod: sidecar.istio.io/inject="false"
   결과: Sidecar 주입 안됨 (Pod annotation 우선)

2. Namespace: istio-injection=disabled
   Pod: sidecar.istio.io/inject="true"
   결과: Sidecar 주입됨 (Pod annotation 우선)

3. Namespace: 레이블 없음
   Pod: annotation 없음
   결과: Sidecar 주입 안됨 (기본값)

Sidecar 주입 검증:

bash
# Pod에 Sidecar가 주입되었는지 확인
kubectl get pods <pod-name> -o jsonpath='{.spec.containers[*].name}'
# 출력 예시: myapp istio-proxy (2개 = Sidecar 있음)

# Sidecar 주입 로그 확인
kubectl logs -n istio-system -l app=istiod --tail=100 | grep injection

# Namespace 설정 확인
kubectl get namespace -L istio-injection

혼합 환경 예시:

yaml
# Namespace 전체에 Sidecar 주입
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    istio-injection: enabled

---
# 특정 Pod만 제외 (예: 레거시 시스템)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: legacy-app
  namespace: production
spec:
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "false"
    spec:
      containers:
      - name: legacy
        image: legacy:v1

---
# 대부분의 Pod는 자동으로 Sidecar 주입됨
apiVersion: apps/v1
kind: Deployment
metadata:
  name: modern-app
  namespace: production
spec:
  template:
    spec:
      containers:
      - name: modern
        image: modern:v2

각 옵션 분석:

  • A (O): Namespace 레벨에서 Sidecar 주입 제어 가능
  • B (O): Pod 레벨에서 Sidecar 주입 제어 가능
  • C (X): Istiod 재시작은 불필요
  • D (O): A와 B 모두 유효한 방법

참고 자료:


문제 5: Argo Rollouts 통합

Argo Rollouts와 Istio를 함께 사용할 때 트래픽 분할을 담당하는 것은?

A. Argo Rollouts Controller B. Istio VirtualService C. Kubernetes Service D. Istio Gateway

정답 및 해설

정답: B

Istio VirtualService가 실제 트래픽 분할을 수행하고, Argo Rollouts는 VirtualService의 weight 값을 자동으로 업데이트합니다.

해설:

Argo Rollouts + Istio 통합 아키텍처:

사용자 요청이 Istio Gateway와 VirtualService를 거쳐 안정 파드와 카나리 파드로 가중치 분할되고, Argo Rollouts 컨트롤러가 Prometheus 메트릭 분석 결과에 따라 가중치와 파드 수를 자동 조정하는 카나리 배포 흐름을 보여준다.

VirtualService 역할:

yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - name: primary  # Argo Rollouts가 참조하는 route 이름
    route:
    - destination:
        host: reviews
        subset: stable
      weight: 100  # Argo Rollouts가 자동으로 변경
    - destination:
        host: reviews
        subset: canary
      weight: 0    # Argo Rollouts가 자동으로 변경

Argo Rollouts 설정:

yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: reviews
spec:
  strategy:
    canary:
      # Istio 통합 설정
      trafficRouting:
        istio:
          virtualService:
            name: reviews        # VirtualService 이름
            routes:
            - primary            # route 이름
          destinationRule:
            name: reviews        # DestinationRule 이름
            canarySubsetName: canary
            stableSubsetName: stable

      # Canary 단계
      steps:
      - setWeight: 10   # VirtualService weight를 10으로 변경
      - pause: {duration: 2m}
      - setWeight: 25   # VirtualService weight를 25로 변경
      - pause: {duration: 2m}
      - setWeight: 50
      - pause: {duration: 2m}

배포 프로세스:

1. Argo Rollouts가 새 버전 (v2) Pod 생성

2. Argo Rollouts가 VirtualService의 canary weight를 10으로 설정

3. Istio Envoy가 실제 10% 트래픽을 v2로 라우팅

4. AnalysisTemplate이 메트릭 확인 (에러율, 지연시간)

5. 성공 시 Argo Rollouts가 weight를 25로 증가

6. 반복...

7. 최종적으로 weight 100 (완전 전환)

책임 분담:

컴포넌트역할
Argo Rollouts

- Pod 생성/삭제
- VirtualService weight 업데이트
- 배포 전략 실행
- 자동 롤백

Istio VirtualService

- 실제 트래픽 분할
- 라우팅 규칙 적용
- Envoy 구성 생성

Envoy Proxy

- 트래픽 라우팅 실행
- 메트릭 수집

Prometheus

- 메트릭 저장
- AnalysisTemplate에 데이터 제공

실제 트래픽 흐름:

bash
# 사용자 요청 100개
100개 요청 Istio Gateway

         VirtualService
         (weight: stable=90, canary=10)

         ┌────┴────┐

      90개       10개
    Stable v1   Canary v2

각 옵션 분석:

  • A (X): Argo Rollouts는 VirtualService를 업데이트만 함 (직접 트래픽 분할 안함)
  • B (O): VirtualService가 실제 트래픽 분할 수행
  • C (X): Kubernetes Service는 로드 밸런싱만 담당 (트래픽 분할 안함)
  • D (X): Gateway는 외부 트래픽 진입점 (트래픽 분할 안함)

참고 자료:


주관식 문제 (6-10번)

문제 6: Ambient Mode 비용 절감 분석

AWS EKS 클러스터에서 Sidecar Mode에서 Ambient Mode로 전환할 때의 비용 절감 효과를 계산하세요. (가정: 500개 Pod, 5개 노드, r5.xlarge 인스턴스, 월 730시간 운영)

예시 답안

답변:

비용 절감 분석:


1. 가정 조건

클러스터 규모:
- Pod 수: 500개
- 노드 수: 5개
- 인스턴스 타입: r5.xlarge (4 vCPU, 32GB RAM)
- 인스턴스 비용: $0.252/시간
- 운영 시간: 월 730시간

리소스 사용량:
- Sidecar 메모리: 50MB/Pod
- Sidecar CPU: 0.1 vCPU/Pod
- ztunnel 메모리: 50MB/Node
- ztunnel CPU: 0.1 vCPU/Node
- waypoint 메모리: 200MB
- waypoint CPU: 0.5 vCPU

2. Sidecar Mode 리소스 계산

메모리 사용량:
= 500 Pod × 50MB
= 25,000MB
= 25GB

CPU 사용량:
= 500 Pod × 0.1 vCPU
= 50 vCPU

필요 인스턴스 수 (r5.xlarge: 4 vCPU, 32GB RAM):

CPU 기준:
= 50 vCPU ÷ 4 vCPU/인스턴스
= 12.5 인스턴스
≈ 13 인스턴스 필요

메모리 기준:
= 25GB ÷ 32GB/인스턴스
= 0.78 인스턴스
≈ 1 인스턴스 필요

실제 필요: max(13, 1) = 13 인스턴스

Sidecar Mode 월간 비용:

= 13 인스턴스 × $0.252/시간 × 730시간
= $2,395.56/월

3. Ambient Mode 리소스 계산

메모리 사용량:
= (5 노드 × 50MB) + 200MB
= 250MB + 200MB
= 450MB

CPU 사용량:
= (5 노드 × 0.1 vCPU) + 0.5 vCPU
= 0.5 vCPU + 0.5 vCPU
= 1.0 vCPU

필요 인스턴스 수:

CPU 기준:
= 1.0 vCPU ÷ 4 vCPU/인스턴스
= 0.25 인스턴스
≈ 1 인스턴스 필요

메모리 기준:
= 0.45GB ÷ 32GB/인스턴스
= 0.01 인스턴스
≈ 1 인스턴스 필요

실제 필요: max(1, 1) = 1 인스턴스

Ambient Mode 월간 비용:

= 1 인스턴스 × $0.252/시간 × 730시간
= $183.96/월

4. 비용 절감 효과

월간 절감액:
= $2,395.56 - $183.96
= $2,211.60/월

절감률:
= ($2,211.60 ÷ $2,395.56) × 100
= 92.3%

연간 절감액:
= $2,211.60 × 12
= $26,539.20/년

5. 리소스 절감 요약

항목Sidecar ModeAmbient Mode절감
메모리25GB0.45GB24.55GB (98.2%)
CPU50 vCPU1.0 vCPU49 vCPU (98.0%)
인스턴스13대1대12대 (92.3%)
월간 비용$2,395.56$183.96$2,211.60 (92.3%)
연간 비용$28,746.72$2,207.52$26,539.20 (92.3%)

6. 추가 비용 절감 요인

네트워크 비용:

  • Sidecar Mode: localhost 통신 없음 (모든 트래픽이 네트워크 통과)
  • Ambient Mode: ztunnel 간 직접 통신으로 효율 향상

운영 비용:

  • Pod 재시작 불필요 (배포 시간 단축)
  • Sidecar 주입 오류 없음
  • 관리 복잡도 감소

성능 향상:

  • 메모리 압박 감소로 Pod 성능 향상
  • OOMKilled 빈도 감소
  • 노드 자원 여유 확보

7. ROI (Return on Investment)

Ambient Mode 전환 비용 (1회):
- 학습 시간: 40시간 × $100/시간 = $4,000
- 테스트 및 검증: 20시간 × $100/시간 = $2,000
- 총 전환 비용: $6,000

투자 회수 기간:
= $6,000 ÷ $2,211.60/월
= 2.7개월

3년 총 절감액:
= ($26,539.20 × 3) - $6,000
= $73,617.60

8. 실전 고려사항

장점:

  • ✅ 92% 이상 비용 절감
  • ✅ 운영 간소화
  • ✅ 배포 속도 향상
  • ✅ 리소스 효율 극대화

주의사항:

  • ⚠️ Istio 1.28+ 베타 기능
  • ⚠️ L7 기능 필요 시 waypoint 추가 배포
  • ⚠️ 일부 고급 기능은 Sidecar 모드 필요
  • ⚠️ 충분한 테스트 필요

참고 자료:


문제 7: Multi-cluster Service Mesh 구성

2개의 EKS 클러스터(us-east-1, us-west-2)를 하나의 Istio Mesh로 통합하는 방법을 설명하세요. Primary-Remote 모델을 사용하고, 클러스터 간 서비스 호출 예시를 포함해야 합니다.

예시 답안

답변:

Multi-cluster Istio Mesh 구성:


1. 아키텍처 개요

us-east-1과 us-west-2 두 클러스터가 각자 프라이머리 컨트롤 플레인을 두고 서비스 검색 정보를 교환하며, 두 클러스터의 파드가 East-West 게이트웨이를 거쳐 mTLS로 통신하는 멀티 프라이머리 멀티 네트워크 구조를 보여준다.


2. 사전 준비

bash
# 두 클러스터에 접근 가능한 kubeconfig 설정
export CTX_CLUSTER1=eks-us-east-1
export CTX_CLUSTER2=eks-us-west-2

# 컨텍스트 확인
kubectl config get-contexts

# CA 인증서 생성 (공유 Root CA)
mkdir -p certs
cd certs

# Root CA 생성
make -f ../istio-1.28.0/tools/certs/Makefile.selfsigned.mk root-ca

# 각 클러스터용 중간 인증서 생성
make -f ../istio-1.28.0/tools/certs/Makefile.selfsigned.mk cluster1-cacerts
make -f ../istio-1.28.0/tools/certs/Makefile.selfsigned.mk cluster2-cacerts

3. 클러스터 1 (Primary) 설정

bash
# CA 인증서 Secret 생성
kubectl create namespace istio-system --context="${CTX_CLUSTER1}"
kubectl create secret generic cacerts -n istio-system \
  --from-file=cluster1/ca-cert.pem \
  --from-file=cluster1/ca-key.pem \
  --from-file=cluster1/root-cert.pem \
  --from-file=cluster1/cert-chain.pem \
  --context="${CTX_CLUSTER1}"

# Primary Istio 설치
istioctl install --context="${CTX_CLUSTER1}" -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      meshID: mesh1
      multiCluster:
        clusterName: cluster1
      network: network1

  components:
    ingressGateways:
    - name: istio-eastwestgateway
      label:
        istio: eastwestgateway
        app: istio-eastwestgateway
        topology.istio.io/network: network1
      enabled: true
      k8s:
        env:
        - name: ISTIO_META_REQUESTED_NETWORK_VIEW
          value: network1
        service:
          type: LoadBalancer
          ports:
          - name: status-port
            port: 15021
            targetPort: 15021
          - name: tls
            port: 15443
            targetPort: 15443
          - name: tls-istiod
            port: 15012
            targetPort: 15012
          - name: tls-webhook
            port: 15017
            targetPort: 15017
EOF

# East-West Gateway 노출
kubectl apply --context="${CTX_CLUSTER1}" -n istio-system -f \
  samples/multicluster/expose-services.yaml

4. 클러스터 2 (Remote) 설정

bash
# CA 인증서 Secret 생성
kubectl create namespace istio-system --context="${CTX_CLUSTER2}"
kubectl create secret generic cacerts -n istio-system \
  --from-file=cluster2/ca-cert.pem \
  --from-file=cluster2/ca-key.pem \
  --from-file=cluster2/root-cert.pem \
  --from-file=cluster2/cert-chain.pem \
  --context="${CTX_CLUSTER2}"

# Remote Secret 생성 (cluster1에서 cluster2 접근)
istioctl create-remote-secret \
  --context="${CTX_CLUSTER2}" \
  --name=cluster2 | \
  kubectl apply -f - --context="${CTX_CLUSTER1}"

# Remote Istio 설치
istioctl install --context="${CTX_CLUSTER2}" -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      meshID: mesh1
      multiCluster:
        clusterName: cluster2
      network: network2
      remotePilotAddress: <CLUSTER1_EAST_WEST_GATEWAY_IP>

  components:
    ingressGateways:
    - name: istio-eastwestgateway
      label:
        istio: eastwestgateway
        app: istio-eastwestgateway
        topology.istio.io/network: network2
      enabled: true
      k8s:
        env:
        - name: ISTIO_META_REQUESTED_NETWORK_VIEW
          value: network2
        service:
          type: LoadBalancer
          ports:
          - name: status-port
            port: 15021
          - name: tls
            port: 15443
          - name: tls-istiod
            port: 15012
          - name: tls-webhook
            port: 15017
EOF

5. 서비스 배포 및 검증

클러스터 1에 Service A 배포:

yaml
# cluster1: service-a.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-a
  labels:
    app: service-a
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: service-a

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-a
spec:
  replicas: 2
  selector:
    matchLabels:
      app: service-a
  template:
    metadata:
      labels:
        app: service-a
    spec:
      containers:
      - name: service-a
        image: nginx:latest
        ports:
        - containerPort: 8080
bash
kubectl apply --context="${CTX_CLUSTER1}" -f service-a.yaml

클러스터 2에 Service B 배포:

yaml
# cluster2: service-b.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-b
  labels:
    app: service-b
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: service-b

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-b
spec:
  replicas: 2
  selector:
    matchLabels:
      app: service-b
  template:
    metadata:
      labels:
        app: service-b
    spec:
      containers:
      - name: service-b
        image: nginx:latest
        ports:
        - containerPort: 8080
bash
kubectl apply --context="${CTX_CLUSTER2}" -f service-b.yaml

6. Cross-cluster 서비스 호출 테스트

bash
# 클러스터 1에서 클러스터 2의 서비스 호출
kubectl exec --context="${CTX_CLUSTER1}" -it \
  $(kubectl get pod --context="${CTX_CLUSTER1}" -l app=service-a -o jsonpath='{.items[0].metadata.name}') \
  -- curl http://service-b.default.svc.cluster.local:8080

# 클러스터 2에서 클러스터 1의 서비스 호출
kubectl exec --context="${CTX_CLUSTER2}" -it \
  $(kubectl get pod --context="${CTX_CLUSTER2}" -l app=service-b -o jsonpath='{.items[0].metadata.name}') \
  -- curl http://service-a.default.svc.cluster.local:8080

7. 서비스 검색 확인

bash
# 클러스터 1에서 Envoy 구성 확인
istioctl --context="${CTX_CLUSTER1}" proxy-config endpoints \
  $(kubectl get pod --context="${CTX_CLUSTER1}" -l app=service-a -o jsonpath='{.items[0].metadata.name}') | \
  grep service-b

# 출력 예시:
# service-b.default.svc.cluster.local:8080  HEALTHY  <cluster2-pod-ip>:8080

8. 트래픽 정책 적용

yaml
# Cross-cluster 트래픽 라우팅
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: service-b
spec:
  hosts:
  - service-b.default.svc.cluster.local
  http:
  - match:
    - sourceLabels:
        app: service-a
    route:
    - destination:
        host: service-b.default.svc.cluster.local
        port:
          number: 8080
      weight: 80  # 80%는 로컬 클러스터
    - destination:
        host: service-b.default.svc.cluster.local
        port:
          number: 8080
      weight: 20  # 20%는 원격 클러스터

---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: service-b
spec:
  host: service-b.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      localityLbSetting:
        enabled: true  # Locality-aware 라우팅

9. 모니터링 및 검증

bash
# Prometheus에서 Cross-cluster 트래픽 확인
kubectl port-forward --context="${CTX_CLUSTER1}" -n istio-system \
  svc/prometheus 9090:9090

# Prometheus 쿼리:
# sum(rate(istio_requests_total{source_cluster="cluster1", destination_cluster="cluster2"}[5m]))

# Kiali로 시각화
istioctl dashboard kiali --context="${CTX_CLUSTER1}"

10. 주의사항 및 모범 사례

주의사항:

  • ⚠️ 공유 Root CA 필수
  • ⚠️ 네트워크 레이턴시 고려
  • ⚠️ East-West Gateway 보안 강화
  • ⚠️ DNS 해석 올바르게 설정

모범 사례:

  • ✅ Locality-aware 라우팅 활성화
  • ✅ Circuit Breaker 설정
  • ✅ 클러스터별 replica 유지
  • ✅ Cross-cluster 트래픽 모니터링

참고 자료:


문제 8: EnvoyFilter로 커스텀 Rate Limiting

EnvoyFilter를 사용하여 특정 경로(/api/premium/*)에만 사용자별 Rate Limiting(분당 100 요청)을 적용하는 방법을 구현하세요.

예시 답안

답변:

EnvoyFilter 기반 Rate Limiting 구현:


1. 아키텍처 개요

클라이언트 요청이 Envoy 프록시를 거쳐 Redis의 Rate Limit 카운터를 확인하고, 한도 내이면 백엔드로 전달하고 초과하면 429 Too Many Requests로 거부하는 흐름을 보여준다.


2. Redis Rate Limit 서버 배포

yaml
# redis-ratelimit.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis-ratelimit
  namespace: istio-system
spec:
  ports:
  - port: 6379
    name: redis
  selector:
    app: redis-ratelimit

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-ratelimit
  namespace: istio-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-ratelimit
  template:
    metadata:
      labels:
        app: redis-ratelimit
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        ports:
        - containerPort: 6379
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi

---
# Envoy Rate Limit 서비스
apiVersion: v1
kind: ConfigMap
metadata:
  name: ratelimit-config
  namespace: istio-system
data:
  config.yaml: |
    domain: premium-ratelimit
    descriptors:
      # 사용자별 Rate Limit: 분당 100 요청
      - key: user_id
        rate_limit:
          unit: minute
          requests_per_unit: 100

---
apiVersion: v1
kind: Service
metadata:
  name: ratelimit
  namespace: istio-system
spec:
  ports:
  - port: 8081
    name: http
  - port: 9091
    name: grpc
  selector:
    app: ratelimit

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ratelimit
  namespace: istio-system
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ratelimit
  template:
    metadata:
      labels:
        app: ratelimit
    spec:
      containers:
      - name: ratelimit
        image: envoyproxy/ratelimit:master
        ports:
        - containerPort: 8081
        - containerPort: 9091
        env:
        - name: REDIS_URL
          value: redis-ratelimit.istio-system.svc.cluster.local:6379
        - name: USE_STATSD
          value: "false"
        - name: LOG_LEVEL
          value: debug
        - name: RUNTIME_ROOT
          value: /data
        - name: RUNTIME_SUBDIRECTORY
          value: ratelimit
        volumeMounts:
        - name: config-volume
          mountPath: /data/ratelimit/config
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
      volumes:
      - name: config-volume
        configMap:
          name: ratelimit-config
bash
kubectl apply -f redis-ratelimit.yaml

3. EnvoyFilter 구성

yaml
# envoyfilter-ratelimit.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: premium-ratelimit
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      app: api-gateway

  configPatches:
  # HTTP 필터 체인에 Rate Limit 필터 추가
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.ratelimit
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
          domain: premium-ratelimit
          failure_mode_deny: true  # Rate Limit 서버 장애 시 거부
          enable_x_ratelimit_headers: DRAFT_VERSION_03
          rate_limit_service:
            grpc_service:
              envoy_grpc:
                cluster_name: rate_limit_cluster
            transport_api_version: V3

  # Rate Limit 클러스터 정의
  - applyTo: CLUSTER
    patch:
      operation: ADD
      value:
        name: rate_limit_cluster
        type: STRICT_DNS
        connect_timeout: 1s
        lb_policy: ROUND_ROBIN
        http2_protocol_options: {}
        load_assignment:
          cluster_name: rate_limit_cluster
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: ratelimit.istio-system.svc.cluster.local
                    port_value: 9091

  # HTTP 라우트에 Rate Limit 액션 추가
  - applyTo: HTTP_ROUTE
    match:
      context: SIDECAR_INBOUND
      routeConfiguration:
        vhost:
          route:
            action: ANY
    patch:
      operation: MERGE
      value:
        route:
          rate_limits:
          # /api/premium/* 경로만 Rate Limit 적용
          - actions:
            - header_value_match:
                descriptor_value: "premium"
                headers:
                - name: ":path"
                  prefix_match: "/api/premium/"
            - request_headers:
                header_name: "x-user-id"
                descriptor_key: "user_id"
bash
kubectl apply -f envoyfilter-ratelimit.yaml

4. VirtualService 구성

yaml
# virtualservice.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: api-service
spec:
  hosts:
  - api.example.com
  gateways:
  - api-gateway
  http:
  # Premium API 경로
  - match:
    - uri:
        prefix: /api/premium/
    route:
    - destination:
        host: premium-backend
        port:
          number: 8080

  # 일반 API 경로 (Rate Limit 없음)
  - match:
    - uri:
        prefix: /api/
    route:
    - destination:
        host: backend
        port:
          number: 8080

5. 테스트 애플리케이션

yaml
# backend.yaml
apiVersion: v1
kind: Service
metadata:
  name: premium-backend
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: premium-backend

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: premium-backend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: premium-backend
  template:
    metadata:
      labels:
        app: premium-backend
        app: api-gateway  # EnvoyFilter 적용 대상
    spec:
      containers:
      - name: backend
        image: nginx:latest
        ports:
        - containerPort: 8080
bash
kubectl apply -f backend.yaml

6. 테스트

bash
# 정상 요청 (사용자별 100 요청/분 이하)
for i in {1..50}; do
  curl -H "x-user-id: user123" \
       -H "Host: api.example.com" \
       http://<INGRESS_GATEWAY>/api/premium/data
  sleep 0.1
done

# 출력: 200 OK (모두 성공)

# Rate Limit 초과 (100 요청/분 초과)
for i in {1..150}; do
  curl -H "x-user-id: user123" \
       -H "Host: api.example.com" \
       http://<INGRESS_GATEWAY>/api/premium/data
done

# 출력:
# 1-100번: 200 OK
# 101-150번: 429 Too Many Requests

# 다른 사용자는 영향 없음
curl -H "x-user-id: user456" \
     -H "Host: api.example.com" \
     http://<INGRESS_GATEWAY>/api/premium/data

# 출력: 200 OK

7. Rate Limit 헤더 확인

bash
curl -I -H "x-user-id: user123" \
     -H "Host: api.example.com" \
     http://<INGRESS_GATEWAY>/api/premium/data

# 출력:
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 73
# X-RateLimit-Reset: 1735689600

8. Redis 모니터링

bash
# Redis에 저장된 Rate Limit 데이터 확인
kubectl exec -it -n istio-system \
  $(kubectl get pod -n istio-system -l app=redis-ratelimit -o jsonpath='{.items[0].metadata.name}') \
  -- redis-cli

# Redis CLI에서:
KEYS *
# 출력: "premium-ratelimit_user123_..."

GET "premium-ratelimit_user123_..."
# 출력: "27" (남은 요청 수)

TTL "premium-ratelimit_user123_..."
# 출력: "42" (초 단위 TTL)

9. Prometheus 메트릭

promql
# Rate Limit 거부된 요청 수
sum(rate(envoy_http_ratelimit_rejected_total[5m])) by (pod)

# Rate Limit 허용된 요청 수
sum(rate(envoy_http_ratelimit_ok_total[5m])) by (pod)

# Rate Limit 서버 오류
sum(rate(envoy_http_ratelimit_error_total[5m])) by (pod)

10. 주의사항 및 모범 사례

주의사항:

  • ⚠️ Redis 고가용성 구성 필요 (프로덕션)
  • ⚠️ Rate Limit 서버 장애 시 동작 정의 (failure_mode_deny)
  • ⚠️ 사용자 식별 헤더 (x-user-id) 신뢰성 확보
  • ⚠️ EnvoyFilter는 Istio 버전 업그레이드 시 호환성 확인 필요

모범 사례:

  • ✅ Redis Sentinel 또는 Cluster 사용
  • ✅ Rate Limit 서버 replica ≥ 2
  • ✅ 적절한 모니터링 및 알림
  • ✅ 사용자별 예외 처리 (VIP 사용자 등)

참고 자료:


문제 9: Argo Rollouts Blue/Green 배포

Argo Rollouts와 Istio를 사용하여 Blue/Green 배포를 구현하세요. 자동 분석(AnalysisTemplate)을 포함하고, 실패 시 자동 롤백되도록 구성해야 합니다.

예시 답안

답변:

Argo Rollouts Blue/Green 배포 구현:


1. Blue/Green 배포 개념

사용자 트래픽은 Gateway를 거쳐 Active Service의 Blue 버전으로 가고 Preview Service는 미리보기 트래픽만 Green 버전으로 보내며, AnalysisTemplate이 Green을 분석해 성공하면 트래픽을 전환하고 실패하면 롤백하는 블루-그린 배포 흐름을 보여준다.


2. Kubernetes Service 생성

yaml
# services.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-active
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: myapp
    # Argo Rollouts가 자동으로 selector 관리

---
apiVersion: v1
kind: Service
metadata:
  name: myapp-preview
spec:
  ports:
  - port: 8080
    name: http
  selector:
    app: myapp
    # Argo Rollouts가 자동으로 selector 관리
bash
kubectl apply -f services.yaml

3. Istio Gateway 및 VirtualService

yaml
# gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: myapp-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - myapp.example.com

---
# virtualservice.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
  - myapp.example.com
  gateways:
  - myapp-gateway
  http:
  # 프로덕션 트래픽 (Active)
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: myapp-active
        port:
          number: 8080

---
# preview-virtualservice.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-preview
spec:
  hosts:
  - myapp-preview.example.com
  gateways:
  - myapp-gateway
  http:
  # 미리보기 트래픽 (Preview)
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: myapp-preview
        port:
          number: 8080
bash
kubectl apply -f gateway.yaml

4. AnalysisTemplate 정의

yaml
# analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
  - name: service-name

  metrics:
  # 메트릭 1: 성공률 (95% 이상)
  - name: success-rate
    interval: 30s
    count: 5
    successCondition: result >= 0.95
    failureLimit: 2
    provider:
      prometheus:
        address: http://prometheus.istio-system:9090
        query: |
          sum(rate(
            istio_requests_total{
              destination_service_name="{{args.service-name}}",
              response_code!~"5.*"
            }[2m]
          ))
          /
          sum(rate(
            istio_requests_total{
              destination_service_name="{{args.service-name}}"
            }[2m]
          ))

---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: latency
spec:
  args:
  - name: service-name

  metrics:
  # 메트릭 2: P95 지연시간 (500ms 이하)
  - name: latency-p95
    interval: 30s
    count: 5
    successCondition: result <= 500
    failureLimit: 2
    provider:
      prometheus:
        address: http://prometheus.istio-system:9090
        query: |
          histogram_quantile(0.95,
            sum(rate(
              istio_request_duration_milliseconds_bucket{
                destination_service_name="{{args.service-name}}"
              }[2m]
            )) by (le)
          )

---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: error-rate
spec:
  args:
  - name: service-name

  metrics:
  # 메트릭 3: 에러율 (1% 이하)
  - name: error-rate
    interval: 30s
    count: 5
    successCondition: result <= 0.01
    failureLimit: 2
    provider:
      prometheus:
        address: http://prometheus.istio-system:9090
        query: |
          sum(rate(
            istio_requests_total{
              destination_service_name="{{args.service-name}}",
              response_code=~"5.*"
            }[2m]
          ))
          /
          sum(rate(
            istio_requests_total{
              destination_service_name="{{args.service-name}}"
            }[2m]
          ))
bash
kubectl apply -f analysis-template.yaml

5. Rollout 리소스 정의

yaml
# rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
spec:
  replicas: 5
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: myapp

  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v1
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi

  # Blue/Green 배포 전략
  strategy:
    blueGreen:
      # Active Service (프로덕션)
      activeService: myapp-active

      # Preview Service (테스트)
      previewService: myapp-preview

      # 자동 승격 비활성화 (수동 승격 또는 Analysis 기반)
      autoPromotionEnabled: false

      # Green 배포 후 대기 시간
      scaleDownDelaySeconds: 30

      # 배포 전 분석 (Green 환경 검증)
      prePromotionAnalysis:
        templates:
        - templateName: success-rate
        - templateName: latency
        - templateName: error-rate
        args:
        - name: service-name
          value: myapp-preview

      # 승격 후 분석 (Active 전환 후 검증)
      postPromotionAnalysis:
        templates:
        - templateName: success-rate
        - templateName: latency
        - templateName: error-rate
        args:
        - name: service-name
          value: myapp-active
bash
kubectl apply -f rollout.yaml

6. 새 버전 배포

bash
# 새 버전 이미지로 업데이트
kubectl argo rollouts set image myapp \
  myapp=myapp:v2

# 배포 상태 모니터링
kubectl argo rollouts get rollout myapp --watch

# 출력:
# Name:            myapp
# Namespace:       default
# Status:          ॥ Paused
# Strategy:        BlueGreen
# Images:          myapp:v1 (stable, active)
#                  myapp:v2 (preview)
# Replicas:
#   Desired:       5
#   Current:       10
#   Updated:       5
#   Ready:         5
#   Available:     5
# Analysis:        Running

7. 배포 프로세스

1. 새 버전 (Green) Pod 5개 생성

2. Preview Service가 Green을 가리킴

3. prePromotionAnalysis 시작 (2.5분)
   - success-rate 측정 (5회 × 30초)
   - latency-p95 측정 (5회 × 30초)
   - error-rate 측정 (5회 × 30초)

4. 분석 결과 확인
   ├─ 성공 → 5단계 진행
   └─ 실패 → 자동 롤백 (Green Pod 삭제)

5. 수동 승격 또는 자동 승격
   kubectl argo rollouts promote myapp

6. Active Service가 Green을 가리킴
   Preview Service가 Blue를 가리킴

7. postPromotionAnalysis 시작 (2.5분)
   - 프로덕션 트래픽으로 Green 검증

8. 분석 결과 확인
   ├─ 성공 → Blue Pod 삭제 (30초 후)
   └─ 실패 → 즉시 롤백 (Active를 Blue로 복구)

8. 수동 승격

bash
# Green 환경 미리보기 (Preview Service)
curl http://myapp-preview.example.com

# 문제 없으면 승격
kubectl argo rollouts promote myapp

# 승격 후 Active Service로 트래픽 전환됨
curl http://myapp.example.com

9. 자동 롤백 시나리오

시나리오 1: prePromotionAnalysis 실패

bash
# Green 환경에서 에러율이 1% 초과
# Analysis 로그:
# error-rate: FAILED (0.03 > 0.01)
# failureLimit: 2/2

# 자동 롤백 실행
# Green Pod 삭제
# Blue가 계속 Active 유지

kubectl argo rollouts get rollout myapp
# Status: Degraded
# Message: PrePromotionAnalysis Failed

시나리오 2: postPromotionAnalysis 실패

bash
# Active 전환 후 성공률이 95% 미만
# Analysis 로그:
# success-rate: FAILED (0.92 < 0.95)
# failureLimit: 2/2

# 자동 롤백 실행
# Active Service를 즉시 Blue로 복구
# Green은 Preview로 이동

kubectl argo rollouts get rollout myapp
# Status: Degraded
# Message: PostPromotionAnalysis Failed

10. 모니터링 및 대시보드

bash
# Argo Rollouts 대시보드
kubectl argo rollouts dashboard

# Kiali에서 트래픽 시각화
istioctl dashboard kiali

# Grafana에서 메트릭 확인
kubectl port-forward -n istio-system svc/grafana 3000:3000

Prometheus 쿼리:

promql
# 배포 진행 상태
argo_rollouts_info{name="myapp"}

# Analysis 결과
argo_rollouts_analysis_run_metric_phase{name="myapp", metric="success-rate"}

# 활성 버전별 트래픽
sum(rate(istio_requests_total{destination_service_name="myapp"}[5m])) by (destination_version)

11. 모범 사례

장점:

  • ✅ 즉시 롤백 가능 (스위치 전환)
  • ✅ 프로덕션 영향 최소화
  • ✅ 충분한 테스트 시간 확보
  • ✅ 자동 분석 및 롤백

주의사항:

  • ⚠️ 2배 리소스 필요 (Blue + Green)
  • ⚠️ 데이터베이스 스키마 호환성 확인
  • ⚠️ 세션 관리 (Sticky Session 필요 시)

참고 자료:


문제 10: DNS Caching 성능 최적화

Istio에서 DNS Caching을 활성화하여 외부 서비스 호출 성능을 개선하는 방법을 설명하세요. 벤치마크 결과를 포함해야 합니다.

예시 답안

답변:

Istio DNS Caching 구현 및 성능 측정:


1. DNS Caching 필요성

문제: DNS 조회 오버헤드

외부 API 호출 시마다 DNS 조회 발생:
1. 애플리케이션 → Envoy: HTTP 요청
2. Envoy → CoreDNS: DNS 조회 (50-100ms)
3. CoreDNS → 응답: IP 주소
4. Envoy → 외부 API: HTTP 요청 (100-200ms)

총 지연시간: 150-300ms

해결: DNS Caching 활성화

DNS Caching 후:
1. 애플리케이션 → Envoy: HTTP 요청
2. Envoy: 캐시된 IP 사용 (0ms)
3. Envoy → 외부 API: HTTP 요청 (100-200ms)

총 지연시간: 100-200ms (33-50% 개선)

2. ServiceEntry로 외부 서비스 등록

yaml
# external-api-serviceentry.yaml
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-api
spec:
  hosts:
  - api.github.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  location: MESH_EXTERNAL
  resolution: DNS  # DNS 해석 사용
bash
kubectl apply -f external-api-serviceentry.yaml

3. DestinationRule로 DNS Caching 활성화

yaml
# destinationrule-dns-cache.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: external-api
spec:
  host: api.github.com
  trafficPolicy:
    # DNS 리프레시 간격: 5분
    # (TTL이 0이어도 5분마다 DNS 재조회)
    dnsRefreshRate: 5m

    # Connection Pool 설정
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
        http2MaxRequests: 100
        maxRequestsPerConnection: 10

    # Outlier Detection
    outlierDetection:
      consecutiveErrors: 5
      interval: 30s
      baseEjectionTime: 30s
bash
kubectl apply -f destinationrule-dns-cache.yaml

4. EnvoyFilter로 고급 DNS 설정

yaml
# envoyfilter-dns-cache.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: dns-cache-filter
  namespace: istio-system
spec:
  configPatches:
  # DNS 캐시 필터 추가
  - applyTo: NETWORK_FILTER
    match:
      context: SIDECAR_OUTBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.tcp_proxy"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.network.dns_cache
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.dns_cache.v3.DnsCacheConfig
          dns_cache_config:
            name: dynamic_forward_proxy_cache_config
            dns_lookup_family: V4_ONLY
            # DNS 캐시 TTL: 5분
            dns_cache_ttl: 300s
            # 최대 캐시 항목 수
            max_hosts: 1024
            # DNS 조회 타임아웃
            dns_query_timeout: 5s

  # Cluster에 DNS 캐시 적용
  - applyTo: CLUSTER
    match:
      context: SIDECAR_OUTBOUND
      cluster:
        service: "*.external"
    patch:
      operation: MERGE
      value:
        dns_lookup_family: V4_ONLY
        # Strict DNS 사용 (DNS 캐싱 활성화)
        type: STRICT_DNS
        # DNS 리프레시 간격
        dns_refresh_rate: 300s
        # 연결 재사용
        upstream_connection_options:
          tcp_keepalive:
            keepalive_time: 60
bash
kubectl apply -f envoyfilter-dns-cache.yaml

5. 테스트 애플리케이션 배포

yaml
# test-app.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-app
  labels:
    app: test-app
spec:
  containers:
  - name: test
    image: curlimages/curl:latest
    command: ["/bin/sh"]
    args: ["-c", "sleep 3600"]
bash
kubectl apply -f test-app.yaml

6. 성능 벤치마크

DNS Caching 비활성화 (Before):

bash
# 100회 연속 호출 테스트
kubectl exec -it test-app -- sh -c '
for i in $(seq 1 100); do
  time curl -s -o /dev/null -w "%{time_total}\n" https://api.github.com/users/octocat
done' | awk '{sum+=$1; count++} END {print "평균 응답 시간:", sum/count, "초"}'

# 출력:
# 평균 응답 시간: 0.287 초

DNS Caching 활성화 (After):

bash
# DestinationRule 적용 후 동일 테스트
kubectl exec -it test-app -- sh -c '
for i in $(seq 1 100); do
  time curl -s -o /dev/null -w "%{time_total}\n" https://api.github.com/users/octocat
done' | awk '{sum+=$1; count++} END {print "평균 응답 시간:", sum/count, "초"}'

# 출력:
# 평균 응답 시간: 0.152 초

성능 개선:

개선 전: 287ms
개선 후: 152ms
개선율: (287 - 152) / 287 = 47%

DNS 조회 시간: ~135ms 절감

7. Envoy 통계 확인

bash
# Envoy DNS 캐시 통계
kubectl exec -it test-app -c istio-proxy -- \
  curl localhost:15000/stats | grep dns_cache

# 출력:
# cluster.outbound|443||api.github.com.dns_cache_hits: 99
# cluster.outbound|443||api.github.com.dns_cache_misses: 1
# cluster.outbound|443||api.github.com.dns_refresh: 0

# 캐시 히트율: 99 / (99 + 1) = 99%

8. 상세 벤치마크 결과

테스트 환경:

  • 클러스터: AWS EKS 1.34
  • Istio: 1.28.0
  • 노드: r5.xlarge
  • 위치: us-east-1
  • 외부 API: api.github.com

벤치마크 도구: Apache Bench

bash
# DNS Caching 비활성화
kubectl exec -it test-app -- ab -n 1000 -c 10 \
  https://api.github.com/users/octocat

# 결과:
# Requests per second:    12.34 [#/sec]
# Time per request:       81.07 [ms] (mean)
# Time per request:       810.70 [ms] (mean, across all concurrent requests)

# DNS Caching 활성화
kubectl exec -it test-app -- ab -n 1000 -c 10 \
  https://api.github.com/users/octocat

# 결과:
# Requests per second:    23.15 [#/sec]
# Time per request:       43.19 [ms] (mean)
# Time per request:       431.90 [ms] (mean, across all concurrent requests)

# 처리량 개선: 23.15 / 12.34 = 1.88배 (88% 향상)

9. 비교표

항목DNS Caching 비활성화DNS Caching 활성화개선
평균 응답 시간287ms152ms47% ↓
P95 응답 시간350ms180ms49% ↓
P99 응답 시간420ms210ms50% ↓
처리량 (RPS)12.3423.1588% ↑
DNS 캐시 히트율0%99%-
연결 재사용률0%95%-

10. Prometheus 모니터링

promql
# DNS 캐시 히트율
sum(rate(envoy_dns_cache_dns_query_success[5m]))
/
(
  sum(rate(envoy_dns_cache_dns_query_success[5m])) +
  sum(rate(envoy_dns_cache_dns_query_failure[5m]))
)

# 외부 API 지연시간 (P95)
histogram_quantile(0.95,
  sum(rate(
    istio_request_duration_milliseconds_bucket{
      destination_service_name="api.github.com"
    }[5m]
  )) by (le)
)

# 연결 재사용률
rate(envoy_cluster_upstream_cx_active[5m])
/
rate(envoy_cluster_upstream_cx_total[5m])

11. 모범 사례

권장 설정:

  • ✅ DNS 리프레시 간격: 5-15분 (외부 서비스 TTL 고려)
  • ✅ Connection Pool 활성화 (연결 재사용)
  • ✅ HTTP/2 사용 (멀티플렉싱)
  • ✅ Keep-Alive 활성화

주의사항:

  • ⚠️ TTL이 짧은 서비스는 리프레시 간격 줄이기
  • ⚠️ DNS 변경 시 캐시 무효화 시간 고려
  • ⚠️ 장애 조치 시나리오 테스트

참고 자료:


점수 계산

  • 객관식 1-5번: 각 10점 (총 50점)
  • 주관식 6-10번: 각 10점 (총 50점)
  • 총점: 100점

평가 기준:

  • 90-100점: 우수 (Istio 고급 기능 전문가)
  • 80-89점: 양호 (고급 기능 활용 가능)
  • 70-79점: 보통 (추가 학습 권장)
  • 60-69점: 미흡 (기본 개념 복습 필요)
  • 0-59점: 재학습 필요

학습 자료