ICA — Istio Certified Associate
Sizing Resilience Settings
한국어 원문으로 표시합니다.
목표
재시도·타임아웃·서킷브레이커·장애 주입·미러링을 직접 작성하면서, 각 값이 서로 어떤 제약을 거는지 이해합니다.
왜 중요한가
복원력 설정은 복사해 오면 대개 동작하지 않거나, 더 나쁘게는 장애를 증폭시킵니다. 재시도를 호출 체인의 모든 계층에 걸면 3단 체인에서 최악의 경우 9배, 4단이면 27배의 요청이 가장 안쪽 서비스로 몰립니다. 이미 죽어가는 서비스에 재시도가 마지막 일격이 되는 구조입니다.
타임아웃도 마찬가지입니다. timeout은 재시도와 backoff를 포함한 전체 예산이고 perTryTimeout은 각 시도의 상한입니다. 빠른 실패라면 전체 예산이 시도별 상한의 합보다 작아도 재시도할 수 있습니다. 반대로 한 시도가 전체 예산을 다 쓰면 다음 시도가 시작되지 않을 수 있습니다. 이 실습의 3초/1초/추가 2회는 설정 작성용 값이지, 세 시도가 각각 1초씩 반드시 실행된다는 보장이 아닙니다. 실제 횟수는 실패 조건과 응답 시간, backoff를 함께 관측해야 합니다. 바깥 호출자가 기다리기를 끝내도 안쪽의 업무 처리가 취소된다는 보장은 없으므로, 이미 처리된 쓰기를 다시 실행하지 않도록 중복 방지와 취소 전파를 별도로 설계합니다.
서킷브레이커는 값이 너무 크면 사실상 꺼진 것과 같고, 너무 작으면 평시에도 503 이 납니다. 그래서 실측 동시성을 기준으로 산정하고, maxEjectionPercent 로 안전판을 둡니다. 이 실습은 그 감각을 매니페스트로 옮기는 훈련입니다.
Kubernetes 기본 리소스는 실제로 apply 하고, Istio CRD 는 /root/ica-resilience/ 아래 파일로 작성합니다. kwok 기반 설계 실습이므로 실제 Envoy의 HTTP 응답·재시도 횟수·업무 중복 처리를 여기서 검증한 것으로 간주하지 마세요.
단계
- 네임스페이스
ica-resilience를 만들고 라벨istio-injection=enabled를 붙이세요. - 네임스페이스
ica-resilience에 디플로이먼트inventory를 3 레플리카로 배포하세요. 파드 라벨은app=inventory, 이미지는nginx:1.27-alpine입니다. - 같은 네임스페이스에 서비스 두 개를 만드세요.
inventory와inventory-canary이며 둘 다 포트8080, 포트 이름http입니다.inventory의 selector 는app=inventory입니다. /root/ica-resilience/vs-inventory-retry.yaml에 VirtualService 를 작성하세요.spec.hosts[0]은inventory.ica-resilience.svc.cluster.local, http 규칙에timeout: 3s,retries.attempts: 2,retries.perTryTimeout: 1s,retries.retryOn에는5xx와connect-failure를 포함하세요./root/ica-resilience/vs-inventory-fault.yaml에 VirtualService 를 작성하세요. 규칙 두 개입니다. 첫 규칙은 헤더x-chaos-test가true인 요청에만 적용되며fault.delay.fixedDelay: 3s/fault.delay.percentage.value: 50/fault.abort.httpStatus: 503/fault.abort.percentage.value: 10을 갖습니다. 두 번째 규칙은 match 도 fault 도 없이 그냥 라우팅만 합니다./root/ica-resilience/dr-inventory.yaml에 DestinationRule 을 작성하세요.spec.host는inventory.ica-resilience.svc.cluster.local이고trafficPolicy아래에outlierDetection(consecutive5xxErrors 5, interval 10s, baseEjectionTime 30s, maxEjectionPercent 50)과connectionPool(tcp.maxConnections 100, http.http1MaxPendingRequests 50)을 둡니다./root/ica-resilience/vs-inventory-mirror.yaml에 VirtualService 를 작성하세요.inventory.ica-resilience.svc.cluster.local로 100% 라우팅하면서inventory-canary.ica-resilience.svc.cluster.local로 20% 미러링하고, 전체timeout은5s로 둡니다.
참고
retryOn은 쉼표로 이어 붙인 문자열입니다.5xx,connect-failure,reset처럼 씁니다.percentage는value필드를 가진 객체입니다. 숫자만 덜렁 쓰면 안 됩니다.- 흔한 실수 1: 장애 주입 규칙에 catch-all 을 만들지 않아 헤더 없는 일반 트래픽이 갈 곳을 잃는 것.
- 흔한 실수 2: 미러링에 weight 두 개를 주는 것. 미러는 응답을 버리므로 실제 route 는 하나입니다.
- 미러 요청도 DB 쓰기 같은 부수 효과를 일으킵니다. 쓰기 경로를 미러링하려면 대상 애플리케이션이 섀도 모드로 동작해야 합니다.
실습 네임스페이스 준비
네임스페이스 ica-resilience 를 만들고 라벨 istio-injection=enabled 를 붙이세요.
앞 실습과 같은 방식입니다. 자동 주입 라벨을 잊지 마세요.
인스턴스 3개짜리 디플로이먼트 배포
네임스페이스 ica-resilience 에 디플로이먼트 inventory 를 3 레플리카로 배포하세요. 파드 라벨은 app=inventory, 이미지는 nginx:1.27-alpine 입니다.
outlierDetection 의 maxEjectionPercent 를 체감하려면 인스턴스가 여러 개여야 합니다. 파드가 Ready 가 될 때까지 기다렸다가 채점하세요.
본 서비스와 카나리 서비스 만들기
같은 네임스페이스에 서비스 두 개를 만드세요. inventory 와 inventory-canary 이며 둘 다 포트 8080, 포트 이름 http 입니다. inventory 의 selector 는 app=inventory 입니다.
미러링 대상은 별도 서비스로 두는 편이 안전합니다. 두 서비스 모두 포트 이름을 프로토콜이 드러나게 지으세요.
타임아웃과 재시도의 관계 맞추기
/root/ica-resilience/vs-inventory-retry.yaml 에 VirtualService 를 작성하세요. spec.hosts[0] 은 inventory.ica-resilience.svc.cluster.local, http 규칙에 timeout: 3s, retries.attempts: 2, retries.perTryTimeout: 1s, retries.retryOn 에는 5xx 와 connect-failure 를 포함하세요.
timeout 은 재시도를 포함한 전체 데드라인입니다. perTryTimeout x (attempts + 1) 이 timeout 을 넘으면 재시도가 실행되지 못합니다. retryOn 에는 요청이 도달하기 전에 실패한 경우도 포함하세요.
헤더로 게이팅한 장애 주입
/root/ica-resilience/vs-inventory-fault.yaml 에 VirtualService 를 작성하세요. 규칙 두 개입니다. 첫 규칙은 헤더 x-chaos-test 가 true 인 요청에만 적용되며 fault.delay.fixedDelay: 3s / fault.delay.percentage.value: 50 / fault.abort.httpStatus: 503 / fault.abort.percentage.value: 10 을 갖습니다. 두 번째 규칙은 match 도 fault 도 없이 그냥 라우팅만 합니다.
운영 클러스터에서 전체 트래픽에 fault 를 거는 것은 카오스 테스트가 아니라 장애입니다. 매칭 규칙과 일반 트래픽용 규칙을 나누고, fault 는 매칭된 쪽에만 두세요.
서킷브레이커 한도 정하기
/root/ica-resilience/dr-inventory.yaml 에 DestinationRule 을 작성하세요. spec.host 는 inventory.ica-resilience.svc.cluster.local 이고 trafficPolicy 아래에 outlierDetection(consecutive5xxErrors 5, interval 10s, baseEjectionTime 30s, maxEjectionPercent 50)과 connectionPool(tcp.maxConnections 100, http.http1MaxPendingRequests 50)을 둡니다.
connectionPool 과 outlierDetection 은 같은 DestinationRule 의 trafficPolicy 아래에 나란히 들어갑니다. 인스턴스가 3개일 때 동시 퇴출 비율을 100 으로 두면 어떤 일이 벌어질지 생각해 보세요.
섀도 트래픽 흘려보내기
/root/ica-resilience/vs-inventory-mirror.yaml 에 VirtualService 를 작성하세요. inventory.ica-resilience.svc.cluster.local 로 100% 라우팅하면서 inventory-canary.ica-resilience.svc.cluster.local 로 20% 미러링하고, 전체 timeout 은 5s 로 둡니다.
미러링은 응답을 버리므로 실제 route 는 하나만 둡니다. 미러 대상은 3단계에서 만든 카나리 서비스이고, 비율은 mirror 옆의 별도 필드로 지정합니다.