실습환경 구성
실습 template
https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-7w.yaml
위 url을 cloudformation stack 으로 실행합니다.
stack name, keyName 등을 적절히 선택해줍니다.
cloudformation에서 생성된 리소스는 다음과 같이 확인이 가능합니다.
Istio 소개
개요
MSA 환경에서 시스템 전체의 모니터링의 어려움과 운영 중 장애 발생시 원인과 문제점을 찾기가 어려워졌습니다. 이를 해결하기 위해 네트워크 통신의 안정성과 보안, o11y 등의 요구사항이 증가하였습니다. 이런 문제점들의 해결책으로 서비스메시가 등장하였습니다. istio는 서비스메시의 구현체중 하나로 데이터 플레인과 컨트롤 플레인이 존재합니다. 데이터플레인은 envoy proxy를 사이드카로 활용하고, 컨트롤 플레인은 이러한 envoy proxy를 관리하고 구성합니다.
istio는 2가지 모드를 제공하고 2가지 모드에 대해서 설명하겠지만 sidecar pattern에 대해서 더 자세히 다룰 예정입니다.
구성
istio는 control plane과 data plane이라는 영역으로 논리적으로 나뉩니다. data plane은 sidecar 형태로 배포된 일종의 지능형 proxy 입니다. 이러한 프록시는 microservice 사이의 모든 네트워크 통신을 중개하고 제어합니다. 또한 모든 메시 트래픽에 대한 원격 분석을 수집(collect)하고 보고(report) 합니다. control plane은 트래픽 라우팅을 위해 프록시를 관리하고 구성합니다.
istio는 각 pod 내에 sidecar 혀앹로 envoy proxy가 포함된 형태
Control Plane
1.5 버전 이전에는 Pilot, Citadel, Galley, Mixer 4가지 구성을 포함했습니다. 1.5 버전 이후에는 Mixer를 제외한 3가지 구성요소를 istiod라는 단일 구성으로 통합되었습니다.
- Pilot: envoy sidecar에서 proxy routing rule을 관리, service discovery, load balancing 설정을 제공합니다.
- Citadel: 보안 기능을 담당하며 TLS 인증서 발급 및 관리를 통해 서비스간 통신 암호화를 수행합니다.
- Gally: istio와 쿠버네티스를 연결해주는 역할을 합니다.
Data Plane
istio는 확장된 버전의 envoy proxy를 사용합니다. 엔보이는 모든 인바운드 아웃바운드 트래픽을 중개(mediate)하기위해서 c++로 개발된 고성능 프록시입니다.
envoy 가 하는일
- Dynamic service discovery
- 로드밸런싱
- TLS 종료
- HTTP/2 and gRPC proxies
- 서킷 브레이커
- 헬스체크
- Staged rollouts with %-based traffic split
- Fault injection
- Rich metrics
장점
- 사이드카 배포를 통해 원격 분석, 모니터링시스템 전송을 활용하여 전체 메시 동작 정보를 제공할 수 있습니다.
- 코드 재설계 없이 기존 배포에 istio 기능을 추가할 수 있습니다.
Envoy
개요
Envoy는 대규모 최신 서비스 지향 아키텍처를 위해 설계된 L7 프록시 및 통신 버스입니다. envoy는 '네트워크는 애플리케이션에 투명해야 한다'는 신념 아래에 탄생하였습니다. 결국 네트워크와 애플리케이션의 문제가 발생했을 때 문제 원인을 쉽게 파악하기 위한 목적으로 탄생한 것입니다.
envoy에서 사용되는 몇가지 단어가 있습니다.
Host: 네트워크 통신이 가능한 entity를 말합니다. logical network application을 뜻합니다.
Downstream: downstream host는 envoy에 요청을 전달하고, 응답을 받습니다.
Upstream: Upstream host는 envoy로부터 요청을 전달받고 응답을 반환합니다.
Listener: downstream client에 의해 연결된 포트, 유닉스 도메인 소켓과 같은 네트워크 영역을 말합니다. envoy는 downstream host가 연결할 수 있는 1개 이상의 listener를 노출합니다.
Cluster: envoy 가 트래픽을 포워드할 수 있는 논리적인 서비스 (엔드포인트 세트), 실제 요청이 처리되는 IP 또는 엔드포인트의 묶음을 의미합니다.
요청 흐름도.
출처: https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request#high-level-architecture
SideCar 모드
설치
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
먼저, 실습환경 구성때만든 k3s-s 서버에 ssh를 통해서 접속합니다.
istioctl 설치 코드블록을 복사 및 적용하여 istioctl을 설치합니다.
현재 설치된 istioctl profile을 조회합니다.
우리는 이중 demo profile을 활용합니다. 설정을 조금 변경하도록 하겠습니다.
istioctl profile dump demo > demo-profile.yaml
명령을 통해, profile을 dump 해줍니다. 여기서 egressGateways를 비활성화로 변경합니다.
istioctl install 명령을 사용하여 변경된 demo profile을 적용해줍니다.
ingressgateway 살펴보기
적용이 잘 되었는지 확인합니다.
kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
svc: service
ep: endpoint
sa: service account
cm: configmap
pdb: pod disruption budget
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"type":"NodePort"}}'
istio-ingressgateway 서비스의 서비스타입이 LoadBalancer 입니다. 이를 NodePort로 변경해줍니다.
이때 istio-ingressgateway pod는 여러 포트를 노출하고 있습니다.
kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports}' | jq
각각의 포트는 위 명령어를 통해 확인할 수 있습니다. 15021 포트는 health check목적으로 사용됩니다.
그밖에 사용되는 port는 istio 공식 문서를 참조할 수 있습니다.
istio 외부 노출
설정
# port 설정
export IGWHTTP=$(kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[1].nodePort}')
# /etc/hosts 파일 수정
MYDOMAIN=www.yeoli.io
echo "192.168.10.10 $MYDOMAIN" >> /etc/hosts
echo -e "export MYDOMAIN=$MYDOMAIN" >> /etc/profile
# istio ingress gw 접속 테스트 : 아직은 설정이 없어서 접속 실패가 된다
curl -v -s $MYDOMAIN:$IGWHTTP
### istio sidecar injection practice ###
# istio의 injection을 허용하는 네임스페이스를 설정합니다.
kubectl label namespace default istio-injection=enabled
# istio 네임스페이스의 로그를 모니터링합니다.
kubetail -n istio-system -l app=istiod -f
# nginx pod를 생성합니다.
cat <<EOF | kubectl create -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
Nginx 파드 구성
설정 에서 istio sidecar injection practice 항목을 따라해보겠습니다.
우측에서는 istio-system을 모니터링하고, 좌측에서는 nginx 파드를 생성합니다.
파드가 생성되면서 sidecar injection이 발생하였습니다.
kubectl get pod 명령어로 파드를 조회해보면, 파드 내 컨테이너가 1이 아닌 2인 것을 확인할 수 있습니다. 이를 좀 더 살펴보면, pod 내 정보에서는 init-proxy라는 컨테이너가 함께 구성되는 것을 알 수 있습니다. sidecar injection 형태로 istio의 컨테이너가 생성된 것을 알 수 있습니다.
Gateway/Virtual Service 구성
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
위 manifest를 실행시켜 gateway, virtual service를 생성해줍니다.
생성된 gateway, virtual service는 다음과 같은 설정 정보를 포함하고 있습니다.
# gateway, virtual service 조회
kubectl get gw,vs
# istio proxy status 조회
istioctl ps
명령어를 사용하여 설정된 gateway, vs, proxy 상태를 조회합니다.
자 이제 www.yeoli.io 라는 도메인으로 테스트를 할 준비가 되었습니다.
curl -s $MYDOMAIN:$IGWHTTP | grep -o "<title>.*</title>"
# 결과
Welcome to nginx!
로그
kubetail -n default
Will tail 3 logs...
deploy-websrv-7d7cf8586c-qspjs deploy-websrv
deploy-websrv-7d7cf8586c-qspjs istio-proxy
deploy-websrv-7d7cf8586c-qspjs istio-init
[deploy-websrv-7d7cf8586c-qspjs deploy-websrv] 127.0.0.6 - - [19/Oct/2024:10:18:59 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.10.1" "-"
[deploy-websrv-7d7cf8586c-qspjs istio-proxy] [2024-10-19T10:18:59.053Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 615 0 0 "-" "curl/8.10.1" "5f7bee9b-d764-9e14-ad4a-a583233d16a8" "10.10.200.134" "172.16.2.8:80" inbound|80|| 127.0.0.6:55867 172.16.2.8:80 172.16.2.8:53002 invalid:outbound_.80_._.svc-clusterip.default.svc.cluster.local default
[deploy-websrv-7d7cf8586c-qspjs istio-proxy] [2024-10-19T10:18:59.053Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 615 1 0 "-" "curl/8.10.1" "5f7bee9b-d764-9e14-ad4a-a583233d16a8" "10.10.200.134" "172.16.2.8:80" outbound|80||svc-clusterip.default.svc.cluster.local 172.16.2.8:53002 10.10.200.134:80 172.16.2.8:50182 - default
출력 로그 이해하기
출력로그는 위와같은 구조로 구성되어있습니다. 한 번 이해해두시면 로그분석이 필요할 때 손쉽게 사용할 수 있습니다.
모니터링
이러한 복잡한 구조를 매번 확인할 때마다 로그를 보거나 routing rule, kubectl 등으로 확인하는 것은 매우 비효율적일 수 있습니다. 우리는 kiali를 활용하여 서비스 메시의 모니터링을 하고자 합니다.
구성된 실습환경에서 해당 경로에 포함된 리소스를 모두 실행시켜보겠습니다.
kubectl apply -f ~/istio-$ISTIOV/samples/addons # 디렉터리에 있는 모든 yaml 자원을 생성
kubectl rollout status deployment/kiali -n istio-system
# service type을 NodePort로 변경해줍니다.
kubectl patch svc -n istio-system kiali -p '{"spec":{"type":"NodePort"}}'
# grafana service 타입 변경: NodePort
kubectl patch svc -n istio-system grafana -p '{"spec":{"type":"NodePort"}}'
# prometheus service 타입 변경: NodePort
kubectl patch svc -n istio-system prometheus -p '{"spec":{"type":"NodePort"}}'
# kiali nodeport의 포트를 확인합니다.
KIALINodePort=$(kubectl get svc -n istio-system kiali -o jsonpath={.spec.ports[0].nodePort})
# 인터넷 브라우저를 통해 접속할 kiali url을 확인합니다.
echo -e "KIALI UI URL = http://$(curl -s ipinfo.io/ip):$KIALINodePort"
# grafana url도 확인할 수 있습니다.
GRAFANANodePort=$(kubectl get svc -n istio-system grafana -o jsonpath={.spec.ports[0].nodePort})
echo -e "Grafana URL = http://$(curl -s ipinfo.io/ip):$GRAFANANodePort"
kiali의 대시보드 화면입니다. 이 화면에서는 service mesh, istio를 모니터링할 수 있습니다.
kiali에서 일정 기간동안 트래픽 혹은 애플리케이션 정보, 워크로드, 서비스, 메시등의 정보를 모두 확인할 수 있습니다.
물론 prometheus에서도 수집되는 메트릭을 prometheus 서비스의 포트를 통해 브라우저에서 확인할 수 있습니다.
다만 istio, prometheus를 매번 각각의 콘솔에서 확인하는 건 불편합니다. 이를 해결하기 위해 grafana에서 prometheus, istio를 모두 확인할 수 있습니다.
grafana url에 접속하면, istio dashboard를 확인할 수 있습니다.
istio control plane dashboard
istio service dashboard 입니다.
여기까지 istio 모니터링에 대해 살펴보았습니다.
istio 트래픽 흐름
외부 클라이언트로부터 k8s 클러스터 내부의 application 파드로 전달되는 트래픽 흐름은 다음과 같습니다.
1. client 요청은 istio ingress gateway로 전달됩니다.
2. istio ingress gateway로 전달된 요청은 cluster의 node로 전달되고 host namespace로 전달됩니다.
3. host namespace에서 iptables 규칙에 따라 pod namespace로 전달 됩니다.
4. pod namespace내의 iptables 규칙에 따라서 파드 내부의 istio-proxy로 먼저 전달이 됩니다.
5. istio-proxy 컨테이너에서 istio의 iptables 규칙에 따라서 application 컨테이너로 요청이 전달됩니다.
Ambient mode
개요
정환열님의 블로그중 발췌 (https://www.anyflow.net/sw-engineer/istio-ambient-mode)
- Ambient mode는 Sidecar mode 하의 Istio 기능을 계승하면서, 더 빠르고 더 적은 리소스를 사용한다. 특히 메모리 사용량 개선은 극적이다.
- Ambient mode에서는 Ztunnel(L4)을 데몬셋으로, Waypoint(L7)를 디플로이먼트셋으로 활용하여 istio-proxy의 sidecar를 대체한다.
- Waypoint 는 Kubernetes Gateway API의 Gateway 를 통해 Namespace 단위로 생성하는 것이 기본이다. 이는 Waypoint 가 특정 workload 군에 대한 gateway 역할도 함께함을 의미한다.
istio가 없는 구성 (Baseline), Ambient Mode, Sidecar Mode를 비교했을 때 응답 지연차이를 확인할 수 있습니다.
성능은 baseline > ambient > sidecar 순서입니다.