トラフィックポリシーをクラスターに移し、あふれさせてみる
한국어 원문으로 표시합니다.
목표
DestinationRule 의 트래픽 정책을 Envoy 클러스터 필드로 번역하고, 이상치 감지와 서킷 브레이커가 실제로 어떻게 동작하는지 요청을 보내 센다.
왜 중요한가
트래픽 정책은 설정이 틀려서가 아니라 동작에 대한 기대가 틀려서 사고가 난다. 한도는 사이드카마다 세고, 이상치 감지는 사후 조치이며, 서브셋 정책은 부모를 덩어리째 덮어쓴다. 번역된 클러스터와 실제 동작을 한 번 보고 나면 설정 리뷰에서 이 세 가지를 바로 짚을 수 있다.
단계
/root/ist2-dr/dr.yaml에 DestinationRule 을 쓰세요 — 이름ratings, 네임스페이스default, hostratings.default.svc.cluster.local.trafficPolicy는loadBalancer.simple: LEAST_REQUEST,connectionPool의tcp.maxConnections: 3·http.http1MaxPendingRequests: 2·http.http2MaxRequests: 5,outlierDetection의consecutive5xxErrors: 2·interval: 5s·baseEjectionTime: 30s·maxEjectionPercent: 50. 서브셋은v2(라벨version: v2) 하나이고, 그 서브셋에만trafficPolicy.connectionPool.tcp.maxConnections: 1을 줍니다.istioctl validate의 출력과 종료 코드를/root/ist2-dr/01-validate.txt에 담으세요(마지막 줄rc=0)./root/ist2-dr/02-map.txt에 DestinationRule 필드가 Envoy 클러스터의 어느 필드가 되는지 일곱 줄로 적으세요. 한 줄은<trafficPolicy 아래 경로>=<클러스터 아래 경로>꼴이고, 점으로 이은 경로에 배열 첨자는 쓰지 않습니다. 왼쪽은 이 일곱 개입니다 —loadBalancer.simple,connectionPool.tcp.maxConnections,connectionPool.http.http1MaxPendingRequests,connectionPool.http.http2MaxRequests,outlierDetection.consecutive5xxErrors,outlierDetection.baseEjectionTime,outlierDetection.maxEjectionPercent./root/ist2-dr/pool.yaml에 Envoy 설정을 쓰세요 — 관리 포트9985, 리스너127.0.0.1:10085의 모든 경로를 클러스터outbound|9080||ratings.default.svc.cluster.local로. 그 클러스터는 엔드포인트 셋(127.0.0.1:8107,127.0.0.1:8108,127.0.0.1:8115)과 1단계의 부모 트래픽 정책을 2단계 대응표대로 옮긴 필드(lb_policy,circuit_breakers.thresholds한 칸,outlier_detection— interval 도 함께)를 가집니다.envoy --mode validate의 출력과 종료 코드를/root/ist2-dr/03-validate.txt에 담으세요(마지막 줄rc=0).- 업스트림 셋을 띄우고(
8107·8115는ok,8108는fail)pool.yaml로 Envoy 를 띄운 뒤,localhost:9985/config_dump?resource=static_clusters에서 이 클러스터의 값을 뽑아/root/ist2-dr/04-dump.txt에 한 줄로 적으세요 —lb=<lb_policy> maxconn=<max_connections> pend=<max_pending_requests> req=<max_requests> c5xx=<consecutive_5xx> base=<base_ejection_time> pct=<max_ejection_percent>. pool.yaml로 Envoy 를 다시 띄운 직후 요청 30 번을 차례로 보내고,/root/ist2-dr/05-eject.txt에 네 줄을 적으세요 —failed_requests=(30 번 중 503 을 받은 수),ejected=(/clusters에서 health_flags 가/failed_outlier_check인 엔드포인트의주소:포트),ejections_enforced_total=(통계outlier_detection.ejections_enforced_total의 값),ejections_active=(통계outlier_detection.ejections_active의 값).pool.yaml을/root/ist2-dr/pool-subset.yaml로 복사하고 서브셋 v2 의 클러스터outbound|9080|v2|ratings.default.svc.cluster.local(엔드포인트127.0.0.1:8115)를 더하세요. Istio 가 1단계의 DestinationRule 로 만드는 것과 같게 —lb_policy와outlier_detection은 부모와 같고,circuit_breakers.thresholds는 서브셋의 connectionPool 만으로 만듭니다:max_connections: 1, 그리고 서브셋이 정하지 않은max_pending_requests·max_requests·max_retries는 Istio 의 기본값4294967295. 라우트는 접두사/v2를 이 클러스터로, 나머지는 그대로. 다시 띄운 뒤/clusters의default_priority줄에서 읽어/root/ist2-dr/06-subset.txt에v2_max_connections=,v2_max_pending_requests=,default_max_pending_requests=(부모 클러스터의 값) 세 줄을 적으세요.pool.yaml을/root/ist2-dr/pool-cb.yaml로 복사하고 클러스터outbound|9080|slow|ratings.default.svc.cluster.local를 더하세요 — 엔드포인트127.0.0.1:8116(3초 걸려 답하는 업스트림),circuit_breakers.thresholds는max_connections: 1,max_pending_requests: 1(Istio 로는tcp.maxConnections: 1,http.http1MaxPendingRequests: 1), 이상치 감지는 없음. 라우트는 접두사/slow를 이 클러스터로. 업스트림을8116에slow로 띄우고 Envoy 를--concurrency 1로 다시 띄운 뒤,/slow요청 다섯 개를 동시에 보내세요(&로 띄우고wait)./root/ist2-dr/07-overflow.txt에ok=(200 수),overflow_503=(503 수),pending_overflow=(slow 클러스터 통계upstream_rq_pending_overflow의 값) 세 줄을 적으세요./root/ist2-dr/08-report.md에lb_policy=,failures_before_eject=(5단계에서 빠지기 전에 맞은 503 수),v2_pending_limit=(6단계에서 본 v2 의 대기열 한도),overflow_status=(7단계에서 넘친 요청이 받은 코드) 네 줄을 적고, 그 아래-로 시작하는 설명을 네 줄 이상 적으세요.
참고
- 이 파드에는 진짜 istiod 도 진짜 사이드카도 없습니다. 그래서
istioctl proxy-config로 실제 생성물을 볼 수 없고, 번역 규칙을 알고 손으로 등가 Envoy 설정을 만들어 동작을 확인합니다. 같은 규칙이 운영 클러스터의proxy-config출력에 그대로 보입니다. - 4단계부터는 Envoy 를
--concurrency 1로 띄우세요. 서킷 브레이커와 이상치 감지를 세는 실험이 흔들리지 않습니다. - 통계와 이상치 상태는 프로세스가 살아 있는 동안 누적됩니다. 세는 단계는 다시 띄운 직후에 하세요.
/clusters와/stats의 이름에는|가 들어 있습니다.grep -F를 쓰거나\|로 이스케이프하세요.- Envoy 를 띄울 때는
setsid --fork nohup envoy -c <파일> --log-level warn > <로그> 2>&1 </dev/null로 셸에서 완전히 떼어 놓으세요. 다시 띄우기 전에는pkill -x envoy로 정리합니다 (pkill -f 'envoy -c'는 그 문자열이 든 셸 자신까지 죽입니다). - 업스트림 흉내용 서버가 이미지에 있습니다:
python3 /opt/lab/envoy/upstream.py <포트> ok|fail|slow. 응답 본문은<모드>:<포트> <경로>입니다. - 설정을 고친 뒤에는 띄우기 전에
envoy --mode validate -c <파일>로 먼저 거르세요. 클러스터 이름에|가 들어가므로 YAML 에서는 반드시 따옴표로 감쌉니다.
트래픽 정책이 든 DestinationRule 을 쓴다
/root/ist2-dr/dr.yaml 에 DestinationRule 을 쓰세요 — 이름 ratings, 네임스페이스 default, host ratings.default.svc.cluster.local. trafficPolicy 는 loadBalancer.simple: LEAST_REQUEST, connectionPool 의 tcp.maxConnections: 3·http.http1MaxPendingRequests: 2·http.http2MaxRequests: 5, outlierDetection 의 consecutive5xxErrors: 2·interval: 5s·baseEjectionTime: 30s·maxEjectionPercent: 50. 서브셋은 v2(라벨 version: v2) 하나이고, 그 서브셋에만 trafficPolicy.connectionPool.tcp.maxConnections: 1 을 줍니다. istioctl validate 의 출력과 종료 코드를 /root/ist2-dr/01-validate.txt 에 담으세요(마지막 줄 rc=0).
DestinationRule 은 '보낸 뒤 어떻게 다룰지' 입니다. 트래픽 정책은 세 덩어리 — 누구에게 보낼지(loadBalancer), 한꺼번에 얼마나 받아 줄지(connectionPool), 아픈 엔드포인트를 언제 뺄지(outlierDetection). 서브셋 아래에도 같은 모양의 trafficPolicy 를 둘 수 있는데, 그것이 부모와 어떻게 합쳐지는지가 6단계의 주제입니다.
필드 일곱 개의 대응표를 만든다
/root/ist2-dr/02-map.txt 에 DestinationRule 필드가 Envoy 클러스터의 어느 필드가 되는지 일곱 줄로 적으세요. 한 줄은 <trafficPolicy 아래 경로>=<클러스터 아래 경로> 꼴이고, 점으로 이은 경로에 배열 첨자는 쓰지 않습니다. 왼쪽은 이 일곱 개입니다 — loadBalancer.simple, connectionPool.tcp.maxConnections, connectionPool.http.http1MaxPendingRequests, connectionPool.http.http2MaxRequests, outlierDetection.consecutive5xxErrors, outlierDetection.baseEjectionTime, outlierDetection.maxEjectionPercent.
Envoy 의 클러스터 설정 문서(cluster.proto)에서 이름이 닮은 필드를 찾으면 됩니다. 연결 풀 한도는 Envoy 에서 circuit_breakers.thresholds 아래 우선순위별 목록으로 들어갑니다 — Istio 가 '연결 풀' 이라 부르는 것과 Envoy 가 '서킷 브레이커' 라 부르는 것이 같은 숫자입니다. 이상치 감지의 필드 이름은 consecutive5xxErrors 처럼 낙타 표기에서 밑줄 표기로 바뀌면서 조금씩 줄어듭니다.
대응표대로 클러스터를 세운다
/root/ist2-dr/pool.yaml 에 Envoy 설정을 쓰세요 — 관리 포트 9985, 리스너 127.0.0.1:10085 의 모든 경로를 클러스터 outbound|9080||ratings.default.svc.cluster.local 로. 그 클러스터는 엔드포인트 셋(127.0.0.1:8107, 127.0.0.1:8108, 127.0.0.1:8115)과 1단계의 부모 트래픽 정책을 2단계 대응표대로 옮긴 필드(lb_policy, circuit_breakers.thresholds 한 칸, outlier_detection — interval 도 함께)를 가집니다. envoy --mode validate 의 출력과 종료 코드를 /root/ist2-dr/03-validate.txt 에 담으세요(마지막 줄 rc=0).
circuit_breakers.thresholds 는 목록입니다 — 우선순위(DEFAULT·HIGH)별로 한도를 따로 줄 수 있어서입니다. Istio 는 DEFAULT 한 칸만 씁니다. 시간 값은 30s 처럼 단위를 붙인 문자열로 적습니다. 8108 은 늘 503 을 내는 엔드포인트로 쓸 자리입니다(5단계).
config_dump 에서 여섯 값을 되읽는다
업스트림 셋을 띄우고(8107·8115 는 ok, 8108 는 fail) pool.yaml 로 Envoy 를 띄운 뒤, localhost:9985/config_dump?resource=static_clusters 에서 이 클러스터의 값을 뽑아 /root/ist2-dr/04-dump.txt 에 한 줄로 적으세요 — lb=<lb_policy> maxconn=<max_connections> pend=<max_pending_requests> req=<max_requests> c5xx=<consecutive_5xx> base=<base_ejection_time> pct=<max_ejection_percent>.
파일에 쓴 것과 Envoy 가 읽어 들인 것을 맞대 보는 단계입니다. 운영에서 istioctl proxy-config cluster <파드> --fqdn … -o json 이 보여 주는 것이 바로 이 덤프입니다. .configs[].cluster | select(.name==…) 로 고른 뒤 jq 문자열 보간으로 한 줄을 만드세요. 덤프는 기본값인 필드를 생략하므로 없는 값이 보이면 설정에 안 들어간 것입니다.
이상치 감지는 실패를 겪은 뒤에 뺀다
pool.yaml 로 Envoy 를 다시 띄운 직후 요청 30 번을 차례로 보내고, /root/ist2-dr/05-eject.txt 에 네 줄을 적으세요 — failed_requests=(30 번 중 503 을 받은 수), ejected=(/clusters 에서 health_flags 가 /failed_outlier_check 인 엔드포인트의 주소:포트), ejections_enforced_total=(통계 outlier_detection.ejections_enforced_total 의 값), ejections_active=(통계 outlier_detection.ejections_active 의 값).
이상치 감지는 당하고 나서 빼는 장치입니다. 한 엔드포인트가 연달아 consecutive5xxErrors 번 5xx 를 내면 그때 baseEjectionTime 동안 부하 분산에서 뺍니다. 그러니 그 횟수만큼은 사용자가 먼저 503 을 맞습니다. 빠진 뒤로는 나머지 둘만 받으므로 503 이 멈춥니다. maxEjectionPercent: 50 은 셋 중 하나까지만 뺄 수 있다는 뜻입니다. /clusters 줄은 클러스터::주소::health_flags::값 꼴입니다.
서브셋 정책은 덩어리째 덮어쓴다
pool.yaml 을 /root/ist2-dr/pool-subset.yaml 로 복사하고 서브셋 v2 의 클러스터 outbound|9080|v2|ratings.default.svc.cluster.local(엔드포인트 127.0.0.1:8115)를 더하세요. Istio 가 1단계의 DestinationRule 로 만드는 것과 같게 — lb_policy 와 outlier_detection 은 부모와 같고, circuit_breakers.thresholds 는 서브셋의 connectionPool 만으로 만듭니다: max_connections: 1, 그리고 서브셋이 정하지 않은 max_pending_requests·max_requests·max_retries 는 Istio 의 기본값 4294967295. 라우트는 접두사 /v2 를 이 클러스터로, 나머지는 그대로. 다시 띄운 뒤 /clusters 의 default_priority 줄에서 읽어 /root/ist2-dr/06-subset.txt 에 v2_max_connections=, v2_max_pending_requests=, default_max_pending_requests=(부모 클러스터의 값) 세 줄을 적으세요.
공식 문서는 '서브셋 수준의 트래픽 정책이 DestinationRule 수준의 해당 설정을 덮어쓴다' 고만 적습니다. 덮어쓰는 단위는 connectionPool·loadBalancer·outlierDetection·tls 같은 덩어리입니다. 그래서 서브셋에 tcp.maxConnections 하나만 적으면 connectionPool 덩어리가 통째로 바뀌어 부모의 http 한도(2·5)는 v2 에 따라오지 않습니다. 빈자리는 Istio 가 넣는 기본값(4294967295, 사실상 무제한)입니다 — Envoy 자체의 기본값 1024 보다도 느슨합니다. /clusters 에서 <이름>::default_priority::max_pending_requests::<값> 줄을 찾으세요.
서킷 브레이커가 실제로 열리는 것을 센다
pool.yaml 을 /root/ist2-dr/pool-cb.yaml 로 복사하고 클러스터 outbound|9080|slow|ratings.default.svc.cluster.local 를 더하세요 — 엔드포인트 127.0.0.1:8116(3초 걸려 답하는 업스트림), circuit_breakers.thresholds 는 max_connections: 1, max_pending_requests: 1 (Istio 로는 tcp.maxConnections: 1, http.http1MaxPendingRequests: 1), 이상치 감지는 없음. 라우트는 접두사 /slow 를 이 클러스터로. 업스트림을 8116 에 slow 로 띄우고 Envoy 를 --concurrency 1 로 다시 띄운 뒤, /slow 요청 다섯 개를 동시에 보내세요(& 로 띄우고 wait). /root/ist2-dr/07-overflow.txt 에 ok=(200 수), overflow_503=(503 수), pending_overflow=(slow 클러스터 통계 upstream_rq_pending_overflow 의 값) 세 줄을 적으세요.
업스트림이 느리면 연결 하나가 3초 동안 묶입니다. 그동안 온 요청은 대기열에 서고, 대기열마저 차면 Envoy 는 업스트림에 가 보지도 않고 곧바로 503 과 x-envoy-overloaded: true 헤더를 돌려줍니다. 그래서 받아 주는 수는 '연결 수 + 대기열 길이' 입니다. 차례로 보내면 한 번에 하나씩 끝나 아무것도 넘치지 않으니 반드시 동시에 보내세요. 통계는 누적이라 다시 띄운 직후에 한 번만 셉니다.
DestinationRule 번역표로 정리한다
/root/ist2-dr/08-report.md 에 lb_policy=, failures_before_eject=(5단계에서 빠지기 전에 맞은 503 수), v2_pending_limit=(6단계에서 본 v2 의 대기열 한도), overflow_status=(7단계에서 넘친 요청이 받은 코드) 네 줄을 적고, 그 아래 - 로 시작하는 설명을 네 줄 이상 적으세요.
값은 앞 단계 파일에서 옮기세요. 설명 줄에는 'DestinationRule 을 고칠 때 무엇을 조심하겠다' 를 적으면 좋습니다 — 특히 서브셋 정책이 부모를 덮어쓰는 방식은 리뷰 때 놓치기 쉽습니다.