서비스 메시
마이크로 서비스 아키텍쳐의 환경에서 전체 시스템에 대한 모니터링의 어려움과 운영시 장애 또는 문제 발생시 원친 찾기가 어려움에서 출발했습니다. 주로 Istio, Linkerd와 같은 것들이 대표적이고 MSA로 배포된 어플리케이션들에 대해 통신이나 경로를 제어하는데 사용합니다.
# 기본 동작
App -> App
# Sidecar를 통한 Proxy사용
APP APP
Proxy -> Proxy
# 관리가 필요하다
App App
Proxy -> Proxy
Control Plane ┘
- Proxy 는 중앙에서 설정 관리가 잘되는 툴을 선택. 즉, 원격에서 동적인 설정 관리가 유연해야함 → 풍부한 API 지원이 필요 ⇒ Envoy
- ‘구글 IBM 리프트(Lyft)‘가 중심이 되어 개발하고 있는 오픈 소스 소프트웨어이며, C++ 로 구현된 고성능 Proxy 인 엔보이(Envoy)
- 네트워크의 투명성을 목표, 다양한 필터체인 지원(L3/L4, HTTP L7), 동적 configuration API 제공, api 기반 hot reload 제공
- 중앙에서 어떤 동작/설정을 관리해야 될까? 라우팅, 보안 통신을 위한 mTLS 관련, 동기화 상태 정보 등
이를 통해 아래의 효과들을 얻을수 있습니다.
- 트래픽 모니터링 : 요청의 ‘에러율, 레이턴시, 커넥션 개수, 요청 개수’ 등 메트릭 모니터링, 특정 서비스간 혹은 특정 요청 경로로 필터링 → 원인 파악 용이!
- 트래픽 컨트롤 : 트래픽 시프팅(Traffic shifting), 서킷 브레이커(Circuit Breaker), 폴트 인젝션(Fault Injection), 속도 제한(Rate Limit)
- 트래픽 시프팅(Traffic shifting) : 예시) 99% 기존앱 + 1% 신규앱 , 특정 단말/사용자는 신규앱에 전달하여 단계적으로 적용하는 카니리 배포 가능
- 서킷 브레이커(Circuit Breaker) : 목적지 마이크로서비스에 문제가 있을 시 접속을 차단하고 출발지 마이크로서비스에 요청 에러를 반환 (연쇄 장애, 시스템 전제 장애 예방)
- 폴트 인젝션(Fault Injection) : 의도적으로 요청을 지연 혹은 실패를 구현
- 속도 제한(Rate Limit) : 요청 개수를 제한
Istio
- 파일럿(Pilot): 모든 Envoy 사이드카에서 프록시 라우팅 규칙을 관리하며, 서비스 디스커버리와 로드 밸런싱 설정을 제공합니다.
- 갤리(Galley): Istio와 쿠버네티스(TLS 연결 및 파일럿에 필요한 설정)를 연결해 주는 역할을 합니다. 서비스 메시 구성 데이터를 검증하고 변환합니다.
- 시타델(Citadel): 보안 기능을 담당하며, TLS 인증서 발급 및 관리를 통해 서비스 간 통신의 암호화를 수행합니다.
Istio 구성요소와 envoy : 컨트롤 플레인(istiod) , 데이터 플레인(istio-proxy > envoy)
istiod : Pilot(데이터 플레인과 통신하면서 라우팅 규칙을 동기화, ADS), Gally(Istio 와 K8S 연동, Endpoint 갱신 등), Citadel(연결 암호화, 인증서 관리 등)
Istio proxy : Golang 으로 작성되었고 envoy 래핑한 Proxy, istiod와 통신하고 서비스 트래픽을 통제, 옵저버빌리티를 위한 메트릭 제공
이스티오는 각 파드 안에 사이드카로 엔보이 프록시가 들어가 있는 형태
모든 마이크로서비스간 통신은 엔보이를 통과하여, 메트릭을 수집하거나 트래픽 컨트롤을 할 수 있음
트래픽 컨트롤을 하기위해 엔보이 프록시에 전송 룰을 설정 → 컨트롤 플레인의 이스티오가 정의된 정보를 기반으로 엔보이 설정을 하게 함
마이크로서비스 간의 통신을 mutual TLS 인증(mTLS)으로 서로 TLS 인증으로 암호화 할 수 있음
각 애플리케이션은 파드 내의 엔보이 프록시에 접속하기 위해 localhost 에 TCP 접속을 함
Envoy(Use Istio Sidecar)
Envoy는 그 자체로 L4/L7용 Proxy이지만, Istio에서는 이를 POD의 통신을 위한 Sidecar Proxy로 사용됩니다. 그리고 가장 좋은 부분은 구성(설정)을 동적으로 관리할수 있도록 API가 제공이 된다는 점입니다.
Istio 구성요소와 envoy : 컨트롤 플레인(istiod) - ADS 를 이용한 Configuration 동기화 - 데이터 플레인(istio-proxy → envoy)
Cluster : envoy 가 트래픽을 포워드할 수 있는 논리적인 서비스 (엔드포인트 세트), 실제 요청이 처리되는 IP 또는 엔드포인트의 묶음을 의미.
Endpoint : IP 주소, 네트워크 노드로 클러스터로 그룹핑됨, 실제 접근이 가능한 엔드포인트를 의미. 엔드포인트가 모여서 하나의 Cluster 가 된다.
Listener : 무엇을 받을지 그리고 어떻게 처리할지 IP/Port 를 바인딩하고, 요청 처리 측면에서 다운스트림을 조정하는 역할.
Route : Listener 로 들어온 요청을 어디로 라우팅할 것인지를 정의. 라우팅 대상은 일반적으로 Cluster 라는 것에 대해 이뤄지게 된다.
Filter : Listener 로부터 서비스에 트래픽을 전달하기까지 요청 처리 파이프라인
UpStream : envoy 요청을 포워딩해서 연결하는 백엔드 네트워크 노드 - 사이드카일때 application app, 아닐때 원격 백엔드
DownStream : An entity connecting to envoy, In non-sidecar models this is a remote client
Envoy API 사용 사례
- Service Mesh 솔루션이나, Gateway API 구현체들을 Enovy를 내부적으로 사용하고 있으며, Envoy가 제공하는 동적 구성을 위한 API (xDS Sync API)를 이용하여 다양한 네트워크 정책을 구성하게 됩니다.
- Envoy의 xDS Sync API는 아래와 같은 레이어에서 동작하게 됩니다.
- LDS - Listener Discovery Service
- RDS - Route Discovery Service
- CDS - Cluseter Discovery Service
- EDS - Endpoint Discovery Service
실습
Istio 설치(K3s)
istioctl 설치
export ISTIOV=1.23.2
echo "export ISTIOV=1.23.2" >> /etc/profile
curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV TARGET_ARCH=x86_64 sh -
tree istio-$ISTIOV -L 2 # sample yaml 포함
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl version --remote=false
실습을 위한 커스터마이징 배포
istioctl profile list
istioctl profile dump default
istioctl profile dump --config-path components.ingressGateways
istioctl profile dump --config-path values.gateways.istio-ingressgateway
istioctl profile dump demo
istioctl profile dump demo > demo-profile.yaml
vi demo-profile.yaml # 복잡성을 줄이게 실습 시나리오 환경 맞춤
--------------------
egressGateways:
- enabled: false
--------------------
istioctl install -f demo-profile.yaml -y
|\
| \
| \
| \
/|| \
/ || \
/ || \
/ || \
/ || \
/ || \
/______||__________\
____________________
\__ _____/
\_____/
✔ Istio core installed ⛵️
✔ Istiod installed 🧠
✔ Ingress gateways installed 🛬
✔ Installation complete Made this installation the default for cluster-wide operations.
설치 확인
k get all,svc,ep,sa,cm,secret,pdb -n istio-system
NAME READY STATUS RESTARTS AGE
pod/istio-ingressgateway-64f9774bdc-x54sg 1/1 Running 0 2m49s
pod/istiod-868cc8b7d7-qchx7 1/1 Running 0 2m59s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/istio-ingressgateway LoadBalancer 10.200.1.162 <pending> 15021:31242/TCP,80:31662/TCP,443:30634/TCP 2m49s
service/istiod ClusterIP 10.200.1.187 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 2m59s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/istio-ingressgateway 1/1 1 1 2m49s
deployment.apps/istiod 1/1 1 1 2m59s
NAME DESIRED CURRENT READY AGE
replicaset.apps/istio-ingressgateway-64f9774bdc 1 1 1 2m49s
replicaset.apps/istiod-868cc8b7d7 1 1 1 2m59s
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/istio-ingressgateway Deployment/istio-ingressgateway cpu: <unknown>/80% 1 5 1 2m49s
horizontalpodautoscaler.autoscaling/istiod Deployment/istiod cpu: <unknown>/80% 1 5 1 2m59s
NAME ENDPOINTS AGE
endpoints/istio-ingressgateway 10.10.0.6:15021,10.10.0.6:8080,10.10.0.6:8443 2m49s
endpoints/istiod 10.10.0.5:15012,10.10.0.5:15010,10.10.0.5:15017 + 1 more... 2m59s
NAME SECRETS AGE
serviceaccount/default 0 3m1s
serviceaccount/istio-ingressgateway-service-account 0 2m49s
serviceaccount/istio-reader-service-account 0 3m
serviceaccount/istiod 0 2m59s
NAME DATA AGE
configmap/istio 2 2m59s
configmap/istio-ca-root-cert 1 2m51s
configmap/istio-gateway-status-leader 0 2m51s
configmap/istio-leader 0 2m51s
configmap/istio-namespace-controller-election 0 2m51s
configmap/istio-sidecar-injector 2 2m59s
configmap/kube-root-ca.crt 1 3m1s
NAME TYPE DATA AGE
secret/istio-ca-secret istio.io/ca-root 5 2m51s
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
poddisruptionbudget.policy/istio-ingressgateway 1 N/A 0 2m49s
poddisruptionbudget.policy/istiod 1 N/A 0 2m59s
Ingress Gateway 설정 변경
k patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
Egress Gateway 설정 변경
k patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
default namespace에 sidecar 설정
mutating Webhook admisstion controller 사용
k label namespace default istio-injection=enabled
k get ns -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 7m33s enabled
Nginx 설정 배포 및 Istio 설정
Nginx 배포
cat <<EOF | k apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: kans-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-websrv
spec:
replicas: 1
selector:
matchLabels:
app: deploy-websrv
template:
metadata:
labels:
app: deploy-websrv
spec:
serviceAccountName: kans-nginx
terminationGracePeriodSeconds: 0
containers:
- name: deploy-websrv
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-clusterip
spec:
ports:
- name: svc-webport
port: 80
targetPort: 80
selector:
app: deploy-websrv
type: ClusterIP
EOF
Istio 설정
cat <<EOF | k apply -f -
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: test-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: nginx-service
spec:
hosts:
- "*" # 도메인 접속이 잘 되지 않을 경우 "*" 로 변경하고 IP로 접속 할 것
gateways:
- test-gateway
http:
- route:
- destination:
host: svc-clusterip
port:
number: 80
EOF
로컬테스트
curl -v -s 127.0.0.1:30000
* Trying 127.0.0.1:30000...
* Connected to 127.0.0.1 (127.0.0.1) port 30000
GET / HTTP/1.1
Host: 127.0.0.1:30000
User-Agent: curl/8.7.1
Accept: */*
* Request completely sent off
< HTTP/1.1 200 OK
< server: istio-envoy
...
리소스 정리
k delete gw,vs,deploy,svc --all
Bookinfo(데모)를 통한 Istio 실습
bookinfo 배포
echo $ISTIOV
cat ~/istio-$ISTIOV/samples/bookinfo/platform/kube/bookinfo.yaml
k apply -f ~/istio-$ISTIOV/samples/bookinfo/platform/kube/bookinfo.yaml
확인
k exec "$(k get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
인입 설정
cat ~/istio-$ISTIOV/samples/bookinfo/networking/bookinfo-gateway.yaml
k apply -f ~/istio-$ISTIOV/samples/bookinfo/networking/bookinfo-gateway.yaml
확인
k get gw,vs
NAME AGE
gateway.networking.istio.io/bookinfo-gateway 23s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/bookinfo ["bookinfo-gateway"] ["*"] 23s
istioctl proxy-status
NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION
details-v1-65cfcf56f9-pl7xh.default Kubernetes SYNCED (2m38s) SYNCED (2m38s) SYNCED (2m38s) SYNCED (2m38s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2
istio-ingressgateway-64f9774bdc-x54sg.istio-system Kubernetes SYNCED (60s) SYNCED (60s) SYNCED (15m) SYNCED (60s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2
productpage-v1-d5789fdfb-xmk69.default Kubernetes SYNCED (5m50s) SYNCED (5m50s) SYNCED (5m50s) SYNCED (5m50s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2
ratings-v1-7c9bd4b87f-6pwzk.default Kubernetes SYNCED (2m32s) SYNCED (2m32s) SYNCED (2m32s) SYNCED (2m32s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2
reviews-v1-6584ddcf65-mkd8f.default Kubernetes SYNCED (6m10s) SYNCED (6m10s) SYNCED (6m10s) SYNCED (6m10s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2
reviews-v2-6f85cb9b7c-fgqct.default Kubernetes SYNCED (5m53s) SYNCED (5m53s) SYNCED (5m53s) SYNCED (5m53s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2
reviews-v3-6f5b775685-bv47t.default Kubernetes SYNCED (2m52s) SYNCED (2m52s) SYNCED (2m52s) SYNCED (2m52s) IGNORED istiod-868cc8b7d7-qchx7 1.23.2

모니터링
Add-on 설치
tree ~/istio-$ISTIOV/samples/addons/
k apply -f ~/istio-$ISTIOV/samples/addons # 디렉터리에 있는 모든 yaml 자원을 생성
k rollout status deployment/kiali -n istio-system
Add-on 포트 변경
k patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
k patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
k patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'

