지난 포스팅에선 Envoy, Istio Gateway에 대해 다뤄봤습니다.
이번 포스팅에선 5장 Traffic Control, 6장 Resilience을 다뤄보도록 하겠습니다.
git clone https://github.com/AcornPublishing/istio-in-action
cd istio-in-action/book-source-code-masterkind create cluster --name myk8s --image kindest/node:v1.23.17 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000 # Sample Application (istio-ingrssgateway) HTTP
hostPort: 30000
- containerPort: 30001 # Prometheus
hostPort: 30001
- containerPort: 30002 # Grafana
hostPort: 30002
- containerPort: 30003 # Kiali
hostPort: 30003
- containerPort: 30004 # Tracing
hostPort: 30004
- containerPort: 30005 # Sample Application (istio-ingrssgateway) HTTPS
hostPort: 30005
- containerPort: 30006 # TCP Route
hostPort: 30006
- containerPort: 30007 # kube-ops-view
hostPort: 30007
*extraMounts: # 해당 부분 생략 가능
- hostPath: /Users/bkshin/IdeaProjects/istio-in-action/book-source-code-master # 각자 자신의 pwd 경로로 설정
containerPath: /istiobook*
networking:
podSubnet: 10.10.0.0/16
serviceSubnet: 10.200.1.0/24
EOF
docker ps 
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30007 --set env.TZ="Asia/Seoul" --namespace kube-system
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view 
open "http://localhost:30007/#scale=1.3" 
helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/
helm install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system
kubectl get all -n kube-system -l app.kubernetes.io/instance=metrics-server 
docker exec -it myk8s-control-plane bashtree /istiobook/ -L 1 
# istioctl 설치
export ISTIOV=1.17.8
echo 'export ISTIOV=1.17.8' >> /root/.bashrc
curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl version --remote=falseistioctl install --set profile=default -ykubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
kubectl get crd | grep istio.io | sort 

kubectl apply -f istio-$ISTIOV/samples/addons
kubectl get pod -n istio-system 
exitkubectl create ns istioinaction
kubectl label namespace istioinaction istio-injection=enabled
kubectl get ns --show-labels 
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30005}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kubectl describe svc -n istio-system istio-ingressgateway 
kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'# Prometheus 접속 : envoy, istio 메트릭 확인
open http://127.0.0.1:30001
# Grafana 접속
open http://127.0.0.1:30002
# Kiali 접속 1 : NodePort
open http://127.0.0.1:30003
# tracing 접속 : 예거 트레이싱 대시보드
open http://127.0.0.1:30004 



cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: netshoot
spec:
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF 
소프트웨어를 운영하면서 자주 듣는 두 용어가 있습니다. 바로 "배포(Deployment)" 와 "릴리스(Release)" 입니다.
많은 팀이 이 둘을 혼용해 사용하지만, 실제로는 아주 중요한 차이가 존재합니다.
이번 글에서는 가상의 catalog 서비스를 예로 들어, 배포와 릴리스의 차이를 명확하게 설명해 보겠습니다.
현재 catalog 서비스 v1이 운영되고 있다고 가정해봅시다.
이제 여기에 코드 변경을 적용해 v2.0 버전을 출시하려고 합니다.
일반적인 과정은 다음과 같습니다:
여기까지는 일반적인 소프트웨어 배포 과정처럼 보이죠.
하지만 이 시점에서 중요한 포인트가 있습니다.
배포(Deployment)란 운영 환경에 설치되지만, 아직 트래픽을 받지 않는 상태입니다.

catalog v2.0을 운영 서버에 설치한다고 해서, 모든 사용자가 바로 새로운 코드를 사용하는 것은 아닙니다.
정리: 배포는 설치(Deployment)일 뿐, 사용자 영향은 없습니다.
릴리스(Release)란 새 버전으로 실제 트래픽을 이동시키는 행위입니다.

운영 서버에 배포만 되어 있다면 아직 아무 일도 일어나지 않았습니다.
진짜 변화는 "사용자 요청"을 새로운 catalog v2.0로 보내기 시작할 때 발생합니다.
릴리스 방법은 여러 가지가 있습니다:
릴리스를 통해 트래픽을 점진적으로 v2.0로 넘기고, 문제가 없으면 범위를 확장합니다.

초기에 일부 사용자만 새로운 버전을 사용하게 합니다.
이 과정을 통해, 신버전에 대한 위험을 최소화할 수 있습니다.

만약 v2.0 버전에서 문제가 발생한다면?
릴리스를 점진적으로 하고, 항상 롤백 경로를 준비해두는 것은 안정적인 운영을 위한 핵심 전략입니다.
한때 ACME라는 회사는 새 버전을 배포하자마자 바로 전체 릴리스를 했습니다.
이런 방식은 위험합니다.
배포와 릴리스를 분리하지 않으면, 문제가 발생했을 때 피해 범위가 커지기 때문입니다.
Istio 같은 서비스 메시를 사용하면, 릴리스를 훨씬 세밀하게 제어할 수 있습니다.
운영 리스크를 줄이고, 훨씬 유연한 릴리스를 할 수 있게 됩니다.
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction```bash
kubectl get pod -n istioinaction -owide
kubectl describe pod -n istioinaction catalog-6cf4b97d-h9xsd
```

echo "127.0.0.1 catalog.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 3 
kubectl exec -it netshoot -- curl -s http://catalog.istioinaction/items | jq 
cat ch5/catalog-gateway.yaml
kubectl apply -f ch5/catalog-gateway.yaml -n istioinaction 
cat ch5/catalog-vs.yaml
kubectl apply -f ch5/catalog-vs.yaml -n istioinaction 
kubectl get gw,vs -n istioinaction 
kubectl get svc -n istio-system istio-ingressgateway -o jsonpath="{.spec.ports}" | jq 
curl -v -H "Host: catalog.istioinaction.io" http://localhost:30000
kubectl stern -l app=catalog -n istioinaction
open http://localhost:30000
open http://catalog.istioinaction.io:30000
open http://catalog.istioinaction.io:30000/items


while true; do curl -s http://catalog.istioinaction.io:30000/items/ ; sleep 1; echo; done
while true; do curl -s http://catalog.istioinaction.io:30000/items/ -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
while true; do curl -s http://catalog.istioinaction.io:30000/items/ -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 0.5; echo; done
kubectl port-forward deploy/istio-ingressgateway -n istio-system 15000:15000
open http://127.0.0.1:15000 
kubectl apply -f services/catalog/kubernetes/catalog-deployment-v2.yaml -n istioinactionkubectl get deploy -n istioinaction --show-labels
kubectl get pod -n istioinaction -o wide
docker exec -it myk8s-control-plane istioctl proxy-statusfor i in {1..10}; do curl -s http://catalog.istioinaction.io:30000/items/ ; printf "\n\n"; done
- v2 접속 확인

docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local -o json 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||catalog.istioinaction.svc.cluster.local'

docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||catalog.istioinaction.svc.cluster.local' -o json 



v1.0 : version=v1 로 설정
v2.0 : version=v2 로 설정
kubectl get pod -l app=catalog -n istioinaction --show-labels

```bash
cat ch5/catalog-dest-rule.yaml
kubectl apply -f ch5/catalog-dest-rule.yaml -n istioinaction
```
```
kubectl get destinationrule -n istioinaction
kubectl describe destinationrule -n istioinaction catalog 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local 
상세 확인
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --subset version-v1 -o json
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --subset version-v2 -o json


endpoint 확인
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system | egrep 'ENDPOINT|istioinaction'

docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||catalog.istioinaction.svc.cluster.local' 
cat ch5/catalog-vs-v1.yaml
kubectl apply -f ch5/catalog-vs-v1.yaml -n istioinaction 
for i in {1..100}; do curl -s http://catalog.istioinaction.io:30000/items/ ; printf "\n\n"; done 

docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system --name http.8080 -o json 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --subset version-v1 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --subset version-v1 -o json 
```bash
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80|version-v1|catalog.istioinaction.svc.cluster.local'
```
)http 요청 헤더에 x-istio-cohort: internal 가 포함된 경우 catalog v2.0으로 가도록 설정

cat ch5/catalog-vs-v2-request.yaml
kubectl apply -f ch5/catalog-vs-v2-request.yaml -n istioinaction 
for i in {1..10}; do curl -s http://catalog.istioinaction.io:30000/items/ ; printf "\n\n"; donex-istio-cohort: internal 포함되지 않아 v1.0으로만 통신 

curl http://catalog.istioinaction.io:30000/items -H "x-istio-cohort: internal"
while true; do curl -s http://catalog.istioinaction.io:30000/items/ -H "x-istio-cohort: internal" -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 2; echo; done
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system --name http.8080 
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system --name http.8080 -o json 
기존 실습에 라우팅 수행위치가 edge, gateway에서만 이루어졌다.
이번 트래픽 규칙은 호출 그래프 내 깊은 곳에도 적용하는 것을 실습한다.

kubectl delete gateway,virtualservice,destinationrule --all -n istioinactionkubectl apply -n istioinaction -f services/webapp/kubernetes/webapp.yamlkubectl get deploy,pod,svc,ep -n istioinactionkubectl get deploy,pod,svc,ep -n istioinaction 
cat services/webapp/istio/webapp-catalog-gw-vs.yaml
kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction 
echo "127.0.0.1 webapp.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 3 
curl -s http://webapp.istioinaction.io:30000/api/catalog | jq 
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -H "x-istio-cohort: internal" -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 2; echo; done 
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system --name http.8080 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system | egrep 'webapp|catalog' 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn webapp.istioinaction.svc.cluster.local -o json 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||webapp.istioinaction.svc.cluster.local' 
kubectl logs -n istioinaction -l app=webapp -c istio-proxy -f 
cat << EOF | kubectl apply -f -
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: webapp
namespace: istioinaction
spec:
selector:
matchLabels:
app: webapp
accessLogging:
- providers:
- name: envoy #2 액세스 로그를 위한 프로바이더 설정
disabled: false #3 disable 를 false 로 설정해 활성화한다
EOF 

ch5/catalog-dest-rule.yaml
kubectl apply -f ch5/catalog-dest-rule.yaml -n istioinaction 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/istio-ingressgateway.istio-system | egrep 'ENDPOINT|istioinaction' 
cat ch5/catalog-vs-v1-mesh.yaml
kubectl apply -f ch5/catalog-vs-v1-mesh.yaml -n istioinaction 
kubectl get vs -n istioinaction 
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -H "x-istio-cohort: internal" -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 2; echo; donekubectl logs -n istioinaction -l app=webapp -c istio-proxy -f 
proxy-config 확인
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction | egrep 'NAME|catalog'

docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction --name 80 -o json > webapp-routes.json
cat webapp-routes.json | jq 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn catalog.istioinaction.svc.cluster.local 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/webapp.istioinaction --subset version-v1 -o json 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/webapp.istioinaction | egrep 'ENDPOINT|catalog' 

cat ch5/catalog-vs-v2-request-mesh.yaml
kubectl apply -f ch5/catalog-vs-v2-request-mesh.yaml -n istioinaction 
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -H "x-istio-cohort: internal" -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 2; echo; donedocker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction | egrep 'NAME|catalog' 
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction --name 80 -o json > webapp-routes.json
cat webapp-routes.json | jq 

istio로 가중치 기반의 트래픽 전환을 수행하는 방법에 대한 실습을 진행
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction # 이미 배포 상태kubectl get deploy,rs,pod -n istioinaction --show-labels 
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; donecat ch5/catalog-vs-v1-mesh.yaml
kubectl apply -f ch5/catalog-vs-v1-mesh.yaml -n istioinaction 
curl -s http://webapp.istioinaction.io:30000/api/catalog | jq 
cat ch5/catalog-vs-v2-10-90-mesh.yaml
kubectl apply -f ch5/catalog-vs-v2-10-90-mesh.yaml -n istioinaction 
kubectl get vs -n istioinaction catalog 
for i in {1..100}; do curl -s http://webapp.istioinaction.io:30000/api/catalog | grep -i imageUrl ; done | wc -l 
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction --name 80 -o json 
cat ch5/catalog-vs-v2-50-50-mesh.yaml
kubectl apply -f ch5/catalog-vs-v2-50-50-mesh.yaml -n istioinaction 
for i in {1..100}; do curl -s http://webapp.istioinaction.io:30000/api/catalog | grep -i imageUrl ; done | wc -l 
Flagger를 이용하면 릴리스를 어떻게 수행할지, 언제 더 많은 사용자에게 릴리스를 개방할지, 릴리스가 문제를 일으킬 경우 언제 롤백할지 등에 관련된 파라미터를 지정할 수 있다.
Flagger는 릴리스를 수행하는 데 필요한 작절한 설정을 모두 만든다.

출처 : https://github.com/stefanprodan/gitops-istio
kubectl delete virtualservice catalog -n istioinaction
kubectl delete deploy catalog-v2 -n istioinaction
kubectl delete service catalog -n istioinaction
kubectl delete destinationrule catalog -n istioinactionkubectl get deploy,svc,ep -n istioinaction
kubectl get gw,vs -n istioinaction 
kubectl apply -f https://raw.githubusercontent.com/fluxcd/flagger/main/artifacts/flagger/crd.yaml
kubectl get crd | grep flagger 
helm repo add flagger https://flagger.app
helm install flagger flagger/flagger \
--namespace=istio-system \
--set crd.create=false \
--set meshProvider=istio \
--set metricServer=http://prometheus:9090kubectl get pod -n istio-system -l app.kubernetes.io/name=flagger 
kubectl get secret -n istio-system | grep flagger-token 
kubectl view-secret -n istio-system flagger-token-65shq --all 
Flagger Canary 리소스를 이용한 배포를 위한 yaml 파일 확인
cat ch5/flagger/catalog-release.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: catalog-release
namespace: istioinaction
spec:
targetRef: #1
apiVersion: apps/v1
kind: Deployment
name: catalog
progressDeadlineSeconds: 60
# Service / VirtualService Config
service: #2
name: catalog
port: 80
targetPort: 3000
gateways:
- mesh
hosts:
- catalog
analysis: #3
interval: 45s
threshold: 5
maxWeight: 50
stepWeight: 10
match:
- sourceLabels:
app: webapp
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 30s
sourceLabels가 app=webapp인 트래픽만 고려| 이름 | 내용 |
|---|---|
| request-success-rate | 성공률이 99% 미만이면 Canary 롤백 |
| request-duration | 응답 시간이 500ms 이상이면 Canary 롤백 |
반복 호출 테스트
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
kubectl apply -f ch5/flagger/catalog-release.yaml -n istioinactionkubectl logs -f deploy/flagger -n istio-system 
kubectl get canary -n istioinaction -owide 
kubectl get deploy,svc,ep -n istioinaction -o wide 
kubectl get vs -n istioinaction catalog -o yaml 
kubectl get destinationrule -n istioinaction 
kubectl get destinationrule -n istioinaction catalog-primary -o yaml
kubectl get destinationrule -n istioinaction catalog-canary -o yaml 
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/webapp.istioinaction --name 80 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/webapp.istioinaction | grep catalog 

이제 catalog v2 를 도입하고 Flagger가 어떻게 릴리스에서 이를 자동화하는지, 어떻게 메트릭에 기반해 의사결정을 내리는지 살펴보자.

https://docs.flagger.app/tutorials/istio-progressive-delivery
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; donekubectl logs -f deploy/flagger -n istio-systemkubectl get canary -n istioinaction -w 
cat ch5/flagger/catalog-deployment-v2.yaml
kubectl apply -f ch5/flagger/catalog-deployment-v2.yaml -n istioinaction 
kubectl get vs -n istioinaction catalog -o yaml -w 








kubectl describe canary -n istioinaction catalog-release | grep Events: -A20 

promtheus 확인
flagger_canary_weight 
flagger_canary_metric_analysis{metric="request-duration"} 
flagger_canary_metric_analysis{metric="request-success-rate"} 
for i in {1..100}; do curl -s http://webapp.istioinaction.io:30000/api/catalog | grep -i imageUrl ; done | wc -l 
# Canary 삭제 : Flagger가 만든 service (catalog, catalog-canary, catalog-primary), destinationrule (catalog-canary, catalog-primary), deployment (catalog-primary) 를 제거함
kubectl delete canary catalog-release -n istioinaction
# catalog 삭제
kubectl delete deploy catalog -n istioinaction
# Flagger 삭제
helm uninstall flagger -n istio-system
서비스를 운영하다 보면 새 버전을 배포할 때 항상 따라오는 고민이 있습니다.
"새 버전이 실제 트래픽에서 문제를 일으키지는 않을까?"
이를 위해 우리는 보통 요청 수준 라우팅(request-level routing)이나 트래픽 전환(traffic shifting) 같은 기술을 사용해 왔습니다.
예를 들어 일부 요청만 새 버전으로 보내거나, 트래픽 비율을 조절하면서 점진적으로 전환하는 방식이죠.
하지만 이 방식들 모두 실제 사용자 트래픽을 직접 건드린다는 점에서 완벽하진 않습니다.
아무리 신중하게 제어하더라도 예상치 못한 문제가 발생할 수 있고, 그 여파는 바로 사용자에게 전해질 수 있습니다.
그래서 등장한 또 다른 접근 방식이 있습니다.
바로 운영 트래픽을 복사(Mirroring) 해서 요청 경로 외부의 새로운 디플로이먼트로 보내는 것입니다.

위 그림처럼 실제 고객 요청은 여전히 기존 catalog 서비스로 정상 처리되고, 동시에 이 요청이 복제되어 테스트용 catalog-v2.0 서비스에도 전달됩니다.
즉, 진짜 트래픽으로 새 버전을 실험해보지만, 사용자 경험에는 전혀 영향을 주지 않는 것입니다.
[장점]
kubectl apply -f services/catalog/kubernetes/catalog-svc.yaml -n istioinaction
kubectl apply -f services/catalog/kubernetes/catalog-deployment.yaml -n istioinaction
kubectl apply -f services/catalog/kubernetes/catalog-deployment-v2.yaml -n istioinaction
kubectl apply -f ch5/catalog-dest-rule.yaml -n istioinaction
kubectl apply -f ch5/catalog-vs-v1-mesh.yaml -n istioinactionkubectl get deploy,svc,ep,gw,vs -n istioinaction -o wide 
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
for i in {1..100}; do curl -s http://webapp.istioinaction.io:30000/api/catalog | grep -i imageUrl ; done | wc -l 
미러링 수행이 필요한 Virtual Service 확인
cat ch5/catalog-vs-v2-mirror.yaml
# ch5/catalog-vs-v2-mirror.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: catalog
spec:
hosts:
- catalog
gateways:
- mesh
http:
- route:
- destination:
host: catalog
subset: version-v1
weight: 100
mirror:
host: catalog
subset: version-v2
반복 접속
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
cat << EOF | kubectl apply -f -
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: catalog
namespace: istioinaction
spec:
accessLogging:
- disabled: false
providers:
- name: envoy
selector:
matchLabels:
app: catalog
EOFkubectl get telemetries -n istioinaction 
kubectl logs -n istioinaction -l app=webapp -c istio-proxy -f
kubectl logs -n istioinaction -l app=catalog -l version=v2 -c istio-proxy -f 
kubectl apply -f ch5/catalog-vs-v2-mirror.yaml -n istioinaction 
for i in {1..100}; do curl -s http://webapp.istioinaction.io:30000/api/catalog | grep -i imageUrl ; done | wc -l

kubectl logs -n istioinaction -l app=catalog -l version=v1 -c catalog -f 
kubectl logs -n istioinaction -l app=catalog -l version=v2 -c catalog -f 

Istio는 기본적으로 애플리케이션이 메시 외부(예: 외부 웹사이트나 서비스)로 트래픽을 보낼 수 있도록 허용합니다.
모든 트래픽은 사이드카 프록시를 거치기 때문에, 어느 정도 라우팅 제어는 가능하지만 기본 설정은 '허용'입니다.
[왜 외부 트래픽을 막아야 할까?]
만약 메시 내 서비스나 애플리케이션이 손상된다면?
악의적인 공격자가 외부 서버와 통신하며 추가적인 침해를 시도할 수 있습니다.
이를 막기 위해 "어떤 트래픽도 메시를 떠날 수 없게" 차단하는 정책이 필요합니다.
이것은 일종의 심층 방어(Defense in Depth) 전략입니다.
외부 통신을 차단함으로써 손상된 서비스가 공격자에게 "집으로 연락"하는 것을 원천적으로 막을 수 있습니다.
[주의점]
주의할 점은, 사이드카 프록시를 우회하는 방법도 존재한다는 것입니다.
따라서 추가적으로 3계층, 4계층 네트워크 수준 보호를 병행해야 합니다.
(예: VPC 보안 그룹, 네트워크 ACL, 방화벽 등으로 IP·포트 레벨 차단)
[요약]

kubectl get istiooperators -n istio-system -o json 
kubectl exec -it deploy/webapp -n istioinaction -c webapp -- wget https://raw.githubusercontent.com/gasida/KANS/refs/heads/main/msa/sock-shop-demo.yamlkubectl logs -n istioinaction -l app=webapp -c istio-proxy -f 
docker exec -it myk8s-control-plane bashistioctl install --set profile=default --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY 
exitdocker exec -it myk8s-control-plane istioctl proxy-statuskubectl exec -it deploy/webapp -n istioinaction -c webapp -- wget https://raw.githubusercontent.com/gasida/KANS/refs/heads/main/msa/sock-shop-demo.yamlkubectl exec -it deploy/webapp -n istioinaction -c webapp -- wget https://raw.githubusercontent.com/gasida/KANS/refs/heads/main/msa/sock-shop-demo.yaml 

docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn BlackHoleCluster -o json 
kubectl get istiooperators -n istio-system -o json 
[Istio 내부 서비스 저장소]
Istio는 메쉬 내부에서 사용할 수 있도록 자체 서비스 저장소(internal service registry) 를 운영합니다.

이 저장소는 메쉬 내부 서비스들이 서로를 찾기 위한 공식 서비스 디스커버리 역할을 합니다.
Service 객체를 읽어와서 서비스 카탈로그를 생성하죠.⇒ istiod는 k8s API(Service 리소스)를 통해 서비스/엔드포인트 정보를 동적으로 발견하고 저장합니다.
하지만 이 기본 저장소에는 외부 서비스 정보가 없습니다.
외부 서비스를 인식시키려면 별도로 등록해주어야 합니다.
이때 사용하는 것이 바로 ServiceEntry 입니다.
[외부 서비스 연결 예시: JSONPlaceholder]
가상의 온라인 포럼 서비스를 운영한다고 가정해봅시다.
외부의 jsonplaceholder.typicode.com API를 사용해서 사용자 피드백을 받고 싶다고 할 때, Istio에 이 외부 API를 등록해야 합니다.
JSONPlaceholder는 테스트용 가짜 데이터 API를 무료로 제공하는 서비스입니다.
다음과 같은 리소스를 제공합니다:
| 리소스 | 설명 | 예시 요청 |
|---|---|---|
/posts | 게시글 목록 | GET /posts |
/comments | 댓글 목록 | GET /comments |
/albums | 앨범 목록 | GET /albums |
/photos | 사진 정보 | GET /photos |
/todos | 할 일 목록 | GET /todos |
/users | 사용자 정보 | GET /users |
[ServiceEntry 리소스 등록 방법]
Istio에 외부 서비스를 등록하려면 다음과 같은 ServiceEntry를 생성합니다.
# cat ch5/forum-serviceentry.yaml
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: jsonplaceholder
spec:
hosts:
- jsonplaceholder.typicode.com
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
[주요 설정]
hosts: 연결할 외부 서비스 도메인 (여기서는 jsonplaceholder.typicode.com)ports: 통신할 포트와 프로토콜 (HTTP/80)resolution: DNS: 도메인 이름 기반으로 주소를 찾겠다는 의미location: MESH_EXTERNAL: 외부에 위치한 서비스임을 명시이렇게 하면 메쉬 내부 서비스가 이 외부 API를 향해 트래픽을 보낼 수 있게 됩니다.
cat services/forum/kubernetes/forum-all.yaml
kubectl apply -f services/forum/kubernetes/forum-all.yaml -n istioinaction 
kubectl get deploy,svc -n istioinaction -l app=webapp
docker exec -it myk8s-control-plane istioctl proxy-status 
open http://webapp.istioinaction.io:30000/ 
for i in {1..100}; do curl http://webapp.istioinaction.io:30000/ ; done
curl -s http://webapp.istioinaction.io:30000/api/users 
cat ch5/forum-serviceentry.yaml
kubectl apply -f ch5/forum-serviceentry.yaml -n istioinaction 
docker exec -it myk8s-control-plane istioctl proxy-config all deploy/forum.istioinaction -o short > forum-2.json
cat forum-2.json | grep jsonplaceholder.typicode.com 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/forum.istioinaction --cluster 'outbound|80||jsonplaceholder.typicode.com' 
curl -s http://webapp.istioinaction.io:30000/api/users 
while true; do curl -s http://webapp.istioinaction.io:30000/ ; date "+%Y-%m-%d %H:%M:%S" ; sleep 2; echo; done 
open http://webapp.istioinaction.io:30000/ 

kind delete cluster --name myk8s
마이크로서비스를 구축할 때 가장 최우선으로 고려해야 할 것은 복원력(Resilience) 입니다.
"장애가 발생하지 않도록 구축하면 된다"는 말은 현실을 무시한 이야기입니다.
실제로는 언제든 장애가 발생할 수 있고, 단일 장애가 전체 시스템의 중단으로 이어질 위험이 존재합니다.
[복잡한 분산 시스템, 그리고 장애의 위험]
마이크로서비스는 네트워크를 통해 서로 통신하는 수많은 작은 서비스들로 구성됩니다.
이 과정에서 장애 지점(Failure Point) 은 오히려 더 많이 생길 수 있습니다.
특히 다음과 같은 문제가 발생할 수 있습니다:
이러한 장애들은 시간이 지나면서 전체 시스템의 안정성에 큰 위협이 됩니다.
[서비스 소유자가 준비해야 할 것]
서비스 소유자(Service Owner) 는 이를 대비해,
애플리케이션과 서비스 전반에 걸쳐 복원력 패턴을 일관성 있게 채택해야 합니다.
대표적인 복원력 패턴은 다음과 같습니다:
[예시: 서비스 A → 서비스 B 호출 시]
[장애를 예상하고 설계하라]
복원력 있는 시스템을 만든다는 것은 장애를 '없애는' 것이 아니라 '예상하고 대응하는' 것을 의미합니다.
마이크로서비스 아키텍처에서 복원력(Resilience)을 확보하는 방법은 오랫동안 개발자들의 주요 고민거리였습니다.
서비스 메시 기술이 등장하기 전까지는, 복원력 패턴(재시도, 타임아웃, 서킷 브레이커 등)을 직접 애플리케이션 코드에 작성해야 했습니다.
하지만 이 방식에는 여러 한계가 있었습니다.
[오픈소스 프레임워크의 등장]
개발자들의 부담을 줄이기 위해, 몇몇 오픈소스 프레임워크가 등장했습니다.
[문제점: 언어와 프레임워크 종속성]
하지만 이런 오픈소스 복원력 라이브러리들은 몇 가지 중요한 문제를 가지고 있었습니다.
[운영 부담 증가]
또한, 복원력 코드가 애플리케이션 내부에 깊이 침투하는 문제가 있었습니다.
이스티오 서비스 프록시는 애플리케이션 옆에 위치하며 애클리케이션에 모든 I/O 트래픽을 처리합니다.
또한 애플리케이션 수준 요청과 메시지(HTTP 요청 등)를 이해하므로 프록시 안에서 복원력 기능을 구현할 수 있습니다.

이스티오의 서비스 프록시는 기본적으로 다음과 같은 복원력 패턴을 구현합니다.
마이크로서비스 환경에서는 복원력을 고려할 때 어디에서 이를 처리할지에 대한 선택이 매우 중요합니다.
이스티오(Istio)를 사용하면, 애플리케이션 인스턴스 옆에 배치된 데이터 플레인 프록시가 복원력 패턴을 처리합니다.
따라서 별도의 중앙집중식 게이트웨이 없이도 복원력 있는 통신을 구현할 수 있습니다.
[과거의 방식: 중앙집중식 장치]
예전에는 복잡한 네트워크 문제를 해결하기 위해
하드웨어 로드 밸런서, 메시징 시스템, 엔터프라이즈 서비스 버스(ESB), API 게이트웨이 같은
중앙 집중식 미들웨어를 사용했습니다.
하지만 문제는 다음과 같았습니다:
이런 이유로, 고도로 분산된 방식으로 복원력을 구현하는 것이 필수적이 되었습니다.
[이스티오가 제공하는 접근법]
이스티오는 복원력 패턴을 서비스 코드와 분리하고, 애플리케이션 인스턴스 옆(sidecar 프록시) 에 배치하여
언어와 프레임워크에 상관없이 일관되게 관리할 수 있게 해줍니다.
이는 과거의 중앙집중식 모델과 명확히 대비되는, 현대적인 분산 클라우드 아키텍처에 최적화된 방법입니다.

이스티오는 서비스 및 엔드포인트 디스커버리를 사용하여 위와 같이 서비스 간 통신의 클라이언트 측 프록시에 올바른 최신 정보를 제공합니다.
서비스 운영자와 개발자는 DestinationRule 리소스를 이용하여 클라이언트가 어떤 로드 벨런싱 알고리즘을 사용할지 설정할수 있다.
kubectl delete gw,vs,deploy,svc,destinationrule --all -n istioinactioncat ch6/simple-backend.yaml
kubectl apply -f ch6/simple-backend.yaml -n istioinaction
kubectl apply -f ch6/simple-web.yaml -n istioinactionkubectl get deploy,pod,svc,ep -n istioinaction -o wide 
cat ch6/simple-web-gateway.yaml
kubectl apply -f ch6/simple-web-gateway.yaml -n istioinactionkubectl get gw,vs -n istioinaction 
echo "127.0.0.1 simple-web.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 3 
curl -s http://simple-web.istioinaction.io:30000
open http://simple-web.istioinaction.io:30000 

while true; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; donekubectl stern -l app=simple-web -n istioinaction -c simple-web
kubectl stern -l app=simple-backend -n istioinaction -c simple-backend 

docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' 

DestinationRule 적용 (ROUND_ROBIN)cat ch6/simple-backend-dr-rr.yaml
kubectl apply -f ch6/simple-backend-dr-rr.yaml -n istioinactionkubectl get dr -n istioinaction 
DestinationRule 상세 확인kubectl get destinationrule simple-backend-dr -n istioinaction \
-o jsonpath='{.spec.trafficPolicy.loadBalancer.simple}{"\n"}' 
curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"kubectl stern -l app=simple-web -n istioinaction -c simple-web
kubectl stern -l app=simple-backend -n istioinaction -c simple-backend 

docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json 
현실적인 환경에서 서비스가 요청을 처리하는데 시간이 소요됩니다.
소요 시간은 여러 이유로 달라질 수 있습니다.
또한 서비스 외적인 이유로도 응답시간에 영향을 미칠수 있습니다.
예제 서비스를 다시 호출하고 최초 설정한 서비스 응답시간에 따라 차이가 발생합니다.
kubectl exec -it netshoot -- time curl -s -o /dev/null http://simple-web.istioinaction

이떄 Fortio 라는 CLI 부하 생성 도구를 사용해 서비스를 실행하고 클라이언트 측 로드 밸런싱의 차이를 관찰할 예정입니다. → Link
brew install fortio
fortio -h
fortio server
open http://127.0.0.1:8080/fortio 

fortio curl http://simple-web.istioinaction.io:30000 
[테스트 환경]

[배포]
cat ch6/simple-backend-delayed.yaml
kubectl apply -f ch6/simple-backend-delayed.yaml -n istioinaction 
kubectl rollout restart deployment -n istioinaction simple-backend-1kubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep TIMING 
kubectl exec -it deploy/simple-backend-2 -n istioinaction -- env | grep TIMING 
KUBE_EDITOR="vi" kubectl edit deploy/simple-backend-1 -n istioinaction
...
- name: /
value: 1000ms
...
kubectl describe pod -n istioinaction -l app=simple-backend | grep TIMING_50_PERCENTILE: 
curl -s http://simple-web.istioinaction.io:30000 | grep duration 

fortio 접근하여 다음과 같이 세팅 - Link

테스트 결과

- target 50% 0.188919
- target 75% 1.0329
- target 90% 1.09842
- target 99% 1.13774
- target 99.9% 1.14167
cat ch6/simple-backend-dr-random.yaml
kubectl apply -f ch6/simple-backend-dr-random.yaml -n istioinactionkubectl get destinationrule simple-backend-dr -n istioinaction \
-o jsonpath='{.spec.trafficPolicy.loadBalancer.simple}{"\n"}'
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json | grep lbPolicy 
동일한 환경에서 fortio 테스트 진행

- target 50% 0.189739
- target 75% 1.05903
- target 90% 1.15788
- target 99% 1.21719
- target 99.9% 1.22312
로드 밸런싱 알고리듬을 Least connection 으로 변경하고 다시 로드 테스트 진행
cat ch6/simple-backend-dr-least-conn.yaml
kubectl apply -f ch6/simple-backend-dr-least-conn.yaml -n istioinaction
# 확인
kubectl get destinationrule simple-backend-dr -n istioinaction \
-o jsonpath='{.spec.trafficPolicy.loadBalancer.simple}{"\n"}'
#
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json | grep lbPolicy 
fortio 동일하게 테스트 수행

- target 50% 0.181418
- target 75% 0.194569
- target 90% 1.02382
- target 99% 1.0772
- target 99.9% 1.08254
[서비스 메시와 서비스 토폴로지 이해]
Istio 같은 컨트롤 플레인의 핵심 역할 중 하나는 서비스 토폴로지(서비스들의 위치와 관계) 를 이해하고,
그 토폴로지가 어떻게 변화할 수 있는지 예측하는 것입니다.
서비스 메시에서 전체 토폴로지를 파악하면, 서비스와 피어 서비스 간 위치 정보를 기반으로
자동으로 라우팅과 로드 밸런싱 결정을 내릴 수 있습니다.

[Istio가 지원하는 로드 밸런싱 최적화 방식]
Istio는 다음과 같은 방법으로 로드 밸런싱을 최적화합니다.
simple-backend 서비스가 us-west, us-east, europe-west 리전에 배포되어 있다고 가정합니다.simple-web이 us-west 리전에 있다면, simple-backend 호출은 us-west에 배포된 인스턴스를 우선적으로 선택합니다.만약 모든 엔드포인트를 동등하게 취급한다면, 리전 간 트래픽이 오가며 지연이 발생하고 추가 비용이 발생할 수 있습니다.
지역 인식 로드벨런싱이 잘 동작하는지 테스트를 진행합니다.
vi ch6/simple-service-locality.yaml---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: simple-web
name: simple-web
spec:
replicas: 1
selector:
matchLabels:
app: simple-web
template:
metadata:
labels:
app: simple-web
istio-locality: us-west1.us-west1-a
...
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: simple-backend
name: simple-backend-1
spec:
replicas: 1
selector:
matchLabels:
app: simple-backend
template:
metadata:
labels:
app: simple-backend
istio-locality: us-west1.us-west1-a
version: v1 # 추가해두자!
...
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: simple-backend
name: simple-backend-2
spec:
replicas: 2
selector:
matchLabels:
app: simple-backend
template:
metadata:
labels:
app: simple-backend
istio-locality: us-west1.us-west1-b
version: v2 # 추가해두자!
...kubectl apply -f ch6/simple-service-locality.yaml -n istioinactionkubectl get deployment.apps/simple-backend-1 -n istioinaction \
-o jsonpath='{.spec.template.metadata.labels.istio-locality}{"\n"}'
kubectl get deployment.apps/simple-backend-1 -n istioinaction \
-o jsonpath='{.spec.template.metadata.labels.version}{"\n"}' 
kubectl get deployment.apps/simple-backend-2 -n istioinaction \
-o jsonpath='{.spec.template.metadata.labels.istio-locality}{"\n"}'
kubectl get deployment.apps/simple-backend-2 -n istioinaction \
-o jsonpath='{.spec.template.metadata.labels.version}{"\n"}' 
cat ch6/simple-backend-dr-outlier.yaml
kubectl apply -f ch6/simple-backend-dr-outlier.yaml -n istioinaction 
kubectl get dr -n istioinaction simple-backend-dr -o jsonpath='{.spec}' | jq 
for in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr 


docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o jsondocker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json 
kubectl stern -l app=simple-backend -n istioinaction 

cat ch6/simple-service-locality-failure.yaml 
kubectl apply -f ch6/simple-service-locality-failure.yaml -n istioinactionfor in in {1..10}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done
for in in {1..50}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr 

docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' 
```bash
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
```
)kubectl apply -f ch6/simple-service-locality.yaml -n istioinaction가중치에 따른 동작 방식 테스트를 진행한다.

cat ch6/simple-backend-dr-outlier-locality.yaml 
kubectl apply -f ch6/simple-backend-dr-outlier-locality.yaml -n istioinactionfor in in {1..200}; do curl -s http://simple-web.istioinaction.io:30000 | jq ".upstream_calls[0].body"; done | sort | uniq -c | sort -nr 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' 

이스티오를 사용해 타임아웃 정책을 제어하는지 살펴보도록 하겠습니다.
kubectl apply -f ch6/simple-web.yaml -n istioinaction
kubectl apply -f ch6/simple-backend.yaml -n istioinaction
kubectl delete destinationrule simple-backend-dr -n istioinactionfor in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done 
cat ch6/simple-backend-delayed.yaml
kubectl apply -f ch6/simple-backend-delayed.yaml -n istioinactionkubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep TIMING 
kubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
-----------------------------------
export TIMING_50_PERCENTILE=1000ms
exit
-----------------------------------for in in {1..10}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done 
cat ch6/simple-backend-vs-timeout.yaml
kubectl apply -f ch6/simple-backend-vs-timeout.yaml -n istioinaction 
kubectl get vs -n istioinaction !
for in in {1..100}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done 

이스티오에서는 재시도가 기본적으로 활성화돼 있고, 두 번까지 재시도한다.
kubectl apply -f ch6/simple-web.yaml -n istioinaction
kubectl apply -f ch6/simple-backend.yaml -n istioinactiondocker exec -it myk8s-control-plane bash
----------------------------------------
# Retry 옵션 끄기 : 최대 재시도 0 설정
istioctl install --set profile=default --set meshConfig.defaultHttpRetryPolicy.attempts=0
y
exit
----------------------------------------kubectl get istiooperators -n istio-system -o yaml 

cat ch6/simple-backend-periodic-failure-503.yaml 
kubectl apply -f ch6/simple-backend-periodic-failure-503.yaml -n istioinactionkubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep ERRORkubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
---------------------------------------------------------------
export ERROR_TYPE=http_error
export ERROR_RATE=0.75
export ERROR_CODE=503
exit
---------------------------------------------------------------for in in {1..100}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done 

cat ch6/simple-backend-enable-retry.yaml
kubectl apply -f ch6/simple-backend-enable-retry.yaml -n istioinaction 
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/simple-web.istioinaction --name 80 -o json 
for in in {1..100}; do time curl -s http://simple-web.istioinaction.io:30000 | jq .code; done

서킷 브레이커 기능을 사용하면 부분적이거나 연쇄적인 장애를 방지할수 있습니다.
이스티오에는 서킷브레이커 라는 명시적인 설정은 존재하지 않으나, 백엔드 서비스, 특히 문제가 있는 서비스로의 부하를 제한할 수 있는 방법이 두 가지 있어 서킷 브레이커를 효과적으로 시행할 수 있습니다.

docker exec -it myk8s-control-plane bash
----------------------------------------
istioctl install --set profile=default --set meshConfig.accessLogFile=/dev/stdout --set meshConfig.defaultConfig.tracing.sampling=100 --set meshConfig.defaultHttpRetryPolicy.attempts=0
y
exit
----------------------------------------kubectl describe cm -n istio-system istio 
kubectl rollout restart deploy -n istio-system istiod
kubectl rollout restart deploy -n istio-system istio-ingressgateway
kubectl rollout restart deploy -n istioinaction simple-web
kubectl rollout restart deploy -n istioinaction simple-backend-1kubectl delete destinationrule --all -n istioinactionkubectl scale deploy simple-backend-2 --replicas=0 -n istioinactionkubectl apply -f ch6/simple-backend-delayed.yaml -n istioinactionkubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
-----------------------------------
export TIMING_50_PERCENTILE=3000ms
exit
-----------------------------------curl -s http://simple-web.istioinaction.io:30000 | grep duration 
fortio load -quiet -jitter -t 30s -c 1 -qps 1 http://simple-web.istioinaction.io:30000 
설정 변경
cat ch6/simple-backend-dr-conn-limit.yaml

배포 진행
kubectl apply -f ch6/simple-backend-dr-conn-limit.yaml -n istioinaction
kubectl get dr -n istioinaction 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-backend-1.istioinaction | egrep 'RULE|backend' 
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-backend-1.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json 
테스트 재실행
fortio load -quiet -jitter -t 30s -c 1 -qps 1 --allow-initial-errors http://simple-web.istioinaction.io:30000

정확한 확인이 필요(서킷 브레이크 영향인지 vs 업스트림의 장애인지 확인)
sample-web 서비스에 통계 수집을 활성화
cat ch6/simple-web-stats-incl.yaml | grep statsInclusionPrefixes
kubectl apply -f ch6/simple-web-stats-incl.yaml -n istioinaction

kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_counterskubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend | grep overflow
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream


fortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl logs -n istioinaction -l app=simple-web -c istio-proxy -f

업스트림 서버가 느리게 응답하거나, 다운됨
트래픽 급증으로 인해 큐에 쌓인 요청이 너무 많음
Envoy의 circuit breaker 설정 (예: max_requests, max_connections)을 초과함




프로메테우스 확인
kubectl patch destinationrule simple-backend-dr -n istioinaction \
-n istioinaction --type merge --patch \
'{"spec": {"trafficPolicy": {"connectionPool": {"http": {"http2MaxRequests": 2}}}}}'docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-backend-1.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json | grep maxRequests

kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_counterskubectl logs -n istioinaction -l app=simple-web -c istio-proxy -f 
fortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend | grep overflow 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream 


jaeger 에서 Tags 필터링 찾기 : guid:x-request-id=3e1789ba-2fa4-94b6-a782-cfdf0a405e13 , guid:x-request-id=304fd07c-0d09-9749-8e36-c0758c7464e3

보류 대기열 깊이 2로 변경
kubectl patch destinationrule simple-backend-dr \
-n istioinaction --type merge --patch \
'{"spec": {"trafficPolicy": {"connectionPool": {"http": {"http1MaxPendingRequests": 2}}}}}'
docker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-backend-1.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json | grep maxPendingRequests 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_countersfortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend | grep overflow 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream


guid:x-request-id=3e1789ba-2fa4-94b6-a782-cfdf0a405e13 , guid:x-request-id=304fd07c-0d09-9749-8e36-c0758c7464e3 
이번엔 오동작 misbehaving 하는 특정 호스트를 서비스에서 제거하는 이스티오의 접근법을 다룹니다.
이스티오는 이를 위해 엔보이의 이상값 감지 가능을 사용합니다.
kubectl delete destinationrule --all -n istioinaction
kubectl delete vs simple-backend-vs -n istioinaction
kubectl apply -f ch6/simple-backend.yaml -n istioinaction
kubectl apply -f ch6/simple-web-stats-incl.yaml -n istioinactionkubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_countersfortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream 

kubectl apply -n istioinaction -f ch6/simple-backend-periodic-failure-500.yaml
kubectl exec -it deploy/simple-backend-1 -n istioinaction -- env | grep ERROR
kubectl exec -it deploy/simple-backend-1 -n istioinaction -- sh
---------------------------------------------------------------
export ERROR_TYPE=http_error
export ERROR_RATE=0.75
export ERROR_CODE=500
exit
---------------------------------------------------------------kubectl get deploy,pod -n istioinaction -o wide 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_countersfortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream 

이상 값 감지 설정
| 이름 | 설명 |
|---|---|
consecutive5xxErrors | 잘못된 요청이 하나만 발생해도 이상값 감지가 발동. 기본값 5, 연속적인 에러 횟수 |
interval | 이스티오 서비스 프록시가 체크하는 주기. 기본값 10초 |
baseEjectionTime | 서비스 엔드포인트에서 제거된다면, 제거 시간은 n / 해당 시간이 지나면 로드 밸런싱 풀에 다시 추가됨. 기본값 30초 |
maxEjectionPercent | 로드 밸런싱 풀에서 제거 가능한 호스트 개수(%) , 기본값 10% |
배포 파일 확인
cat ch6/simple-backend-dr-outlier-5s.yaml

kubectl apply -f ch6/simple-backend-dr-outlier-5s.yaml -n istioinaction
kubectl get dr -n istioinactiondocker exec -it myk8s-control-plane istioctl proxy-config cluster deploy/simple-web.istioinaction --fqdn simple-backend.istioinaction.svc.cluster.local -o json 
docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_counterswhile true; do docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' ; date; sleep 1; echo; done 
fortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend | grep outlier 




cat ch6/simple-backend-vs-retry-500.yaml
kubectl apply -f ch6/simple-backend-vs-retry-500.yaml -n istioinaction 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl -X POST localhost:15000/reset_counterswhile true; do docker exec -it myk8s-control-plane istioctl proxy-config endpoint deploy/simple-web.istioinaction --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' ; date; sleep 1; echo; done 
fortio load -quiet -jitter -t 30s -c 2 -qps 2 --allow-initial-errors http://simple-web.istioinaction.io:30000 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend | grep outlier 
kubectl exec -it deploy/simple-web -c istio-proxy -n istioinaction \
-- curl localhost:15000/stats | grep simple-backend.istioinaction.svc.cluster.local.upstream | grep retry


kind delete cluster --name myk8s
/etc/hosts # 설정된 host 삭제