[7주차] 조직에서 Istio 확장 : 멀티 클러스터, 멀티 네트워크, 멀티 Control Plane 의 Service Mesh 개요
🌐 멀티 클러스터 서비스 메시 개요
- 두 개의 클러스터(west-cluster, east-cluster)가 서로 다른 지역과 네트워크에 위치한 구조
- west-cluster: us-west 지역에 위치한 Kubernetes 클러스터로, 자체 private network를 가지고 있어요. 여기서는 webapp 서비스를 실행합니다.
- east-cluster: us-east 지역에 위치한 Kubernetes 클러스터로, 역시 자체 private network를 사용해요. 여기서는 catalog 서비스를 실행합니다.
- 이처럼 두 클러스터를 서로 다른 지역에 배치하면 한 지역에서 재해가 발생하더라도 서비스 중단을 방지할 수 있습니다.
서로 다른 지역에 위치한 west-cluster와 east-cluster는 각각 webapp과 catalog 서비스를 실행하며,
지역별 재해로부터 서비스를 보호합니다.
🚀 멀티 클러스터 배포 모델 선택하기
- 멀티 네트워크 환경에서는 클러스터 간 통신을 가능하게 하기 위해 east-west gateway가 필요합니다.
이 gateway는 서로 다른 네트워크를 연결하는 다리 역할을 합니다 - 컨트롤 플레인 배포 모델은 비즈니스 요구사항에 따라 달라집니다. 고가용성(high availability) 이 최우선순위입니다.
이를 위해 primary-primary 배포 모델을 선택합니다. 이 모델에서는 각 클러스터에 독립적인 Istio 컨트롤 플레인을 배포합니다.- 멀티 클러스터: west-cluster와 east-cluster.
- 멀티 네트워크: east-west gateway로 네트워크 연결.
- 멀티 컨트롤 플레인: 각 클러스터에 Istio 컨트롤 플레인 배포.
고가용성을 위해 primary-primary 배포 모델을 선택하고,
east-west gateway를 사용해 멀티 네트워크를 연결합니다.
📌 핵심 요약
- west-cluster와 east-cluster는 각각 us-west와 us-east 지역에 위치하며, webapp과 catalog 서비스를 실행
- 두 클러스터를 다른 지역에 배치해 재해로부터 서비스를 보호합니다.
- 멀티 네트워크 환경에서는 east-west gateway를 사용해 클러스터 간 연결을 설정
- 고가용성을 위해 primary-primary 배포 모델을 선택해 각 클러스터에 독립적인 Istio 컨트롤 플레인을 배포합니다.
- 이 구조는 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
Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
$ 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'
- 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
Creating cluster "east" ...
✓ Ensuring node image (kindest/node:v1.23.17) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-east"
You can now use your cluster with:
kubectl cluster-info --context kind-east --kubeconfig ./east-kubeconfig
Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
$ 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'
- kind docker network 에 테스트용 PC(실제로는 컨테이너) 배포
# mypc 컨테이너 기동 : kind 도커 브리지를 사용하고, 컨테이너 IP를 지정 해서 사용
$ docker run -d --rm --name mypc --network kind --ip 172.18.0.100 nicolaka/netshoot sleep infinity
# 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
- MetalLB 배포
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml \
--kubeconfig=./west-kubeconfig
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml \
--kubeconfig=./east-kubeconfig
# 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
ipaddresspool.metallb.io/default created
l2advertisement.metallb.io/default created
# 확인
$ 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
# 외부(mypc)에서 각 클러스터의 Service(LB)로 접속(인입) 확인
$ 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}')
$ docker exec -it mypc curl -s $WNIP
$ docker exec -it mypc curl -s $ENIP
# 확인 후 삭제
$ kubectl delete deploy,svc --all --kubeconfig=./west-kubeconfig
$ kubectl delete deploy,svc --all --kubeconfig=./east-kubeconfig
⚙️ 편리한 alias 설정하기
- 매번 context를 입력하는 건 번거로워 이를 간단하게 하기 위해 alias를 설정합니다.
$ 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'
- 이제 긴 명령어 대신 간단하게 다음을 사용할 수 있습니다
$ kwest get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-bd6b6df9f-4k5nw 1/1 Running 0 15m
coredns-bd6b6df9f-w6s6j 1/1 Running 0 15m
etcd-west-control-plane 1/1 Running 0 15m
kindnet-bpwnl 1/1 Running 0 15m
kube-apiserver-west-control-plane 1/1 Running 0 15m
kube-controller-manager-west-control-plane 1/1 Running 0 15m
kube-proxy-vrjlk 1/1 Running 0 15m
kube-scheduler-west-control-plane 1/1 Running 0 15m
$ keast get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-bd6b6df9f-nz6pl 1/1 Running 0 12m
coredns-bd6b6df9f-zss82 1/1 Running 0 12m
etcd-east-control-plane 1/1 Running 0 12m
kindnet-2p4jm 1/1 Running 0 12m
kube-apiserver-east-control-plane 1/1 Running 0 12m
kube-controller-manager-east-control-plane 1/1 Running 0 12m
kube-proxy-448mv 1/1 Running 0 12m
kube-scheduler-east-control-plane 1/1 Running 0 12m
alias(kwest, keast)를 설정해 kubectl 명령어를 간소화하여 클러스터 관리를 더 쉽게 만듭니다.
📌 핵심 요약
- 멀티 클러스터 환경은 두 개의 Kubernetes 클러스터(west-cluster, east-cluster)를 서로 다른 네트워크에 생성합니다.
- alias(kwest, keast)를 설정해 kubectl 명령어를 간소화하여 효율적으로 클러스터를 관리할 수 있습니다.
🔒 플러그인 CA 인증서 설정하기
- 멀티 클러스터 환경에서 서비스 메시를 안전하게 운영하려면 클러스터 간 신뢰를 구축하는 것이 중요합니다. 이를 위해 플러그인 CA 인증서를 설정해야 합니다.
- cacerts 시크릿은 root CA의 공개 키 와 intermediate CA의 공개 및 개인 키로 구성됩니다.
root CA의 개인 키는 클러스터 외부에 안전하게 저장됩니다.
🛡️ 플러그인 CA 인증서란?
- Istio는 설치 시 자동으로 CA(Certificate Authority)를 생성해 워크로드의 인증서를 서명합니다. 이 CA는 istio-ca-secret이라는 시크릿으로 Istio 설치 네임스페이스에 저장되고, istiod replicas와 공유됩니다. 하지만 기본 동작을 커스터마이징하고 싶다면, 직접 만든 CA를 플러그인으로 사용할 수 있어요. 이렇게 하면 Istio가 새 CA를 생성하는 대신 우리가 제공한 CA를 사용합니다.
- 플러그인 CA를 사용하려면 cacerts라는 이름의 시크릿을 istio-system 네임스페이스에 저장해야 합니다. 이 시크릿에는 다음 네 가지 파일이 포함됩니다:
- ca-cert.pem: intermediate CA의 인증서.
- ca-key.pem: intermediate CA의 개인 키.
- root-cert.pem: intermediate CA를 발급한 root CA의 인증서. 이 root CA는 모든 intermediate CA가 발급한 인증서를 검증하며, 클러스터 간 상호 신뢰를 구축하는 핵심 역할을 합니다.
- cert-chain.pem: intermediate CA 인증서와 root CA 인증서를 연결한 신뢰 체인.
- 이 인증서들은 ./ch12/certs 디렉토리에 생성됩니다. ./ch12/scripts/generate-certificates.sh 스크립트를 실행하면 root CA와 두 개의 intermediate 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
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
플러그인 CA를 사용하면 Istio가 기본 CA 대신 사용자 정의 CA를 사용하며,
cacerts 시크릿에 네 가지 인증서 파일을 저장해야 합니다.
⚙️ 클러스터에 플러그인 CA 인증서 적용하기
- 이제 각 클러스터에 intermediate CA를 설정해 보겠습니다. 먼저 istio-system 네임스페이스를 생성하고, cacerts 시크릿을 만들어 인증서를 적용합니다. 아래 명령어를 사용해 west-cluster와 east-cluster에 각각 설정해 봅시다.
- west-cluster 설정:
$ kwest create namespace istio-system
namespace/istio-system created
$ 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
secret/cacerts created
- east-cluster 설정:
$ keast create namespace istio-system
namespace/istio-system created
$ 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
secret/cacerts created
- 이 명령어들은 각 클러스터의 istio-system 네임스페이스에 cacerts 시크릿을 생성하고, 필요한 인증서 파일을 추가합니다. 이렇게 설정된 인증서는 Istio 컨트롤 플레인이 워크로드 인증서를 서명할 때 사용됩니다.
각 클러스터에 istio-system 네임스페이스를 만들고,
cacerts 시크릿을 생성해 플러그인 CA 인증서를 적용합니다.
📌 핵심 요약
- Istio는 기본적으로 CA를 생성하지만, cacerts 시크릿에 사용자 정의 CA를 저장해 플러그인 CA로 사용할 수 있습니다.
- cacerts 시크릿은 ca-cert.pem, ca-key.pem, root-cert.pem, cert-chain.pem 네 가지 파일로 구성되며, istio-system 네임스페이스에 저장됩니다.
- ./ch12/scripts/generate-certificates.sh 스크립트를 사용해 root CA와 두 개의 intermediate CA를 생성하며, 이들은 공통 신뢰를 공유합니다.
- 각 클러스터(west-cluster, east-cluster)에 cacerts 시크릿을 적용해 플러그인 CA를 설정합니다.
🛠️ 각 클러스터에 Istio 컨트롤 플레인 설치하기
- 멀티 클러스터 환경에서 서비스 메시를 완성하려면 각 클러스터에 Istio 컨트롤 플레인을 설치해야 해요. 이 과정에서 클러스터 간 네트워크 토폴로지를 설정하고, 워크로드를 배포해 클러스터 간 연결을 준비합니다.
- west-cluster와 east-cluster에 각각 컨트롤 플레인이 설치된 상태. 아직 클러스터 간 워크로드 발견 및 연결은 설정되지 않음.
🌐 클러스터 간 연결을 위한 네트워크 라벨링
- Istio가 클러스터의 네트워크 구조를 이해하도록 network metadata를 추가합니다. 이를 통해 Istio는 워크로드의 위치 정보를 활용해 트래픽을 효율적으로 라우팅할 수 있습니다. 예를 들어, 가까운 워크로드는 우선적으로 연결하고, 다른 네트워크에 있는 워크로드에는 east-west gateway를 사용해 트래픽을 보냅니다.
- 네트워크 토폴로지를 설정하는 방법 중 하나는 MeshNetwork 설정을 사용하는 것이지만, 이건 복잡한 경우에만 필요합니다. 여기서는 더 간단한 방법인 네임스페이스 라벨링을 사용합니다. west-cluster의 네트워크는 west-network, east-cluster의 네트워크는 east-network로 설정합니다.
- west-cluster 설정:
$ kwest label namespace istio-system topology.istio.io/network=west-network
namespace/istio-system labeled
- east-cluster 설정:
$ keast label namespace istio-system topology.istio.io/network=east-network
namespace/istio-system labeled
- 이 라벨을 추가하면 Istio가 네트워크 토폴로지를 이해하고, 워크로드 설정 시 이를 반영합니다.
istio-system 네임스페이스에 네트워크 라벨을 추가해
Istio가 클러스터의 네트워크 토폴로지를 인식하도록 설정합니다.
🚀 IstioOperator로 컨트롤 플레인 설치하기
- Istio 설치는 IstioOperator 리소스를 사용해 커스터마이징합니다.
$ cat ./ch12/controlplanes/cluster-west.yaml
apiVersion: install.istio.io/v1alpha1
metadata:
name: istio-controlplane
namespace: istio-system
kind: IstioOperator
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
metadata:
name: istio-controlplane
namespace: istio-system
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: JSON
values:
global:
meshID: usmesh
multiCluster:
clusterName: east-cluster
network: east-network
- demo 프로파일을 사용해 기본 Istio 설정을 적용합니다.
- egress gateway를 비활성화합니다.
- meshID: usmesh로 메시를 식별합니다. (Kubernetes 클러스터는 여러 팀이 사용할 수 있으므로, meshID로 특정 메시를 구분해요.)
- clusterName과 network로 클러스터와 네트워크를 정의합니다.
- west-cluster 설치
# west-control-plane 진입
$ docker exec -it west-control-plane bash
# istioctl 설치
root@west-control-plane:/# export ISTIOV=1.17.8
root@west-control-plane:/# echo 'export ISTIOV=1.17.8' >> /root/.bashrc
root@west-control-plane:/# curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
Downloading istio-1.17.8 from https://github.com/istio/istio/releases/download/1.17.8/istio-1.17.8-linux-amd64.tar.gz ...
Istio 1.17.8 download complete!
The Istio release archive has been downloaded to the istio-1.17.8 directory.
To configure the istioctl client tool for your workstation,
add the /istio-1.17.8/bin directory to your environment path variable with:
export PATH="$PATH:/istio-1.17.8/bin"
Begin the Istio pre-installation check by running:
istioctl x precheck
Try Istio in ambient mode
https://istio.io/latest/docs/ambient/getting-started/
Try Istio in sidecar mode
https://istio.io/latest/docs/setup/getting-started/
Install guides for ambient mode
https://istio.io/latest/docs/ambient/install/
Install guides for sidecar mode
https://istio.io/latest/docs/setup/install/
Need more information? Visit https://istio.io/latest/docs/
root@west-control-plane:/# cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
# IstioOperator 파일 작성
root@west-control-plane:/# 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
# 컨트롤 플레인 배포
root@west-control-plane:/# istioctl install -f west-istio.yaml --set values.global.proxy.privileged=true -y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete Making this installation the default for injection and validation.
Thank you for installing Istio 1.17. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/hMHGiwZHPU7UQRWe9
# 보조 도구 설치
root@west-control-plane:/# kubectl apply -f istio-$ISTIOV/samples/addons
# 빠져나오기
exit
# 설치 확인
$ kwest get istiooperators -n istio-system -o yaml
...
meshID: usmesh
meshNetworks: {}
mountMtlsCerts: false
multiCluster:
clusterName: west-cluster
enabled: false
network: west-network
...
# istio-ingressgateway 서비스 : NodePort 변경 및 nodeport 지정 변경 , externalTrafficPolicy 설정
kwest patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "LoadBalancer", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kwest patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kwest describe svc -n istio-system istio-ingressgateway
# 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}]}}'
service/prometheus patched
service/grafana patched
service/kiali patched
service/tracing patched
- east-cluster의 설정은 ./ch12/controlplanes/cluster-east.yaml에 정의되어 있으며, clusterName과 network만 다릅니다.
동일한 meshID: usmesh를 사용해 두 클러스터가 같은 메시를 형성하도록 합니다:
- east-cluster 설치
# east-control-plane 진입 후 설치 진행
$ docker exec -it east-control-plane bash
root@east-control-plane:/#
# istioctl 설치
root@east-control-plane:/# export ISTIOV=1.17.8
echo 'export ISTIOV=1.17.8' >> /root/.bashrc
root@east-control-plane:/# curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
# IstioOperator 파일 작성
root@east-control-plane:/# 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
# NodePort 변경 및 nodeport 31001~31003으로 변경
$ 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}]}}'
service/prometheus patched
service/grafana patched
service/kiali patched
service/tracing patched
- istioctl에도 alias를 설정합니다
$ alias iwest='docker exec -it west-control-plane istioctl'
$ alias ieast='docker exec -it east-control-plane istioctl'
- 이제 두 클러스터에 각각 컨트롤 플레인이 설치되었고, 각 메시에는 istiod replica와 ingress gateway가 포함되어 있습니다. 하지만 아직 클러스터 간 워크로드 발견과 연결은 설정되지 않았습니다.
IstioOperator를 사용해 west-cluster와 east-cluster에 컨트롤 플레인을 설치하고,
동일한 meshID로 같은 메시를 형성합니다.
⚙️ 워크로드 배포하기
west-cluster: webapp 배포
- west-cluster에는 webapp 서비스를 배포합니다.
$ kwest create ns istioinaction
namespace/istioinaction created
$ kwest label namespace istioinaction istio-injection=enabled
namespace/istioinaction labeled
$ kwest -n istioinaction apply -f ch12/webapp-deployment-svc.yaml
serviceaccount/webapp created
service/webapp created
deployment.apps/webapp created
$ kwest -n istioinaction apply -f ch12/webapp-gw-vs.yaml
gateway.networking.istio.io/coolstore-gateway created
virtualservice.networking.istio.io/webapp-virtualservice created
$ kwest -n istioinaction apply -f ch12/catalog-svc.yaml
service/catalog created
- istioinaction 네임스페이스를 생성하고, istio-injection=enabled 라벨을 추가해 워크로드에 sidecar proxy를 자동 주입합니다.
- webapp-deployment-svc.yaml: webapp과 해당 서비스를 배포합니다.
- webapp-gw-vs.yaml: ingress gateway를 통해 트래픽을 허용하는 Gateway와 VirtualService를 설정합니다.
- catalog-svc.yaml: catalog 서비스의 stub 서비스를 추가합니다.
- 왜 stub 서비스가 필요할까요? webapp은 east-cluster의 catalog 서비스에 요청을 보내지만, west-cluster에서 catalog의 FQDN(Fully Qualified Domain Name)을 확인할 수 없으면 요청이 실패해요.
stub 서비스는 FQDN을 클러스터 IP로 변환해 요청을 시작할 수 있게 하고, 이후 Envoy proxy가 클러스터 간 라우팅을 처리합니다. 이건 Istio의 DNS proxy 개선 전까지 필요한 임시 해결책이에요.
east-cluster: catalog 배포
- east-cluster에는 catalog 서비스를 배포합니다:
$ keast create ns istioinaction
namespace/istioinaction created
$ keast label namespace istioinaction istio-injection=enabled
namespace/istioinaction labeled
$ keast -n istioinaction apply -f ch12/catalog.yaml
serviceaccount/catalog created
service/catalog created
deployment.apps/catalog created
west-cluster에 webapp과 stub catalog 서비스를,
east-cluster에 catalog 서비스를 배포해 클러스터 간 연결 테스트를 준비합니다.
📌 핵심 요약
- 네트워크 라벨링을 통해 Istio가 클러스터의 네트워크 토폴로지(west-network, east-network)를 이해하도록 설정합니다.
- IstioOperator 리소스를 사용해 west-cluster와 east-cluster에 컨트롤 플레인을 설치하며, 동일한 meshID: usmesh로 같은 메시를 형성합니다.
- west-cluster에는 webapp과 stub catalog 서비스를, east-cluster에는 catalog 서비스를 배포합니다.
- stub catalog 서비스는 west-cluster에서 FQDN 확인 문제를 해결해 클러스터 간 라우팅을 가능하게 합니다.
🔗 클러스터 간 워크로드 발견 활성화하기
- 멀티 클러스터 환경에서 Istio가 제대로 작동하려면 각 클러스터의 컨트롤 플레인이 다른 클러스터의 워크로드를 발견할 수 있어야 합니다. 이를 위해 클러스터 간 워크로드 발견(cross-cluster workload discovery) 을 설정합니다. Istio가 원격 클러스터의 정보를 안전하게 조회할 수 있도록 인증과 권한을 설정하는 작업입니다.
🛡️ 원격 클러스터 접근을 위한 서비스 계정
- Istio는 설치 시 istio-reader-service-account 라는 서비스 계정을 자동으로 생성해요. 이 계정은 원격 클러스터의 워크로드 정보(예: 서비스, 엔드포인트)를 조회할 수 있는 최소한의 권한을 가지고 있습니다. 하지만 이 서비스 계정의 토큰과 인증서를 반대쪽 클러스터에 제공해야 Istio가 안전하게 원격 클러스터에 접근할 수 있어요.
- 이 작업은 istioctl의 create-remote-secret 명령어로 쉽게 처리할 수 있습니다. 이 명령어는 원격 클러스터 접근에 필요한 시크릿을 생성하며, IstioOperator 설정에서 지정한 클러스터 이름을 사용합니다. (예: west-cluster, east-cluster).
Istio는 istio-reader-service-account를 사용해 원격 클러스터 정보를 조회하며,
이를 위해 토큰과 인증서가 포함된 시크릿이 필요합니다.
⚙️ 원격 클러스터 접근을 위한 시크릿 생성
- create-remote-secret 명령어는 원격 클러스터에 접근하기 위한 kubeconfig 형식의 시크릿을 생성합니다.
이 시크릿에는 다음 정보가 포함:- clusters: 클러스터 주소와 API 서버의 연결을 검증하는 CA 데이터.
- users: API 서버에 인증하기 위한 토큰.
- contexts: 사용자와 클러스터를 그룹화해 클러스터 전환을 쉽게 함(여기서는 중요하지 않음).
- east-cluster에서 시크릿을 생성
$ 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"
name: istio-remote-secret-east-cluster
namespace: istio-system
stringData:
east-cluster: |
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ...
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: ...
- 이 시크릿을 west-cluster에 적용하려면 출력된 결과를 kubectl로 파이프해 적용합니다:
$ ieast x create-remote-secret --name="east-cluster" | kwest apply -f -
secret/istio-remote-secret-east-cluster created
- 시크릿이 적용되면 west-cluster의 istiod가 east-cluster의 워크로드를 조회하기 시작해요.
이를 확인하려면 istiod 로그를 확인하면 됩니다:
$ kwest logs deploy/istiod -n istio-system | grep 'Adding cluster'
2025-05-19T04:29:38.274445Z info Adding cluster cluster=east-cluster secret=istio-system/istio-remote-secret-east-cluster
- 로그에서 east-cluster가 추가되었음을 확인할 수 있습니다.
이제 west-cluster의 컨트롤 플레인이 east-cluster의 워크로드를 발견할 수 있습니다.
east-cluster에서 생성한 시크릿을 west-cluster에 적용해
west-cluster가 east-cluster의 워크로드를 발견할 수 있게 합니다.
🔄 반대 방향 설정: west-cluster 시크릿 생성
- primary-primary 배포 모델에서는 양방향 워크로드 발견이 필요합니다. 따라서 west-cluster에서도 시크릿을 생성해 east-cluster에 적용해야 합니다:
$ iwest x create-remote-secret --name="west-cluster" | keast apply -f -
secret/istio-remote-secret-west-cluster created
$ keast logs deploy/istiod -n istio-system | grep 'Adding cluster'
2025-05-19T04:31:03.352683Z info Adding cluster cluster=west-cluster secret=istio-system/istio-remote-secret-west-cluster
- 이제 east-cluster의 istiod도 west-cluster의 워크로드를 조회할 수 있어요. 이를 통해 양쪽 컨트롤 플레인이 서로의 워크로드를 발견할 수 있는 상태가 되었습니다.
west-cluster에서 생성한 시크릿을 east-cluster에 적용해
양방향 워크로드 발견을 활성화합니다..
📌 핵심 요약
- Istio는 istio-reader-service-account를 사용해 원격 클러스터의 워크로드 정보를 조회합니다.
- istioctl x create-remote-secret 명령어로 원격 클러스터 접근을 위한 kubeconfig 형식의 시크릿을 생성합니다.
- east-cluster의 시크릿을 west-cluster에, west-cluster의 시크릿을 east-cluster에 적용해 양방향 워크로드 발견을 활성화합니다.
- istiod 로그를 통해 워크로드 발견이 성공적으로 설정되었는지 확인할 수 있습니다.
🌐 클러스터 간 연결 설정하기
- 이제 클러스터 간 워크로드 발견이 설정되었으니, 워크로드가 서로 통신할 수 있도록 클러스터 간 연결(cross-cluster connectivity) 을 설정합니다. 이 과정은 Istio의 east-west gateway를 사용해 클러스터 간 트래픽을 안전하고 효율적으로 라우팅하는 작업입니다.
- North-South 트래픽은 외부에서 내부 네트워크로 들어오는 트래픽이고,
East-West 트래픽은 내부 네트워크 간(예: 클러스터 간) 트래픽입니다.
🛠️ East-West 트래픽이란?
- Istio의 ingress gateway는 외부 네트워크에서 내부 네트워크로 들어오는 north-south 트래픽을 처리합니다. 반면, 클러스터 간 트래픽은 east-west 트래픽이라고 부르며, 서로 다른 내부 네트워크(예: west-cluster와 east-cluster의 네트워크) 간 통신을 의미해요.
- 클라우드 제공자는 network peering을 통해 east-west 트래픽을 간단히 처리할 수 있지만, 이는 네트워크 주소가 겹치지 않을 때만 가능해요. 만약 서로 다른 클라우드 제공자나 온프레미스 환경이라면 network peering이 불가능할 수 있습니다. 이 경우 Istio의 east-west gateway를 사용해 클러스터 간 연결을 설정합니다. 이 gateway는 load balancer를 통해 외부에서 접근 가능해야 해요.
East-west 트래픽은 클러스터 간 내부 네트워크 통신을 의미하며,
Istio의 east-west gateway로 이를 처리합니다.
🚀 East-West Gateway의 역할
- East-west gateway는 클러스터 간 트래픽을 처리하는 ingress gateway로, 다음과 같은 목표를 가지고 있어요:
- 클러스터 간 fine-grained traffic management를 지원.
- 워크로드 간 mutual authentication을 위해 암호화된 트래픽을 라우팅.
- 추가 Istio 리소스 설정 없이 투명하게 동작.
- 즉, 클러스터 내 트래픽과 클러스터 간 트래픽을 동일한 방식으로 관리할 수 있어야 해요. 이를 구현하기 위해 Istio는 SNI clusters 와 SNI auto passthrough라는 두 가지 기능을 사용합니다.
- 1. 클러스터 정보가 SNI에 인코딩됩니다.
- 2. SNI에는 direction, port, version, service name이 포함되어 라우팅 결정을 돕습니다.
East-west gateway는 클러스터 간 트래픽을 투명하게 관리하며,
SNI clusters와 SNI auto passthrough로 이를 구현합니다.
⚙️ SNI Clusters로 East-West Gateway 설정하기
- SNI clusters는 Envoy 클러스터 와 비슷하지만, 모든 클러스터 정보(direction, subset, port, FQDN)를 SNI(Server Name Indication) 에 인코딩합니다. 이를 통해 gateway는 클라이언트가 요청한 클러스터를 SNI에서 읽고, 암호화된 트래픽을 정확한 워크로드로 프록시할 수 있어요.
- 예를 들어, west-cluster의 webapp이 east-cluster의 catalog 워크로드에 연결할 때, SNI에 다음 정보가 포함됩니다:
outbound|80|version-v1|catalog.istioinaction.svc.cluster.local
- east-west gateway는 이 SNI를 읽어 트래픽을 catalog 워크로드로 라우팅합니다.
- east-west gateway를 설치하려면 IstioOperator 리소스를 사용해 sni-dnat 모드를 활성화합니다.
east-cluster의 설정은 ./ch12/gateways/cluster-east-eastwest-gateway.yaml에 정의
$ 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
- name: 컨트롤 플레인 설치와 겹치지 않도록 istio-eastwestgateway로 설정.
- profile: empty: 추가 Istio 컴포넌트를 설치하지 않음.
- ISTIO_META_ROUTER_MODE: sni-dnat: SNI clusters를 자동 설정.
- ISTIO_META_REQUESTED_NETWORK_VIEW: east-network: 트래픽을 라우팅할 네트워크.
- 설치
$ docker cp ./ch12/gateways/cluster-east-eastwest-gateway.yaml east-control-plane:/cluster-east-eastwest-gateway.yaml
Successfully copied 3.07kB to 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
Thank you for installing Istio 1.17. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/hMHGiwZHPU7UQRWe9
east-west gateway를 sni-dnat 모드로 설치해 SNI clusters를 설정하고,
클러스터 간 트래픽 라우팅을 준비합니다.
🔄 SNI Auto Passthrough로 트래픽 라우팅
- 일반 SNI passthrough는 ingress gateway가 SNI 헤더를 기반으로 트래픽을 허용하지만, 트래픽 라우팅을 위해 VirtualService를 수동으로 정의해야 합니다.
반면, SNI auto passthrough는 sni-dnat 모드에서 SNI clusters를 자동으로 설정해 VirtualService 없이도 트래픽을 라우팅합니다.
SNI Passthrough 트래픽 라우팅
- SNI passthrough는 VirtualService를 수동으로 정의해야 트래픽을 라우팅합니다.
SNI Auto Passthrough 트래픽 라우팅
- SNI auto passthrough는 sni-dnat 모드에서 SNI clusters를 사용해 자동으로 트래픽을 라우팅합니다.
- SNI auto passthrough는 Gateway 리소스로 설정합니다.
./ch12/gateways/expose-services.yaml에 정의된 설정:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: cross-network-gateway
namespace: istio-system
spec:
selector: #이 Gateway가 어떤 파드(Pod)를 선택하여 트래픽을 처리할지 정의
istio: eastwestgateway #istio: eastwestgateway라는 레이블을 가진 파드를 선택
servers: #이 Gateway가 리슨(listen)할 서버 설정을 정의
- port: #이 서버가 리슨할 포트 설정을 정의
number: 15443 #Gateway가 포트 15443에서 트래픽을 수신
name: tls #이 포트의 이름
protocol: TLS #이 포트에서 사용하는 프로토콜을 TLS로 설정
tls:
mode: AUTO_PASSTHROUGH #TLS 암호화된 트래픽을 Gateway에서 복호화하지 않고 그대로 통과(passthrough)
hosts: #이 서버가 처리할 호스트(도메인) 이름을 정의
- "*.local" #.local로 끝나는 모든 서브도메인에 대한 트래픽을 이 Gateway가 처리
- port: 15443: 멀티 클러스터 mTLS 트래픽을 위한 Istio의 특수 포트.
- tls: AUTO_PASSTHROUGH: SNI 헤더를 기반으로 트래픽을 자동 라우팅.
- hosts: "*.local": Kubernetes 서비스의 SNI(*.local)와 매칭되는 트래픽을 허용.
- east-cluster에 적용:
$ keast apply -n istio-system -f ch12/gateways/expose-services.yaml
gateway.networking.istio.io/cross-network-gateway created
- west-cluster에도 동일하게 east-west gateway와 Gateway 리소스를 설정합니다:
$ docker cp ./ch12/gateways/cluster-west-eastwest-gateway.yaml west-control-plane:/cluster-west-eastwest-gateway.yaml
Successfully copied 3.07kB to west-control-plane:/cluster-west-eastwest-gateway.yaml
$ iwest install -f /cluster-west-eastwest-gateway.yaml --set values.global.proxy.privileged=true -y
✔ Ingress gateways installed
✔ Installation complete
Thank you for installing Istio 1.17. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/hMHGiwZHPU7UQRWe9
SNI auto passthrough를 설정해
VirtualService 없이 클러스터 간 트래픽을 자동으로 라우팅합니다.
🔍 SNI Clusters 확인
- east-west gateway에 SNI clusters가 제대로 설정되었는지 확인해 봅시다.
catalog 워크로드와 관련된 클러스터를 조회:
$ 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 clusters가 설정되었음을 알 수 있습니다.
Istio 컨트롤 플레인은 이 리소스를 감지하고, 원격 클러스터의 엔드포인트를 워크로드에 업데이트합니다.
SNI clusters가 east-west gateway에 설정되었는지 확인해
클러스터 간 라우팅 준비를 점검합니다.
✅ 클러스터 간 워크로드 발견 검증
- 이제 east-cluster의 워크로드가 west-cluster에 노출되었는지 확인할 차례예요.
west-cluster의 webapp이 east-cluster의 catalog 워크로드에 접근할 때, catalog 엔드포인트는 east-cluster의 east-west gateway 주소를 가리켜야 합니다. - east-cluster의 east-west gateway 주소를 확인합니다:
$ keast -n istio-system get svc istio-eastwestgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
172.18.255.202
- west-cluster의 webapp 프록시 설정을 확인해 catalog 엔드포인트를 조회합니다:
$ iwest pc endpoints deploy/webapp.istioinaction | grep catalog
172.18.255.202:15443 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
Catalog 엔드포인트와 East-West Gateway
- catalog 엔드포인트가 east-west gateway의 멀티 클러스터 포트를 가리킵니다.
- catalog 엔드포인트가 east-west gateway 주소와 일치하면 워크로드 발견과 클러스터 간 트래픽 설정이 완료
- 마지막으로, 요청을 수동으로 보내 최종 검증
$ 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"
},
...
- 성공! 요청이 west-cluster의 ingress gateway를 통해 webapp으로 라우팅되고, east-cluster의 catalog 워크로드로 전달되어 응답을 받았습니다. 이로써 멀티 클러스터, 멀티 네트워크, 멀티 컨트롤 플레인 서비스 메시가 완성되었으며, 워크로드 간 상호 인증된 연결이 가능해졌습니다.
- kiali : west-cluster
- kiali : east-cluster => mTLS 통신이며 TCP Traffic 와 HTTP(S) 2개 트래픽 흐름으로 확인됨.
클러스터 간 워크로드 발견과 연결을 검증해 서비스 메시가 제대로 작동함을 확인합니다.
📌 핵심 요약
- East-west 트래픽은 클러스터 간 내부 네트워크 통신이며, Istio의 east-west gateway로 처리됩니다.
- SNI clusters는 클러스터 정보를 SNI에 인코딩해 암호화된 트래픽을 정확한 워크로드로 라우팅합니다.
- SNI auto passthrough는 VirtualService 없이 SNI clusters를 사용해 트래픽을 자동 라우팅합니다.
- east-west gateway는 sni-dnat 모드로 설치하며, Gateway 리소스로 포트 15443에서 *.local SNI 트래픽을 허용합니다.
- 클러스터 간 워크로드 발견과 연결은 east-west gateway 주소와 엔드포인트 확인, 그리고 실제 요청 테스트로 검증됩니다.
- 멀티 클러스터 서비스 메시 설정은 워크로드 발견, 연결 설정, 공통 신뢰 구축의 세 단계로 완료됩니다.
⚖️ 클러스터 간 로드 밸런싱
- 이제 멀티 클러스터 서비스 메시가 완성되었으니, 클러스터 간 로드 밸런싱과 locality-aware routing을 살펴볼 차례입니다. 이 기능을 통해 트래픽이 클러스터 간에 효율적으로 분배되고, 가까운 워크로드로 우선 라우팅되는 과정을 확인할 수 있습니다.
클러스터 간 로드 밸런싱
- ingress gateway를 통해 들어온 요청이 west-cluster와 east-cluster의 워크로드로 로드 밸런싱됩니다.
🚀 샘플 서비스 배포
- 로드 밸런싱을 테스트하기 위해 두 클러스터에 간단한 백엔드 서비스(simple-backend)를 배포할 거예요. 이 서비스는 응답에 실행 중인 클러스터 이름을 포함해, 요청이 어느 클러스터로 라우팅되었는지 쉽게 확인할 수 있습니다.
west-cluster에 배포:
$ kwest apply -f ch12/locality-aware/west/simple-backend-deployment.yaml
$ kwest apply -f ch12/locality-aware/west/simple-backend-svc.yaml
$ kwest apply -f ch12/locality-aware/west/simple-backend-gw.yaml
$ kwest apply -f ch12/locality-aware/west/simple-backend-vs.yaml
- simple-backend-deployment.yaml: 백엔드 워크로드를 배포.
- simple-backend-svc.yaml: 워크로드를 위한 Kubernetes 서비스.
- simple-backend-gw.yaml: 트래픽을 허용하는 Gateway 리소스.
- simple-backend-vs.yaml: Gateway에서 백엔드로 트래픽을 라우팅하는 VirtualService.
- 배포 후, 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"
- 응답으로 "WEST"가 반환되어 west-cluster에서 서비스가 실행 중임을 알 수 있습니다.
- east-cluster에도 동일한 서비스를 배포합니다:
$ keast apply -f ch12/locality-aware/east/simple-backend-deployment.yaml
keast apply -f ch12/locality-aware/east/simple-backend-svc.yaml
serviceaccount/simple-backend created
deployment.apps/simple-backend-east created
service/simple-backend created
- 이제 두 클러스터에 서비스가 배포되었고, ingress gateway를 통해 요청이 두 클러스터로 로드 밸런싱됩니다.
west-cluster와 east-cluster에 simple-backend 서비스를 배포해
로드 밸런싱 테스트를 준비합니다.
🔄 기본 로드 밸런싱 동작
- Istio는 기본적으로 round-robin 알고리즘을 사용해 워크로드 간 트래픽을 균등하게 분배합니다.
이를 확인하기 위해 여러 번 요청을 보내보겠습니다:
$ 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
"Hello from WEST"
"Hello from EAST"
...
$ 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
4 "Hello from EAST"
6 "Hello from WEST"
- 결과를 보면 요청이 west-cluster와 east-cluster로 번갈아 가며 분배됩니다. 하지만 성능을 더 개선하려면 locality-aware load balancing을 사용해 가까운 워크로드로 트래픽을 우선 라우팅할 수 있습니다.
Istio는 round-robin 방식으로 트래픽을 균등 분배하지만,
locality-aware load balancing으로 성능을 최적화할 수 있습니다.
🌍 Locality-Aware 라우팅 확인
- 클라우드 제공자는 노드에 locality 정보(예: region, zone)를 라벨로 추가합니다.
Istio는 이 정보를 활용해 워크로드의 위치를 파악하고, 가까운 워크로드로 트래픽을 우선 라우팅합니다. - 노드에 지역성 정보 레이블을 설정
$ kwest label node west-control-plane 'topology.kubernetes.io/region=westus'
node/west-control-plane labeled
$ kwest label node west-control-plane 'topology.kubernetes.io/zone=0'
node/west-control-plane labeled
$ keast label node east-control-plane 'topology.kubernetes.io/region=eastus'
node/east-control-plane labeled
$ keast label node east-control-plane 'topology.kubernetes.io/zone=0'
node/east-control-plane labeled
- istio eds 에 정보 반영을 위해 파드 재기 : isiotd 가 노드의 지역성 정보 레이블을 엔드포인트 설정할 때 워크로드로 전파.
$ 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
deployment.apps/istio-ingressgateway restarted
deployment.apps/istio-eastwestgateway restarted
deployment.apps/simple-backend-west restarted
deployment.apps/istio-ingressgateway restarted
deployment.apps/istio-eastwestgateway restarted
deployment.apps/simple-backend-east restarted
- west-cluster의 노드 라벨을 확인합니다:
$ kwest get nodes -o custom-columns="NAME:{.metadata.name},REGI
ON:{.metadata.labels.topology\.kubernetes\.io/region},ZONE:{.metadata.labels.topology\
.kubernetes\.io/zone}"
NAME REGION ZONE
west-control-plane westus 0
$ keast get nodes -o custom-columns="NAME:{.metadata.name},REGI
ON:{.metadata.labels.topology\.kubernetes\.io/region},ZONE:{.metadata.labels.topology\
.kubernetes\.io/zone}"
NAME REGION ZONE
east-control-plane eastus 0
- 출력 결과로 west-cluster 노드가 westus 지역에 있는 것을 확인할 수 있습니다. east-cluster는 eastus 지역에 확인
- 이 locality 정보는 istiod가 엔드포인트를 설정할 때 워크로드에 반영됩니다. ingress gateway의 엔드포인트를 확인:
$ iwest pc endpoints 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' -o json
...
"weight": 1,
"locality": {
"region": "westus",
"zone": "0"
}
...
"weight": 1,
"locality": {
"region": "eastus",
"zone": "0"
}
...
- 출력에서 두 엔드포인트가 각각 westus와 eastus 지역에 있는 것을 볼 수 있습니다.
- locality-aware 라우팅을 활성화하려면 passive health checking이 필요합니다.
이를 위해 outlier detection을 포함한 DestinationRule을 적용합니다:
$ 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 #HTTP/2 연결당 최대 동시 요청 수를 10으로 설정
maxRequestsPerConnection: 10 #HTTP/1.1 연결당 최대 요청 수를 10으로 설정
outlierDetection: #비정상적인 동작을 보이는 인스턴스를 감지하고 격리하는 이상 감지 설정을 정의
consecutive5xx3Errors: 1 #하나의 인스턴스에서 연속적으로 5xx 에러가 1번 발생하면 해당 인스턴스를 이상 있는 것으로 간주
interval: 20s #이상 감지를 수행하는 간격을 20초로 설정
baseEjectionTime: 30s #이상이 감지된 인스턴스를 트래픽에서 제외하는 기본 시간을 30초로 설정
$ kwest apply -f ch12/locality-aware/west/simple-backend-dr.yaml
destinationrule.networking.istio.io/simple-backend-dr created
- 설정이 적용된 후(몇 초 소요), 요청을 다시 보내 확인합니다:
$ 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 | sort | uniq -c
20
20 "Hello from WEST"
- 모든 요청이 west-cluster로 라우팅되었습니다! 이는 ingress gateway가 west-cluster에 가까운 워크로드를 우선 선택했기 때문입니다.
- 엔드포인트 설정을 다시 확인해 봅시다:
$ 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",
"zone": "0"
}
...
"weight": 1,
"priority": 1,
"locality": {
"region": "eastus",
"zone": "0"
}
...
- priority 필드가 추가되었습니다. westus는 우선순위 0(기본값, 최고 우선순위), eastus는 우선순위 1(낮은 우선순위)로 설정되어, 트래픽이 west-cluster로 우선 라우팅됨을 알 수 있습니다.
Locality-aware 라우팅은 노드의 locality 정보를 활용해 가까운 워크로드로 트래픽을 우선 라우팅하며,
DestinationRule로 활성화됩니다.
🔄 클러스터 간 페일오버 확인
- 이제 west-cluster의 워크로드가 실패했을 때 트래픽이 east-cluster로 페일오버되는지 테스트해 봅시다.
west-cluster의 simple-backend에 오류를 유도하기 위해 환경 변수 ERROR_RATE를 1로 설정합니다:
$ kwest -n istioinaction set env deploy simple-backend-west ERROR_RATE='1'
deployment.apps/simple-backend-west env updated
- outlier detection이 워크로드를 비정상으로 감지하면 트래픽이 다음 우선순위인 east-cluster로 라우팅됩니다:
$ for i in {1..10}; do curl --max-time 5 -s $EXT_IP -H "Host: s
imple-backend.istioinaction.io" | jq .body; done
"Hello from EAST"
"Hello from EAST"
...
- west-cluster 워크로드가 비정상으로 감지되어 트래픽이 east-cluster로 페일오버된 것을 확인할 수 있습니다.
Outlier detection을 사용해 비정상 워크로드를 감지하고,
트래픽을 다음 우선순위 클러스터로 페일오버합니다.
🔒 클러스터 간 접근 제어 확인
- 마지막으로, AuthorizationPolicy를 사용해 클러스터 간 접근 제어를 테스트해 봅시다.
예를 들어, simple-backend 서비스가 ingress gateway에서 오는 트래픽만 허용하도록 설정할게요. - east-cluster에 정책을 적용합니다:
# 적용 전에 west-cluster 서비스를 제거해서 east 에서만 트래픽을 처리
$ kwest delete deploy simple-backend-west -n istioinaction
deployment.apps "simple-backend-west" deleted
$ 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
- west-cluster에서 임시 Pod를 실행해 simple-backend에 직접 요청을 보냅니다:
# 임시 파드 실행
$ kwest run netshoot -n istioinaction --rm -it --image=nicolaka/netshoot -- zsh
# 직접 요청하면 실패!
netshoot ~ curl -s simple-backend.istioinaction.svc.cluster.local
RBAC: access denied#
- 요청이 거부되었습니다! 이는 정책이 ingress gateway 외의 트래픽을 차단했기 때문입니다.
- 이제 ingress gateway를 통해 요청을 보내면:
# istio-ingressgateway 로 요청하면 성공!
netshoot ~ 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.18"
],
"start_time": "2025-05-19T05:33:45.554144",
"end_time": "2025-05-19T05:33:45.704590",
"duration": "150.445665ms",
"body": "Hello from EAST",
"code": 200
}
- 정상적으로 응답을 받았습니다. 이는 워크로드 간 mutual authentication이 작동하고, 인증된 메타데이터를 기반으로 접근 제어가 올바르게 적용되었음을 보여줍니다.
AuthorizationPolicy로 클러스터 간 접근 제어를 설정하고,
mutual authentication을 통해 트래픽을 제어합니다.
📌 핵심 요약
- simple-backend 서비스를 west-cluster와 east-cluster에 배포해 클러스터 간 로드 밸런싱을 테스트합니다.
- 기본적으로 round-robin 방식으로 트래픽이 균등 분배되지만, locality-aware load balancing으로 가까운 워크로드(westus)를 우선 라우팅할 수 있습니다.
- DestinationRule과 outlier detection을 사용해 locality 정보를 활용하고, 비정상 워크로드를 감지해 페일오버를 수행합니다.
- AuthorizationPolicy로 ingress gateway에서 오는 트래픽만 허용하도록 설정해 클러스터 간 접근 제어를 구현합니다.
- Istio의 기능(로드 밸런싱, locality-aware routing, 페일오버, 접근 제어)은 추가 설정 없이 멀티 클러스터 환경에서도 동일하게 작동합니다.