ServiceMesh - Istio - Week7
62 minute read
chap12. 조직 내에서 이스티오 스케일링하기
- 여러 클러스터에서 서비스 메시 스케일링하기
- 두 클러스터를 합치기 위한 전체 조건 해결하기
- 여러 클러스터의 워크로드 간에 공통 신뢰(common trust) 설정하기
- 클러스터 간 워크로드 찾기
- east-west 트래픽을 위한 이스티오 인그레스 게이트웨이 설정하기
다중 클러스터 서비스 메시의 이점
- 이점
- 격리성 강화: 팀 간 문제 전파 방지
- 장애 경계: 클러스터 장애 시 전체 시스템 영향 최소화
- 규정 준수: 민감 데이터 접근 제한 기능
- 가용성 및 성능 향상: 다중 리전 운영으로 가용성 증가 및 지연 시간 감소
- 다중/하이브리드 클라우드 지원: 다양한 클라우드 환경에서 워크로드 실행 가능
- 다중 클러스터 접근법 요약
- 다중 클러스터 서비스 메시
- 여러 클러스터에 걸친 단일 메시 구성
- 이스티오 설정(VirtualService, DestinationRule, Sidecar)으로 클러스터 간 트래픽 관리
- 메시 연합(다중 메시)
- 개별 서비스 메시 간 통신 활성화
- 수동 설정 필요성 증가
- 다른 팀 관리 또는 높은 보안 격리 필요 시 적합
- 다중 클러스터 서비스 메시
다중 클러스터 서비스 메시 개요
- 클러스터들을 하나의 메시로 결합을 위한 전제 조건
- 클러스터 간 워크로드 디스커버리: 컨트롤 플레인이 서비스 프록시 설정을 위해 타 클러스터 워크로드를 식별하고 접근할 수 있어야 함
- 클러스터 간 워크로드 연결성: 워크로드 간 실제 네트워크 연결이 가능해야 하며, 단순한 엔드포인트 인식만으로는 불충분함
- 클러스터 간 공통 신뢰: 이스티오 보안 기능 활용을 위해 클러스터 간 워크로드 상호 인증 메커니즘 필요
이스티오 다중 클러스터 배포 모델
- 클러스터 유형
- primary cluster: 이스티오 컨트롤 플레인이 설치된 클러스터
- remote cluster: 컨트롤 플레인과 분리된 클러스터
- 가용성 수준에 따른 배포 모델
- primary-remote 모델
- 단일 컨트롤 플레인 관리 방식
- 리소스 사용 효율성 높음
- 기본 클러스터 장애 시 메시 전체 영향
- 가용성 상대적으로 낮음
- primary-primary 모델
- 복수의 컨트롤 플레인 사용
- 더 많은 리소스 소비
- 장애 영향 범위가 해당 클러스터로 제한됨
- 가용성 향상
- ‘복제된 컨트롤 플레인 배포 모델’로 불림
- external control plane 모델
- 모든 클러스터가 외부 컨트롤 플레인과 연결
- 클라우드 프로바이더의 관리형 서비스 제공 가능
- primary-remote 모델
다중 클러스터 배포에서 워크로드는 어떻게 찾는가?
- 쿠버네티스 API 접근 보안
- 이스티오 컨트롤 플레인은 서비스 프록시 설정을 위해 쿠버네티스 API 서버와 통신 필요
- API 서버 접근은 강력한 권한으로, 민감 정보 조회 및 클러스터 상태 변경 가능성 내포
- 쿠버네티스는 RBAC(Role-Based Access Control)을 통해 API 서버 접근 보호
- 클러스터 간 디스커버리에 사용되는 핵심 개념:
- Service Account: 기계나 서비스에 ID 제공
- Service Account Token: 자동 생성되어 ID 클레임 표현, JWT 형식으로 파드에 주입
- Role and ClusterRole: ID에 대한 권한 집합 정의
- 토큰과 RBAC으로 원격 API 접근 보안이 가능하나 트레이드오프 존재
- 메시 연합이 이러한 위험성 완화에 도움 가능
- 클러스터 간 워크로드 디스커버리
- 클러스터 간 워크로드 디스커버리는 기술적으로 동일한 방식으로 작동
- istiod에 원격 클러스터의 서비스 어카운트 토큰 제공 필요
- API 서버와의 보안 통신을 위한 인증서도 함께 제공
- istiod는 이 토큰을 사용하여 원격 클러스터에 인증 후 워크로드 탐색 수행
클러스터 간 워크로드 연결
- 다중 클러스터 환경에서는 워크로드가 클러스터 간 연결 가능해야 함
- 플랫 네트워크(단일 네트워크 공유 또는 네트워크 피어링) 환경에서는 IP 주소로 직접 연결 가능하여 조건 자동 충족
- 서로 다른 네트워크에 클러스터가 있는 경우:
- 네트워크 에지에 위치한 특수 이스티오 인그레스 게이트웨이 필요
- 이 게이트웨이가 클러스터 간 트래픽 프록시 역할 수행
- 다중 네트워크 메시에서는 이런 게이트웨이를 “east-west 게이트웨이”라고 부름
클러스터 간 공통 신뢰
플러그인 CA 인증서
- 플러그인 중간 CA 인증서 방식은 구현이 간단함
- 이스티오가 자동 생성하는 대신 사용자가 인증서를 지정하여 시크릿으로 제공
- 두 클러스터 모두 동일한 루트 CA가 서명한 중간 CA 사용
- 장점: 간단한 구현 방식
- 단점: 중간 CA 노출 시 보안 위험 존재
- 노출 시 공격자가 취소 전까지 신뢰받는 인증서 서명 가능
- 이러한 위험으로 인해 조직들이 중간 CA 사용을 꺼리는 경향
- 위험 완화 방법:
- 중간 CA를 메모리에만 로드하고 etcd에 시크릿으로 저장하지 않음
- 더 안전한 대안으로 외부 CA 통합 방식 사용 가능
외부 인증 기간 통합
- istiod가 인증서 서명 요청(CSRs)을 검증하고 승인하는 등록 기관 역할 수행
- 승인된 쿠버네티스 CSR은 다음 두 가지 방법으로 외부 CA에 제출:
- cert-manager 사용
- 외부 CA가 cert-manager에서 지원될 경우에만 가능
- cert-manager의 istio-csr이 쿠버네티스 CSR을 모니터링하고 외부 CA에 서명 요청
- 맞춤 개발
- 승인된 쿠버네티스 CSR을 모니터링하여 외부 CA에 제출하는 쿠버네티스 컨트롤러 개발
- 자체 서명 대신 외부 CA 사용하도록 솔루션 조정 필요
- cert-manager 사용
- 외부 CA가 서명한 인증서는 쿠버네티스 CSR에 저장되며, istiod가 SDS(Secret Discovery Service)를 통해 워크로드에 전달
다중 클러스터, 다중 네트워크, 다중 컨트롤 플레인 서비스 메시 개요
다중 클러스터 배포 모델 선택하기
- 다중 네트워크 인프라에서는 클러스터 간 연결을 위한 east-west 게이트웨이 필수
- 컨트롤 플레인 배포 모델은 비즈니스 요구사항에 따라 결정:
- 복제된 컨트롤 플레인 모델 vs 단일 컨트롤 플레인 모델
- ACME 사례 분석:
- 온라인 상점의 서비스 중단 시 매분 수백만 달러 손실 발생
- 고가용성이 최우선 과제
- 최종 선택된 배포 모델:
- 다중 클러스터, 다중 네트워크, 다중 컨트롤 플레인 서비스 메시
- 네트워크 연결을 위한 east-west 게이트웨이 사용
- 각 클러스터에 이스티오 컨트롤 플레인이 배포되는 기본-기본(primary-primary) 배포 모델 채택
플러그인 CA 인증서 설정하기
- 이스티오는 설치 시 워크로드 인증서에 서명할 CA를 자동 생성
- 생성된 CA는 ‘istio-ca-secret’이라는 시크릿으로 이스티오 설치 네임스페이스에 저장
- istiod 복제본들이 이 시크릿을 공유하여 사용
- 기본 동작은 사용자 정의 CA로 대체 가능
- 이스티오가 새 CA를 생성하는 대신 제공된 CA 사용
- 설정 방법:
- CA 인증서를 ‘istio-system’ 네임스페이스에 ‘cacerts’라는 시크릿으로 저장
- 필요한 데이터 포함 항목:
- ca.cert.pem: 중간 CA 인증서
- ca-key.pem: 중간 CA 개인 키
- root-cert.pem: 루트 CA 인증서(중간 CA 발급 기관)
- cert-chain.pem: 중간 CA와 루트 CA를 연결한 신뢰 체인
- 인증서 구조:
- 루트 CA: 모든 클러스터가 신뢰하는 최상위 인증서
- 중간 CA: 각 클러스터별 발급, 워크로드 인증서 서명에 사용
- 인증서 체인: 클라이언트의 인증서 검증을 위한 신뢰 체인 구성
플러그인 CA 인증서 적용하기
인증서 확인
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
openssl x509 -in ch12/certs/root-cert.pem -noout -text
openssl x509 -in ch12/certs/east-cluster/ca-cert.pem -noout -text
openssl x509 -in ch12/certs/east-cluster/cert-chain.pem -noout -text
openssl x509 -in ch12/certs/west-cluster/ca-cert.pem -noout -text openssl x509 -in ch12/certs/west-cluster/cert-chain.pem -noout -text
- istio-system 네임스페이스를 생성후 인증서를 cacerts라는 시크릿으로 적용해 각 클러스터에 intermediate 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
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get secret cacerts -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl view-secret cacerts -n istio-system --all --kubeconfig=./$i-kubeconfig; echo; done
- 플러그인 인증서가 설정되면 이스티오 컨트롤 플레인을 설치할 수 있음
- 컨트롤 플레인은 플러그인 CA 인증서를 갖고 워크로드 인증서에 서명함
각 클러스터에 컨트롤 플레인 설치하기
- 네트워크 메타데이터 추가 필요성
- 이스티오 컨트롤 플레인 설치 전에 각 클러스터에 네트워크 메타데이터를 추가해야 함
- 토폴로지 정보 활용
- 네트워크 메타데이터를 통해 이스티오가 토폴로지 정보를 사용할 수 있음
- 해당 정보를 기반으로 워크로드 설정 가능
- 지역성 기반 트래픽 라우팅 최적화
- 워크로드가 지역 정보를 활용하여 가까운 워크로드를 우선적으로 선택
- 트래픽 라우팅 시 근접성을 고려한 최적화 구현
- East-West 게이트웨이 활용
- 다른 네트워크에 있는 원격 클러스터의 워크로드로 트래픽 라우팅 시
- 이스티오가 자동으로 east-west 게이트웨이를 사용하도록 설정
클러스터 간 연결을 위해 네트워크에 레이블 붙이기
- MeshNetwork vs 레이블 방식
- MeshNetwork 설정: 드문 고급 사용 사례나 레거시 설정에서 사용
- 레이블 방식: 더 간단한 방법으로 권장됨
- 레이블 설정 방법
- 이스티오가 설치된 네임스페이스(istio-system)에 네트워크 토폴로지 정보를 레이블로 추가
- 레이블 형식:
topology.istio.io/network=[네트워크명]
- 실제 설정 예시
- west-cluster:
topology.istio.io/network=west-network
레이블 적용 - east-cluster:
topology.istio.io/network=east-network
레이블 적용
- west-cluster:
- 설정 명령어
kwest label namespace istio-system topology.istio.io/network=west-network
keast label namespace istio-system topology.istio.io/network=east-network
- 설정 효과
- 이스티오가 이 레이블들을 통해 네트워크 토폴로지를 이해함
- 토폴로지 정보를 바탕으로 워크로드 설정 방법을 결정함
IstioOperator 리소스를 사용해 컨트롤 플레인 설치하기
- IstioOperator 리소스 정의
# 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-cluster 설치 과정
# 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
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}]}}'
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}]}}'
# 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
• east-cluster 설치 과정
# 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
• istioctl alias 설정
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-wlm9q.istio-system west-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-5585445f4c-b66zb 1.17.8
ieast proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-7f6f8f8d99-vb7c8.istio-system east-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-85976468f-5bsrk 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 80349990876331570640723939723244297816 2025-05-17T08:47:28Z 2025-05-16T08:45:28Z
ROOTCA CA ACTIVE true 100900981840825465297757884708490534092 2032-06-25T14:11:35Z 2022-06-28T14:11:35Z
# 인증서 확인
# - 미리 준비된 인증서가 적용되었는지 확인
# - 사용자 인증서, 중간 CA 인증서, 최상위 루트 인증서 체인 확인
iwest proxy-config secret deploy/istio-ingressgateway.istio-system -o json
...
# 아래는 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: Jun 28 14:11:35 2022 GMT
Not After : Jun 25 14:11:35 2032 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: 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
#
iwest proxy-config listener deploy/istio-ingressgateway.istio-system
iwest proxy-config route deploy/istio-ingressgateway.istio-system
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system
iwest proxy-config secret deploy/istio-ingressgateway.istio-system
iwest proxy-config bootstrap deploy/istio-ingressgateway.istio-system
iwest proxy-config ecds deploy/istio-ingressgateway.istio-system
#
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
kwest get svc,ep catalog -n istioinaction
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.100.2.43 <none> 80/TCP 2m
NAME ENDPOINTS AGE
endpoints/catalog <none> 2m
kwest get gw,vs,dr -A
NAMESPACE NAME AGE
istioinaction gateway.networking.istio.io/coolstore-gateway 16s
NAMESPACE NAME GATEWAYS HOSTS AGE
istioinaction virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 16s
#
iwest proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
istio-ingressgateway-5db74c978c-wlm9q.istio-system west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-b66zb 1.17.8
webapp-5c8b4fff64-t2rh8.istioinaction west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-5585445f4c-b66zb 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
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
#
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
keast get svc,ep catalog -n istioinaction
keast get gw,vs,dr -A # 없음
#
ieast proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
catalog-6cf4b97d-2qzhj.istioinaction east-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-85976468f-5bsrk 1.17.8
istio-ingressgateway-7f6f8f8d99-vb7c8.istio-system east-cluster SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-85976468f-5bsrk 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
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.15:3000 HEALTHY OK outbound|80||catalog.istioinaction.svc.cluster.local
- 스텁 catalog 서비스가 필요한 이유
- webapp 컨테이너가 FQDN을 IP 주소로 해석할 수 없으면 요청이 실패함
- 트래픽이 애플리케이션을 떠나 프록시로 리다이렉트되기 전에 요청이 중단됨
- 스텁 서비스의 역할
- FQDN을 서비스 클러스터 IP로 해석 가능하게 함
- 애플리케이션이 트래픽을 시작할 수 있도록 지원
- 엔보이 프록시로 리다이렉트되어 실제 엔보이 설정이 클러스터 간 라우팅을 처리
- 현재 상황의 한계
- 이는 DNS 프록시의 에지 케이스로 인한 문제
- 이스티오 커뮤니티가 향후 버전에서 DNS 프록시 개선을 통해 해결 예정
- 현재 상태와 다음 단계
- 각 클러스터에 연결해야 하는 워크로드가 존재
- 클러스터 간 워크로드 디스커버리가 없으면 사이드카 프록시에 반대 클러스터의 워크로드가 설정되지 않음
- 다음 단계: 클러스터 간 디스커버리 활성화 필요
클러스터 간 워크로드 디스커버리 활성화하기
- 원격 클러스터 인증 요구사항
- 이스티오가 원격 클러스터에서 정보를 쿼리하려면 인증이 필요
- ID를 정의하는 서비스 어카운트와 권한에 대한 롤 바인딩이 필수
- istio-reader-service-account
- 이스티오 설치 시 자동으로 생성되는 서비스 어카운트
- 최소 권한으로 설정됨
- 다른 컨트롤 플레인이 자신을 인증하는 데 사용
- 서비스나 엔드포인트 같은 워크로드 관련 정보 조회에 활용
- 보안 연결을 위한 추가 요구사항
- 서비스 어카운트 토큰이 필요
- 원격 클러스터로 보안 커넥션을 시작할 인증서가 필요
- 상대 클러스터가 이들을 사용할 수 있도록 설정해야 함
원격 클러스터 접근용 시크릿 만들기
- create-remote-secret 명령어
- istioctl에서 제공하는 원격 클러스터 접근용 시크릿 생성 명령어
- 기본 istio-reader-service-account 서비스 어카운트를 사용
- 시크릿 생성 시 IstioOperator에서 사용한 클러스터 이름을 지정하는 것이 중요 (east-cluster, west-cluster)
#
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get sa -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
# east
keast describe sa -n istio-system istio-reader-service-account
keast get sa -n istio-system istio-reader-service-account -o yaml
keast get sa -n istio-system istio-reader-service-account -o jsonpath='{.secrets[0].name}'
eirsa=$(keast get sa -n istio-system istio-reader-service-account -o jsonpath='{.secrets[0].name}')
keast get secret -n istio-system $eirsa
keast get secret -n istio-system $eirsa -o json
kubectl rolesum istio-reader-service-account -n istio-system --kubeconfig=./east-kubeconfig
keast auth can-i --list
keast auth can-i --as=system:serviceaccount:istio-system:istio-reader-service-account --list
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
## user.token 정보 :
jwt decode YYY
---------------------------------------------------------------
# west 에 시크릿 생성
ieast x create-remote-secret --name="east-cluster" | kwest apply -f -
# istiod 로그 확인 : 시크릿이 생성되면, 바로 istiod가 이 시크릿을 가지고 새로 추가된 원격 클러스터(east)에 워크로드를 쿼리한다.
kwest logs deploy/istiod -n istio-system | grep 'Adding cluster'
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get secret -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
kwest get secret -n istio-system istio-remote-secret-east-cluster
kwest get secret -n istio-system istio-remote-secret-east-cluster -o yaml
# 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
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system | grep catalog
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
# west 에서 10.20.0.15(10.20.0.0/16)로 라우팅이 가능한 상태인가?
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||catalog.istioinaction.svc.cluster.local' -o json
# 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
ieast proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
---------------------------------------------------------------
# east 에 시크릿 생성
iwest x create-remote-secret --name="west-cluster" | keast apply -f -
# istiod 로그 확인 : 시크릿이 생성되면, 바로 istiod가 이 시크릿을 가지고 새로 추가된 원격 클러스터(east)에 워크로드를 쿼리한다.
keast logs deploy/istiod -n istio-system | grep 'Adding cluster'
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get secret -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
keast get secret -n istio-system istio-remote-secret-west-cluster
keast get secret -n istio-system istio-remote-secret-west-cluster -o yaml
# east 확인 : west 의 모든 CDS/EDS 정보를 east 에서도 확인 가능!
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 webapp
# east 에서 10.10.0.15(10.10.0.0/16)로 라우팅이 가능한 상태인가?
ieast proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep webapp
---------------------------------------------------------------
# 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.2.43 <none> 80/TCP 14h
service/webapp ClusterIP 10.100.2.172 <none> 80/TCP 14h
NAME ENDPOINTS AGE
endpoints/catalog <none> 14h
endpoints/webapp 10.10.0.8:8080 14h
# 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.3.0 <none> 80/TCP 14h
NAME ENDPOINTS AGE
endpoints/catalog 10.20.0.8:3000 14h
클러스터 간 연결 설정하기
- 트래픽 유형 구분
- North-South 트래픽: 퍼블릭 네트워크에서 내부 네트워크로 진입하는 트래픽
- East-West 트래픽: 서로 다른 내부 네트워크(클러스터) 간의 트래픽
- 네트워크 피어링의 한계
- 클라우드 프로바이더는 가상 네트워크 피어링으로 East-West 트래픽을 단순화
- 네트워크 피어링은 클라우드 전용 기능으로 온프레미스나 다른 클라우드 간 연결 불가
- 이때 이스티오의 East-West 게이트웨이가 대안 제공
이스티오의 east-west 게이트웨이
- East-West 게이트웨이의 목적
- 클러스터 간 East-West 트래픽의 진입점 역할
- 서비스 운영 팀에게 투명한 프로세스 제공
- 추가 이스티오 리소스 구성 없이 동작
- East-West 게이트웨이의 요구사항
- 클러스터 사이의 정밀한 트래픽 관리 가능
- 암호화된 트래픽 라우팅으로 워크로드 간 상호 인증 지원
- 클러스터 내 라우팅과 클러스터 간 라우팅의 차이 최소화
SNI 클러스터로 east-west 게이트웨이 설정하기
- SNI 클러스터의 개념
- East-West 게이트웨이는 SNI 클러스터를 모든 서비스에 추가 설정한 인그레스 게이트웨이
- 일반 엔보이 클러스터와 유사하지만 모든 정보를 SNI에 인코딩하는 것이 핵심 차이점
- 방향, 부분집합, 포트, FQDN 속성을 포함
- SNI 클러스터의 동작 방식
- 클라이언트가 원격 클러스터의 워크로드로 연결 시 겨냥하는 클러스터를 SNI에 인코딩
- SNI에 라우팅 결정을 위한 방향, 포트, 버전, 서비스 이름 포함
- 게이트웨이가 SNI 헤더에서 클러스터 정보를 읽어 의도한 워크로드로 트래픽 프록시
- 안전하고 상호 인증된 커넥션을 워크로드 간에 유지
SNI 클러스터가 있는 east-west 게이트웨이 설치하기
- SNI 클러스터 활성화 방법
- 옵트인 기능으로 기본적으로 비활성화되어 있음
- 환경 변수
ISTIO_META_ROUTER_MODE
를sni-dnat
으로 설정하여 활성화 - IstioOperator 정의에서 게이트웨이 라우터 모드 설정을 통해 구성
- IstioOperator 리소스 이름 주의사항
- 컨트롤 플레인 설치에 사용한 IstioOperator 리소스와 같은 이름 사용 금지
- 같은 이름 사용 시 기존 설치를 덮어쓰게 됨
ISTIO_META_ROUTER_MODE
설정sni-dnat
설정 시: SNI 클러스터를 자동으로 구성- 미설정 또는 다른 값 설정 시:
standard
모드로 동작하며 SNI 클러스터 미설정
ISTIO_META_REQUESTED_NETWORK_VIEW
- 네트워크 트래픽이 프록시되는 위치를 정의하는 설정
# 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
# 설치 전 확인
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
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get IstioOperator -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
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
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep catalog
# IstioOperator 로 east 클러스터에 east-west 게이트웨이를 설치
cat ch12/gateways/cluster-east-eastwest-gateway.yaml
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
# east 클러스터에 east-west 게이트웨이를 설치 확인
for i in west east; do echo ">> k8s cluster : $i <<"; kubectl get IstioOperator -n istio-system --kubeconfig=./$i-kubeconfig; echo; done
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
keast get IstioOperator -n istio-system installed-state-istio-eastwestgateway -o yaml
# east 정보 확인
ieast proxy-status
# 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 정보 확인 : 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
ieast proxy-config cluster deploy/istio-eastwestgateway.istio-system | grep istioinaction
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
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
# 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
iwest proxy-config cluster deploy/istio-ingressgateway.istio-system | grep istioinaction
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
# west 에 istio-ingressgateway : east EDS 모든 정보에서 east의 eastwestgateway에 mtls 정보로 변경!
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system | grep istioinaction
# 출력되는 172.18.X.Y에 IP 확인 : east 에 eastwestgateway 의 Service(LoadBalancer)의 External-IP.
keast get svc,ep -n istio-system istio-eastwestgateway
# 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
# west 에서 호출 시도
kwest get svc,ep -n istioinaction
kwest exec -it deploy/webapp -c istio-proxy -n istioinaction -- curl catalog.istioinaction.svc.cluster.local -v
- 다음 설정 단계
- East-west 게이트웨이 설치 및 라우터 모드를 sni-dnat으로 설정 완료 후 진행
- SNI 자동 통과 모드(SNI auto passthrough mode)를 사용하여 설정
- East-west 게이트웨이를 통해 다중 클러스터 상호 TLS 포트를 노출
- 이스티오의 지능적 설정
- 이스티오가 필요한 시점에만 게이트웨이에 SNI 클러스터를 설정
- 자동으로 최적화된 구성을 제공하는 스마트한 동작 방식
SNI 자동 통과로 클러스터 간 트래픽 라우팅하기
- 수동 SNI 통과와의 차이점
- 수동 SNI 통과: SNI 헤더 기반으로 트래픽 허용하지만 VirtualService 리소스를 수작업으로 정의해야 함
- SNI 자동 통과: 허용된 트래픽 라우팅을 위해 VirtualService를 수작업으로 만들 필요 없음
- SNI 자동 통과의 동작 방식
- SNI 클러스터를 사용하여 라우팅 수행
- 라우터 모드가 sni-dnat일 때 east-west 게이트웨이에서 자동으로 설정됨
- 이스티오 Gateway 리소스로 설정 가능
# 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
# west 에서 호출 시도
kwest get svc,ep -n istioinaction
kwest exec -it deploy/webapp -c istio-proxy -n istioinaction -- curl catalog.istioinaction.svc.cluster.local -v
# 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
ieast proxy-config listener deploy/istio-eastwestgateway.istio-system --port 15443 -o json
# 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
# 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
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
kwest get IstioOperator -n istio-system installed-state-istio-eastwestgateway -o yaml
iwest proxy-status
# west 클러스터에 적용하자. east-cluster의 워크로드를 west-cluster 에 노출한다.
cat ch12/gateways/expose-services.yaml
kwest apply -n istio-system -f ch12/gateways/expose-services.yaml
# 확인
kwest get gw,vs,dr -A
kwest get svc,ep -n istioinaction
ieast pc clusters deploy/istio-eastwestgateway.istio-system | grep catalog
# 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 클러스터
- SNI 클러스터 정의 확인
- catalog 워크로드에 SNI 클러스터가 성공적으로 정의됨
- 출력을 통해 SNI 클러스터 설정이 완료되었음을 확인 가능
- SNI 자동 통과를 통한 라우팅
- 게이트웨이가 SNI 자동 통과로 설정되어 있음
- 게이트웨이에 들어오는 트래픽이 SNI 클러스터를 사용하여 의도한 워크로드로 라우팅됨
- 이스티오 컨트롤 플레인의 감지
- 컨트롤 플레인이 리소스 생성을 모니터링함
- 클러스터 간 트래픽을 라우팅할 수 있는 경로가 존재함을 발견
- 워크로드 업데이트
- 컨트롤 플레인이 원격 클러스터에서 새로 발견한 엔드포인트로 모든 워크로드를 업데이트
- 클러스터 간 통신을 위한 설정이 자동으로 완료됨
클러스터 간 워크로드 디스커버리 검증하기
- east-cluster의 워크로드가 west-cluster에 노출되었는지 확인
- 예상 동작
- webapp 엔보이 클러스터가 catalog 워크로드로 향하는 엔드포인트 보유 예상
- 엔드포인트는 east-west 게이트웨이 주소를 가리켜야 함
- east-west 게이트웨이가 catalog 요청을 프록시하는 역할
# east-cluster의 east-west 게이트웨이 주소(Service) 확인
keast -n istio-system get svc istio-eastwestgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
# 이 주소를 west-cluster의 워크로드가 클러스터 간 트래픽을 라우팅할 때 사용하는 주소와 비교
iwest pc endpoints deploy/webapp.istioinaction | grep catalog
# 직접 요청을 트리거해 확인
kwest get svc -n istio-system istio-ingressgateway
EXT_IP=$(kwest -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') echo $EXT_IP
docker exec -it mypc curl -s -H "Host: webapp.istioinaction.io" http://$EXT_IP/api/catalog | jq
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: east-cluster 확인
- kiali: west-cluster 확인
- jaeger: west-cluster 확인
- jaeger: east-cluster 확인
- istio-proxy 로그
# west 에 istio-ingressgateway 로그
kwest logs -n istio-system -l app=istio-ingressgateway -f
# west 에 webapp 로그
kwest logs -n istioinaction -l app=webapp -c istio-proxy -f
kwest logs -n istioinaction -l app=webapp -c webapp -f
# 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
keast logs -n istioinaction -l app=catalog -c catalog -f
- west: webapp
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
keast get svc -n istio-system istio-eastwestgateway
- east: webapp
# 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/
# 출력 결과 파일을 로컬로 다운로드
keast get pod -n istioinaction -l app=catalog -oname
pod/catalog-6cf4b97d-sv9gj
keast cp -n istioinaction -c istio-proxy catalog-6cf4b97d-sv9gj:var/lib/istio/data/dump.pcap ./dump.pcap
# 로컬로 다운 받은 파일을 wireshark 로 불러오기 : XFF 로 요청 Client IP 확인
wireshark dump.pcap
- 다중 클러스터 트래픽 흐름
- 트래픽 라우팅 순서
- west 인그레스 게이트웨이로 요청 수신
- west-cluster의 webapp으로 라우팅
- east-cluster의 catalog 워크로드로 요청 처리
- 검증 결과
- 다중 클러스터, 다중 네트워크, 다중 컨트롤 플레인 서비스 메시 설정 완료
- 두 클러스터가 서로의 워크로드 발견 가능
- east-west 게이트웨이를 통과 지점으로 상호 인증 커넥션 구현
- 트래픽 라우팅 순서
- 다중 클러스터 서비스 메시 설정 요구사항
- 클러스터 간 워크로드 디스커버리
- 서비스 어카운트 토큰과 인증서 포함된 kubeconfig 사용
- 각 컨트롤 플레인에 동료 클러스터 접근 권한 제공
- istioctl로 east-cluster에만 적용
- 클러스터 간 워크로드 연결
- east-west 게이트웨이 설정으로 다른 클러스터 워크로드 간 트래픽 라우팅
- 각 클러스터에 네트워크 정보 레이블 지정
- 클러스터 간 신뢰 설정
- 동일한 루트 신뢰로 중간 인증서 발급
- 몇 단계로 간단하게 구성
- 대부분 자동화된 설정 과정
클러스터 간 로드 밸런싱
- 동일한 루트 신뢰로 중간 인증서 발급
- 몇 단계로 간단하게 구성
- 대부분 자동화된 설정 과정
- 클러스터 간 워크로드 디스커버리
- 다중 클러스터 서비스 메시가 준비되어서, 클러스터 지역 인식 로드 밸런싱을 살펴본다.
- 이를 위해 2개의 샘플 서비스를 배포
- 이 서비스들은 워크로드가 실행 중인 클러스터의 이름을 반환하도록 설정됨
- 즉, 요청을 처리하는 워크로드의 위치 확인 가능
# west-cluster에 첫 번째 서비스 배포
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
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
kwest get svc,ep -n istioinaction simple-backend
# 트래픽을 허용하기 위해 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
# 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"
docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP
# 신규 터미널 : 반복 접속
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
# east-cluster에 서비스 배포
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
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
keast get svc,ep -n istioinaction simple-backend
- kiali: west, east
- 이스티오의 로드밸런싱 기본 값은 라운드 로빈이다.
# 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
# 정보 확인
kwest get svc,ep -n istioinaction simple-backend
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
iwest proxy-config listener deploy/istio-ingressgateway.istio-system
iwest proxy-config listener deploy/istio-ingressgateway.istio-system --port 8080 -o json
iwest proxy-config route deploy/istio-ingressgateway.istio-system
iwest proxy-config route deploy/istio-ingressgateway.istio-system --name http.8080
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
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
- 이스티오는 레이블을 추출한 정보를 사용해 워크로드의 지역을 설정함
클러스터 간 지역 인식 라우팅 검증하기
# 실습을 위해 노드에 지역성 정보 레이블 설정
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
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
# istio eds 에 정보 반영을 위해 파드 재기동하자 : isiotd 가 노드의 지역성 정보 레이블을 엔드포인트 설정할 때 워크로드로 전파.
iwest proxy-config endpoint deploy/istio-ingressgateway.istio-system --cluster 'outbound|80||simple-backend.istioinaction.svc.cluster.local' -o json
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
# 지역성 정보를 사용하려면 수동적 passive 헬스 체크가 필수이다.
# 엔드포인트 상태를 수동적으로 확인
# 이상값 감지를 사용하는 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
kwest get gw,vs,dr -n istioinaction
# 확인
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'
# (전파 대기(몇 초 후)) / 요청이 지역 정보를 사용해 동일 클러스터 안에서 라우팅되는 것을 확인
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
docker exec -it mypc curl -s -H "Host: simple-backend.istioinaction.io" http://$EXT_IP | jq ".body"
# 동일 클러스터 안에서 라우팅 되는 것을 확인
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 "Hello from WEST"
# 모든 요청은 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", # priority 가 없으면(생략 시), 0으로 우선 순위가 가장 높음
"zone": "0"
}
...
"weight": 1,
"priority": 1, # priority 0 다음으로, 두 번쨰 우선순위
"locality": {
"region": "eastus",
"zone": "0"
}
...
# 우선순위가 가장 높은 호스트가 사용불가가 되면, 우선순위가 낮은 호스트로 라우팅됨
클러스터 간 장애 극복 확인하기
- 백엔드 디플로이먼트가 실패하는 상황을 시뮬레이션
ERROR_RATE
값 을 1로 설정
- 시간이 지나면, 호스트가 비정상임을 감지하고 다음 우선순위(east-cluster) 워크로드로 라우팅한다.
# 신규 터미널 : 반복 접속 해두기
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
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
- 클러스터 간 트래픽은 상대 클러스터의 east-west gateway를 통과하며 SNI 통과로 처리됨
- 원격 클러스터에 도달한 트래픽의 로드 밸런싱에 영향을 줌
- 이 호출은 SNI/TCP 커넥션
- 게이트웨이가 TLS 커넥션을 종료하지 않음
- east-west gateway는 커넥션을 그대로 백엔드 서비스에 전달
- 커넥션이 east-west gateway에서 백엔드 서비스까지 이어짐
- 요청 단위로 로드 밸런싱 되지 않음
- 클러스터 사이의 장애 극복 / 로드 밸런싱
- 클라이언트 관점으로는 부하 분산이나 장애 극복이 수행됨
- 트래픽이 원격 클러스터의 모든 인스턴스 사이에서 반드시 균등하게 분산을 보장하지 않음
인가 정책을 사용해 클러스터 간 접근 제어 확인하기
- 접근 제어 요구사항:
- 워크로드 간 트래픽 상호 인증 필요
- 믿을 수 있는 메타데이터 생성 필요
- 트래픽 승인 또는 거부 결정에 사용
- 시연 시나리오:
- 인그레스 게이트웨이 출처 트래픽만 서비스 접근 허용
- 다른 출처 트래픽은 거부
# 적용 전에 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
keast get authorizationpolicy -A
# 업데이트가 전파되면, west-cluster의 워크로드에서 요청을 만들어 정책 검증
# 이를 위해 임시 파드 실행
# 정책이 인그레스 게이트웨이에서 들어온 트래픽을 허용할 것
# 워크로드가 클러스터 간에 mTLS하여 정책이 ID 인증서에 인코딩된 인증데이터를 접근 데어에 사용할 수 있음
kwest run netshoot -n istioinaction --rm -it --image=nicolaka/netshoot -- zsh
-----------------------------------
curl -s webapp.istioinaction/api/ca
talog
# 직접 요청하면 실패!
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
# 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
-----------------------------------
- 검증된 기능들:
- 로드 밸런싱
- 지역 인식 라우팅
- 클러스터 간 장애 극복
- 상호 인증 트래픽
- 접근 제어
- 이스티오의 확장성
- 조직 내에서 확장 가능
- 여러 클러스터를 단일 메시로 통합
- 여러 조직에게 중요한 가치 제공
chap14. 이스티오의 요청 처리 기능 확장하기
-
엔보이 프록시의 주요 강점은 확장 가능성
-
엔보이 Request Flow 처리 단계: - https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request
- 다운스트림 TCP 연결이 워커 스레드의 엔보이 리스너에 수락됨
- 리스너 필터 체인 생성 및 실행 (SNI, pre-TLS 정보 제공)
- TLS 전송 소켓이 TCP 연결 데이터를 복호화
- 네트워크 필터 체인 생성 및 실행 (HTTP 연결 관리자 포함)
- HTTP/2 코덱이 복호화된 데이터 스트림을 독립적인 스트림으로 분리
- 각 HTTP 스트림에 대해 다운스트림 HTTP 필터 체인 생성 및 실행
- 클러스터별 로드 밸런싱 수행하여 엔드포인트 선택
- 각 스트림에 대해 업스트림 HTTP 필터 체인 생성 및 실행
- 업스트림 엔드포인트의 HTTP/2 코덱이 요청 스트림을 멀티플렉싱
- TLS 전송 소켓이 바이트를 암호화하여 TCP 소켓에 전송
- 요청과 응답이 프록시되며, 응답은 HTTP 필터를 역순으로 통과
- 스트림 완료 후 통계 업데이트, 액세스 로그 작성, 추적 스팬 완료
엔보이의 필터 체인 이해하기
- 엔보이 리스너 기본 개념
- 리스너는 네트워킹 인터페이스에 포트를 열고 들어오는 트래픽을 수신하는 방법
- 엔보이는 네트워크 커넥션에서 바이트를 가져와 처리하는 L3/L4 프록시
- 리스너가 네트워크 스트림에서 바이트를 읽어 다양한 필터 단계를 거쳐 처리
- 네트워크 필터
- 엔보이의 가장 기본적인 필터
- 바이트 스트림에서 인코딩/디코딩 작업 수행
- 둘 이상의 필터가 순서대로 동작하는 필터 체인 구성 가능
- 필터 체인으로 프록시 기능 구현
- 주요 네트워크 필터 종류
- MongoDB, Redis, Thrift, Kafka
- HTTP Connection Manager (HCM) - 가장 많이 사용
- HTTP Connection Manager (HCM)
- 바이트 스트림을 HTTP 헤더, 바디, 트레일러로 변환
- HTTP 1.1, HTTP 2, gRPC, HTTP 3 등 HTTP 기반 프로토콜 지원
- 헤더, 경로 접두사 등 요청 속성 기반 라우팅 처리
- 액세스 로깅, 헤더 조작 기능 제공
- HTTP 필터
- HCM 내부에 필터 기반 아키텍처 존재
- HTTP 요청에서 순서대로 동작하는 HTTP 필터 체인 구성 가능
- 터미널 필터(라우터 필터)로 끝나야 함
- 기본 HTTP 필터 예시
- CORS, CSRF, ExternalAuth, RateLimit
- Fault injection, gRPC/JSON transcoding, Gzip
- Lua, RBAC, Tap, Router, WebAssembly
- 라우터 필터
- HTTP 필터 체인의 마지막 터미널 필터
- 요청을 적절한 업스트림 클러스터로 전달
- 타임아웃과 재시도 파라미터 설정 가능
- 커스텀 필터 개발
- 엔보이 핵심 코드 변경 없이 자체 필터 작성 가능
- 프록시 위에 계층화하여 추가
- 이스티오는 엔보이 위에 필터를 추가해 커스텀 엔보이 빌드
- 커스텀 빌드 시 유지보수 부담과 C++ 개발 필요성 존재
확장용 필터
- 엔보이 확장 방법
- C++로 커스텀 필터 작성하여 프록시에 내장 가능
- 엔보이 바이너리 컴파일 없이 HTTP 기능 확장 가능
- 바이너리 변경 없는 확장용 HTTP 필터
- 외부 처리 (External processing)
- 루아 (Lua)
- 웹어셈블리 (Wasm/WebAssembly)
- 필터 활용 방법
- 외부 서비스 호출 설정
- 루아 스크립트 실행
- 커스텀 코드 실행으로 HCM 기능 강화
- HTTP 요청/응답 처리 시 기능 확장
- 주요 활용 사례
- 속도 제한 필터를 통한 외부 서비스 호출 처리 (중점 다룰 예정)
- 외부 인가 요청 (9장)
이스티오의 데이터 플레인 커스터마이징하기
- 엔보이 데이터 플레인 확장 방법
- 엔보이 HTTP 필터를 이스티오 API의 EnvoyFilter 리소스로 설정
- 속도 제한 서버(RLS, Rate-Limit Server) 호출
- 루아 스크립트 구현하여 루아 HTTP 필터에 로드
- 웹어셈블리 HTTP 필터용 Wasm 모듈 구현
- 이스티오의 EnvoyFilter 리소스 사용
- 엔보이의 필터 아키텍처에 대한 깊이 있는 이해 필요
EnvoyFilter 리소스로 엔보이 필터 설정하기
- EnvoyFilter 리소스 기본 개념
- 이스티오 API가 추상화하지 않는 엔보이 설정을 직접 구성할 때 사용
- VirtualService, DestinationRule 등은 결국 엔보이 설정으로 변환됨
- 이스티오는 엔보이의 모든 필터/설정을 노출하지 않음
- 고급 사용 사례를 위한 비상 수단(break glass solution)
- EnvoyFilter 주의사항
- 고급 사용자용으로 전체 데이터 플레인을 중단시킬 수 있음
- 엔보이 API는 이스티오 버전 간 언제든 변경 가능
- 이전 버전과의 호환성 보장 안됨
- 배포 전 반드시 유효성 검증 필요
- EnvoyFilter 적용 규칙
- 달리 지정하지 않으면 네임스페이스의 모든 워크로드에 적용
- istio-system 네임스페이스에 생성 시 메시 전체에 적용
- workloadSelector로 특정 워크로드 지정 가능
- 다른 이스티오 리소스들이 모두 변환/설정된 후에 적용
- tap 필터 사용 목적
- 워크로드의 데이터 플레인을 거치는 특정 요청 디버깅
- 엔보이의 기존 tap 필터 활용
- 메시지 샘플링하여 수신 에이전트로 스트리밍
- EnvoyFilter 구성 요소
- workloadSelector: app: webapp으로 특정 워크로드 지정
- applyTo: HTTP_FILTER로 설정 위치 지정
- match: SIDECAR_INBOUND, 포트 8080, router 필터 지정
- patch: INSERT_BEFORE 작업으로 router 필터 앞에 tap 필터 추가
# 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
외부 호출로 요청 속도 제한하기
- 속도 제한
- 기본 HTTP 필터 기능으로 이스티오 데이터 플레인 확장
- 외부 호출 기능을 가진 기본 필터들 활용
- 외부 서비스 호출하여 요청 계속 여부 결정
- 속도 제한 목적
- 특정 워크로드에서 서비스 측 속도 제한 적용
- 속도 제한 서비스 호출하도록 이스티오 데이터 플레인 설정
- 엔보이 HTTP 필터에서 속도 제한 호출 기능 제공
- 엔보이 속도 제한 방식
- 네트워크 필터, 로컬 속도 제한, 글로벌 속도 제한 등 여러 방법 존재
- 글로벌 속도 제한 기능에 집중
- 모든 엔보이 프록시가 동일한 속도 제한 서비스 호출
- 백엔드 글로벌 키-값 저장소 활용
- 글로벌 속도 제한 아키텍처
- 서비스 복제본 개수와 무관하게 속도 제한 적용 가능
- 요청 속성을 속도 제한 서버로 전송하여 결정
- 특정 요청에 속도 제한 적용 여부 판단
- 속도 제한 서버 배포
- 엔보이 커뮤니티 제공 속도 제한 서버 사용
- 엔보이 속도 제한 API 구현한 서버 배포 필요
- 백엔드 레디스 캐시와 통신 설정
- 레디스에 속도 제한 카운터 저장 (Memcached 사용 가능)
- 설정 요구사항
- 속도 제한 서버 배포 전 기대하는 속도 제한 동작으로 설정 필요
엔보이 속도 제한 이해하기
- 엔보이 HTTP 전역 속도 제한 기본 개념
- HTTP 필터로 존재하며 HCM의 HTTP 필터 체인에 설정 필요
- 속도 제한 서버(RLS) 구성 전 작동 원리 이해 필수
- 속도 제한 필터 처리 과정
- HTTP 요청 처리 시 요청에서 특정 속성 추출
- 추출한 속성을 RLS로 전송하여 평가 받음
- 디스크립터(descriptors): 속도 제한에서 속성들 또는 속성 그룹들
- 디스크립터 종류
- 원격 주소 (remote address)
- 요청 헤더 (request headers)
- 목적지 (destination)
- 요청의 기타 일반 속성들
- RLS 평가 과정
- 전송된 요청 속성을 미리 정의한 속성 집합과 비교
- 일치하는 속성의 카운터를 증가시킴
- 속성들을 트리 형태로 그룹화하거나 정의하여 카운트할 속성 결정
- 속도 제한 적용 기준
- 속성 또는 속성 집합이 RLS 정의와 일치하면 해당 제한 횟수 증가
- 카운트가 임계값 초과 시 해당 요청에 속도 제한 적용
엔보이 속도 제한 서버 설정하기
- 예제의 속도 제한 목적
- 로열티 등급에 따라 특정 사용자 그룹 제한
- x-loyalty 헤더를 검사하여 로열티 등급 판단
- 로열티 등급별 제한 규칙
- 골드 등급 (x-loyalty: gold): 분당 10개 요청 허용
- 실버 등급 (x-loyalty: silver): 분당 5개 요청 허용
- 브론즈 등급 (x-loyalty: bronze): 분당 3개 요청 허용
- 식별 불가능한 등급: 분당 1개 요청 허용
# 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
- 주요 특징
- 실제 요청 헤더를 직접 다루지 않고 전송된 속성만 처리
- 속성 정의 방법은 다음 절에서 다룰 예정
- 요청 처리 시 속성이 규칙 조건과 일치하면 제한 적용
요청 경로에 속도 제한 걸기
- 속도 제한 조치 설정
- 속도 제한 서버 설정 완료 후 엔보이에 속성 전송 설정 필요
- “특정 요청 경로에 취하는 속도 제한 조치(rate-limit action)”
- 설정 목적
- catalog 서비스의
/items
경로 호출 시x-loyalty
헤더 존재 여부 포착 - 요청이 어느 그룹에 속하는지 판단
- catalog 서비스의
- 설정 방법
- 특정 엔보이 루트 설정에 rate_limit 설정 지정 필요
- 적절한 속성 action을 속도 제한 서버로 전송하도록 구성
- 이스티오에서의 구현
- 이스티오에 전용 API가 아직 없음 (저술 시점 기준)
- EnvoyFilter 리소스 사용 필요
- catalog 서비스의 모든 경로에 속도 제한 조치 지정 가능
# 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
# k8s cm으로 규칙을 배포하고, 속도 제한 서버를 레디스 백엔드와 함께 배포
tree ch14/rate-limit
ch14/rate-limit
├── catalog-ratelimit-actions.yaml
├── catalog-ratelimit.yaml
├── rls.yaml
└── rlsconfig.yaml
cat ch14/rate-limit/rlsconfig.yaml
cat ch14/rate-limit/rls.yaml
kubectl apply -f ch14/rate-limit/rlsconfig.yaml -n istioinaction
kubectl apply -f ch14/rate-limit/rls.yaml -n istioinaction
# 확인
kubectl get cm -n istioinaction catalog-ratelimit-config
kubectl get pod -n istioinaction
# 엔보이가 속성을 속도 제한 서버로 보내게 해야 한다.
# 그래야 속도 제한 서버가 개수를 세어 속도 제한을 처리할 수 있기 때문
# 그 역할을 하는 EnvoyFilter를 적용
cat ch14/rate-limit/catalog-ratelimit.yaml
cat ch14/rate-limit/catalog-ratelimit-actions.yaml
kubectl apply -f ch14/rate-limit/catalog-ratelimit.yaml -n istioinaction
kubectl apply -f ch14/rate-limit/catalog-ratelimit-actions.yaml -n istioinaction
kubectl get envoyfilter -A
# 속도 제한 기능 테스트
# sleep 앱에서 catalog 서비스를 호출 시도 : 대략 1분에 한 번 정도 호출 성공! >> x-loyalty 헤더가 없을 때 속도 제한 값!
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://catalog/items -v
kubectl exec -it deploy/sleep -n istioinaction -c sleep -- curl http://catalog/items -v
# silver 헤더는? (반복 호출)
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'
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'InboundPassthroughClusterIpv4' -o json | grep actions
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||'
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||' -o json | grep actions
docker exec -it myk8s-control-plane istioctl proxy-config route deploy/catalog.istioinaction --name 'inbound|3000||' -o json
루아로 이스티오의 데이터 플레인 확장하기
- 루아 확장의 필요성
- 기존 엔보이 필터로 구현할 수 없는 기능이 필요한 경우
- 요청 경로에 커스텀 로직 구현이 필요한 경우
- 자체 커스텀 로직으로 데이터 플레인 동작 확장
- 루아 필터 기능
- 엔보이의 기본 필터 중 하나
- 루아 스크립트를 작성하여 프록시에 주입 가능
- 요청/응답 경로의 동작을 커스터마이징
- 루아 스크립트 활용
- 요청이나 응답의 헤더 조작
- 바디 검사 및 처리
- EnvoyFilter 리소스를 통해 데이터 플레인 설정
- 요청 경로 처리 변경 가능
- 루아 프로그래밍 언어 특징
- 강력하면서도 내장 가능한 스크립팅 언어
- 시스템 기능 강화 목적으로 설계
- 동적 타입의 인터프리터 언어
- 루아 가상머신의 자동 메모리 관리 (엔보이에서는 LuaJIT 사용)
- 성능 고려사항
- 요청 바디 검사 시 프록시의 스트림 처리 방식에 영향
- 바디 전체를 메모리에 적재할 경우 성능에 영향 가능
- 루아 필터 사용 시 엔보이 문서 참조 권장
- 구현 방법
- EnvoyFilter 리소스를 사용하여 루아 스크립트 주입
- 요청 경로 처리 변경을 통한 기능 확장
웹어셈블리로 이스티오의 데이터 플레인 확장하기
웹어셈블리 소개
- 웹어셈블리(Wasm) 기본 개념
- 바이너리 명령 형식으로 설계
- 여러 환경 간 이식 가능을 목표
- 여러 프로그래밍 언어로 컴파일 가능
- 가상머신에서 실행
- 개발 목적
- 브라우저 웹 애플리케이션의 CPU 집약적 작업 실행 속도 향상
- 브라우저 기반 애플리케이션 지원을 자바스크립트 외 언어로 확장
- 2019년 W3C 권고사항으로 승인
- 모든 주요 브라우저에서 지원
- 웹어셈블리 특징
- 모듈로 패키징된 커스텀 코드
- 격리된 가상머신에서 안전하게 실행
- 저장 공간과 메모리를 적게 차지
- 거의 네이티브에 가까운 속도로 실행
- 보안 특성
- 호스트 애플리케이션에 내장되어도 안전
- 메모리 안전(memory safe) 보장
- 격리된(sandboxed) 실행 환경에서 동작
- 호스트 시스템이 허용하는 메모리와 기능에만 접근 가능
- 실행 환경
- 대상 호스트(웹 브라우저 등) 내부의 가상머신에서 실행
- 호스트 시스템의 제어 하에 제한된 접근 권한
왜 엔보이에 웹어셈블리를 사용하는가?
- 네이티브 엔보이 필터 작성의 단점
- C++ 언어 사용 필수
- 변경 사항을 엔보이의 새 바이너리로 정적 빌드 필요
- 사실상 ‘커스텀’ 엔보이 빌드 필요
- 엔보이의 웹어셈블리 지원
- 웹어셈블리 실행 엔진 내장
- HTTP 필터 포함 엔보이의 다양한 영역 커스터마이징 가능
- 확장 기능 제공
- 웹어셈블리 필터 장점
- 웹어셈블리 지원 언어로 엔보이 필터 작성 가능
- 런타임에 프록시로 동적 로드 가능
- 기본 엔보이 프록시 사용하면서 커스텀 필터 동적 로드
- 웹어셈블리 모듈 배포 방식
- 로컬 캐시에 Wasm 확장 설정
- 원하는 Wasm 확장을 로컬 캐시로 풀
- 적절한 워크로드에 wasm-cache 마운트
- EnvoyFilter CRD로 Wasm 필터 사용하도록 엔보이 구성
- Istio의 원격 Wasm 모듈 지원
- Istio 1.9부터 istio-agent가 원격 HTTP 소스에서 Wasm 바이너리 로드
- xDS 프록시와 ECDS 활용한 안정적인 솔루션 제공
- Istio 1.12에서 새로운 Wasm API 구현
- OCI 이미지 지원
- Istio 1.12부터 Wasm OCI 이미지로 기능 확장
- Docker Hub, GCR, ECR 등 모든 OCI 레지스트리에서 Wasm 이미지 가져오기 가능
- Wasm 바이너리 추출, 캐시 후 Envoy 필터 체인에 삽입
- 안정적인 배포 메커니즘
- istio-agent가 확장 구성 리소스 업데이트 가로채기
- 원격 페치 힌트 읽어와 Wasm 모듈 다운로드
- 다운로드 실패 시 ECDS 업데이트 거부로 잘못된 구성 방지
I feedback.
Let me know what you think of this article in the comment section below!
Let me know what you think of this article in the comment section below!
comments powered by Disqus