가시다(gasida) 님이 진행하는 Istio Hands-on Study 1기 과정을 참여하여 정리한 글입니다.
7주차는 이스티오 스케일링, 데이터 플레인 확장 주제로 학습을 하였습니다.
가상회사 ACME는 클라우드 마이그레이션 초기에 단일 클러스터를 선택했지만, 곧 다수의 소규모 클러스터 전략으로 전환했다. 그 이유는 다음과 같다:
또한 ACME는 서비스 메시를 채택한 주요 이유로 다음을 들었다:
이러한 요구를 충족하기 위해 ACME는 다중 클러스터 운영을 위한 두 가지 접근 방식을 고려했다.


Istio는 앱에 투명하게 클러스터 간 통신을 연결하면서도,
트래픽 제어, 복원력, 관찰 가능성, 보안 등 서비스 메시의 핵심 기능을 유지한다.
다중 클러스터 메시 구성 요소
📌 이 세 조건이 충족되면,클러스터는 서로의 워크로드를 인식하고 연결할 수 있으며, Istio의 인증/인가 정책도 적용할 수 있다. 이것이 다중 클러스터 서비스 메시를 구성하기 위한 핵심 요건이다.
✅ 배포 모델 3가지
기본-원격 모델 (Primary-Remote)

기본-기본 모델 (Primary-Primary)

외부 컨트롤 플레인 모델 (External Control Plane)

🔐 Istio 컨트롤 플레인의 클러스터 간 디스커버리와 보안
🛠️ 보안 메커니즘: Kubernetes RBAC
🎯 istiod가 API에 접근하기 위해 사용하는 ID와 권한 리소스를 보여준다.
🔎 클러스터 간 디스커버리
🎞️ istiod가 원격 클러스터를 인증하고 워크로드를 찾는 흐름을 보여준다.
🗜️자동화
✅ 워크로드 간 연결성 (Cross-cluster workload connectivity)
① 클러스터가 같은 네트워크에 있을 경우
예: 같은 VPC, VPC 피어링 등 플랫 네트워크
→ 워크로드가 IP 주소로 직접 통신 가능
→ 추가 구성 없이 연결 조건 충족
② 클러스터가 다른 네트워크에 있을 경우
직접 IP 통신이 불가능
→ 이스티오 인그레스 게이트웨이 필요(네트워크 경계에 배치해 클러스터 간 트래픽 프록시)
🛡️ East-West Gateway

🔗 공식 문서 Multiple networks 제공 기능 : 중복 IP 환경 시 해결 등

📌 Istio 공식 문서에서 언급한 Multi-Network 구성 필요성
💡 참고: Multi-primary 모델에서는 east-west gateway 없이도 네트워크 장비의 L3 라우팅 설정으로 직접 통신 가능
실습 예시:
📦 GitHub 코드 : https://github.com/abasitt/kube6/tree/main/istio/istiocon
▶️ 관련 영상 : https://www.youtube.com/watch?v=4aeeLGrS514
✅ 공통 신뢰(Common Trust)의 필요성
🔐 공통 신뢰 구성 방법
1️⃣ 플러그인 CA 인증서 방식 (Plug-in CA Certificates)

📌 장점: 간단한 구성, Istio 설치 시 지정만 하면 됨
⚠️ 단점: 중간 CA 유출 시 보안 위험, 노출되면 악의적인 인증서 발급 가능, 보안 강화: 중간 CA를 etcd에 저장하지 않고 메모리로만 유지
2️⃣ 외부 CA 통합 방식 (External CA Integration)

📌 구현 방법: cert-manager + istio-csr 사용, cert-manager가 외부 CA에 CSR을 전달하고, 서명된 인증서를 반환
⚠️ 제한사항: cert-manager가 사용하는 외부 CA를 지원해야만 가능
🔗 참고 링크: Istio Plug-in CA Guide, Istio External CA + cert-manager, cert-manager 지원 외부 CA 목록
🔚 결론
| 방법 | 장점 | 단점 |
|---|---|---|
| 플러그인 CA | 쉽고 간단 | 중간 CA 노출 시 위험 |
| 외부 CA 통합 | 더 안전 | 복잡하고 외부 CA 지원 필요ㅍ |
🍎 멀티 클러스터 메시를 보안적으로 잘 구성하려면 조직의 보안 정책과 인증서 관리 전략에 맞춰 두 방식 중 하나를 선택해야 합니다.
🌍 인프라 구성 개요
🧱 클러스터 구성
| 클러스터 리전 | 네트워크 | 실행 서비스 |
|---|---|---|
| west-cluster | us-west 사설 네트워크 | webapp |
| east-cluster | us-east 사설 네트워크 | catalog |

📌 참고 사항
🔁 네트워크 연결
🧠 컨트롤 플레인 모델 선택
💼 ACME의 선택 (사례)
🏗️ 최종 아키텍처 구성
🗜️ west k8s 클러스터 배포
#
kind create cluster --name west --image kindest/node:v1.23.17 --kubeconfig ./west-kubeconfig --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000 # 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 # kube-ops-view
hostPort: 30005
networking:
podSubnet: 10.10.0.0/16
serviceSubnet: 10.100.0.0/24
EOF
Creating cluster "west" ...
✓ Ensuring node image (kindest/node:v1.23.17) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-west"
You can now use your cluster with:
kubectl cluster-info --context kind-west --kubeconfig ./west-kubeconfig
# 설치 확인
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bb963e761e63 kindest/node:v1.23.17 "/usr/local/bin/entr…" 36 seconds ago Up 35 seconds 0.0.0.0:30000-30005->30000-30005/tcp, 127.0.0.1:56471->6443/tcp west-control-plane
cat west-kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJ
...
server: https://127.0.0.1:56471
name: kind-west
contexts:
- context:
cluster: kind-west
user: kind-west
name: kind-west
current-context: kind-west
kind: Config
preferences: {}
users:
- name: kind-west
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJRnBlM3Z
...
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBK1IweGF
...
kubectl get node --kubeconfig=./west-kubeconfig
kubectl get pod -A --kubeconfig=./west-kubeconfig
# 노드에 기본 툴 설치
docker exec -it west-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'
# (옵션) kube-ops-view
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30005 --set env.TZ="Asia/Seoul" --namespace kube-system --kubeconfig=./west-kubeconfig
LAST DEPLOYED: Sat May 24 08:27:11 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace kube-system -o jsonpath="{.spec.ports[0].nodePort}" services kube-ops-view)
export NODE_IP=$(kubectl get nodes --namespace kube-system -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view --kubeconfig=./west-kubeconfig
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kube-ops-view 1/1 1 1 43s
NAME READY STATUS RESTARTS AGE
pod/kube-ops-view-79df45849b-fpjfb 1/1 Running 0 43s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-ops-view NodePort 10.100.0.146 <none> 8080:30005/TCP 43s
NAME ENDPOINTS AGE
endpoints/kube-ops-view 10.10.0.5:8080 43s
## kube-ops-view 접속 URL 확인
open "http://localhost:30005/#scale=1.5"
open "http://localhost:30005/#scale=1.3"
🗜️ east k8s 클러스터 배포
#
kind create cluster --name east --image kindest/node:v1.23.17 --kubeconfig ./east-kubeconfig --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 31000 # istio-ingrssgateway HTTP
hostPort: 31000
- containerPort: 31001 # Prometheus
hostPort: 31001
- containerPort: 31002 # Grafana
hostPort: 31002
- containerPort: 31003 # Kiali
hostPort: 31003
- containerPort: 31004 # Tracing
hostPort: 31004
- containerPort: 31005 # kube-ops-view
hostPort: 31005
networking:
podSubnet: 10.20.0.0/16
serviceSubnet: 10.200.0.0/24
EOF
# 설치 확인
docker ps
cat east-kubeconfig
kubectl get node --kubeconfig=./east-kubeconfig
kubectl get pod -A --kubeconfig=./east-kubeconfig
# 노드에 기본 툴 설치
docker exec -it east-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'
# (옵션) kube-ops-view
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=31005 --set env.TZ="Asia/Seoul" --namespace kube-system --kubeconfig=./east-kubeconfig
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view --kubeconfig=./east-kubeconfig
## kube-ops-view 접속 URL 확인
open "http://localhost:31005/#scale=1.5"
open "http://localhost:31005/#scale=1.3"
▶️ kind docker network 에 테스트용 PC(실제로는 컨테이너) 배포
# kind 설치 시 kind 이름의 도커 브리지가 생성된다 : 172.18.0.0/16 대역
docker network ls
NETWORK ID NAME DRIVER SCOPE
73d09aa3bbc3 bridge bridge local
3d26d2cec1c7 host host local
3fb176856219 kind bridge local
cf676bb6e447 none null local
docker inspect kind
[
{
"Name": "kind",
"Id": "3fb176856219b1257b521c51c749116277bc01fae56b80e418826c251dd1fda2",
"Created": "2025-05-20T23:51:26.849522289+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": true,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
},
{
"Subnet": "fc00:f853:ccd:e793::/64",
"Gateway": "fc00:f853:ccd:e793::1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"bb963e761e6366242cdc5fbe0f86d8295bac5bbaea1c1e0d9e780b391b03d4ee": {
"Name": "west-control-plane",
"EndpointID": "a73a373c187f29e64c4221626aeff7bc75e3c19229f7beb432640341db936bc3",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": "fc00:f853:ccd:e793::2/64"
},
"dfaf1d0dd0fbc43807d5eec2d069e8dce3132d673655ab840b9feb5d7613a099": {
"Name": "east-control-plane",
"EndpointID": "9f8df45a4afccaee3c2ff3197cbf4db7d7a964d94b1c25de7e297dcf2ff53023",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": "fc00:f853:ccd:e793::3/64"
}
},
"Options": {
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
# mypc 컨테이너 기동 : kind 도커 브리지를 사용하고, 컨테이너 IP를 지정 없이 혹은 지정 해서 사용
docker run -d --rm --name mypc --network kind --ip 172.18.0.100 nicolaka/netshoot sleep infinity # IP 지정 실행 시
혹은 IP 지정 실행 시 에러 발생 시 아래 처럼 IP 지정 없이 실행
docker run -d --rm --name mypc --network kind nicolaka/netshoot sleep infinity # IP 지정 없이 실행 시
docker ps
# kind network 중 컨테이너(노드) IP(대역) 확인
docker ps -q | xargs docker inspect --format '{{.Name}} {{.NetworkSettings.Networks.kind.IPAddress}}'
/mypc 172.18.0.100
/east-control-plane 172.18.0.3
/west-control-plane 172.18.0.2
# 동일한 docker network(kind) 내부에서 컨테이너 이름 기반 도메인 통신 가능 확인!
docker exec -it mypc ping -c 1 172.18.0.2
docker exec -it mypc ping -c 1 172.18.0.3
docker exec -it mypc ping -c 1 west-control-plane
docker exec -it mypc ping -c 1 east-control-plane
#
docker exec -it west-control-plane ping -c 1 east-control-plane
docker exec -it east-control-plane ping -c 1 west-control-plane
docker exec -it west-control-plane ping -c 1 mypc
docker exec -it east-control-plane ping -c 1 mypc

Github & Alias 설정(kwest, keast)
MetalLB 배포
# MetalLB 배포
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml \
--kubeconfig=./west-kubeconfig
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/servicel2statuses.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
role.rbac.authorization.k8s.io/controller created
role.rbac.authorization.k8s.io/pod-lister created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/controller created
rolebinding.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
configmap/metallb-excludel2 created
secret/metallb-webhook-cert created
service/metallb-webhook-service created
deployment.apps/controller created
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml \
--kubeconfig=./east-kubeconfig
# 확인
kubectl get crd --kubeconfig=./west-kubeconfig
NAME CREATED AT
bfdprofiles.metallb.io 2025-05-24T00:03:11Z
bgpadvertisements.metallb.io 2025-05-24T00:03:11Z
bgppeers.metallb.io 2025-05-24T00:03:11Z
communities.metallb.io 2025-05-24T00:03:11Z
ipaddresspools.metallb.io 2025-05-24T00:03:11Z
l2advertisements.metallb.io 2025-05-24T00:03:11Z
servicel2statuses.metallb.io 2025-05-24T00:03:11Z
kubectl get crd --kubeconfig=./east-kubeconfig
kubectl get pod -n metallb-system --kubeconfig=./west-kubeconfig
NAME READY STATUS RESTARTS AGE
controller-686c7db689-x5c8k 1/1 Running 0 106s
speaker-nprb2 1/1 Running 0 106s
kubectl get pod -n metallb-system --kubeconfig=./east-kubeconfig
NAME READY STATUS RESTARTS AGE
controller-686c7db689-fnzdp 1/1 Running 0 53s
speaker-g22cc 1/1 Running 0 53s
# IPAddressPool, L2Advertisement 설정
cat << EOF | kubectl apply --kubeconfig=./west-kubeconfig -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 172.18.255.101-172.18.255.120
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
EOF
ipaddresspool.metallb.io/default created
l2advertisement.metallb.io/default created
cat << EOF | kubectl apply --kubeconfig=./east-kubeconfig -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 172.18.255.201-172.18.255.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
EOF
# 확인
kubectl get IPAddressPool,L2Advertisement -A --kubeconfig=./west-kubeconfig
NAMESPACE NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
metallb-system ipaddresspool.metallb.io/default true false ["172.18.255.101-172.18.255.120"]
NAMESPACE NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES
metallb-system l2advertisement.metallb.io/default ["default"]
kubectl get IPAddressPool,L2Advertisement -A --kubeconfig=./east-kubeconfig
NAMESPACE NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
metallb-system ipaddresspool.metallb.io/default true false ["172.18.255.201-172.18.255.220"]
NAMESPACE NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES
metallb-system l2advertisement.metallb.io/default ["default"]
#
cat << EOF | kubectl apply --kubeconfig=./west-kubeconfig -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
EOF
deployment.apps/nginx created
service/nginx-service created
#
cat << EOF | kubectl apply --kubeconfig=./east-kubeconfig -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
EOF
deployment.apps/nginx created
service/nginx-service created
# 확인
kubectl get deploy,pod,svc,ep --kubeconfig=./west-kubeconfig
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 57s
NAME READY STATUS RESTARTS AGE
pod/nginx-8d545c96d-jflbw 1/1 Running 0 57s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 47m
service/nginx-service LoadBalancer 10.100.0.143 172.18.255.101 80:32268/TCP 57s
NAME ENDPOINTS AGE
endpoints/kubernetes 172.18.0.2:6443 47m
endpoints/nginx-service 10.10.0.7:80 57s
kubectl get deploy,pod,svc,ep --kubeconfig=./east-kubeconfig
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 45s
NAME READY STATUS RESTARTS AGE
pod/nginx-8d545c96d-fgj5j 1/1 Running 0 45s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.200.0.1 <none> 443/TCP 37m
service/nginx-service LoadBalancer 10.200.0.68 172.18.255.201 80:30906/TCP 45s
NAME ENDPOINTS AGE
endpoints/kubernetes 172.18.0.3:6443 37m
endpoints/nginx-service 10.20.0.7:80 45s
kubectl get svc nginx-service --kubeconfig=./west-kubeconfig -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
172.18.255.101
kubectl get svc nginx-service --kubeconfig=./east-kubeconfig -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
172.18.255.201
WNIP=$(kubectl get svc nginx-service --kubeconfig=./west-kubeconfig -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
ENIP=$(kubectl get svc nginx-service --kubeconfig=./east-kubeconfig -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# 외부(mypc)에서 각 클러스터의 Service(LB)로 접속(인입) 확인 : TCP 80 포트 사용으로 편리하다!
docker exec -it mypc curl -s $WNIP
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
docker exec -it mypc curl -s $WNIP -v -I
* Trying 172.18.255.101:80...
* Connected to 172.18.255.101 (172.18.255.101) port 80
> HEAD / HTTP/1.1
> Host: 172.18.255.101
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.27.5
Server: nginx/1.27.5
< Date: Sat, 24 May 2025 00:11:10 GMT
Date: Sat, 24 May 2025 00:11:10 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 615
Content-Length: 615
< Last-Modified: Wed, 16 Apr 2025 12:01:11 GMT
Last-Modified: Wed, 16 Apr 2025 12:01:11 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "67ff9c07-267"
ETag: "67ff9c07-267"
< Accept-Ranges: bytes
Accept-Ranges: bytes
<
* Connection #0 to host 172.18.255.101 left intact
docker exec -it mypc curl -s $ENIP
docker exec -it mypc curl -s $ENIP -v -I
* Trying 172.18.255.201:80...
* Connected to 172.18.255.201 (172.18.255.201) port 80
> HEAD / HTTP/1.1
> Host: 172.18.255.201
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.27.5
Server: nginx/1.27.5
< Date: Sat, 24 May 2025 00:11:56 GMT
Date: Sat, 24 May 2025 00:11:56 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 615
Content-Length: 615
< Last-Modified: Wed, 16 Apr 2025 12:01:11 GMT
Last-Modified: Wed, 16 Apr 2025 12:01:11 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "67ff9c07-267"
ETag: "67ff9c07-267"
< Accept-Ranges: bytes
Accept-Ranges: bytes
<
* Connection #0 to host 172.18.255.201 left intact
# 확인 후 삭제
kubectl delete deploy,svc --all --kubeconfig=./west-kubeconfig
deployment.apps "nginx" deleted
service "kubernetes" deleted
service "nginx-service" deleted
kubectl delete deploy,svc --all --kubeconfig=./east-kubeconfig
deployment.apps "nginx" deleted
service "kubernetes" deleted
service "nginx-service" deleted
alias kwest='kubectl --kubeconfig=./west-kubeconfig'
alias keast='kubectl --kubeconfig=./east-kubeconfig'
alias iwest='docker exec -it west-control-plane istioctl'
alias ieast='docker exec -it east-control-plane istioctl'
🔐 Istio의 기본 CA 동작
Istio 설치 시 기본적으로 자체 CA를 생성하여,
→ 워크로드 인증서에 서명
이 CA는 istio-ca-secret 시크릿으로
→ istio-system 네임스페이스에 저장되고
→ 모든 istiod 인스턴스에 공유됨
🧩 사용자 정의 CA 사용 (Plug-in CA)

🤐 이 시크릿에는 다음 항목 포함:
| 파일명 | 설명 |
|---|---|
| ca-cert.pem | 중간 CA 인증서 |
| ca-key.pem | 중간 CA 개인 키 |
| root-cert.pem | 루트 CA 인증서 (모든 클러스터가 신뢰) |
| cert-chain.pem | 중간 CA + 루트 CA 이어 붙인 체인 인증서 |
🏗️ 인증서 체계 구조
Root CA → 모든 클러스터가 신뢰하는 최상위 인증서
↓
Intermediate CA → 각 클러스터별로 발급되어 워크로드 인증서 서명에 사용
↓
Workload Cert → 신뢰 체인을 구성하여 클라이언트가 인증서를 검증할 수 있도록 함
📌 핵심 요점:
✅ 플러그인 CA 인증서 적용하기
# cat ./ch12/scripts/generate-certificates.sh
#!/bin/bash
set -ex
cert_dir=`dirname "$BASH_SOURCE"`/../certs
echo "Clean up contents of dir './chapter12/certs'"
rm -rf ${cert_dir}
echo "Generating new certificates"
mkdir -p ${cert_dir}/west-cluster
mkdir -p ${cert_dir}/east-cluster
# step CLI 설치 확인 : step CLI가 설치되어 있지 않으면 에러 출력 후 종료.
## macOS : brew install step
if ! [ -x "$(command -v step)" ]; then
echo 'Error: Install the smallstep cli (https://github.com/smallstep/cli)'
exit 1
fi
step certificate create root.istio.in.action ${cert_dir}/root-cert.pem ${cert_dir}/root-ca.key \
--profile root-ca --no-password --insecure --san root.istio.in.action \
--not-after 87600h --kty RSA
step certificate create west.intermediate.istio.in.action ${cert_dir}/west-cluster/ca-cert.pem ${cert_dir}/west-cluster/ca-key.pem --ca ${cert_dir}/root-cert.pem --ca-key ${cert_dir}/root-ca.key --profile intermediate-ca --not-after 87600h --no-password --insecure --san west.intermediate.istio.in.action --kty RSA
step certificate create east.intermediate.istio.in.action ${cert_dir}/east-cluster/ca-cert.pem ${cert_dir}/east-cluster/ca-key.pem --ca ${cert_dir}/root-cert.pem --ca-key ${cert_dir}/root-ca.key --profile intermediate-ca --not-after 87600h --no-password --insecure --san east.intermediate.istio.in.action --kty RSA
cat ${cert_dir}/west-cluster/ca-cert.pem ${cert_dir}/root-cert.pem > ${cert_dir}/west-cluster/cert-chain.pem
cat ${cert_dir}/east-cluster/ca-cert.pem ${cert_dir}/root-cert.pem > ${cert_dir}/east-cluster/cert-chain.pem
💁🏻♀️ 기본정보 확인
#
tree ch12/certs
ch12/certs
├── east-cluster
│ ├── ca-cert.pem # 중간 CA 인증서
│ ├── ca-key.pem # 중간 CA 개인키
│ └── cert-chain.pem # 인증서 체인
├── root-ca.key # 루트 인증서
├── root-cert.pem # 루트 개인키
└── west-cluster
├── ca-cert.pem
├── ca-key.pem
└── cert-chain.pem
# (참고) 인증서 체인 생성 (기 인증서 생성되어 있음)
## 중간 CA 인증서(ca-cert.pem)와 루트 CA 인증서(root-cert.pem)를 결합 -> 결과는 {west/east}-cluster/cert-chain.pem 에 저장
cat ${cert_dir}/west-cluster/ca-cert.pem ${cert_dir}/root-cert.pem > ${cert_dir}/west-cluster/cert-chain.pem
cat ${cert_dir}/east-cluster/ca-cert.pem ${cert_dir}/root-cert.pem > ${cert_dir}/east-cluster/cert-chain.pem
# 인증서 계층 구조
root.istio.in.action (Root CA)
└── east.intermediate.istio.in.action (Intermediate CA)
# 루트 CA 인증서 확인
openssl x509 -in ch12/certs/root-cert.pem -noout -text
...
Issuer: CN=root.istio.in.action
Validity
Not Before: Jun 28 14:11:35 2022 GMT
Not After : Jun 25 14:11:35 2032 GMT
Subject: CN=root.istio.in.action
...
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
...
#
openssl x509 -in ch12/certs/east-cluster/ca-cert.pem -noout -text
...
Issuer: CN=root.istio.in.action
Validity
Not Before: Jun 28 14:11:35 2022 GMT
Not After : Jun 25 14:11:35 2032 GMT
Subject: CN=east.intermediate.istio.in.action
...
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0 # 이 중간 CA는 추가적인 하위 CA를 만들 수 없음
...
openssl x509 -in ch12/certs/east-cluster/cert-chain.pem -noout -text
Issuer: CN=root.istio.in.action
Validity
Not Before: Jun 28 14:11:35 2022 GMT
Not After : Jun 25 14:11:35 2032 GMT
Subject: CN=east.intermediate.istio.in.action
...
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
#
openssl x509 -in ch12/certs/west-cluster/ca-cert.pem -noout -text
openssl x509 -in ch12/certs/west-cluster/cert-chain.pem -noout -text
✅ (옵션) step 로 인증서 생성 시
# step CLI 설치
# macOS : brew install step
# 스크립트 실행
chmod +x ch12/scripts/generate-certificates.sh
./ch12/scripts/generate-certificates.sh
...
# 생성 결과 확인
tree ch12/certs
ch12/certs
├── east-cluster
│ ├── ca-cert.pem
│ ├── ca-key.pem
│ └── cert-chain.pem
├── root-ca.key
├── root-cert.pem
└── west-cluster
├── ca-cert.pem
├── ca-key.pem
└── cert-chain.pem
3 directories, 8 files
📌 istio-system 네임스페이스를 만든 후 인증서를 cacerts 라는 시크릿으로 배포하여 각 클러스터에 중간 CA를 만들어두기
# west-cluster 용 인증서 설정하기
kwest create namespace istio-system
kwest create secret generic cacerts -n istio-system \
--from-file=ch12/certs/west-cluster/ca-cert.pem \
--from-file=ch12/certs/west-cluster/ca-key.pem \
--from-file=ch12/certs/root-cert.pem \
--from-file=ch12/certs/west-cluster/cert-chain.pem
# east-cluster 용 인증서 설정하기
keast create namespace istio-system
keast create secret generic cacerts -n istio-system \
--from-file=ch12/certs/east-cluster/ca-cert.pem \
--from-file=ch12/certs/east-cluster/ca-key.pem \
--from-file=ch12/certs/root-cert.pem \
--from-file=ch12/certs/east-cluster/cert-chain.pem
# 확인
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get ns istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME STATUS AGE
istio-system Active 77s
>> k8s cluster : east <<
NAME STATUS AGE
istio-system Active 20s
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get secret cacerts -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME TYPE DATA AGE
cacerts Opaque 4 66s
>> k8s cluster : east <<
NAME TYPE DATA AGE
cacerts Opaque 4 48s
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl view-secret cacerts -n istio-system --all --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
ca-cert.pem='-----BEGIN CERTIFICATE-----
MIIDOzCCAiOgAwIBAgIQSqOt0fx21muREMs47sO1rjANBgkqhkiG9w0BAQsFADAf
...
-----END CERTIFICATE-----'
ca-key.pem='-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvajcTkjrfb4pGh22UGGTyqiTxAwNBY5iYvMOGUlnOJ5NWP9U
...
-----END RSA PRIVATE KEY-----'
cert-chain.pem='-----BEGIN CERTIFICATE-----
MIIDOzCCAiOgAwIBAgIQSqOt0fx21muREMs47sO1rjANBgkqhkiG9w0BAQsFADAf
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIQGq1YcjF2woccVP0GX4qnKjANBgkqhkiG9w0BAQsFADAf
...
-----END CERTIFICATE-----'
root-cert.pem='-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIQGq1YcjF2woccVP0GX4qnKjANBgkqhkiG9w0BAQsFADAf
...
-----END CERTIFICATE-----'
>> k8s cluster : east <<
ca-cert.pem='-----BEGIN CERTIFICATE-----
MIIDPDCCAiSgAwIBAgIRAPuIC1hSYpzkxBjkHnS7NS8wDQYJKoZIhvcNAQELBQAw
...
-----END CERTIFICATE-----'
ca-key.pem='-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAv9j6bhn1RYhyjepOlr3/uwUS4Ssqj40C/qyKl3KaTGYTbgNR
...
-----END RSA PRIVATE KEY-----'
cert-chain.pem='-----BEGIN CERTIFICATE-----
MIIDPDCCAiSgAwIBAgIRAPuIC1hSYpzkxBjkHnS7NS8wDQYJKoZIhvcNAQELBQAw
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIQGq1YcjF2woccVP0GX4qnKjANBgkqhkiG9w0BAQsFADAf
...
-----END CERTIFICATE-----'
root-cert.pem='-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIQGq1YcjF2woccVP0GX4qnKjANBgkqhkiG9w0BAQsFADAf
...
-----END CERTIFICATE-----'
플러그인 인증서가 설정되면 이스티오 컨트롤 플레인을 설치할 수 있다. 컨트롤 플레인은 플러그인 CA 인증서(사용자가 정의한 중간 인증서)를 갖고 워크로드 인증서에 서명한다.
🌐 네트워크 메타데이터 설정
Istio 컨트롤 플레인 설치 전에, 각 클러스터에 네트워크 메타데이터(network name)를 추가해야 함
📍 네트워크 메타데이터의 목적과 효과
✅ 핵심 요점:
topology.istio.io/network=**west-network** 레이블을 붙인다. east 도 설정하자.#
kwest label namespace istio-system topology.istio.io/network=west-network
keast label namespace istio-system topology.istio.io/network=east-network
# 확인
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get ns istio-system --show-labels --kubeconfig=./$i-kubeconfig; echo; done
NAME STATUS AGE LABELS
istio-system Active 36m kubernetes.io/metadata.name=istio-system,topology.istio.io/network=west-network
>> k8s cluster : east <<
NAME STATUS AGE LABELS
istio-system Active 35m kubernetes.io/metadata.name=istio-system,topology.istio.io/network=east-network
# cat ./ch12/controlplanes/cluster-west.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-controlplane
namespace: istio-system
spec:
profile: demo
components:
egressGateways: # 이그레스 게이트웨이 비활성화
- name: istio-egressgateway
enabled: false
values:
global:
meshID: usmesh # 메시 이름
multiCluster:
clusterName: west-cluster # 멀티 클러스터 메시 내부의 클러스터 식별자
network: west-network # 이 설치가 이뤄지는 네트워크
# cat ./ch12/controlplanes/cluster-east.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-controlplane
namespace: istio-system
spec:
profile: demo
components:
egressGateways: # 이그레스 게이트웨이 비활성화
- name: istio-egressgateway
enabled: false
values:
global:
meshID: usmesh # 메시 이름
multiCluster:
clusterName: east-cluster
network: east-network
# west-control-plane 진입 후 설치 진행
docker exec -it west-control-plane bash
-----------------------------------
# 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
# IstioOperator 파일 작성
cat << EOF > west-istio.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-controlplane
namespace: istio-system
spec:
profile: demo
components:
egressGateways:
- name: istio-egressgateway
enabled: false
values:
global:
meshID: usmesh
multiCluster:
clusterName: west-cluster
network: west-network
EOF
# 컨트롤 플레인 배포
istioctl install -f west-istio.yaml --set values.global.proxy.privileged=true -y
# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
# 빠져나오기
exit
-----------------------------------
# 설치 확인 : istiod, istio-ingressgateway, crd 등
kwest get istiooperators -n istio-system -o yaml
...
meshID: usmesh
meshNetworks: {}
mountMtlsCerts: false
multiCluster:
clusterName: west-cluster
enabled: false
network: west-network
...
kwest get all,svc,ep,sa,cm,secret,pdb -n istio-system
NAME READY STATUS RESTARTS AGE
pod/grafana-b854c6c8-km4w7 1/1 Running 0 86s
pod/istio-ingressgateway-5db74c978c-wvn65 1/1 Running 0 106s
pod/istiod-5585445f4c-7v25t 1/1 Running 0 2m3s
pod/jaeger-5556cd8fcf-sxr67 1/1 Running 0 85s
pod/kiali-648847c8c4-cc85f 1/1 Running 0 85s
pod/prometheus-7b8b9dd44c-hs8x6 2/2 Running 0 85s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/grafana ClusterIP 10.100.0.58 <none> 3000/TCP 86s
service/istio-ingressgateway LoadBalancer 10.100.0.85 172.18.255.101 15021:32239/TCP,80:31651/TCP,443:30754/TCP,31400:32736/TCP,15443:32637/TCP 106s
service/istiod ClusterIP 10.100.0.190 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 2m3s
service/jaeger-collector ClusterIP 10.100.0.63 <none> 14268/TCP,14250/TCP,9411/TCP 85s
service/kiali ClusterIP 10.100.0.180 <none> 20001/TCP,9090/TCP 85s
service/prometheus ClusterIP 10.100.0.245 <none> 9090/TCP 85s
service/tracing ClusterIP 10.100.0.43 <none> 80/TCP,16685/TCP 85s
service/zipkin ClusterIP 10.100.0.77 <none> 9411/TCP 85s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/grafana 1/1 1 1 86s
deployment.apps/istio-ingressgateway 1/1 1 1 106s
deployment.apps/istiod 1/1 1 1 2m3s
deployment.apps/jaeger 1/1 1 1 85s
deployment.apps/kiali 1/1 1 1 85s
deployment.apps/prometheus 1/1 1 1 85s
NAME DESIRED CURRENT READY AGE
replicaset.apps/grafana-b854c6c8 1 1 1 86s
replicaset.apps/istio-ingressgateway-5db74c978c 1 1 1 106s
replicaset.apps/istiod-5585445f4c 1 1 1 2m3s
replicaset.apps/jaeger-5556cd8fcf 1 1 1 85s
replicaset.apps/kiali-648847c8c4 1 1 1 85s
replicaset.apps/prometheus-7b8b9dd44c 1 1 1 85s
NAME ENDPOINTS AGE
endpoints/grafana 10.10.0.10:3000 86s
endpoints/istio-ingressgateway 10.10.0.9:15443,10.10.0.9:15021,10.10.0.9:31400 + 2 more... 106s
endpoints/istiod 10.10.0.8:15012,10.10.0.8:15010,10.10.0.8:15017 + 1 more... 2m2s
endpoints/jaeger-collector 10.10.0.11:9411,10.10.0.11:14250,10.10.0.11:14268 85s
endpoints/kiali 10.10.0.12:9090,10.10.0.12:20001 85s
endpoints/prometheus 10.10.0.13:9090 85s
endpoints/tracing 10.10.0.11:16685,10.10.0.11:16686 85s
endpoints/zipkin 10.10.0.11:9411 85s
NAME SECRETS AGE
serviceaccount/default 1 43m
serviceaccount/grafana 1 86s
serviceaccount/istio-ingressgateway-service-account 1 106s
serviceaccount/istio-reader-service-account 1 2m3s
serviceaccount/istiod 1 2m3s
serviceaccount/istiod-service-account 1 2m3s
serviceaccount/kiali 1 85s
serviceaccount/prometheus 1 85s
NAME DATA AGE
configmap/grafana 4 86s
configmap/istio 2 2m3s
configmap/istio-ca-root-cert 1 108s
configmap/istio-gateway-deployment-leader 0 109s
configmap/istio-gateway-status-leader 0 109s
configmap/istio-grafana-dashboards 2 86s
configmap/istio-leader 0 109s
configmap/istio-namespace-controller-election 0 109s
configmap/istio-services-grafana-dashboards 4 85s
configmap/istio-sidecar-injector 2 2m3s
configmap/kiali 1 85s
configmap/kube-root-ca.crt 1 43m
configmap/prometheus 5 85s
NAME TYPE DATA AGE
secret/cacerts Opaque 4 42m
secret/default-token-ndvmn kubernetes.io/service-account-token 3 43m
secret/grafana-token-8zzsv kubernetes.io/service-account-token 3 86s
secret/istio-ingressgateway-service-account-token-hl5px kubernetes.io/service-account-token 3 106s
secret/istio-reader-service-account-token-mjw94 kubernetes.io/service-account-token 3 2m3s
secret/istiod-service-account-token-f6482 kubernetes.io/service-account-token 3 2m3s
secret/istiod-token-4qrrt kubernetes.io/service-account-token 3 2m3s
secret/kiali-token-r7vvb kubernetes.io/service-account-token 3 85s
secret/prometheus-token-5rhpb kubernetes.io/service-account-token 3 85s
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
poddisruptionbudget.policy/istio-ingressgateway 1 N/A 0 106s
poddisruptionbudget.policy/istiod 1 N/A 0 2m3s
kwest get secret -n istio-system cacerts -o json # 미리 만들어둔 인증서/키 확인
# istio-ingressgateway 서비스 : NodePort 변경 및 nodeport 지정 변경 , externalTrafficPolicy 설정 (ClientIP 수집)
kwest patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "LoadBalancer", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
service/istio-ingressgateway patched
kwest patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kwest describe svc -n istio-system istio-ingressgateway
Name: istio-ingressgateway
Namespace: istio-system
Labels: app=istio-ingressgateway
install.operator.istio.io/owning-resource=istio-controlplane
install.operator.istio.io/owning-resource-namespace=istio-system
istio=ingressgateway
istio.io/rev=default
operator.istio.io/component=IngressGateways
operator.istio.io/managed=Reconcile
operator.istio.io/version=1.17.8
release=istio
Annotations: metallb.io/ip-allocated-from-pool: default
Selector: app=istio-ingressgateway,istio=ingressgateway
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.100.0.85
IPs: 10.100.0.85
LoadBalancer Ingress: 172.18.255.101
Port: status-port 15021/TCP
TargetPort: 15021/TCP
NodePort: status-port 32239/TCP
Endpoints: 10.10.0.9:15021
Port: http2 80/TCP
TargetPort: 8080/TCP
NodePort: http2 30000/TCP
Endpoints: 10.10.0.9:8080
Port: https 443/TCP
TargetPort: 8443/TCP
NodePort: https 30754/TCP
Endpoints: 10.10.0.9:8443
Port: tcp 31400/TCP
TargetPort: 31400/TCP
NodePort: tcp 32736/TCP
Endpoints: 10.10.0.9:31400
Port: tls 15443/TCP
TargetPort: 15443/TCP
NodePort: tls 32637/TCP
Endpoints: 10.10.0.9:15443
Session Affinity: None
External Traffic Policy: Local
Internal Traffic Policy: Cluster
HealthCheck NodePort: 30820
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal IPAllocated 3m21s metallb-controller Assigned IP ["172.18.255.101"]
Normal nodeAssigned 0s (x3 over 3m9s) metallb-speaker announcing from node "west-control-plane" with protocol "layer2"
Normal ExternalTrafficPolicy 0s service-controller Cluster -> Local
# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004)
kwest patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kwest patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kwest patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kwest 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 접속 : NodePort
open http://127.0.0.1:30003
# tracing 접속 : 예거 트레이싱 대시보드
open http://127.0.0.1:30004
# west-control-plane 진입 후 설치 진행
docker exec -it east-control-plane bash
-----------------------------------
# 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
# IstioOperator 파일 작성
cat << EOF > east-istio.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-controlplane
namespace: istio-system
spec:
profile: demo
components:
egressGateways:
- name: istio-egressgateway
enabled: false
values:
global:
meshID: usmesh
multiCluster:
clusterName: east-cluster
network: east-network
EOF
# 컨트롤 플레인 배포
istioctl install -f east-istio.yaml --set values.global.proxy.privileged=true -y
# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
# 빠져나오기
exit
-----------------------------------
# 설치 확인 : istiod, istio-ingressgateway, crd 등
keast get istiooperators -n istio-system -o yaml
...
meshID: usmesh
meshNetworks: {}
mountMtlsCerts: false
multiCluster:
clusterName: east-cluster
enabled: false
network: east-network
...
keast get all,svc,ep,sa,cm,secret,pdb -n istio-system
keast get secret -n istio-system cacerts -o json # 미리 만들어둔 인증서/키 확인
# NodePort 변경 및 nodeport 31001~31003으로 변경 : prometheus(31001), grafana(31002), kiali(31003), tracing(31004)
keast patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 31001}]}}'
keast patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 31002}]}}'
keast patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 31003}]}}'
keast patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 31004}]}}'
# Prometheus 접속 : envoy, istio 메트릭 확인
open http://127.0.0.1:31001
# Grafana 접속
open http://127.0.0.1:31002
# Kiali 접속
open http://127.0.0.1:31003
# tracing 접속 : 예거 트레이싱 대시보드
open http://127.0.0.1:31004
#
docker exec -it west-control-plane istioctl -h
docker exec -it east-control-plane istioctl -h
#
alias iwest='docker exec -it west-control-plane istioctl'
alias ieast='docker exec -it east-control-plane istioctl'
#
iwest proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-5db74c978c-wvn65.istio-system west-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-5585445f4c-7v25t 1.17.8
ieast proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-7f6f8f8d99-lgvfc.istio-system east-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-85976468f-sb2dc 1.17.8
#
iwest proxy-config secret deploy/istio-ingressgateway.istio-system
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 52818176540999573926987976529334739020 2025-05-25T01:40:03Z 2025-05-24T01:38:03Z
ROOTCA CA ACTIVE true 35459989146298323207776648461378299690 2035-05-22T00:52:38Z 2025-05-24T00:52:38Z
iwest proxy-config secret deploy/istio-ingressgateway.istio-system -o json
{
"dynamicActiveSecrets": [
{
"name": "default",
"lastUpdated": "2025-05-24T01:40:03.292Z",
"secret": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
"name": "default",
"tlsCertificate": {
"certificateChain": {
"inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURkakNDQWw2Z0F3SUJBZ0lRSjd4cE
... TFZOV0tsdTZWdm50RzdVMGFZRT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
},
"privateKey": {
"inlineBytes": "W3JlZGFjdGVkXQ=="
}
}
}
},
{
"name": "ROOTCA",
"lastUpdated": "2025-05-24T01:40:03.288Z",
"secret": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
"name": "ROOTCA",
"validationContext": {
"trustedCa": {
"inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lRR3ExWW
... BTlAKdXRMaExWTldLbHU2VnZudEc3VTBhWUU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0="
}
}
}
}
]
}
...
# 아래는 default 에 inlineBytes 값을 decode64 -d 시 3개의 인증서 정보 출력 후 각 개별 인증서를 openssl x509 -in Y.pem -noout -text 로 출력 확인
## (1) 사용자 인증서
-----BEGIN CERTIFICATE-----
MIIDdjCCAl6gAwIBAgIQPHLYaJhiIjAwJkg6cAVeWDANBgkqhkiG9w0BAQsFADAs
...
5xYNi7u0APTzE1swNbx2TF5eeTsFvYcbFh56ahLp0izGkahOv97bEgnZdeTsLRyH
K+5+1ZdJ2n8CuxoSY+FXUlMDwGjdvCXAKBM=
-----END CERTIFICATE-----
Issuer: CN=west.intermediate.istio.in.action
Validity
Not Before: May 16 08:45:28 2025 GMT
Not After : May 17 08:47:28 2025 GMT
Subject:
...
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Authority Key Identifier:
D3:83:9A:3A:51:D9:03:62:35:8F:6A:A4:DA:99:88:BB:74:70:4F:33
X509v3 Subject Alternative Name: critical
URI:spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account
## (2) 중간 CA 루트 인증서
-----BEGIN CERTIFICATE-----
MIIDPDCCAiSgAwIBAgIRAMkJ23sotpqiiWps+38Df/YwDQYJKoZIhvcNAQELBQAw
...
usSjiM6KR77xogslodbQw4QQG+w5HQOwMa1k8WTCNrplxdsnaQJjdqUwCdixicq2
DeHuSkz4cykAI/NWc2cZIw==
-----END CERTIFICATE-----
Issuer: CN=root.istio.in.action
Validity
Not Before: May 24 00:52:38 2025 GMT
Not After : May 22 00:52:38 2035 GMT
Subject: CN=west.intermediate.istio.in.action
...
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
## (3) 최상위 루트 인증서
-----BEGIN CERTIFICATE-----
MIIDDTCCAfWgAwIBAgIQS+jSffZX7itohjyrautczDANBgkqhkiG9w0BAQsFADAf
...
3fRtDApNHbbmi7WXrM+pG4D+Buk2FUEHJVpu16Ch2K2vpRzpkliqes+T/5E92uY9
ob7MBgt61g4VZ/p8+RMJWYw=
-----END CERTIFICATE-----
Issuer: CN=root.istio.in.action
Validity
Not Before: May 24 00:52:38 2025 GMT
Not After : May 22 00:52:38 2035 GMT
Subject: CN=root.istio.in.actionll
...
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
#
iwest proxy-config listener deploy/istio-ingressgateway.istio-system
ADDRESS PORT MATCH DESTINATION
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
iwest proxy-config route deploy/istio-ingressgateway.istio-system
NAME DOMAINS MATCH VIRTUAL SERVICE
* /healthz/ready*
* /stats/prometheus*
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.10.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.10.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.10.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.10.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.10.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.10.0.2:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.2:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.10.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.10.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.10.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.10.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.10.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.10.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.100.0.77:9411 HEALTHY OK zipkin
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.2:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
iwest proxy-config secret deploy/istio-ingressgateway.istio-system
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 52818176540999573926987976529334739020 2025-05-25T01:40:03Z 2025-05-24T01:38:03Z
ROOTCA CA ACTIVE true 35459989146298323207776648461378299690 2035-05-22T00:52:38Z 2025-05-24T00:52:38Z
iwest proxy-config bootstrap deploy/istio-ingressgateway.istio-system
❯ iwest proxy-config bootstrap deploy/istio-ingressgateway.istio-system
{
"bootstrap": {
"node": {
"id": "router~10.10.0.9~istio-ingressgateway-5db74c978c-wvn65.istio-system~istio-system.svc.cluster.local",
"cluster": "istio-ingressgateway.istio-system",
"metadata": {
"ANNOTATIONS": {
"kubernetes.io/config.seen": "2025-05-24T01:39:52.049902129Z",
"kubernetes.io/config.source": "api",
"prometheus.io/path": "/stats/prometheus",
"prometheus.io/port": "15020",
"prometheus.io/scrape": "true",
"sidecar.istio.io/inject": "false"
},
"CLUSTER_ID": "west-cluster",
"ENVOY_PROMETHEUS_PORT": 15090,
"ENVOY_STATUS_PORT": 15021,
"INSTANCE_IPS": "10.10.0.9",
"ISTIO_PROXY_SHA": "e1222b5645a29ad3d02b280797ac1219dd88cfbc",
"ISTIO_VERSION": "1.17.8",
"LABELS": {
"app": "istio-ingressgateway",
"chart": "gateways",
"heritage": "Tiller",
"install.operator.istio.io/owning-resource": "unknown",
"istio": "ingressgateway",
"istio.io/rev": "default",
"operator.istio.io/component": "IngressGateways",
"release": "istio",
"service.istio.io/canonical-name": "istio-ingressgateway",
"service.istio.io/canonical-revision": "latest",
"sidecar.istio.io/inject": "false"
},
"MESH_ID": "usmesh",
"NAME": "istio-ingressgateway-5db74c978c-wvn65",
"NAMESPACE": "istio-system",
"NETWORK": "west-network",
"NODE_NAME": "west-control-plane",
"OWNER": "kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway",
...
"bootstrapExtensions": [
{
"name": "envoy.bootstrap.internal_listener",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.extensions.bootstrap.internal_listener.v3.InternalListener"
}
}
]
},
"lastUpdated": "2025-05-24T01:40:03.197Z"
}
iwest proxy-config ecds deploy/istio-ingressgateway.istio-system
Error: config dump has no configuration type type.googleapis.com/envoy.admin.v3.EcdsConfigDump
#
ieast proxy-config listener deploy/istio-ingressgateway.istio-system
ieast proxy-config route deploy/istio-ingressgateway.istio-system
ieast proxy-config cluster deploy/istio-ingressgateway.istio-system
ieast proxy-config endpoint deploy/istio-ingressgateway.istio-system
ieast proxy-config secret deploy/istio-ingressgateway.istio-system
ieast proxy-config bootstrap deploy/istio-ingressgateway.istio-system
ieast proxy-config ecds deploy/istio-ingressgateway.istio-system

#
kwest create ns istioinaction
kwest label namespace istioinaction istio-injection=enabled
kwest -n istioinaction apply -f ch12/webapp-deployment-svc.yaml
kwest -n istioinaction apply -f ch12/webapp-gw-vs.yaml
kwest -n istioinaction apply -f ch12/catalog-svc.yaml # Stub catalog service to which webapp makes request
cat ch12/catalog-svc.yaml
piVersion: v1
kind: Service
metadata:
labels:
app: catalog
name: catalog
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 3000
selector:
app: catalog
# 확인
kwest get deploy,pod,svc,ep -n istioinaction
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/webapp 1/1 1 1 46s
NAME READY STATUS RESTARTS AGE
pod/webapp-5c8b4fff64-rk6v2 2/2 Running 0 46s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.0.123 <none> 80/TCP 30s
service/webapp ClusterIP 10.100.0.149 <none> 80/TCP 46s
NAME ENDPOINTS AGE
endpoints/catalog <none> 30s
endpoints/webapp 10.10.0.14:8080 46s
kwest get svc,ep catalog -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.0.123 <none> 80/TCP 45s
NAME ENDPOINTS AGE
endpoints/catalog <none> 45s
kwest get gw,vs,dr -A
NAMESPACE NAME AGE
istioinaction gateway.networking.istio.io/coolstore-gateway 72s
NAMESPACE NAME GATEWAYS HOSTS AGE
istioinaction virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 72s
#
iwest proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-5db74c978c-wvn65.istio-system west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-7v25t 1.17.8
webapp-5c8b4fff64-rk6v2.istioinaction west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-7v25t 1.17.8
# endpoint 에 IP 는 10.10.0.0/16 대역들 다수 확인
for i in listener route cluster endpoint; do echo ">> k8s cluster : west - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> k8s cluster : west - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL Route: http.8080
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> k8s cluster : west - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 webapp.istioinaction.io /* webapp-virtualservice.istioinaction
* /healthz/ready*
* /stats/prometheus*
>> k8s cluster : west - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
webapp.istioinaction.svc.cluster.local 80 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> k8s cluster : west - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.10.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.10.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.10.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.10.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.10.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.10.0.14:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
10.10.0.2:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.2:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.10.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.10.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.10.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.10.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.10.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.10.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.100.0.77:9411 HEALTHY OK zipkin
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.2:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system | grep catalog
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
🧩 Stub Service가 필요한 이유

⚠️ 문제:
✅ 해결:
📌 참고:
#
keast create ns istioinaction
keast label namespace istioinaction istio-injection=enabled
keast -n istioinaction apply -f ch12/catalog.yaml
cat ch12/catalog.yaml
# 확인
keast get deploy,pod,svc,ep -n istioinaction
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/catalog 1/1 1 1 16s
NAME READY STATUS RESTARTS AGE
pod/catalog-6cf4b97d-p8xbj 2/2 Running 0 16s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.200.0.93 <none> 80/TCP 16s
NAME ENDPOINTS AGE
endpoints/catalog 10.20.0.14:3000 16s
keast get svc,ep catalog -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.200.0.93 <none> 80/TCP 32s
NAME ENDPOINTS AGE
endpoints/catalog 10.20.0.14:3000 32s
keast get gw,vs,dr -A # 없음
#
ieast proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
catalog-6cf4b97d-p8xbj.istioinaction east-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-85976468f-sb2dc 1.17.8
istio-ingressgateway-7f6f8f8d99-lgvfc.istio-system east-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-85976468f-sb2dc 1.17.8
# endpoint 에 IP 는 10.20.0.0/16 대역들 다수 확인
for i in listener route cluster endpoint; do echo ">> k8s cluster : east - istio-config $i <<"; docker exec -it east-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> k8s cluster : east - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> k8s cluster : east - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
* /stats/prometheus*
* /healthz/ready*
>> k8s cluster : east - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> k8s cluster : east - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.20.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.20.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.20.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.20.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.20.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.20.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
10.20.0.3:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.20.0.3:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.20.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.20.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.20.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.20.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.20.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.20.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.20.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.20.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.20.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.200.0.206:9411 HEALTHY OK zipkin
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.3:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
ieast proxy-config cluster deploy/istio-ingressgateway.istio-system | grep catalog
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
ieast proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
클러스터 2개를 각자 연결해야 하는 워크로드가 있는 지금을 시작점이라고 해보자. 그러나 클러스터 간 워크로드 디스커버리 없이는 사이드카 프록시에 반대 클러스터의 워크로드가 설정되지 않는다. 그러므로 다음 단계는 클러스터 간 디스커버리를 활성화해보자.
📌 Istio는 원격 클러스터의 정보를 조회하려면 인증이 필요하므로, 설치 시 최소 권한의 istio-reader-service-account를 생성한다. 이 계정은 다른 컨트롤 플레인이 워크로드 정보(서비스, 엔드포인트 등)를 쿼리할 수 있게 하며, 이를 위해 서비스 어카운트 토큰과 인증서를 원격 클러스터에서 사용할 수 있도록 공유해야 한다.
🔐 원격 클러스터 접근용 시크릿 만들기
istioctl 에는 create-remote-secret 명령어가 있는데, 기본 istio-reader-service-account 서비스 어카운트를 사용해 원격 클러스터 접근용으로 시크릿을 만드는 것이다.IstioOperator 에서 사용한 클러스터 이름을 지정하는 것이 중요하다(east-cluster 및 west-cluster 값은 앞서 ‘IstioOperator 리소스를 사용해 컨트롤 플레인 설치하기’ 절 참조).✅ 원격 클러스터에 접근하기 위한 설정의 식별자로 클러스터 이름이 어떻게 사용되는지에는 주의를 기울이자
#
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get sa -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME SECRETS AGE
default 1 119m
grafana 1 77m
istio-ingressgateway-service-account 1 78m
istio-reader-service-account 1 78m
istiod 1 78m
istiod-service-account 1 78m
kiali 1 77m
prometheus 1 77m
>> k8s cluster : east <<
NAME SECRETS AGE
default 1 119m
grafana 1 69m
istio-ingressgateway-service-account 1 69m
istio-reader-service-account 1 69m
istiod 1 69m
istiod-service-account 1 69m
kiali 1 69m
prometheus 1 69m
# east
keast describe sa -n istio-system istio-reader-service-account
...
Mountable secrets: istio-reader-service-account-token-r28c8
Tokens: istio-reader-service-account-token-r28c8
keast get sa -n istio-system istio-reader-service-account -o yaml
...
name: istio-reader-service-account
namespace: istio-system
resourceVersion: "10629"
uid: cd6ce452-c5cb-42bf-98fd-6a4dc79964a4
secrets:
- name: istio-reader-service-account-token-r28c8
keast get sa -n istio-system istio-reader-service-account -o jsonpath='{.secrets[0].name}'
istio-reader-service-account-token-r28c8
eirsa=$(keast get sa -n istio-system istio-reader-service-account -o jsonpath='{.secrets[0].name}')
keast get secret -n istio-system $eirsa
NAME TYPE DATA AGE
istio-reader-service-account-token-r28c8 kubernetes.io/service-account-token 3 72m
keast get secret -n istio-system $eirsa -o json
{
"apiVersion": "v1",
"data": {
"ca.crt": "LS0t,,,==",
"namespace": "aXN0aW8tc3lzdGVt", # istio-system
"token": "ZXl...TmREdw=="
},
...
kubectl rolesum istio-reader-service-account -n istio-system --kubeconfig=./east-kubeconfig
ServiceAccount: istio-system/istio-reader-service-account
Secrets:
• */istio-reader-service-account-token-r28c8
Policies:
• [CRB] */istio-reader-clusterrole-istio-system ⟶ [CR] */istio-reader-clusterrole-istio-system
Resource Name Exclude Verbs G L W C U P D DC
*.[config.istio.io,security.istio.io,networking.istio.io,authentication.istio.io,rbac.istio.io] [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
customresourcedefinitions.apiextensions.k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
endpoints [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
endpointslices.discovery.k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
namespaces [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
nodes [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
pods [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
replicasets.apps [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
replicationcontrollers [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
secrets [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
serviceexports.multicluster.x-k8s.io [*] [-] [-] ✔ ✔ ✔ ✔ ✖ ✖ ✔ ✖
serviceimports.multicluster.x-k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
services [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
subjectaccessreviews.authorization.k8s.io [*] [-] [-] ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
tokenreviews.authentication.k8s.io [*] [-] [-] ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
workloadentries.networking.istio.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
• [CRB] */istio-reader-istio-system ⟶ [CR] */istio-reader-istio-system
Resource Name Exclude Verbs G L W C U P D DC
*.[config.istio.io,security.istio.io,networking.istio.io,authentication.istio.io,rbac.istio.io] [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
customresourcedefinitions.apiextensions.k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
endpoints [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
endpointslices.discovery.k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
namespaces [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
nodes [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
pods [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
replicasets.apps [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
replicationcontrollers [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
secrets [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
serviceexports.multicluster.x-k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
serviceimports.multicluster.x-k8s.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
services [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
subjectaccessreviews.authorization.k8s.io [*] [-] [-] ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
tokenreviews.authentication.k8s.io [*] [-] [-] ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
workloadentries.networking.istio.io [*] [-] [-] ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
keast auth can-i --list
Resources Non-Resource URLs Resource Names Verbs
*.* [] [] [*]
[*] [] [*]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/livez] [] [get]
[/livez] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/readyz] [] [get]
[/readyz] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
keast auth can-i --as=system:serviceaccount:istio-system:istio-reader-service-account --list
Resources Non-Resource URLs Resource Names Verbs
tokenreviews.authentication.k8s.io [] [] [create]
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
subjectaccessreviews.authorization.k8s.io [] [] [create]
serviceexports.multicluster.x-k8s.io [] [] [get list watch create delete]
endpoints [] [] [get list watch]
namespaces [] [] [get list watch]
nodes [] [] [get list watch]
pods [] [] [get list watch]
replicationcontrollers [] [] [get list watch]
secrets [] [] [get list watch]
services [] [] [get list watch]
customresourcedefinitions.apiextensions.k8s.io [] [] [get list watch]
replicasets.apps [] [] [get list watch]
*.authentication.istio.io [] [] [get list watch]
*.config.istio.io [] [] [get list watch]
endpointslices.discovery.k8s.io [] [] [get list watch]
serviceimports.multicluster.x-k8s.io [] [] [get list watch]
*.networking.istio.io [] [] [get list watch]
*.rbac.istio.io [] [] [get list watch]
*.security.istio.io [] [] [get list watch]
workloadentries.networking.istio.io [] [] [get watch list]
[/.well-known/openid-configuration] [] [get]
[/api/*] [] [get]
[/api] [] [get]
[/apis/*] [] [get]
[/apis] [] [get]
[/healthz] [] [get]
[/healthz] [] [get]
[/livez] [] [get]
[/livez] [] [get]
[/openapi/*] [] [get]
[/openapi] [] [get]
[/openid/v1/jwks] [] [get]
[/readyz] [] [get]
[/readyz] [] [get]
[/version/] [] [get]
[/version/] [] [get]
[/version] [] [get]
[/version] [] [get]
#
ieast x create-remote-secret --help
Create a secret with credentials to allow Istio to access remote Kubernetes apiservers
ieast x create-remote-secret --name="east-cluster"
# This file is autogenerated, do not edit.
apiVersion: v1
kind: Secret
metadata:
annotations:
networking.istio.io/cluster: east-cluster
creationTimestamp: null
labels:
istio/multiCluster: "true" # 이 레이블이 true로 설정된 시크릿은 이스티오의 컨트롤 플레인이 새 클러스터를 등록하기 위해 감시한다
name: istio-remote-secret-east-cluster
namespace: istio-system
stringData:
east-cluster: |
apiVersion: v1
clusters:
- cluster: # 아래 'certificate-authority-data'는 이 클러스터에 보안 커넥션을 시작하는 데 사용하는 CA
certificate-authority-data: LS0tLS1CR....
server: https://east-control-plane:6443
name: east-cluster
contexts:
- context:
cluster: east-cluster
user: east-cluster
name: east-cluster
current-context: east-cluster
kind: Config
preferences: {}
users:
- name: east-cluster
user: # 아래 'token'은 서비스 어카운트의 ID를 나타내는 토큰
token: eyJhb...
---
## certificate-authority-data 정보 : k8s 루트 인증서
openssl x509 -in YYY -noout -text
...
Issuer: CN=kubernetes
Validity
Not Before: May 16 05:13:20 2025 GMT
Not After : May 14 05:13:20 2035 GMT
Subject: CN=kubernetes
...
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Certificate Sign
X509v3 Basic Constraints: critical
CA:TRUE
## user.token 정보 :
jwt decode YYY
Token header
------------
{
"alg": "RS256",
"kid": "4BqK2FN-Bxz_3Q1mMc7IW3HZoH8dz1Z2svNfoJDwvl4"
}
Token claims
------------
{
"iss": "kubernetes/serviceaccount",
"kubernetes.io/serviceaccount/namespace": "istio-system",
"kubernetes.io/serviceaccount/secret.name": "istio-reader-service-account-token-r28c8",
"kubernetes.io/serviceaccount/service-account.name": "istio-reader-service-account",
"kubernetes.io/serviceaccount/service-account.uid": "cd6ce452-c5cb-42bf-98fd-6a4dc79964a4",
"sub": "system:serviceaccount:istio-system:istio-reader-service-account"
}
✅ 시크릿 내용을 출력하는 대신, kubectl 명령어에 파이프해 west-cluster 에 적용하자
# west 에 시크릿 생성
ieast x create-remote-secret --name="east-cluster" | kwest apply -f -
secret/istio-remote-secret-east-cluster created
# istiod 로그 확인 : 시크릿이 생성되면, 바로 istiod가 이 시크릿을 가지고 새로 추가된 원격 클러스터(east)에 워크로드를 쿼리한다.
kwest logs deploy/istiod -n istio-system | grep 'Adding cluster'
2025-05-24T03:09:45.516282Z info Adding cluster cluster=east-cluster secret=istio-system/istio-remote-secret-east-cluster
#
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get secret -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME TYPE DATA AGE
cacerts Opaque 4 132m
default-token-ndvmn kubernetes.io/service-account-token 3 132m
grafana-token-8zzsv kubernetes.io/service-account-token 3 90m
istio-ingressgateway-service-account-token-hl5px kubernetes.io/service-account-token 3 91m
istio-reader-service-account-token-mjw94 kubernetes.io/service-account-token 3 91m
istio-remote-secret-east-cluster Opaque 1 77s
istiod-service-account-token-f6482 kubernetes.io/service-account-token 3 91m
istiod-token-4qrrt kubernetes.io/service-account-token 3 91m
kiali-token-r7vvb kubernetes.io/service-account-token 3 90m
prometheus-token-5rhpb kubernetes.io/service-account-token 3 90m
>> k8s cluster : east <<
NAME TYPE DATA AGE
cacerts Opaque 4 131m
default-token-s7stk kubernetes.io/service-account-token 3 131m
grafana-token-2gn8t kubernetes.io/service-account-token 3 82m
istio-ingressgateway-service-account-token-vppcz kubernetes.io/service-account-token 3 82m
istio-reader-service-account-token-r28c8 kubernetes.io/service-account-token 3 82m
istiod-service-account-token-8h9sz kubernetes.io/service-account-token 3 82m
istiod-token-srt76 kubernetes.io/service-account-token 3 82m
kiali-token-xgkkw kubernetes.io/service-account-token 3 82m
prometheus-token-x8m62 kubernetes.io/service-account-token 3 82m
kwest get secret -n istio-system istio-remote-secret-east-cluster
NAME TYPE DATA AGE
istio-remote-secret-east-cluster Opaque 1 110s
kwest get secret -n istio-system istio-remote-secret-east-cluster -o yaml
apiVersion: v1
data:
east-cluster: YXBpVmVyc2lvbjogdjEKY2x1c3RlcnM6Ci0gY2x1c3RlcjoKICAgIGNlcnRpZmljYXRlLWF
...
UzZwZnllVDAtdVBfaXQzOUZBTjdOQnFOZER3Cg==
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{"networking.istio.io/cluster":"east-cluster"},"creationTimestamp":null,"labels":{"istio/multiCluster":"true"},"name":"istio-remote-secret-east-cluster","namespace":"istio-system"},"stringData":{"east-cluster":"apiVersion: v1\nclusters:\n- cluster:\n certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJ
...
SEgKTGFzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n server: https://east-control-plane:6443\n name: east-cluster\ncontexts:\n- context:\n cluster: east-cluster\n user: east-cluster\n name: east-cluster\ncurrent-context: east-cluster\nkind: Config\npreferences: {}\nusers:\n- name: east-cluster\n user:\n token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjRCcUsyRk4tQnh6XzNRMW1NYzdJVzNIWm9IOGR6MVo
...
mp4kJu3trYClJziJALR0msQOLRD2H5mDYb6TtMoau2ZSCF1y9kKJouqoUb4I940oxAhwIkOsMd-S6pfyeT0-uP_it39FAN7NBqNdDw\n"}}
networking.istio.io/cluster: east-cluster
creationTimestamp: "2025-05-24T03:09:45Z"
labels:
istio/multiCluster: "true"
name: istio-remote-secret-east-cluster
namespace: istio-system
resourceVersion: "20443"
uid: 85edcfa5-cc6b-4116-a8e0-6f648071757b
type: Opaque
...
# west 확인 : east 의 모든 CDS/EDS 정보를 west 에서도 확인 가능!
for i in listener route cluster endpoint; do echo ">> k8s cluster : west - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> k8s cluster : west - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL Route: http.8080
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> k8s cluster : west - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 webapp.istioinaction.io /* webapp-virtualservice.istioinaction
* /healthz/ready*
* /stats/prometheus*
>> k8s cluster : west - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
webapp.istioinaction.svc.cluster.local 80 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> k8s cluster : west - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.10.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.10.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.10.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.10.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.10.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.10.0.14:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
10.10.0.2:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.2:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.10.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.10.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.10.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.10.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.10.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.10.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.100.0.77:9411 HEALTHY OK zipkin
10.20.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.20.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.20.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.20.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.20.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.20.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
10.20.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.20.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.2:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system | grep catalog
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local -o json
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
# west 에서 10.20.0.14(10.20.0.0/16)로 라우팅이 가능한 상태인가?
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||catalog.istioinaction.svc.cluster.local' -o json
...
"address": {
"socketAddress": {
"address": "10.20.0.14",
"portValue": 3000
...
# east 확인 : west 의 CDS/EDS 정보를 아직 모름!
for i in listener route cluster endpoint; do echo ">> k8s cluster : east - istio-config $i <<"; docker exec -it east-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
ieast proxy-config cluster deploy/istio-ingressgateway.istio-system | grep catalog
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
ieast proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
✅ 이제 컨트롤 플레인이 상대 클러스터의 워크로드를 퀴리할 수 있다.
# catalog stub service 정보 확인 : endpoints 는 아직도 none.
kwest get svc,ep -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.0.123 <none> 80/TCP 53m
service/webapp ClusterIP 10.100.0.149 <none> 80/TCP 53m
NAME ENDPOINTS AGE
endpoints/catalog <none> 53m
endpoints/webapp 10.10.0.14:8080 53m
# webapp stub service 생성하지 않았으므로 별도 west 의 webapp service 정보가 없다
keast get svc,ep -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.200.0.93 <none> 80/TCP 45m
NAME ENDPOINTS AGE
endpoints/catalog 10.20.0.14:3000 45m
✅ 다음으로는 클러스터 간 연결을 설정해보자.
💁🏻♀️ 들어가며 : north-south 트래픽, east-west 트래픽
이스티오에서 트래픽은 크게 두 가지로 나뉩니다:
North-South 트래픽: 퍼블릭 인터넷 등 외부 네트워크에서 내부 클러스터로 들어오는 트래픽입니다. 이 트래픽은 인그레스 게이트웨이(Envoy 프록시 기반)를 통해 수신되어 조직의 내부 서비스로 전달됩니다.
East-West 트래픽: 클러스터 간, 또는 내부 네트워크 간에 오가는 트래픽입니다. 예: us-west 리전의 클러스터에서 us-east 리전의 클러스터로 요청을 보내는 경우.
대부분의 클라우드 제공업체는 가상 네트워크 피어링 기능을 통해 east-west 트래픽을 단순화합니다. 이때 조건은 네트워크 주소 공간이 겹치지 않아야 하며, 클러스터 간에는 직접 IP 통신이 가능합니다.
하지만 이 방법은 클라우드 내부 전용이므로,
이 경우, 이스티오는 east-west 게이트웨이를 통해 해결책을 제공합니다.
이 게이트웨이는:
즉, east-west 게이트웨이는 서로 다른 네트워크에 위치한 클러스터 간의 트래픽을 보안된 방식으로 전달하는 역할을 하며, 다음 절에서는 이를 어떻게 설정하고 내부적으로 작동하는지 다룰 예정입니다.
이스티오의 east-west 게이트웨이는 단순한 클러스터 간 트래픽의 진입점 역할을 넘어, 서비스 운영팀에게 투명한 방식으로 작동하도록 설계되었습니다. 이 목표를 위해 게이트웨이는 다음 기능을 반드시 수행해야 합니다:
이러한 설정 덕분에:
이러한 자동화와 투명성이 어떻게 가능해지는지는 SNI clusters와 SNI auto passthrough라는 두 가지 이스티오 기능을 통해 설명됩니다.
📌 east-west 게이트웨이는 모든 서비스에 대해 SNI 클러스터 구성이 추가된 인그레스 게이트웨이입니다. 여기서 핵심은 SNI 클러스터인데, 이는 일반적인 Envoy 클러스터와 비슷하지만 다음과 같은 중요한 차이가 있습니다:
✅ SNI 클러스터란?
✅ east-west 게이트웨이의 역할
🎯 결과적으로 SNI 클러스터 덕분에, Istio는 클러스터 간의 서비스 호출을 안전하고 정밀하게 처리할 수 있게 됩니다.
✅ SNI 클러스터 설정은 옵트인 기능으로, 다음 IstioOpertor 정의처럼 환경 변수 ISTIO_META_ROUTER_MODE 로 게이트웨이 라우터 모드를 sni-dnat 으로 설정해서 활성화할 수 있다.
# cat ch12/gateways/cluster-east-eastwest-gateway.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-eastwestgateway # IstioOperator 이름은 앞 선 이스티오 설정 이름과 겹치지 않아야 한다
namespace: istio-system
spec:
profile: empty # empty 프로필은 추가 이스티오 구성 요소를 설치하지 않는다
components:
ingressGateways:
- name: istio-eastwestgateway # 게이트웨이 이름
label:
istio: eastwestgateway
app: istio-eastwestgateway
topology.istio.io/network: east-network
enabled: true
k8s:
env:
- name: ISTIO_META_ROUTER_MODE # sni-dnat 모드는 트래픽을 프록시하는 데 필요한 SNI 클러스터를 추가한다
value: "sni-dnat"
# The network to which traffic is routed
- name: ISTIO_META_REQUESTED_NETWORK_VIEW # 게이트웨이가 트래픽을 라우팅하는 네트워크
value: east-network
service:
ports:
... (생략) ...
values:
global:
meshID: usmesh # 메시, 클러스터, 네트워크 식별 정보
multiCluster:
clusterName: east-cluster
network: east-network
ISTIO_META_ROUTER_MODE 를 sni-dnat 으로 설정하면 SNI 클러스터를 자동으로 구성한다. 지정하지 않으면 standard 모드로 돌아가며, 이는 SNI 클러스터를 설정하지 않는다.ISTIO_META_REQUESTED_NETWORK_VIEW 는 네트워크 트래픽이 프록시되는 곳을 정의한다.✅ IstioOperator 로 east 클러스터에 east-west 게이트웨이를 설치하자.
# 설치 전 확인
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get pod -n istio-system -l istio.io/rev=default --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-5db74c978c-wvn65 1/1 Running 0 122m
istiod-5585445f4c-7v25t 1/1 Running 0 122m
>> k8s cluster : east <<
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-7f6f8f8d99-lgvfc 1/1 Running 0 113m
istiod-85976468f-sb2dc 1/1 Running 0 113m
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get IstioOperator -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME REVISION STATUS AGE
installed-state-istio-controlplane 122m
>> k8s cluster : east <<
NAME REVISION STATUS AGE
installed-state-istio-controlplane 113m
kwest get IstioOperator -n istio-system installed-state-istio-controlplane -o yaml
keast get IstioOperator -n istio-system installed-state-istio-controlplane -o yaml
# 설치 전 확인 : west 에서 catalog endpoint 에 IP 확인
for i in listener route cluster endpoint; do echo ">> k8s cluster : west - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> k8s cluster : west - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL Route: http.8080
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> k8s cluster : west - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 webapp.istioinaction.io /* webapp-virtualservice.istioinaction
* /healthz/ready*
* /stats/prometheus*
>> k8s cluster : west - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
webapp.istioinaction.svc.cluster.local 80 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> k8s cluster : west - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.10.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.10.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.10.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.10.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.10.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.10.0.14:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
10.10.0.2:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.2:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.10.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.10.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.10.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.10.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.10.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.10.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.100.0.77:9411 HEALTHY OK zipkin
10.20.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.20.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.20.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.20.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.20.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.20.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
10.20.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.20.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.2:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
# IstioOperator 로 east 클러스터에 east-west 게이트웨이를 설치
cat ch12/gateways/cluster-east-eastwest-gateway.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: istio-eastwestgateway
namespace: istio-system
spec:
meshConfig:
accessLogFile: /dev/stdout
profile: empty
components:
ingressGateways:
- name: istio-eastwestgateway
label:
istio: eastwestgateway
app: istio-eastwestgateway
topology.istio.io/network: east-network
enabled: true
k8s:
env:
- name: ISTIO_META_ROUTER_MODE
value: "sni-dnat"
# The network to which traffic is routed
- name: ISTIO_META_REQUESTED_NETWORK_VIEW
value: east-network
service:
ports:
- name: status-port
port: 15021
targetPort: 15021
- name: mtls
port: 15443
targetPort: 15443
- name: tcp-istiod
port: 15012
targetPort: 15012
- name: tcp-webhook
port: 15017
targetPort: 15017
values:
global:
meshID: usmesh
multiCluster:
clusterName: east-cluster
network: east-network
docker cp ./ch12/gateways/cluster-east-eastwest-gateway.yaml east-control-plane:/cluster-east-eastwest-gateway.yaml
ieast install -f /cluster-east-eastwest-gateway.yaml --set values.global.proxy.privileged=true -y
✔ Ingress gateways installed ✔ Installation complete
# east 클러스터에 east-west 게이트웨이를 설치 확인
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get IstioOperator -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME REVISION STATUS AGE
installed-state-istio-controlplane 126m
>> k8s cluster : east <<
NAME REVISION STATUS AGE
installed-state-istio-controlplane 117m
installed-state-istio-eastwestgateway 33s
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get pod -n istio-system -l istio.io/rev=default --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-5db74c978c-wvn65 1/1 Running 0 126m
istiod-5585445f4c-7v25t 1/1 Running 0 127m
>> k8s cluster : east <<
NAME READY STATUS RESTARTS AGE
istio-eastwestgateway-866794c798-nr29l 1/1 Running 0 58s
istio-ingressgateway-7f6f8f8d99-lgvfc 1/1 Running 0 118m
istiod-85976468f-sb2dc 1/1 Running 0 118m
keast get IstioOperator -n istio-system installed-state-istio-eastwestgateway -o yaml
...
ingressGateways:
- enabled: true
k8s:
env:
- name: ISTIO_META_ROUTER_MODE
value: sni-dnat
- name: ISTIO_META_REQUESTED_NETWORK_VIEW
value: east-network
service:
ports:
- name: status-port
port: 15021
targetPort: 15021
- name: mtls
port: 15443
targetPort: 15443
- name: tcp-istiod
port: 15012
targetPort: 15012
- name: tcp-webhook
port: 15017
targetPort: 15017
label:
app: istio-eastwestgateway
istio: eastwestgateway
topology.istio.io/network: east-network
name: istio-eastwestgateway
...
# east 정보 확인
ieast proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
catalog-6cf4b97d-p8xbj.istioinaction east-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-85976468f-sb2dc 1.17.8
istio-eastwestgateway-866794c798-nr29l.istio-system east-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-85976468f-sb2dc 1.17.8
istio-ingressgateway-7f6f8f8d99-lgvfc.istio-system east-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-85976468f-sb2dc 1.17.8
# east 에 istio-ingressgateway 에 istio-config 정보 확인 : west 의 CDS/EDS 모두 알고 있음!
for i in listener route cluster endpoint; do echo ">> east k8s cluster : ingressgateway - istio-config $i <<"; docker exec -it east-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> east k8s cluster : ingressgateway - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> east k8s cluster : ingressgateway - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
* /stats/prometheus*
* /healthz/ready*
>> east k8s cluster : ingressgateway - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15012 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15017 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> east k8s cluster : ingressgateway - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.20.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.20.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.20.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.20.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.20.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.20.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
10.20.0.15:15012 HEALTHY OK outbound|15012||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.15:15017 HEALTHY OK outbound|15017||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.15:15021 HEALTHY OK outbound|15021||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.15:15443 HEALTHY OK outbound|15443||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.3:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.20.0.3:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.20.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.20.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.20.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.20.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.20.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.20.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.20.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.20.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.20.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.200.0.206:9411 HEALTHY OK zipkin
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.3:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
# east 에 istio-eastwestgateway 에 istio-config 정보 확인 : webapp(CDS) OK, west 에 EDS 아직 모름!
for i in listener route cluster endpoint; do echo ">> east k8s cluster : eastwestgateway - istio-config $i <<"; docker exec -it east-control-plane istioctl proxy-config $i deploy/istio-eastwestgateway.istio-system; echo; done
>> east k8s cluster : eastwestgateway - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> east k8s cluster : eastwestgateway - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
* /healthz/ready*
* /stats/prometheus*
>> east k8s cluster : eastwestgateway - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15012 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15017 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> east k8s cluster : eastwestgateway - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.20.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.20.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.20.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.20.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.20.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.20.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.20.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.20.0.14:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
10.20.0.15:15012 HEALTHY OK outbound|15012||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.15:15017 HEALTHY OK outbound|15017||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.15:15021 HEALTHY OK outbound|15021||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.15:15443 HEALTHY OK outbound|15443||istio-eastwestgateway.istio-system.svc.cluster.local
10.20.0.3:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.20.0.3:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.20.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.20.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.20.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.20.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.20.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.20.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.20.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.20.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.20.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.20.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.200.0.206:9411 HEALTHY OK zipkin
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.3:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
ieast proxy-config cluster deploy/istio-eastwestgateway.istio-system | grep istioinaction
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
ieast proxy-config cluster deploy/istio-eastwestgateway.istio-system --fqdn webapp.istioinaction.svc.cluster.local -o json
ieast proxy-config cluster deploy/istio-eastwestgateway.istio-system --fqdn webapp.istioinaction.svc.cluster.local -o json | grep sni
"sni": "outbound_.80_._.webapp.istioinaction.svc.cluster.local"
ieast proxy-config endpoint deploy/istio-eastwestgateway.istio-system | grep istioinaction
ieast proxy-config endpoint deploy/istio-eastwestgateway.istio-system --cluster 'outbound|80||catalog.istioinaction.svc.cluster.local' -o json
# west 정보 확인
iwest proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-5db74c978c-wvn65.istio-system west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-7v25t 1.17.8
webapp-5c8b4fff64-rk6v2.istioinaction west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-7v25t 1.17.8
# west 에 istio-ingressgateway 에 istio-config 정보 확인
for i in listener route cluster endpoint; do echo ">> west k8s cluster : ingressgateway - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> west k8s cluster : ingressgateway - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL Route: http.8080
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
>> west k8s cluster : ingressgateway - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 webapp.istioinaction.io /* webapp-virtualservice.istioinaction
* /healthz/ready*
* /stats/prometheus*
>> west k8s cluster : ingressgateway - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
BlackHoleCluster - - - STATIC
agent - - - STATIC
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
grafana.istio-system.svc.cluster.local 3000 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15012 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15017 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-eastwestgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 15443 - outbound EDS
istio-ingressgateway.istio-system.svc.cluster.local 31400 - outbound EDS
istiod.istio-system.svc.cluster.local 443 - outbound EDS
istiod.istio-system.svc.cluster.local 15010 - outbound EDS
istiod.istio-system.svc.cluster.local 15012 - outbound EDS
istiod.istio-system.svc.cluster.local 15014 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 9411 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14250 - outbound EDS
jaeger-collector.istio-system.svc.cluster.local 14268 - outbound EDS
kiali.istio-system.svc.cluster.local 9090 - outbound EDS
kiali.istio-system.svc.cluster.local 20001 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
kube-ops-view.kube-system.svc.cluster.local 8080 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
metallb-webhook-service.metallb-system.svc.cluster.local 443 - outbound EDS
prometheus.istio-system.svc.cluster.local 9090 - outbound EDS
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
tracing.istio-system.svc.cluster.local 80 - outbound EDS
tracing.istio-system.svc.cluster.local 16685 - outbound EDS
webapp.istioinaction.svc.cluster.local 80 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
zipkin.istio-system.svc.cluster.local 9411 - outbound EDS
>> west k8s cluster : ingressgateway - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.10:3000 HEALTHY OK outbound|3000||grafana.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:9411 HEALTHY OK outbound|9411||zipkin.istio-system.svc.cluster.local
10.10.0.11:14250 HEALTHY OK outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:14268 HEALTHY OK outbound|14268||jaeger-collector.istio-system.svc.cluster.local
10.10.0.11:16685 HEALTHY OK outbound|16685||tracing.istio-system.svc.cluster.local
10.10.0.11:16686 HEALTHY OK outbound|80||tracing.istio-system.svc.cluster.local
10.10.0.12:9090 HEALTHY OK outbound|9090||kiali.istio-system.svc.cluster.local
10.10.0.12:20001 HEALTHY OK outbound|20001||kiali.istio-system.svc.cluster.local
10.10.0.13:9090 HEALTHY OK outbound|9090||prometheus.istio-system.svc.cluster.local
10.10.0.14:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
10.10.0.2:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.2:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.4:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.10.0.4:9153 HEALTHY OK outbound|9153||kube-dns.kube-system.svc.cluster.local
10.10.0.5:8080 HEALTHY OK outbound|8080||kube-ops-view.kube-system.svc.cluster.local
10.10.0.6:9443 HEALTHY OK outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.10.0.8:15010 HEALTHY OK outbound|15010||istiod.istio-system.svc.cluster.local
10.10.0.8:15012 HEALTHY OK outbound|15012||istiod.istio-system.svc.cluster.local
10.10.0.8:15014 HEALTHY OK outbound|15014||istiod.istio-system.svc.cluster.local
10.10.0.8:15017 HEALTHY OK outbound|443||istiod.istio-system.svc.cluster.local
10.10.0.9:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:8443 HEALTHY OK outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15021 HEALTHY OK outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:15443 HEALTHY OK outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.10.0.9:31400 HEALTHY OK outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
10.100.0.77:9411 HEALTHY OK zipkin
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
172.18.0.2:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system | grep istioinaction
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
webapp.istioinaction.svc.cluster.local 80 - outbound EDS
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local -o json
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn catalog.istioinaction.svc.cluster.local -o json | grep sni
"sni": "outbound_.80_._.catalog.istioinaction.svc.cluster.local"
# west 에 istio-ingressgateway : east EDS 모든 정보에서 east의 eastwestgateway에 mtls 정보로 변경!
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep istioinaction
10.10.0.14:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
# 출력되는 172.18.X.Y에 IP 확인 : east 에 eastwestgateway 의 Service(LoadBalancer)의 External-IP.
keast get svc,ep -n istio-system istio-eastwestgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/istio-eastwestgateway LoadBalancer 10.200.0.139 172.18.255.202 15021:30532/TCP,15443:30060/TCP,15012:30003/TCP,15017:31492/TCP 10m
NAME ENDPOINTS AGE
endpoints/istio-eastwestgateway 10.20.0.15:15021,10.20.0.15:15017,10.20.0.15:15012 + 1 more... 10m
# west 에 webapp 에 istio-config 정보 확인
for i in listener route cluster endpoint; do echo ">> west k8s cluster : webapp - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/webapp.istioinaction; echo; done
iwest proxy-config endpoint deploy/webapp.istioinaction | grep istioinaction
10.10.0.14:8080 HEALTHY OK outbound|80||webapp.istioinaction.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
# west 에서 호출 시도
kwest get svc,ep -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.0.123 <none> 80/TCP 91m
service/webapp ClusterIP 10.100.0.149 <none> 80/TCP 92m
NAME ENDPOINTS AGE
endpoints/catalog <none> 91m
endpoints/webapp 10.10.0.14:8080 92m
kwest exec -it deploy/webapp -c istio-proxy -n istioinaction -- curl catalog.istioinaction.svc.cluster.local -v
* Trying 10.100.0.123:80...
* connect to 10.100.0.123 port 80 failed: Connection refused
* Failed to connect to catalog.istioinaction.svc.cluster.local port 80 after 3 ms: Connection refused
* Closing connection 0
curl: (7) Failed to connect to catalog.istioinaction.svc.cluster.local port 80 after 3 ms: Connection refused
command terminated with exit code 7
✅ 문제: 수동 SNI 통과의 한계

✅ 해결책: SNI 자동 통과
sni-dnat**일 때 자동 적용됩니다.
✅ 구성 방법
*.local과 매칭되는 모든 SNI 트래픽에 자동 통과를 적용하면 모든 쿠버네티스 서비스가 자동 대상이 됩니다.✅ SNI 자동 통과는 이스티오 Gateway 리소스로 설정할 수 있다. 다음 정의에서는 SNI 헤더의 값이 *.local 인 모든 트래픽에 대해 SNI 자동 통과를 사용한는데, 이는 모든 쿠버네티스 서비스에 해당한다.
# cat ch12/gateways/expose-services.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: cross-network-gateway
namespace: istio-system
spec:
selector:
istio: eastwestgateway # 셀렉터와 일치하는 게이트웨이에만 설정이 적용된다.
servers:
- port:
number: 15443 # 이스티오에서 15443 포트는 멀티 클러스터 상호 TLS 트래픽 용도로 지정된 특수 포트다
name: tls
protocol: TLS
tls:
mode: AUTO_PASSTHROUGH # SNI 헤더를 사용해 목적지를 해석하고 SNI 클러스터를 사용한다.
hosts:
- "*.local" # 정규식 *.local 과 일치하는 SNI에 대해서만 트래픽을 허용한다.
✅ east 클러스터에 적용 시, east-cluster의 워크로드를 west-cluster 에 노출한다.
# east 클러스터에 적용하자. east-cluster의 워크로드를 west-cluster 에 노출한다.
cat ch12/gateways/expose-services.yaml
keast apply -n istio-system -f ch12/gateways/expose-services.yaml
# 확인
keast get gw,vs,dr -A
NAMESPACE NAME AGE
istio-system gateway.networking.istio.io/cross-network-gateway 13s
# west 에서 호출 시도
kwest get svc,ep -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.0.123 <none> 80/TCP 108m
service/webapp ClusterIP 10.100.0.149 <none> 80/TCP 108m
NAME ENDPOINTS AGE
endpoints/catalog <none> 108m
endpoints/webapp 10.10.0.14:8080 108m
kwest exec -it deploy/webapp -c istio-proxy -n istioinaction -- curl catalog.istioinaction.svc.cluster.local -v
* Trying 10.100.0.123:80...
* connect to 10.100.0.123 port 80 failed: Connection refused
...
# east 에 istio-ingressgateway 에 istio-config 정보 확인 : 이전 내용과 동일하게 west 의 CDS/EDS 모두 알고 있음!
for i in listener route cluster endpoint; do echo ">> east k8s cluster : ingressgateway - istio-config $i <<"; docker exec -it east-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
# east 에 istio-eastwestgateway 에 istio-config 정보 확인 : SNI 자동 통과를 위한 listener 추가 확인!
for i in listener route cluster endpoint; do echo ">> east k8s cluster : eastwestgateway - istio-config $i <<"; docker exec -it east-control-plane istioctl proxy-config $i deploy/istio-eastwestgateway.istio-system; echo; done
ieast proxy-config listener deploy/istio-eastwestgateway.istio-system
ieast proxy-config listener deploy/istio-eastwestgateway.istio-system | grep istioinaction
0.0.0.0 15443 SNI: outbound_.80_._.webapp.istioinaction.svc.cluster.local; App: istio,istio-peer-exchange,istio-http/1.0,istio-http/1.1,istio-h2 Cluster: outbound_.80_._.webapp.istioinaction.svc.cluster.local
0.0.0.0 15443 SNI: outbound_.80_._.catalog.istioinaction.svc.cluster.local; App: istio,istio-peer-exchange,istio-http/1.0,istio-http/1.1,istio-h2 Cluster: outbound_.80_._.catalog.istioinaction.svc.cluster.local
ieast proxy-config listener deploy/istio-eastwestgateway.istio-system --port 15443 -o json
...
"filterChainMatch": {
"serverNames": [
"outbound_.80_._.catalog.istioinaction.svc.cluster.local"
...
},
"filters": [
...
{
"name": "envoy.filters.network.tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
"statPrefix": "outbound_.80_._.catalog.istioinaction.svc.cluster.local",
"cluster": "outbound_.80_._.catalog.istioinaction.svc.cluster.local",
...
# west 정보 확인
iwest proxy-status
# west 에 istio-ingressgateway 에 istio-config 정보 확인
for i in listener route cluster endpoint; do echo ">> west k8s cluster : ingressgateway - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
# west 에 webapp 에 istio-config 정보 확인
for i in listener route cluster endpoint; do echo ">> west k8s cluster : webapp - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/webapp.istioinaction; echo; done
✅ 반대편 클러스터에도 작업 수행. west-cluster 에 east-west 게이트웨이를 만들고, 그 서비스를 east-cluster 워크로드에 노출.
# IstioOperator 로 west 클러스터에 east-west 게이트웨이를 설치
cat ch12/gateways/cluster-west-eastwest-gateway.yaml
docker cp ./ch12/gateways/cluster-west-eastwest-gateway.yaml west-control-plane:/cluster-west-eastwest-gateway.yaml
iwest install -f /cluster-west-eastwest-gateway.yaml --set values.global.proxy.privileged=true -y
# west 클러스터에 east-west 게이트웨이를 설치 확인
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get IstioOperator -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME REVISION STATUS AGE
installed-state-istio-controlplane 162m
installed-state-istio-eastwestgateway 12s
>> k8s cluster : east <<
NAME REVISION STATUS AGE
installed-state-istio-controlplane 153m
installed-state-istio-eastwestgateway 36m
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get pod -n istio-system -l istio.io/rev=default --kubeconfig=./$i-kubeconfig; echo; done
>> k8s cluster : west <<
NAME READY STATUS RESTARTS AGE
istio-eastwestgateway-6f7995db66-ql658 1/1 Running 0 38s
istio-ingressgateway-5db74c978c-wvn65 1/1 Running 0 162m
istiod-5585445f4c-7v25t 1/1 Running 0 163m
>> k8s cluster : east <<
NAME READY STATUS RESTARTS AGE
istio-eastwestgateway-866794c798-nr29l 1/1 Running 0 36m
istio-ingressgateway-7f6f8f8d99-lgvfc 1/1 Running 0 154m
istiod-85976468f-sb2dc 1/1 Running 0 154m
kwest get IstioOperator -n istio-system installed-state-istio-eastwestgateway -o yaml
iwest proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-eastwestgateway-6f7995db66-ql658.istio-system west-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-5585445f4c-7v25t 1.17.8
istio-ingressgateway-5db74c978c-wvn65.istio-system west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-7v25t 1.17.8
webapp-5c8b4fff64-rk6v2.istioinaction west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-7v25t 1.17.8
# west 클러스터에 적용하자. east-cluster의 워크로드를 west-cluster 에 노출한다.
cat ch12/gateways/expose-services.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: cross-network-gateway
namespace: istio-system
spec:
selector:
istio: eastwestgateway
servers:
- port:
number: 15443
name: tls
protocol: TLS
tls:
mode: AUTO_PASSTHROUGH
hosts:
- "*.local"
kwest apply -n istio-system -f ch12/gateways/expose-services.yaml
# 확인
kwest get gw,vs,dr -A
NAMESPACE NAME AGE
istio-system gateway.networking.istio.io/cross-network-gateway 5s
istioinaction gateway.networking.istio.io/coolstore-gateway 89m
NAMESPACE NAME GATEWAYS HOSTS AGE
istioinaction virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 89m
kwest get svc,ep -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.0.123 <none> 80/TCP 120m
service/webapp ClusterIP 10.100.0.149 <none> 80/TCP 120m
NAME ENDPOINTS AGE
endpoints/catalog <none> 120m
endpoints/webapp 10.10.0.14:8080 120m
ieast pc clusters deploy/istio-eastwestgateway.istio-system | grep catalog
catalog.istioinaction.svc.cluster.local 80 - outbound EDS
outbound_.80_._.catalog.istioinaction.svc.cluster.local - - - EDS
# sni 클러스터 확인
ieast pc clusters deploy/istio-eastwestgateway.istio-system | grep catalog | awk '{printf "CLUSTER: %s\n", $1}'
CLUSTER: catalog.istioinaction.svc.cluster.local
CLUSTER: outbound_.80_._.catalog.istioinaction.svc.cluster.local # catalog 서비스용 SNI 클러스터
#
keast -n istio-system get svc istio-eastwestgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
172.18.255.202
#
iwest pc endpoints deploy/webapp.istioinaction | grep catalog
172.18.255.202:15443 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local

# west 에 istio-ingressgateway 인입을 위한 접속 정보 확인
kwest get svc -n istio-system istio-ingressgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.100.0.85 172.18.255.101 15021:32239/TCP,80:30000/TCP,443:30754/TCP,31400:32736/TCP,15443:32637/TCP 171m
EXT_IP=$(kwest -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $EXT_IP
172.18.255.101
#
docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog | jq
[
{
"id": 1,
"color": "amber",
"department": "Eyewear",
"name": "Elinor Glasses",
"price": "282.00"
},
{
"id": 2,
"color": "cyan",
"department": "Clothing",
"name": "Atlas Shirt",
"price": "127.00"
},
{
"id": 3,
"color": "teal",
"department": "Clothing",
"name": "Small Metal Shoes",
"price": "232.00"
},
{
"id": 4,
"color": "red",
"department": "Watches",
"name": "Red Dragon Watch",
"price": "232.00"
}
]
# 신규 터미널 : 반복 접속
alias kwest='kubectl --kubeconfig=./west-kubeconfig'
EXT_IP=$(kwest -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
while true; do docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
kiali : west-cluster 확인

kiali : east-cluster 확인 , mTLS 통신이며 TCP Traffic 와 HTTP(S) 2개 트래픽 흐름으로 확인됨.

istio-proxy 로그 확인
# west 에 istio-ingressgateway 로그
kwest logs -n istio-system -l app=istio-ingressgateway -f
[2025-05-24T04:43:56.484Z] "GET /api/catalog HTTP/1.1" 200 - via_upstream - "-" 0 357 8 7 "172.18.0.100" "curl/8.7.1" "e8660ec1-a451-95c2-98f0-f366af767c0e" "webapp.istioinaction.io" "10.10.0.14:8080" outbound|80||webapp.istioinaction.svc.cluster.local 10.10.0.9:47236 10.10.0.9:8080 172.18.0.100:51548 - -
# west 에 webapp 로그
kwest logs -n istioinaction -l app=webapp -c istio-proxy -f
[2025-05-24T04:44:34.448Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 2 2 "172.18.0.100" "beegoServer" "8a493851-2606-97a3-b8e1-0348d7a272f5" "catalog.istioinaction.svc.cluster.local:80" "172.18.255.202:15443" outbound|80||catalog.istioinaction.svc.cluster.local 10.10.0.14:51284 10.100.0.123:80 172.18.0.100:0 - default
kwest logs -n istioinaction -l app=webapp -c webapp -f
2025/05/24 04:44:54.248 [M] [router.go:1014] 172.18.0.100 - - [24/May/2025 04:44:54] "GET /api/catalog HTTP/1.1 200 0" 0.019467 curl/8.7.1
# west 에 istio-eastwestgateway 로그
kwest exec -it -n istio-system deploy/istio-eastwestgateway -- curl -X POST http://localhost:15000/logging?level=debug
kwest logs -n istio-system -l app=istio-eastwestgateway -f
2025-05-24T04:45:25.666899Z debug envoy pool external/envoy/source/common/http/http1/conn_pool.cc:53 [C3] response complete thread=30
2025-05-24T04:45:25.666910Z debug envoy pool external/envoy/source/common/conn_pool/conn_pool_base.cc:215 [C3] destroying stream: 0 remaining thread=30
2025-05-24T04:45:25.666996Z debug envoy connection external/envoy/source/common/network/connection_impl.cc:720 [C713] write flush complete thread=30
2025-05-24T04:45:25.667000Z debug envoy connection external/envoy/source/common/network/connection_impl.cc:250 [C713] closing socket: 1 thread=30
2025-05-24T04:45:25.667014Z debug envoy conn_handler external/envoy/source/extensions/listener_managers/listener_manager/active_stream_listener_base.cc:120 [C713] adding to cleanup list thread=30
2025-05-24T04:45:27.264865Z debug envoy dns external/envoy/source/extensions/network/dns_resolver/cares/dns_impl.cc:354 dns resolution for zipkin.istio-system started thread=21
2025-05-24T04:45:27.267066Z debug envoy dns external/envoy/source/extensions/network/dns_resolver/cares/dns_impl.cc:275 dns resolution for zipkin.istio-system completed with status 0 thread=21
2025-05-24T04:45:27.267198Z debug envoy upstream external/envoy/source/common/upstream/upstream_impl.cc:451 transport socket match, socket default selected for host with address 10.100.0.77:9411 thread=21
2025-05-24T04:45:27.267319Z debug envoy upstream external/envoy/source/extensions/clusters/strict_dns/strict_dns_cluster.cc:180 DNS refresh rate reset for zipkin.istio-system, refresh rate 30000 ms thread=21
2025-05-24T04:45:27.439750Z debug envoy main external/envoy/source/server/server.cc:265 flushing stats thread=21
failed to create fsnotify watcher: too many open files
...
# east 에 istio-eastwestgateway 로그
keast exec -it -n istio-system deploy/istio-eastwestgateway -- curl -X POST http://localhost:15000/logging?level=debug
keast logs -n istio-system -l app=istio-eastwestgateway -f
...
# east 에 catalog 로그
keast logs -n istioinaction -l app=catalog -c istio-proxy -f
[2025-05-24T04:46:06.861Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 1 1 "172.18.0.100" "beegoServer" "22e938a3-4e9a-9568-abd0-499fa3f8df39" "catalog.istioinaction.svc.cluster.local:80" "10.20.0.14:3000" inbound|3000|| 127.0.0.6:52925 10.20.0.14:3000 172.18.0.100:0 outbound_.80_._.catalog.istioinaction.svc.cluster.local default
keast logs -n istioinaction -l app=catalog -c catalog -f
request path: /items
blowups: {}
number of blowups: 0
GET catalog.istioinaction.svc.cluster.local:80 /items 200 502 - 0.295 ms
GET /items 200 0.295 ms - 502
request path: /items
blowups: {}
number of blowups: 0
GET catalog.istioinaction.svc.cluster.local:80 /items 200 502 - 0.589 ms
GET /items 200 0.589 ms - 502
#
kwest exec -it -n istioinaction deploy/webapp -c istio-proxy -- sudo tcpdump -i any tcp -nn
kwest exec -it -n istioinaction deploy/webapp -c istio-proxy -- sudo tcpdump -i lo tcp -nn
kwest exec -it -n istioinaction deploy/webapp -c istio-proxy -- sudo tcpdump -i eth0 tcp -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
04:48:18.432381 IP 10.10.0.9.47236 > 10.10.0.14.8080: Flags [P.], seq 1195725563:1195727205, ack 3236564876, win 4280, options [nop,nop,TS val 4060446648 ecr 1706652361], length 1642: HTTP
04:48:18.432413 IP 10.10.0.14.8080 > 10.10.0.9.47236: Flags [.], ack 1642, win 812, options [nop,nop,TS val 1706657818 ecr 4060446648], length 0
04:48:18.437333 IP 10.10.0.14.57408 > 172.18.255.202.15443: Flags [P.], seq 1763303002:1763304380, ack 425370800, win 890, options [nop,nop,TS val 1761527357 ecr 605657766], length 1378
04:48:18.440319 IP 172.18.255.202.15443 > 10.10.0.14.57408: Flags [P.], seq 1:1789, ack 1378, win 814, options [nop,nop,TS val 605659977 ecr 1761527357], length 1788
...
#
keast get svc -n istio-system istio-eastwestgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-eastwestgateway LoadBalancer 10.200.0.139 172.18.255.202 15021:30532/TCP,15443:30060/TCP,15012:30003/TCP,15017:31492/TCP 63m
# istio-proxy 에 tcp port 3000 에서 패킷 덤프에 출력 결과를 파일로 저장
keast exec -it -n istioinaction deploy/catalog -c istio-proxy -- sudo tcpdump -i any tcp port 3000 -w /var/lib/istio/data/dump.pcap
keast exec -it -n istioinaction deploy/catalog -c istio-proxy -- ls -l /var/lib/istio/data/
total 112
-rw-r--r-- 1 tcpdump tcpdump 114139 May 24 04:49 dump.pcap
# 출력 결과 파일을 로컬로 다운로드
keast get pod -n istioinaction -l app=catalog -oname
pod/catalog-6cf4b97d-p8xbj
keast cp -n istioinaction -c istio-proxy catalog-6cf4b97d-p8xbj:var/lib/istio/data/dump.pcap ./dump.pcap
# 로컬로 다운 받은 파일을 wireshark 로 불러오기 : XFF 로 요청 Client IP 확인
wireshark dump.pcap

1. west의 인그레스 게이트웨이에 요청을 트리거하면 요청이 west-cluster 의 webapp 으로 라우팅됨을 알 수 있다.
2. 그런 다음, 요청을 처리하는 east-cluster 의 catalog 워크로드로 해석된다.
#
tree ch12/locality-aware/west
ch12/locality-aware/west
├── simple-backend-deployment.yaml
├── simple-backend-dr.yaml
├── simple-backend-gw.yaml
├── simple-backend-svc.yaml
└── simple-backend-vs.yaml
# west-cluster 에 간단한 백엔드 디플로이먼트/서비스를 배포
cat ch12/locality-aware/west/simple-backend-deployment.yaml
...
- name: "MESSAGE"
value: "Hello from WEST"
...
cat ch12/locality-aware/west/simple-backend-svc.yaml
kwest apply -f ch12/locality-aware/west/simple-backend-deployment.yaml
kwest apply -f ch12/locality-aware/west/simple-backend-svc.yaml
kwest get deploy -n istioinaction simple-backend-west
NAME READY UP-TO-DATE AVAILABLE AGE
simple-backend-west 1/1 1 1 14s
kwest get svc,ep -n istioinaction simple-backend
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/simple-backend ClusterIP 10.100.0.62 <none> 80/TCP 27s
NAME ENDPOINTS AGE
endpoints/simple-backend 10.10.0.16:8080 27s
# 트래픽을 허용하기 위해 Gateway, 게이트웨이에서 백엔드 워크로드로 트래픽을 라우팅하기 위해 VirtualService 적용
cat ch12/locality-aware/west/simple-backend-gw.yaml
cat ch12/locality-aware/west/simple-backend-vs.yaml
kwest apply -f ch12/locality-aware/west/simple-backend-gw.yaml
kwest apply -f ch12/locality-aware/west/simple-backend-vs.yaml
kwest get gw,vs,dr -n istioinaction
NAME AGE
gateway.networking.istio.io/coolstore-gateway 154m
gateway.networking.istio.io/simple-backend-gateway 46s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/simple-backend-vs-for-gateway ["simple-backend-gateway"] ["simple-backend.istioinaction.io"] 46s
virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 154m
# west-cluster의 서비스로 요청하고 클러스터 이름을 반환하는지 확인
EXT_IP=$(kwest -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body"
"Hello from WEST"
docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP
{
"name": "simple-backend-west",
"uri": "/",
"type": "HTTP",
"ip_addresses": [
"10.10.0.16"
],
"start_time": "2025-05-24T05:01:47.801083",
"end_time": "2025-05-24T05:01:47.952141",
"duration": "151.058ms",
"body": "Hello from WEST",
"code": 200
}
# 신규 터미널 : 반복 접속
alias kwest='kubectl --kubeconfig=./west-kubeconfig'
EXT_IP=$(kwest -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
while true; do docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
#
tree ch12/locality-aware/east
ch12/locality-aware/east
├── simple-backend-deployment.yaml
└── simple-backend-svc.yaml
# east-cluster 에 서비스를 배포
cat ch12/locality-aware/east/simple-backend-deployment.yaml
...
- name: "MESSAGE"
value: "Hello from EAST"
...
cat ch12/locality-aware/east/simple-backend-svc.yaml
keast apply -f ch12/locality-aware/east/simple-backend-deployment.yaml
keast apply -f ch12/locality-aware/east/simple-backend-svc.yaml
keast get deploy -n istioinaction simple-backend-east
NAME READY UP-TO-DATE AVAILABLE AGE
simple-backend-east 1/1 1 1 13s
keast get svc,ep -n istioinaction simple-backend
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/simple-backend ClusterIP 10.200.0.94 <none> 80/TCP 20s
NAME ENDPOINTS AGE
endpoints/simple-backend 10.20.0.16:8080 20s



# 10회 요청 후 확인
for i in {1..10}; do docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body" ; echo ; done
for i in {1..10}; do docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body" ; echo ; done | sort | uniq -c
10
5 "Hello from EAST"
5 "Hello from WEST"
# 정보 확인
kwest get svc,ep -n istioinaction simple-backend
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/simple-backend ClusterIP 10.100.0.62 <none> 80/TCP 12m
NAME ENDPOINTS AGE
endpoints/simple-backend 10.10.0.16:8080 12m # k8s service 에 endpoint 에는 west 에 파드 ip만 출력
#
for i in listener route cluster endpoint; do echo ">> k8s cluster : west - istio-config $i <<"; docker exec -it west-control-plane istioctl proxy-config $i deploy/istio-ingressgateway.istio-system; echo; done
>> k8s cluster : west - istio-config listener <<
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL Route: http.8080
...
>> k8s cluster : west - istio-config route <<
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 simple-backend.istioinaction.io /* simple-backend-vs-for-gateway.istioinaction
...
>> k8s cluster : west - istio-config cluster <<
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
simple-backend.istioinaction.svc.cluster.local 80 - outbound EDS
...
>> k8s cluster : west - istio-config endpoint <<
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.14:8080 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local
...
#
iwest proxy-config listener deploy/istio-ingressgateway.istio-system
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL Route: http.8080
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
iwest proxy-config listener deploy/istio-ingressgateway.istio-system --port 8080 -o json
iwest proxy-config route deploy/istio-ingressgateway.istio-system
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 simple-backend.istioinaction.io /* simple-backend-vs-for-gateway.istioinaction
http.8080 webapp.istioinaction.io /* webapp-virtualservice.istioinaction
* /healthz/ready*
* /stats/prometheus*
iwest proxy-config route deploy/istio-ingressgateway.istio-system --name http.8080
NAME DOMAINS MATCH VIRTUAL SERVICE
http.8080 simple-backend.istioinaction.io /* simple-backend-vs-for-gateway.istioinaction
http.8080 webapp.istioinaction.io /* webapp-virtualservice.istioinaction
iwest proxy-config route deploy/istio-ingressgateway.istio-system --name http.8080 -o json
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system --fqdn simple-backend.istioinaction.svc.cluster.local -o json
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep simple
10.10.0.16:8080 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
[
{
"name": "outbound|80||simple-backend.istioinaction.svc.cluster.local",
"addedViaApi": true,
"hostStatuses": [
{
"address": {
"socketAddress": {
"address": "10.10.0.16",
"portValue": 8080
}
"weight": 1,
"locality": {}
...
{
"address": {
"socketAddress": {
"address": "172.18.255.202",
"portValue": 15443
}
"weight": 1,
"locality": {}
...
#
kwest label node west-control-plane 'topology.kubernetes.io/region=westus'
kwest label node west-control-plane 'topology.kubernetes.io/zone=0'
kwest get node -o yaml
...
topology.kubernetes.io/region: westus
topology.kubernetes.io/zone: "0"
...
keast label node east-control-plane 'topology.kubernetes.io/region=eastus'
keast label node east-control-plane 'topology.kubernetes.io/zone=0'
keast get node -o yaml
...
topology.kubernetes.io/region: eastus
topology.kubernetes.io/zone: "0"
...
# istio eds 에 정보 반영을 위해 파드 재기동하자 : isiotd 가 노드의 지역성 정보 레이블을 엔드포인트 설정할 때 워크로드로 전파.
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
...
"weight": 1,
"locality": {}
...
kwest rollout restart -n istio-system deploy/istio-ingressgateway
kwest rollout restart -n istio-system deploy/istio-eastwestgateway
kwest rollout restart -n istioinaction deploy/simple-backend-west
keast rollout restart -n istio-system deploy/istio-ingressgateway
keast rollout restart -n istio-system deploy/istio-eastwestgateway
keast rollout restart -n istioinaction deploy/simple-backend-east
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
...
"weight": 1,
"locality": {
"region": "eastus", # east-cluster 에 있는 워크로드의 위치 정보
"zone": "0"
}
...
"weight": 1,
"locality": {
"region": "westus", # west-cluster 에 있는 워크로드의 위치 정보
"zone": "0"
}
...
DestinationRole 을 적용해보자.#
cat ch12/locality-aware/west/simple-backend-dr.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: simple-backend-dr
namespace: istioinaction
spec:
host: simple-backend.istioinaction.svc.cluster.local
trafficPolicy:
connectionPool:
http:
http2MaxRequests: 10
maxRequestsPerConnection: 10
outlierDetection:
consecutive5xxErrors: 1
interval: 20s
baseEjectionTime: 30s
kwest apply -f ch12/locality-aware/west/simple-backend-dr.yaml
destinationrule.networking.istio.io/simple-backend-dr created
kwest get gw,vs,dr -n istioinaction
NAME AGE
gateway.networking.istio.io/coolstore-gateway 3h
gateway.networking.istio.io/simple-backend-gateway 25m
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/simple-backend-vs-for-gateway ["simple-backend-gateway"] ["simple-backend.istioinaction.io"] 25m
virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 3h
NAME HOST AGE
destinationrule.networking.istio.io/simple-backend-dr simple-backend.istioinaction.svc.cluster.local 24s
# 확인
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local'
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.19:8080 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local
#
EXT_IP=$(kwest -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP
{
"name": "simple-backend-west",
"uri": "/",
"type": "HTTP",
"ip_addresses": [
"10.10.0.19"
],
"start_time": "2025-05-24T05:27:32.144871",
"end_time": "2025-05-24T05:27:32.296805",
"duration": "151.935ms",
"body": "Hello from WEST",
"code": 200
}
docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body"
"Hello from WEST"
# 동일 클러스터 안에서 라우팅 되는 것을 확인
for i in {1..20}; do docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body" ; echo ; done | sort | uniq -c
20
20 "Hello from WEST"
#
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
...
"weight": 1,
"locality": {
"region": "westus", # priority 가 없으면(생략 시), 0으로 우선 순위가 가장 높음
"zone": "0"
}
...
"weight": 1,
"priority": 1, # priority 0 다음으로, 두 번쨰 우선순위
"locality": {
"region": "eastus",
"zone": "0"
}
...
ERROR_RATE 값을 1로 설정해 요청이 실패하게 만들자.# 신규 터미널 : 반복 접속 해두기
while true; do docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
...
"Hello from WEST"
2025-05-18 09:31:21
"Hello from EAST" # failover 시점
2025-05-18 09:31:23
...
#
kwest -n istioinaction set env deploy simple-backend-west ERROR_RATE='1'
kwest exec -it -n istioinaction deploy/simple-backend-west -- env | grep ERROR
ERROR_RATE=1
#
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local'
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.10.0.20:8080 HEALTHY FAILED outbound|80||simple-backend.istioinaction.svc.cluster.local
172.18.255.202:15443 HEALTHY OK outbound|80||simple-backend.istioinaction.svc.cluster.local


ch12/security/allow-only-ingress-policy.yaml 파일에 저장해뒀다. 이를 east-cluster 에 적용하자.# 적용 전에 west-cluster 서비스를 제거해서 east 에서만 트래픽을 처리하게 하자 >> 이미 위에서 장애 상황이라 안해도 되긴함
kwest delete deploy simple-backend-west -n istioinaction
#
cat ch12/security/allow-only-ingress-policy.yaml
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "allow-only-ingress"
namespace: istioinaction
spec:
selector:
matchLabels:
app: simple-backend
rules:
- from:
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
keast apply -f ch12/security/allow-only-ingress-policy.yaml
authorizationpolicy.security.istio.io/allow-only-ingress created
keast get authorizationpolicy -A
NAMESPACE NAME AGE
istioinaction allow-only-ingress 11s
#
kwest run netshoot -n istioinaction --rm -it --image=nicolaka/netshoot -- zsh
-----------------------------------
#
curl -s webapp.istioinaction/api/catalog
[{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}
# 직접 요청하면 실패!
curl -s simple-backend.istioinaction.svc.cluster.local
RBAC: access denied
# istio-ingressgateway 로 요청하면 성공!
curl -s -H "Host: simple-backend.istioinaction.io" http://istio-ingressgateway.istio-system
{
"name": "simple-backend-east",
"uri": "/",
"type": "HTTP",
"ip_addresses": [
"10.20.0.19"
],
"start_time": "2025-05-24T05:42:16.015504",
"end_time": "2025-05-24T05:42:16.166680",
"duration": "151.176ms",
"body": "Hello from EAST",
"code": 200
}
# kiali 등 확인을 위해 반복 접속 실행
watch curl -s simple-backend.istioinaction.svc.cluster.local
watch 'curl -s -H "Host: simple-backend.istioinaction.io" http://istio-ingressgateway.istio-system'
exit
-----------------------------------
- 로드 밸런싱, 지역 인식 라우팅, 클러스터 간 장애 극복, 상호 인증 트래픽, 접근 제어에 대한 우리의 모든 예제는 다중 클러스터 서비스 메시에서의 워크로드가 실행 중인 클러스터가 어디든 상관없이 이스티오의 모든 기능을 사용할 수 있음을 보여준다. 그리고 설정을 따로 더 하지 않아도 그럴 수 있다.
⛔️ kind delete cluster --name west && kind delete cluster --name east && docker rm -f mypc
✅ Istio 확장의 필요성
✅ Envoy는 Istio의 핵심
✅ Envoy 확장 예시
✅ 핵심 메시지






📌 Envoy의 전체 요청 처리 흐름을 설명한 12단계 과정
다운스트림으로부터 TCP 연결이 들어오면, Envoy의 리스너(listener)가 실행 중인 워커 스레드에서 해당 연결을 수락합니다.
리스너 필터 체인이 생성되고 실행됩니다. 이 필터는 SNI 등 TLS 이전의 정보를 제공할 수 있습니다. 필터 체인이 완료되면, 리스너는 네트워크 필터 체인을 매칭합니다. 리스너는 대상 IP CIDR 범위, SNI, ALPN, 소스 포트 등 조합으로 여러 필터 체인을 가질 수 있습니다. 이 필터 체인에는 전송 소켓(이 경우 TLS 소켓)이 연결됩니다.
네트워크로부터 데이터를 읽는 과정에서, TLS 전송 소켓은 TCP 연결에서 읽은 암호화된 데이터를 복호화하여 처리 가능한 데이터 스트림으로 변환합니다.
네트워크 필터 체인이 생성되고 실행됩니다. 이 중 가장 중요한 필터는 HTTP 연결 관리자(HTTP connection manager)로, 네트워크 필터 체인의 마지막 필터입니다.
HTTP 연결 관리자의 HTTP/2 코덱은 TLS 연결에서 복호화된 데이터를 프레임 해제 및 멀티플렉싱하여, 독립적인 여러 스트림으로 분리합니다. 각 스트림은 하나의 요청과 응답을 처리합니다.
각 HTTP 스트림마다 다운스트림 HTTP 필터 체인이 생성되고 실행됩니다. 요청은 CustomFilter를 먼저 통과하며, 이 필터는 요청을 읽고 수정할 수 있습니다. 필터 체인의 마지막에는 라우터 필터(router filter)가 있으며, 이 필터에서 decodeHeaders가 호출되면 라우트를 선택하고 클러스터를 결정합니다. 선택된 클러스터 내의 업스트림 엔드포인트로 요청 헤더가 전달됩니다. 이 때 라우터 필터는 매칭된 클러스터에 대해 HTTP 커넥션 풀을 가져옵니다.
클러스터에 따라 로드 밸런싱이 수행되어 엔드포인트가 선택됩니다. 클러스터의 서킷 브레이커(circuit breaker)를 확인하여 새로운 스트림이 허용 가능한지 확인한 후, 커넥션 풀이 비었거나 용량이 부족하면 새로운 연결이 생성됩니다.
각 스트림마다 업스트림 HTTP 필터 체인이 생성되어 실행됩니다. 기본적으로는 CodecFilter만 포함되며, 이 필터는 데이터를 적절한 코덱으로 전송합니다. 클러스터가 업스트림 HTTP 필터 체인을 구성하고 있는 경우, 재시도나 섀도 요청 처리를 위한 필터 체인도 별도로 실행됩니다.
업스트림 엔드포인트와의 연결에 존재하는 HTTP/2 코덱은 해당 스트림을 다른 스트림들과 함께 하나의 TCP 연결로 멀티플렉싱 및 프레이밍합니다.
업스트림 연결의 TLS 전송 소켓은 이러한 바이트를 암호화한 뒤, 업스트림으로 향하는 TCP 소켓에 기록합니다.
요청(헤더, 선택적 본문 및 트레일러로 구성됨)은 업스트림으로 프록시되고, 응답은 다운스트림으로 프록시됩니다. 응답은 HTTP 필터들을 요청의 반대 순서로 통과합니다. 즉, CodecFilter부터 시작하여 업스트림 HTTP 필터 → 라우터 필터 → CustomFilter를 거쳐 다운스트림으로 전달됩니다.
스트림의 종료 처리는 다음 조건에 따라 다릅니다:
END_STREAM 수신됨), 응답 상태 코드가 성공(2xx)이면 스트림이 종료됩니다.📘 Envoy의 리스너와 필터 개념
3장에서 소개한 리스너, 라우트, 클러스터는 고수준 개념이었고, 이번 장에서는 그 중 리스너와 필터 체인에 대해 더 자세히 다룸.
리스너(listener)는 네트워크 인터페이스의 포트를 열고 수신 트래픽을 처리하기 시작하는 Envoy의 기본 단위.

Envoy는 L3/L4 계층 프록시로서, 네트워크 연결에서 바이트를 읽어 다양한 방식으로 처리함.
이 처리 과정에서 핵심이 되는 구성 요소는 바로 필터(filter).
리스너는 네트워크 스트림에서 바이트를 읽은 후, 이를 여러 필터 단계(filter chain)를 통해 순차적으로 처리함.

🔧 Envoy의 네트워크 필터와 필터 체인
네트워크 필터는 Envoy에서 가장 기본적인 필터로, 바이트 스트림을 인코딩/디코딩하는 데 사용됨.
여러 필터를 순차적으로 구성한 것을 필터 체인(filter chain)이라고 하며, 이를 통해 프록시의 다양한 기능을 구현할 수 있음.
Envoy는 다양한 프로토콜을 지원하는 네트워크 필터를 제공함:
이 중 HttpConnectionManager는 가장 널리 사용되는 필터 중 하나이며, 바이트 스트림을 HTTP 헤더, 바디, 트레일러 등으로 변환하는 역할.
HTTP 1.1, HTTP/2, gRPC, HTTP/3 등의 HTTP 기반 프로토콜을 추상화함.
이 필터는 Envoy가 L7 기능을 수행할 수 있게 해주는 핵심 컴포넌트입니다.

🌐 HttpConnectionManager (HCM)의 주요 기능
HTTP 요청 처리 외에도 다음을 지원:
필터 기반 아키텍처를 사용:
주요 HTTP 필터 예시 (전체 목록은 공식 문서 참조):
Router 필터:
즉, HCM은 L7 HTTP 요청을 처리하고, 필터 체인을 통해 요청을 세밀하게 조작하거나 제어하며, 최종적으로 라우터 필터를 통해 업스트림으로 전송합니다.


또한 사용자는 엔보이의 핵심 코드를 변경하지 않고도 자신만의 필터를 직접 작성하고 프록시 위에 얹어 계층화할 수 있다.
예를 들어, 이스티오의 프록시는 데이터 플레인용으로 엔보이 위에 필터를 추가해 커스텀 엔보이를 빌드한다.
그렇지만 이렇게 커스텀 엔보이 프록시 빌드를 도입하면, 유지 보수할 것이 많아질 수 있고 개발자가 C++를 사용해야 한다.
엔보이에는 범용 처리 목적으로 외부 서비스를 호출하기 위한 외부 처리 필터가 있다. 이 필터는 코드베이스에 존재하기는 하지만, 저술 시점에는 아무것도 하지 않는다. 우리는 전역 속도 제한 필터를 사용하는 등 외부 서비스를 호출하는 다른 방법에 초점을 맞춘다.
#
git clone https://github.com/AcornPublishing/istio-in-action
cd istio-in-action/book-source-code-master
pwd # 각자 자신의 pwd 경로
code .
# 아래 extramounts 생략 시, myk8s-control-plane 컨테이너 sh/bash 진입 후 직접 git clone 가능
kind 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/sjkim/Labs/CloudNeta/istio/book-source-code-master # 각자 자신의 pwd 경로로 설정
containerPath: /istiobook
networking:
podSubnet: 10.10.0.0/16
serviceSubnet: 10.200.0.0/22
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'
# (옵션) kube-ops-view
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
## kube-ops-view 접속 URL 확인
open "http://localhost:30007/#scale=1.5"
open "http://localhost:30007/#scale=1.3"
# (옵션) metrics-server
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
# kind 설치 시 kind 이름의 도커 브리지가 생성된다 : 172.18.0.0/16 대역
docker network ls
docker inspect kind
# mypc 컨테이너 기동 : kind 도커 브리지를 사용하고, 컨테이너 IP를 지정 없이 혹은 지정 해서 사용
docker run -d --rm --name mypc --network kind --ip 172.18.0.100 nicolaka/netshoot sleep infinity # IP 지정 실행 시
혹은 IP 지정 실행 시 에러 발생 시 아래 처럼 IP 지정 없이 실행
docker run -d --rm --name mypc --network kind nicolaka/netshoot sleep infinity # IP 지정 없이 실행 시
docker ps
# kind network 중 컨테이너(노드) IP(대역) 확인
docker ps -q | xargs docker inspect --format '{{.Name}} {{.NetworkSettings.Networks.kind.IPAddress}}'
/mypc 172.18.0.100
/myk8s-control-plane 172.18.0.2
# 동일한 docker network(kind) 내부에서 컨테이너 이름 기반 도메인 통신 가능 확인!
docker exec -it mypc ping -c 1 172.18.0.2
docker exec -it mypc ping -c 1 myk8s-control-plane
docker exec -it myk8s-control-plane ping -c 1 mypc
# MetalLB 배포
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
# 확인
kubectl get crd
kubectl get pod -n metallb-system
# IPAddressPool, L2Advertisement 설정 : MetalLB 파드(speaker) 배포 정상 완료 후 아래 설정 실행하자.
cat << EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 172.18.255.101-172.18.255.120
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
EOF
# 확인
kubectl get IPAddressPool,L2Advertisement -A
NAMESPACE NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
metallb-system ipaddresspool.metallb.io/default true false ["172.18.255.101-172.18.255.120"]
NAMESPACE NAME IPADDRESSPOOLS IPADDRESSPOOL SELECTORS INTERFACES
metallb-system l2advertisement.metallb.io/default ["default"]
#
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
EOF
# 확인
kubectl get deploy,pod,svc,ep
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 1/1 1 1 101s
NAME READY STATUS RESTARTS AGE
pod/nginx-8d545c96d-sd66k 1/1 Running 0 101s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.200.0.1 <none> 443/TCP 7m3s
service/nginx-service LoadBalancer 10.200.1.231 172.18.255.101 80:30981/TCP 101s
NAME ENDPOINTS AGE
endpoints/kubernetes 172.18.0.2:6443 7m3s
endpoints/nginx-service 10.10.0.6:80 101s
kubectl get svc nginx-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
172.18.255.101
LBIP=$(kubectl get svc nginx-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# 외부?에서 각 클러스터의 Service(LB)로 접속(인입) 확인 : TCP 80 포트 사용으로 편리하다!
docker exec -it mypc curl -s $LBIP
docker exec -it mypc curl -s $LBIP -v -I
* Trying 172.18.255.101:80...
* Connected to 172.18.255.101 (172.18.255.101) port 80
> HEAD / HTTP/1.1
> Host: 172.18.255.101
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: nginx/1.27.5
Server: nginx/1.27.5
< Date: Sat, 24 May 2025 07:38:45 GMT
Date: Sat, 24 May 2025 07:38:45 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 615
Content-Length: 615
< Last-Modified: Wed, 16 Apr 2025 12:01:11 GMT
Last-Modified: Wed, 16 Apr 2025 12:01:11 GMT
< Connection: keep-alive
Connection: keep-alive
< ETag: "67ff9c07-267"
ETag: "67ff9c07-267"
< Accept-Ranges: bytes
Accept-Ranges: bytes
<
* Connection #0 to host 172.18.255.101 left intact
# 확인 후 삭제
kubectl delete deploy,svc --all
# myk8s-control-plane 진입 후 설치 진행
docker exec -it myk8s-control-plane bash
-----------------------------------
# (옵션) 코드 파일들 마운트 확인
tree /istiobook/ -L 1
혹은
git clone ... /istiobook
# 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
# demo 프로파일 컨트롤 플레인 배포
istioctl install --set profile=demo --set values.global.proxy.privileged=true -y
# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
# 빠져나오기
exit
-----------------------------------
# 설치 확인 : istiod, istio-ingressgateway, crd 등
kubectl get istiooperators -n istio-system -o yaml
kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
kubectl get cm -n istio-system istio -o yaml
kubectl get crd | grep istio.io | sort
# 실습을 위한 네임스페이스 설정
kubectl create ns istioinaction
kubectl label namespace istioinaction istio-injection=enabled
kubectl get ns --show-labels
# istio-ingressgateway 서비스 : nodeport 지정 변경 , externalTrafficPolicy 설정 (ClientIP 수집)
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "LoadBalancer", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "LoadBalancer", "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
# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004)
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 접속 : NodePort
open http://127.0.0.1:30003
# tracing 접속 : 예거 트레이싱 대시보드
open http://127.0.0.1:30004
🧩 Istio 데이터 플레인 확장의 첫 단계: EnvoyFilter
EnvoyFilter 리소스를 사용해 직접 Envoy 설정 가능.🎛️ EnvoyFilter vs Istio 고수준 API
Istio의 리소스(VirtualService, DestinationRule, AuthorizationPolicy 등)는 일반적으로 Envoy 설정을 추상화함.
하지만 Istio는 모든 Envoy 기능을 노출하지 않음 → 일부 고급 시나리오에서는 Envoy를 직접 설정해야 함.
이때 사용하는 것이 바로 EnvoyFilter 리소스:
⚠️ EnvoyFilter 사용 시 주의사항
EnvoyFilter는 고급 사용자용이며, 일종의 비상 수단(break-glass solution)📌 요약하자면, EnvoyFilter는 Istio가 추상화하지 않은 Envoy의 고급 기능을 활용할 수 있는 강력하지만 위험한 도구로, 신중하게 사용해야 합니다.
✅ 예제를 보고 어떻게 작동하는지 이해해보자. 사용할 서비스를 배포하자.
#
kubectl get envoyfilter -A
NAMESPACE NAME AGE
istio-system stats-filter-1.13 7m7s
istio-system stats-filter-1.14 7m7s
istio-system stats-filter-1.15 7m7s
istio-system stats-filter-1.16 7m7s
istio-system stats-filter-1.17 7m7s
istio-system tcp-stats-filter-1.13 7m7s
istio-system tcp-stats-filter-1.14 7m7s
istio-system tcp-stats-filter-1.15 7m7s
istio-system tcp-stats-filter-1.16 7m7s
istio-system tcp-stats-filter-1.17 7m7s
# 배포
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction
kubectl apply -f ch9/sleep.yaml -n istioinaction
serviceaccount/sleep created
service/sleep created
deployment.apps/sleep created
# 확인
kubectl get gw,vs,dr -n istioinaction
NAME AGE
gateway.networking.istio.io/coolstore-gateway 31s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 31s
# 호출 확인 : mypc
EXT_IP=$(kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Web App - Istio in Action</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="/static/css/main.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.19.0/cytoscape.min.js" integrity="sha512-TOWs340KHbJjY/a2SCtsUcXYBg7/xPX72NKpJ3VITogkHJTy2yMyoJE0pxJjumMGHCg46ud89KO5q1Toe3Aeaw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
...
</script>
</body>
</html>
docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog
[{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}]
# 신규 터미널 : mypc 에서 반복 접속
EXT_IP=$(kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
while true; do docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog ; echo ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
# 호출 확인 : 자신의 호스트 PC
curl -s http://webapp.istioinaction.io:30000
curl -s http://webapp.istioinaction.io:30000/api/catalog
🛠️ 특정 요청 디버깅을 위한 tap 필터 설정
tap 필터를 사용:🔧 Istio에서 tap 필터 사용하기
tap 필터는 Istio의 고수준 API에 노출되어 있지 않음EnvoyFilter 리소스를 사용해야 함⚠️ EnvoyFilter 사용 시 핵심 사항 3가지
istio-system에 생성 시 메시 전체에 영향workloadSelector 사용📌 요약하면, EnvoyFilter를 이용한 tap 필터 설정은 특정 요청을 디버깅하는 데 강력한 도구지만, 잘못 쓰면 위험하므로 대상 워크로드 지정과 설정 순서, 안정성을 반드시 고려해야 합니다.

✅ EnvoyFilter 리소스는 다음과 같다
# cat ch14/tap-envoy-filter.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: tap-filter
namespace: istioinaction
spec:
workloadSelector:
labels:
app: webapp # 워크로드 셀렉터
configPatches:
- applyTo: HTTP_FILTER # 설정할 위치
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch: # 엔보이 설정 패치
operation: INSERT_BEFORE
value:
name: envoy.filters.http.tap
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.tap.v3.Tap"
commonConfig:
adminConfig:
configId: tap_config
✅ 이 EnvoyFilter를 istioinaction 네임스페이스에 webapp 워크로드에 적용하자
#
cat ch14/tap-envoy-filter.yaml
kubectl apply -f ch14/tap-envoy-filter.yaml
kubectl get envoyfilter -n istioinaction
NAME AGE
tap-filter 10s
#
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/webapp.istioinaction
ADDRESS PORT MATCH DESTINATION
10.200.0.10 53 ALL Cluster: outbound|53||kube-dns.kube-system.svc.cluster.local
0.0.0.0 80 Trans: raw_buffer; App: http/1.1,h2c Route: 80
0.0.0.0 80 ALL PassthroughCluster
10.200.0.1 443 ALL Cluster: outbound|443||kubernetes.default.svc.cluster.local
10.200.1.144 443 ALL Cluster: outbound|443||istio-egressgateway.istio-system.svc.cluster.local
10.200.2.30 443 ALL Cluster: outbound|443||istiod.istio-system.svc.cluster.local
10.200.2.80 443 ALL Cluster: outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.200.3.36 443 Trans: raw_buffer; App: http/1.1,h2c Route: metallb-webhook-service.metallb-system.svc.cluster.local:443
10.200.3.36 443 ALL Cluster: outbound|443||metallb-webhook-service.metallb-system.svc.cluster.local
10.200.0.21 3000 Trans: raw_buffer; App: http/1.1,h2c Route: grafana.istio-system.svc.cluster.local:3000
10.200.0.21 3000 ALL Cluster: outbound|3000||grafana.istio-system.svc.cluster.local
0.0.0.0 9090 Trans: raw_buffer; App: http/1.1,h2c Route: 9090
0.0.0.0 9090 ALL PassthroughCluster
10.200.0.10 9153 Trans: raw_buffer; App: http/1.1,h2c Route: kube-dns.kube-system.svc.cluster.local:9153
10.200.0.10 9153 ALL Cluster: outbound|9153||kube-dns.kube-system.svc.cluster.local
0.0.0.0 9411 Trans: raw_buffer; App: http/1.1,h2c Route: 9411
0.0.0.0 9411 ALL PassthroughCluster
10.200.2.135 14250 Trans: raw_buffer; App: http/1.1,h2c Route: jaeger-collector.istio-system.svc.cluster.local:14250
10.200.2.135 14250 ALL Cluster: outbound|14250||jaeger-collector.istio-system.svc.cluster.local
10.200.2.135 14268 Trans: raw_buffer; App: http/1.1,h2c Route: jaeger-collector.istio-system.svc.cluster.local:14268
10.200.2.135 14268 ALL Cluster: outbound|14268||jaeger-collector.istio-system.svc.cluster.local
0.0.0.0 15001 ALL PassthroughCluster
0.0.0.0 15001 Addr: *:15001 Non-HTTP/Non-TCP
0.0.0.0 15006 Addr: *:15006 Non-HTTP/Non-TCP
0.0.0.0 15006 Trans: tls; App: istio-http/1.0,istio-http/1.1,istio-h2; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: raw_buffer; App: http/1.1,h2c; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: raw_buffer; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: istio,istio-peer-exchange,istio-http/1.0,istio-http/1.1,istio-h2; Addr: *:8080 Cluster: inbound|8080||
0.0.0.0 15006 Trans: raw_buffer; Addr: *:8080 Cluster: inbound|8080||
0.0.0.0 15010 Trans: raw_buffer; App: http/1.1,h2c Route: 15010
0.0.0.0 15010 ALL PassthroughCluster
10.200.2.30 15012 ALL Cluster: outbound|15012||istiod.istio-system.svc.cluster.local
0.0.0.0 15014 Trans: raw_buffer; App: http/1.1,h2c Route: 15014
0.0.0.0 15014 ALL PassthroughCluster
0.0.0.0 15021 ALL Inline Route: /healthz/ready*
10.200.2.80 15021 Trans: raw_buffer; App: http/1.1,h2c Route: istio-ingressgateway.istio-system.svc.cluster.local:15021
10.200.2.80 15021 ALL Cluster: outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
0.0.0.0 15090 ALL Inline Route: /stats/prometheus*
10.200.2.80 15443 ALL Cluster: outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
0.0.0.0 16685 Trans: raw_buffer; App: http/1.1,h2c Route: 16685
0.0.0.0 16685 ALL PassthroughCluster
0.0.0.0 20001 Trans: raw_buffer; App: http/1.1,h2c Route: 20001
0.0.0.0 20001 ALL PassthroughCluster
10.200.2.80 31400 ALL Cluster: outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/webapp.istioinaction --port 15006
ADDRESS PORT MATCH DESTINATION
0.0.0.0 15006 Addr: *:15006 Non-HTTP/Non-TCP
0.0.0.0 15006 Trans: tls; App: istio-http/1.0,istio-http/1.1,istio-h2; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: raw_buffer; App: http/1.1,h2c; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: raw_buffer; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: istio,istio-peer-exchange,istio-http/1.0,istio-http/1.1,istio-h2; Addr: *:8080 Cluster: inbound|8080||
0.0.0.0 15006 Trans: raw_buffer; Addr: *:8080 Cluster: inbound|8080||
docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/webapp.istioinaction --port 15006 -o json
...
{
"name": "envoy.filters.http.tap",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.tap.v3.Tap",
"commonConfig": {
"adminConfig": {
"configId": "tap_config"
}
}
}
},
{
"name": "envoy.filters.http.router",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
}
}
...
✅ tap 기능이 동작하는지 확인해보자. 2개의 터미널 창이 필요한다. 창 하나에서는 curl 로 tap 설정을 전달해 webapp 워크로드에서 tap을 시작하자.
# 터미널 1 : 포트 포워딩 설정 후 tap 시작
kubectl port-forward -n istioinaction deploy/webapp 15000 &
curl -X POST -d @./ch14/tap-config.json localhost:15000/tap
# 터미널 2 : 기존 반복 접속하는 것 활용
EXT_IP=$(kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog
docker exec -it mypc curl -s -H "x-app-tap: true" -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog
while true; do docker exec -it mypc curl -s -H "x-app-tap: true" -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog ; echo ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
# 터미널 3 : 로그 확인
docker exec -it myk8s-control-plane istioctl proxy-config log deploy/webapp -n istioinaction --level http:debug
docker exec -it myk8s-control-plane istioctl proxy-config log deploy/webapp -n istioinaction --level tap:debug
kubectl logs -n istioinaction -l app=webapp -c istio-proxy -f
2025-05-24T08:08:04.975535Z debug envoy http external/envoy/source/common/http/conn_manager_impl.cc:1049 [C895][S12870699181831768119] request headers complete (end_stream=true):
':authority', 'webapp.istioinaction.io'
':path', '/api/catalog'
':method', 'GET'
'user-agent', 'curl/8.7.1'
'accept', '*/*'
'x-app-tap', 'true'
...
2025-05-24T08:08:47.713852Z debug envoy tap external/envoy/source/extensions/filters/http/tap/tap_config_impl.cc:172 submitting buffered trace sink thread=31
2025-05-24T08:08:47.713860Z debug envoy tap external/envoy/source/extensions/common/tap/admin.cc:145 admin submitting buffered trace to main thread thread=31
...
🎯 외부 호출 기반의 속도 제한 기능으로 Istio 데이터 플레인 확장
📈 적용 예: 글로벌 속도 제한(Global Rate Limiting)

✅ 특징

⚙️ 구성 요소
1. Envoy HTTP 필터 (Global Rate Limit Filter)
속도 제한 서버
Istio EnvoyFilter 리소스
🛑 주의점
요약하면, 이 절은 속도 제한 기능을 외부 서버와 연동해 Istio 데이터 플레인에 통합하는 방법을 설명하며, 이를 위해 EnvoyFilter, 속도 제한 서버, Redis 등을 활용합니다.

속성 카운터와 한도가 포함된 속도 제한 서버 설정을 만들어보자
우리 예제에서는 예제 조직에서 보유한 로열티 등급에 따라 특정 사용자 집단을 제한하고자 한다.
요청의 로열티 등급은 x-loyalty 헤더를 검사해 판단할 수 있다.
골드 등급(x-loyalty: gold)의 사용자 그룹에는 요청을 분당 10개까지 허용하고, 실버 등급(x-loyalty: silver)에는 요청을 분당 5개까지 허용한다. 또한 브론즈 등급(x-loyalty: bronze)에는 요청을 분당 3개까지 허용한다.
식별할 수 없는 로열티 등급의 경우, 분당 요청이 하나를 넘어가면 속도 제한이 처리를 제한한다.
요청이 디스크립터를 포착하는 속도 제한 서버 설정은 다음과 같이 표현할 수 있다.
# cat ch14/rate-limit/rlsconfig.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: catalog-ratelimit-config
namespace: istioinaction
data:
config.yaml: |
domain: catalog-ratelimit
descriptors:
- key: header_match
value: no_loyalty
rate_limit:
unit: MINUTE
requests_per_unit: 1
- key: header_match
value: gold_request
rate_limit:
unit: MINUTE
requests_per_unit: 10
- key: header_match
value: silver_request
rate_limit:
unit: MINUTE
requests_per_unit: 5
- key: header_match
value: bronze_request
rate_limit:
unit: MINUTE
requests_per_unit: 3
/items 경로로 호출하면 요청에 x-loyalty 헤더가 있는지와 어느 그룹에 속하는지를 포착하려고 한다.# cat ch14/rate-limit/catalog-ratelimit-actions.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: catalog-ratelimit-actions
namespace: istioinaction
spec:
workloadSelector:
labels:
app: catalog
configPatches:
- applyTo: VIRTUAL_HOST
match:
context: SIDECAR_INBOUND
routeConfiguration:
vhost:
route:
action: ANY
patch:
operation: MERGE
# Applies the rate limit rules.
value:
rate_limits: # 속도 제한 조치
- actions:
- header_value_match:
descriptor_value: no_loyalty
expect_match: false
headers:
- name: "x-loyalty"
- actions:
- header_value_match:
descriptor_value: bronze_request
headers:
- name: "x-loyalty"
exact_match: bronze
- actions:
- header_value_match:
descriptor_value: silver_request
headers:
- name: "x-loyalty"
exact_match: silver
- actions:
- header_value_match:
descriptor_value: gold_request
headers:
- name: "x-loyalty"
exact_match: gold
#
tree ch14/rate-limit
ch14/rate-limit
├── catalog-ratelimit-actions.yaml
├── catalog-ratelimit.yaml
├── rls.yaml
└── rlsconfig.yaml
cat ch14/rate-limit/rlsconfig.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: catalog-ratelimit-config
namespace: istioinaction
data:
config.yaml: |
domain: catalog-ratelimit
descriptors:
- key: header_match
value: no_loyalty
rate_limit:
unit: MINUTE
requests_per_unit: 1
- key: header_match
value: gold_request
rate_limit:
unit: MINUTE
requests_per_unit: 10
- key: header_match
value: silver_request
rate_limit:
unit: MINUTE
requests_per_unit: 5
- key: header_match
value: bronze_request
rate_limit:
unit: MINUTE
requests_per_unit: 3
cat ch14/rate-limit/rls.yaml
# Copyright Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: istioinaction
labels:
app: redis
spec:
ports:
- name: redis
port: 6379
selector:
app: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: istioinaction
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
labels:
app: redis
spec:
containers:
- image: redis:alpine
imagePullPolicy: IfNotPresent
name: redis
ports:
- name: redis
containerPort: 6379
restartPolicy: Always
serviceAccountName: ""
---
apiVersion: v1
kind: Service
metadata:
name: ratelimit
namespace: istioinaction
labels:
app: ratelimit
spec:
ports:
- name: http-port
port: 8080
targetPort: 8080
protocol: TCP
- name: grpc-port
port: 8081
targetPort: 8081
protocol: TCP
- name: http-debug
port: 6070
targetPort: 6070
protocol: TCP
selector:
app: ratelimit
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ratelimit
namespace: istioinaction
spec:
replicas: 1
selector:
matchLabels:
app: ratelimit
strategy:
type: Recreate
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
labels:
app: ratelimit
spec:
containers:
- image: envoyproxy/ratelimit:6f5de117
imagePullPolicy: IfNotPresent
name: ratelimit
command: ["/bin/ratelimit"]
env:
- name: LOG_LEVEL
value: debug
- name: REDIS_SOCKET_TYPE
value: tcp
- name: REDIS_URL
value: redis:6379
- name: USE_STATSD
value: "false"
- name: RUNTIME_ROOT
value: /data
- name: RUNTIME_SUBDIRECTORY
value: ratelimit
- name: RUNTIME_WATCH_ROOT
value: "false"
ports:
- containerPort: 8080
- containerPort: 8081
- containerPort: 6070
volumeMounts:
- name: config-volume
mountPath: /data/ratelimit/config/config.yaml
subPath: config.yaml
volumes:
- name: config-volume
configMap:
name: catalog-ratelimit-config
#
kubectl apply -f ch14/rate-limit/rlsconfig.yaml -n istioinaction
configmap/catalog-ratelimit-config created
kubectl apply -f ch14/rate-limit/rls.yaml -n istioinaction
service/redis created
deployment.apps/redis created
service/ratelimit created
deployment.apps/ratelimit created
# 확인
kubectl get cm -n istioinaction catalog-ratelimit-config
NAME DATA AGE
catalog-ratelimit-config 1 34s
kubectl get pod -n istioinaction
NAME READY STATUS RESTARTS AGE
catalog-6cf4b97d-8w4k9 2/2 Running 0 4h34m
ratelimit-99d5d9c5-prxsw 1/1 Running 2 (23s ago) 30s
redis-6cf4ff9768-xzsq8 1/1 Running 0 30s
sleep-6f8cfb8c8f-xtx4s 2/2 Running 0 4h34m
webapp-7685bcb84-bl7xq 2/2 Running 0 4h34m
# 기존에 반복 호출은 취소해두자
#
cat ch14/rate-limit/catalog-ratelimit.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: catalog-ratelimit-filter
namespace: istioinaction
spec:
workloadSelector:
labels:
app: catalog
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 3000
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: catalog-ratelimit
failure_mode_deny: true
rate_limit_service:
grpc_service:
envoy_grpc:
cluster_name: outbound|8081||ratelimit.istioinaction.svc.cluster.local
timeout: 10s
transport_api_version: V3
cat ch14/rate-limit/catalog-ratelimit-actions.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: catalog-ratelimit-actions
namespace: istioinaction
spec:
workloadSelector:
labels:
app: catalog
configPatches:
- applyTo: VIRTUAL_HOST
match:
context: SIDECAR_INBOUND
routeConfiguration:
vhost:
route:
action: ANY
patch:
operation: MERGE
# Applies the rate limit rules.
value:
rate_limits:
- actions:
- header_value_match:
descriptor_value: no_loyalty
expect_match: false
headers:
- name: "x-loyalty"
- actions:
- header_value_match:
descriptor_value: bronze_request
headers:
- name: "x-loyalty"
exact_match: bronze
- actions:
- header_value_match:
descriptor_value: silver_request
headers:
- name: "x-loyalty"
exact_match: silver
- actions:
- header_value_match:
descriptor_value: gold_request
headers:
- name: "x-loyalty"
exact_match: gold
kubectl apply -f ch14/rate-limit/catalog-ratelimit.yaml -n istioinaction
envoyfilter.networking.istio.io/catalog-ratelimit-filter created
kubectl apply -f ch14/rate-limit/catalog-ratelimit-actions.yaml -n istioinaction
envoyfilter.networking.istio.io/catalog-ratelimit-actions created
kubectl get envoyfilter -A
NAMESPACE NAME AGE
istio-system stats-filter-1.13 4h44m
istio-system stats-filter-1.14 4h44m
istio-system stats-filter-1.15 4h44m
istio-system stats-filter-1.16 4h44m
istio-system stats-filter-1.17 4h44m
istio-system tcp-stats-filter-1.13 4h44m
istio-system tcp-stats-filter-1.14 4h44m
istio-system tcp-stats-filter-1.15 4h44m
istio-system tcp-stats-filter-1.16 4h44m
istio-system tcp-stats-filter-1.17 4h44m
istioinaction catalog-ratelimit-actions 16s
istioinaction catalog-ratelimit-filter 29s
istioinaction tap-filter 4h24m
# sleep 앱에서 catalog 서비스를 호출 시도 : 대략 1분에 한 번 정도 호출 성공! >> x-loyalty 헤더가 없을 때 속도 제한 값!
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://catalog/items -v
* Host catalog:80 was resolved.
* IPv6: (none)
* IPv4: 10.200.3.112
* Trying 10.200.3.112:80...
* Connected to catalog (10.200.3.112) port 80
> GET /items HTTP/1.1
> Host: catalog
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 500 Internal Server Error
< date: Sat, 24 May 2025 12:28:00 GMT
< server: envoy
< content-length: 0
< x-envoy-upstream-service-time: 30
<
* Connection #0 to host catalog left intact
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://catalog/items -v
...
< HTTP/1.1 429 Too Many Requests
< x-envoy-ratelimited: true
...
# silver 헤더는?
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl -H "x-loyalty: silver" http://catalog/items -v
...
#
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'InboundPassthroughClusterIpv4'
NAME DOMAINS MATCH VIRTUAL SERVICE
InboundPassthroughClusterIpv4 * /*
InboundPassthroughClusterIpv4 * /*
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'InboundPassthroughClusterIpv4' -o json | grep actions
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||'
NAME DOMAINS MATCH VIRTUAL SERVICE
inbound|3000|| * /*
inbound|3000|| * /*
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||' -o json | grep actions
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
"actions": [
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||' -o json
...
"rateLimits": [
{
"actions": [
{
"headerValueMatch": {
"descriptorValue": "no_loyalty",
"expectMatch": false,
"headers": [
{
"name": "x-loyalty"
}
]
}
}
]
},
{
"actions": [
{
"headerValueMatch": {
"descriptorValue": "bronze_request",
"headers": [
{
"name": "x-loyalty",
"exactMatch": "bronze"
...

#
kubectl delete envoyfilter -n istioinaction --all
kubectl get envoyfilter -A
#
kubectl delete -f ch14/rate-limit/rlsconfig.yaml -n istioinaction
kubectl delete -f ch14/rate-limit/rls.yaml -n istioinaction
🎯 기본 Envoy 필터에 없는 기능을 커스텀 로직으로 구현
🔧 Lua 필터 개요
📌 Lua로 할 수 있는 일
⚠️ 주의사항
✅ 설정 방법

#
cat ch14/bucket-tester-service.yaml
...
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: bucket-tester
version: v1
name: bucket-tester
spec:
replicas: 1
selector:
matchLabels:
app: bucket-tester
version: v1
template:
metadata:
labels:
app: bucket-tester
version: v1
spec:
containers:
- image: hashicorp/http-echo:1.0 # 수정 https://hub.docker.com/r/hashicorp/http-echo/tags
imagePullPolicy: IfNotPresent
name: bucket-tester
args:
- "-text=dark-launch-7"
ports:
- containerPort: 5678
name: http
protocol: TCP
securityContext:
privileged: false
#
kubectl apply -f ch14/httpbin.yaml -n istioinaction
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created
kubectl apply -f ch14/bucket-tester-service.yaml -n istioinaction
service/bucket-tester created
deployment.apps/bucket-tester created
# 확인
kubectl get pod -n istioinaction
NAME READY STATUS RESTARTS AGE
bucket-tester-688c598b47-86fbr 2/2 Running 0 25s
httpbin-85d76b4bb6-dz6b5 2/2 Running 0 2m56s
...
envoy_on_reqest() 혹은 envoy_on_response() 를 구현해 요청과 응답 각각을 확인하고 조작할 수 있다.httpCall() 함수를 사용하면 외부 서비스와 통신할 수 있다. 다음 스크립트는 우리의 사용 사례를 구현한 것이다.# cat ch14/lua-filter.yaml
...
function envoy_on_request(request_handle)
local headers, test_bucket = request_handle:httpCall(
"bucket_tester",
{
[":method"] = "GET",
[":path"] = "/",
[":scheme"] = "http",
[":authority"] = "bucket-tester.istioinaction.svc.cluster.local",
["accept"] = "*/*"
}, "", 5000)
request_handle:headers():add("x-test-cohort", test_bucket)
end
function envoy_on_response(response_handle)
response_handle:headers():add("istioinaction", "it works!")
end
...
envoy_on_reqest() 함수를 구현하고, httpCall() 내장 함수를 사용해 외부 서비스와 통신하고 있다.httpCall() 포함한 내장 함수는 문서 참조 - Docs# cat ch14/lua-filter.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: httpbin-lua-extension
namespace: istioinaction
spec:
workloadSelector:
labels:
app: httpbin
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 80
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"
inlineCode: |
function envoy_on_request(request_handle) # 아래 줄에 코드 입력
local headers, test_bucket = request_handle:httpCall(
"bucket_tester",
{
[":method"] = "GET",
[":path"] = "/",
[":scheme"] = "http",
[":authority"] = "bucket-tester.istioinaction.svc.cluster.local",
["accept"] = "*/*"
}, "", 5000)
request_handle:headers():add("x-test-cohort", test_bucket)
end
function envoy_on_response(response_handle) # 아래 줄에 코드 입력
response_handle:headers():add("istioinaction", "it works!")
end
- applyTo: CLUSTER
match:
context: SIDECAR_OUTBOUND
patch:
operation: ADD
value: # cluster specification
name: bucket_tester
type: STRICT_DNS
connect_timeout: 0.5s
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: bucket_tester
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
protocol: TCP
address: bucket-tester.istioinaction.svc.cluster.local
port_value: 80
#
kubectl apply -f ch14/lua-filter.yaml
kubectl get envoyfilter -n istioinaction
# istio-proxy config 확인 내용 추가해두자
# httpbin 서비스 호출 확인!
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://httpbin.istioinaction:8000/ -v
...
< HTTP/1.1 503 Service Unavailable
< content-length: 39
< content-type: text/plain
< istioinaction: it works!
< date: Sun, 18 May 2025 07:59:34 GMT
< server: envoy
< x-envoy-upstream-service-time: 51
...
invalid header value for: x-test-cohort
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://httpbin.istioinaction:8000/headers
...
invalid header value for: x-test-cohort
# 정상 실습 시..
{
"headers": {
"Accept": "*/*",
"Content-Length": "0",
"Host": "httpbin.istioinaction:8000",
"User-Agent": "curl/7.69.1",
"X-B3-Sampled": "1",
"X-B3-Spanid": "1d066f4b17ee147b",
"X-B3-Traceid": "1ec27110e4141e131d066f4b17ee147b",
"X-Test-Cohort": "dark-launch-7" # A/B 테스트 서비스를 호출할 때 덧붙이는 새 헤더 x-test-cohort 가 보임
}
}
ch14/lua-filter.yaml 파일에서 살펴볼 수 있다.#
kubectl delete envoyfilter -n istioinaction --all
kubectl get envoyfilter -A
#
kubectl delete -f ch14/httpbin.yaml -n istioinaction
kubectl delete -f ch14/bucket-tester-service.yaml -n istioinaction