목표:
1. 서비스 메시 소개
2. Envoy 소개
3. istio 소개
4. istio 기본 default 설정 (gateway , virtual service) 를 통한 기본 인입
서비스 메시
등장배경 :
마이크로서비스 아키텍처 환경의 시스템 전체 모니터링의 어려움, 운영 시 시스템 장애나 문제 발생할 때 원인과 병목 구간 찾기 어려움
내부망 진입점에 역할을 하는 GW(예. API Gateway) 경우 모든 동작 처리에 무거워지거나, 내부망 내부 통신 제어는 어려움
기본 동작 :
파드 간 통신 경로에 프록시를 놓고 트래픽 모니터링이나 트래픽 컨트롤 → 기존 애플리케이션 코드에 수정 없이 구성 가능!
1. 애플리케이션의 변경 없이 , 모든 애플리케이션 통신 사이에 Proxy를 두고 통신 해보자.
- 파드 내에 사이드 카 컨테이너로 주입
- Proxy 컨테이너가 Application 트래픽을 가로채야됨 ( iptables rule 구현)
2. Proxy는 결국 Dataplane이니, 이를 중앙에서 관리하는 ControlPlane을 두고 중앙에서 관리
- Proxy는 중앙에서 설정관리가 잘되는 툴을 선택, 즉 원격에서 동적인 설정관리가 유연해야함
- 중앙에서 어떤 동작/설정을 관리해야 할까? 라우팅 , 보안 통신을 위한 mtLS 관련, 동기화 상태 정보 등
특징:
Observablity
- 에러율, 레이턴시 , 커넥션 개수, 요청 개수 등
- 메트릭 모니터링 , 특정 서비스 간 혹은 특정 요청 경로로 필터링 가능
Traffic Control
- 트래픽 시프팅 - 카나리 배포
- 서킷 브레이커 - 연쇄 장애, 시스템 전체 장애 예방
- 폴트 인젝션 - 의도적으로 요청을 지연 및 실패 구현
- 속도 제한 - 요청 개수를 제한
Envoy
Envoy
- L4/7 Proxy, istio의 Sidecar proxy로 사용
- 서비스메시 솔루션이나 Gatway API 구현체들을 Envoy를 내부적으로 사용하고 있으며, 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
실습에서 계속 xDS에 대한 언급이 있으므로 주요 구성요소를 조금 더 살펴보겠습니다,
- Configuration (좌측):
- 여러 소스에서 수집된 설정 데이터입니다. 이는 다양한 네트워크, 보안, 라우팅, 엔드포인트 정보를 포함할 수 있습니다. 컨트롤 플레인은 이러한 설정 데이터를 모아서 Envoy에 전달합니다.
- Control Plane (중앙):
- Envoy가 사용할 설정 정보를 수집하고 관리하는 역할을 합니다. 컨트롤 플레인은 xDS API를 통해 Envoy에게 다양한 설정 데이터를 제공합니다. 여기서 각 API는 서로 다른 유형의 설정을 제공하며, 이를 통해 Envoy가 트래픽을 효과적으로 제어할 수 있습니다.
- xDS APIs (우측):
- 컨트롤 플레인은 다양한 xDS API를 통해 Envoy로 데이터를 전송하며, 각 API의 역할은 다음과 같습니다
- SDS (Secret Discovery Service): Envoy가 TLS 인증서와 같은 보안 정보를 동적으로 가져오는 서비스
- EDS (Endpoint Discovery Service): 백엔드 서비스의 엔드포인트 정보를 Envoy에게 제공
- CDS (Cluster Discovery Service): 클러스터 정보를 전달합니다. 클러스터는 백엔드 서버의 그룹으로, Envoy는 이를 통해 어떤 서버로 트래픽을 보낼지 결정
- LDS (Listener Discovery Service): Envoy의 리스너 설정을 관리합니다. 리스너는 네트워크 요청을 수신하는 엔티티
- RDS (Route Discovery Service): 트래픽 라우팅 규칙을 제공합니다. Envoy는 이를 통해 클라이언트 요청을 적절한 백엔드 서비스로 라우팅
- GRPC (Envoy컨테이너와의 통신):
- 앞서 설명했듯이 컨트롤 플레인은 Envoy와 gRPC를 통해 통신합니다. gRPC는 고성능 원격 프로시저 호출(Remote Procedure Call) 시스템으로, Envoy는 이 프로토콜을 통해 컨트롤 플레인으로부터 동적으로 설정을 받아 트래픽을 제어
Envoy 실습
- envoy install
# 설치
# echo "deb [signed-by=/etc/apt/keyrings/envoy-keyring.gpg] https://apt.envoyproxy.io focal main" | sudo tee /etc/apt/sources.list.d/envoy.list
wget -O- https://apt.envoyproxy.io/signing.key | sudo gpg --dearmor -o /etc/apt/keyrings/envoy-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/envoy-keyring.gpg] https://apt.envoyproxy.io jammy main" | sudo tee /etc/apt/sources.list.d/envoy.list
sudo apt-get update && sudo apt-get install envoy -y
# 확인
envoy --version
# 도움말
envoy --help
- envoy test
# (터미널1) 데모 config 적용하여 실행
curl -O https://www.envoyproxy.io/docs/envoy/latest/_downloads/92dcb9714fb6bc288d042029b34c0de4/envoy-demo.yaml
envoy -c envoy-demo.yaml
# (터미널2) 정보 확인
ss -tnlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 0.0.0.0:10000 0.0.0.0:* users:(("envoy",pid=8007,fd=18),("envoy",pid=8007,fd=16))
# 접속 테스트
curl -s http://127.0.0.1:10000 | grep -o "<title>.*</title>"
# 외부 접속 정보 출력
echo -e "http://$(curl -s ipinfo.io/ip):10000"
http://[외부아이피]:10000
--------------------
# 자신의 PC 웹브라우저에서 외부 접속 정보 접속 확인!
# k3s-s 에서 접속 테스트
curl -s http://192.168.10.200:10000 | grep -o "<title>.*</title>"
--------------------
# 연결 정보 확인
ss -tnp
# (터미널1) envoy 실행 취소(CTRL+C) 후 (관리자페이지) 설정 덮어쓰기 - 링크
cat <<EOT> envoy-override.yaml
admin:
address:
socket_address:
address: 0.0.0.0
port_value: 9902
EOT
envoy -c envoy-demo.yaml --config-yaml "$(cat envoy-override.yaml)"
# envoy 관리페이지 외부 접속 정보 출력
echo -e "http://$(curl -s ipinfo.io/ip):9902"
http://[외부아이피]:9902
--------------------
# 자신의 PC 웹브라우저에서 관리 페이지 외부 접속 정보 접속 확인!
istio
1. istio install
# 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
# (default 프로파일) 컨트롤 플레인 배포 - 링크 Customizing
# The istioctl command supports the full IstioOperator API via command-line options for individual settings or for passing a yaml file containing an IstioOperator custom resource (CR).
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 🧠
✔ Istio core installed ⛵️
✔ Istiod installed 🧠
✔ Ingress gateways installed 🛬
✔ Installation complete
# 설치 확인 : istiod, istio-ingressgateway
kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
kubectl get crd | grep istio.io | sort
# istio-ingressgateway 의 envoy 버전 확인
kubectl exec -it deploy/istio-ingressgateway -n istio-system -c istio-proxy -- envoy --version
envoy version: 6c72b2179f5a58988b920a55b0be8346de3f7b35/1.31.2-dev/Clean/RELEASE/BoringSSL
# istio-ingressgateway 서비스 NodePort로 변경
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"type":"NodePort"}}'
# istio-ingressgateway 서비스 확인
kubectl get svc,ep -n istio-system istio-ingressgateway
## istio-ingressgateway 서비스 포트 정보 확인
kubectl get svc -n istio-system istio-ingressgateway -o jsonpath={.spec.ports[*]} | jq
## istio-ingressgateway 디플로이먼트 파드의 포트 정보 확인
kubectl get deploy/istio-ingressgateway -n istio-system -o jsonpath={.spec.template.spec.containers[0].ports[*]} | jq
kubectl get deploy/istio-ingressgateway -n istio-system -o jsonpath={.spec.template.spec.containers[0].readinessProbe} | jq
# istiod(컨트롤플레인) 디플로이먼트 정보 확인
kubectl exec -it deployment.apps/istiod -n istio-system -- ss -tnlp
kubectl exec -it deployment.apps/istiod -n istio-system -- ss -tnp
kubectl exec -it deployment.apps/istiod -n istio-system -- ps -ef
UID PID PPID C STIME TTY TIME CMD
istio-p+ 1 0 0 05:27 ? 00:00:07 /usr/local/bin/pilot-discovery discovery --monitoringAddr=:15014 --log_output_l
# istio-ingressgateway 디플로이먼트 정보 확인
kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ss -tnlp
kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ss -tnp
kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ps -ef
istio-p+ 1 0 0 05:27 ? 00:00:01 /usr/local/bin/pilot-agent proxy router --domain istio-system.svc.cluster.local
istio-p+ 15 1 0 05:27 ? 00:00:11 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev.json --drain-time-s 45 --drai
kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- cat /etc/istio/proxy/envoy-rev.json
kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ss -xnlp
kubectl exec -it deployment.apps/istio-ingressgateway -n istio-system -- ss -xnp
- 사이드카 주입 : Auto Injection with namespace label : 해당 네임스페이스에 생성되는 모든 파드들은 istio 사이드카가 자동으로 injection 됨
(⎈|default:N/A) root@k3s-s:~# kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"type":"NodePort"}}'
service/istio-ingressgateway patched
(⎈|default:N/A) root@k3s-s:~# kubectl label namespace default istio-injection=enabled
namespace/default labeled
(⎈|default:N/A) root@k3s-s:~# kubectl get ns -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 2d8h enabled
istio-system Active 92s
kube-node-lease Active 2d8h
kube-public Active 2d8h
kube-system Active 2d8h
2. Istio 접속 테스트를 위한 변수 지정
k3s-s )
mypc)
## istio-ingressgateway 파드가 배치된 노드의 유동 공인 IP 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text
k3s-s 3.38.151.222 running
k3s-w1 15.165.75.117 running
k3s-w2 3.39.223.99 running
testpc 54.180.243.135 running
k3s-s)
# istio ingress gw NodePort(HTTP 접속용) 변수 지정 : 아래 ports[0] 은 어떤 용도의 포트일까요?
export IGWHTTP=$(kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[1].nodePort}')
echo $IGWHTTP
IGWHTTP=<각자 자신의 NodePort>
# /etc/hosts 파일 수정
MYDOMAIN=<각자 자신의 www 도메인> # 단, 사용하고 있지 않는 공인 도메인을 사용 할 것
MYDOMAIN=www.gasida.dev
echo "<istio-ingressgateway 파드가 있는 워커 노드> $MYDOMAIN" >> /etc/hosts
MYDOMAIN=<각자 자신의 www 도메인>
export MYDOMAIN=www.gasida.dev
echo -e "192.168.10.10 $MYDOMAIN" >> /etc/hosts
echo -e "export MYDOMAIN=$MYDOMAIN" >> /etc/profile
# istio ingress gw 접속 테스트 : 아직은 설정이 없어서 접속 실패가 된다
curl -v -s $MYDOMAIN:$IGWHTTP
testpc )
# 아래 변수는 각자 자신의 값을 직접 입력 할 것
IGWHTTP=<각자 출력된 NodePort>
IGWHTTP=32759
export MYDOMAIN=www.gasida.dev
echo -e "192.168.10.10 $MYDOMAIN" >> /etc/hosts
echo -e "export MYDOMAIN=$MYDOMAIN" >> /etc/profile
# istio ingress gw 접속 테스트 : 아직은 설정이 없어서 접속 실패가 된다
curl -v -s $MYDOMAIN:$IGWHTTP
curl -v -s $MYDOMAIN:$IGWHTTP
3. Istio 통한 외부 노출
# 로그 모니터링
kubectl get pod -n istio-system -l app=istiod
kubetail -n istio-system -l app=istiod -f
kubectl get pod -n istio-system -l app=istio-ingressgateway
kubetail -n istio-system -l app=istio-ingressgateway -f
- 파드와 서비스 배포
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-websrv
spec:
replicas: 1
selector:
matchLabels:
app: deploy-websrv
template:
metadata:
labels:
app: deploy-websrv
spec:
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
# 사이드카 컨테이너 배포 확인
kubectl get pod,svc,ep -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-websrv-7d7cf8586c-rhhv8 2/2 Running 0 29s 172.16.2.6 k3s-w2 <none> <none>
...
kc describe pod
- gw/vs/ 배포
cat <<EOF | kubectl create -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:
- "$MYDOMAIN"
gateways:
- test-gateway
http:
- route:
- destination:
host: svc-clusterip
port:
number: 80
EOF
(⎈|default:N/A) root@k3s-s:~# kubectl get gw,vs
NAME AGE
gateway.networking.istio.io/test-gateway 82s
NAME GATEWAYS HOSTS AGE
virtualservice.networking.istio.io/nginx-service ["test-gateway"] ["www.koo.dev"] 82s
4. istio Book info 실습
Kubernetes 클러스터 내에서 실행되고 있는 ratings 애플리케이션의 Pod에서 (아직 외부 호출 아 님)
productpage 서비스에 요청 을 보내고 그 응답에서 <title> 태그를 추출
- 배포 후 모니터링
# 모니터링
watch -d 'kubectl get pod -owide;echo;kubectl get svc'
# Bookinfo 애플리케이션 배포
echo $ISTIOV
cat ~/istio-$ISTIOV/samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f ~/istio-$ISTIOV/samples/bookinfo/platform/kube/bookinfo.yaml
# 확인
kubectl get all,sa
# product 웹 접속 확인
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
# 로그
kubetail -l app=productpage -f
- 초록 글씨 - istio proxy / 빨간 글씨 - productpage
- Istio의 VirtualService 리소스를 정의
- 앞단의 istio-proxy에 대한 로그가 확인됩니다.
- 사용자가 클러스터 내부 pod에서 호출요청을 할 수 있음.
- http://<gateway-ip>:8080/productpage에 접근하면 productpage 서비스의 포트 9080으로 요청이 전달됩니다.
- review 1, 2에 대한 페이징이 랜덤으로 전달됩니다.
- Istio의 VirtualService 리소스를 정의
- 이제 ingress-gateway를 통한 클러스터 외부에서의 인입을 생성하겠다.
- 그러기 위해선 gateway와 virtual service가 필요하다.
(⎈|default:N/A) root@k3s-s:~# cat ~/istio-$ISTIOV/samples/bookinfo/networking/bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 8080
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
(⎈|default:N/A) root@k3s-s:~# kubectl apply -f ~/istio-$ISTIOV/samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
- k8s-s에서 통신 테스트
# k8s-s에 접속해서 실행
export IGWHTTP=$(kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[1].nodePort}')
echo $IGWHTTP
32759
# 접속 확인
kubectl get svc -n istio-system istio-ingressgateway
curl -s http://localhost:$IGWHTTP/productpage
curl -s http://192.168.10.101:$IGWHTTP/productpage
curl -s http://192.168.10.102:$IGWHTTP/productpage
# 정보 확인
echo $MYDOMAIN
cat /etc/hosts
#
curl -s http://$MYDOMAIN:$IGWHTTP/productpage
- 내 노트북에서 통신 테스트
# 노트북에서 실행
echo $MYDOMAIN $IGWHTTP
cat /etc/hosts
#
curl -v -s $MYDOMAIN:$IGWHTTP/productpage
echo -e "http://$MYDOMAIN:$IGWHTTP/productpage"
#
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text
'컨테이너 > 쿠버네티스 네트워크' 카테고리의 다른 글
[KANS] 쿠버네티스 네트워크 (15) Cilium (0) | 2024.10.26 |
---|---|
[KANS] 쿠버네티스 네트워크 (14) Service Mesh (istio) : Traffic Management (0) | 2024.10.19 |
[KANS] 쿠버네티스 네트워크 (12) Gateway API (0) | 2024.10.12 |
[KANS] 쿠버네티스 네트워크 (11) ingress (3) | 2024.10.08 |
[KANS] 쿠버네티스 네트워크 (10) Service : LoadBalancer (0) | 2024.10.03 |