Istio 살펴보기
Istio 살펴보기
💡 KANS 스터디
CloudNet에서 주관하는 KANS(Kubernetes Advanced Networking Study)으로 쿠버네티스 네트워킹 스터디입니다. 아래의 글은 스터디의 내용을 기반으로 작성했습니다.스터디에 관심이 있으신 분은 CloudNet Blog를 참고해주세요.
들어가며
이번 스터디 주차는 서비스 매시인 Istio이다. 아직 서비스 매시를 다뤄본적이 없는데, 입문부터 좋은 자료로 정리하게 됐다.
Service Mesh
마이크로 서비스간의 통신을 도와주는 별도의 인프라 Layer이다. 전체적인 네트워크 모니터링이 가능하며, 네트워크를 제어할 수 있다. 하지만, 서비스 매시를 도입하면 Layer가 하나 더 추가되므로 무겁다. (아래에 사진만 봐도..) 그렇기에 서비스 매시를 도입하기전에 현재 환경에 정말 필요한지 고민해봐야 한다. 관련 SDS 블로그
출처: https://www.redhat.com/ko/topics/microservices/what-is-a-service-mesh
Istio
Istio는 서비스 Mesh 구현체 중 하나로, 마이크로서비스 전반의 트래픽 흐름을 관리, 정책 설정, 데이터 수집이 가능하다. 모드로는 파드 당 하나의 프록시를 두는 sidecar모드와 노드 당 전용 커널을 두는 Ambient가 있다. 여기서는 sidecar 모드에 대해서 주로 알아본다.
구성
Istio는 Control Plane과 Data Plane으로 구성된다.
Control Plane은 Istiod로 프록시 라우팅 규칙을 관리, 보안 및 암호화, Kubernetes와 상호 작용한다.
Data Plane은 실제 애플리케이션 바로 앞에 있는 프록시 집합을 의미하며, Sidecar 모드에서는 각 파드마다 sidecar proxy(envoy)가 존재한다.
Control Plane
Istiod는 Pilot, Galley, Citadel 3개의 요소가 존재한다. Pilot은 프록시 라우팅 규칙을 관리하며, Galley는 Endpoint 갱신 등 K8s와 상호작용하며, Citadel은 보안 및 암호화 관련 기능을 담당한다. “Istiod는 golang으로 작성되었다.”
아래의 그림을 통해 각 구성요소의 역할을 확인할 수 있다.
스터디원이신 데브로스님이 각 구성요소에 대해 도식화를 해주셨다.
Data Plane
Data Plane은 Envoy 프록시 집합을 의미한다.
Envoy는 멀티 스레딩을 사용하며, 각 서비스에 대해 Listener를 통해 요청을 수신하며 이후 HTTP Router Filer를 통해 대상 클러스터로 옮기고 클러스터에서 실제 엔드포인트(Pod)로 라우팅한다. “Listeners > Routes > Clusters > Endpoints”
통신흐름
특정 파드로 향하는 트래픽을 어떻게 envoy가 제어할 수 있을까? istio는 pod 수준에서 iptables를 사용하여, 파드로 향하는 트래픽을 가로챈다. 파드내의 컨테이너는 모든 네트워크 스택을 공유하므로 이것이 가능하다. 하지만 이미 해당 파드에 오기까지 Iptables 혹은 CNI에 맞게 여러 네트워크 홉을 거쳐왔지만, 또 다시 Iptables 지옥에 빠지는 느낌이 든다.
자세한 Kernel Space의 흐름도는 jimmysong님의 블로그에 잘정리되어있다.
Ambient mode 모드 아키텍처
Ambient 모드는 각 파드마다 전용 Proxy 사이드카를 붙이는 방식이 아닌, 하나의 노드에 하나의 ztunnel을 두어 서비스 매시를 구현하는 방식이다. Ambient 모드에서는 L4 Proxy와 L7 Proxy 기능을 분리한다.
출처: https://istio.io/latest/docs/ambient/architecture/control-plane/
출처: https://istio.io/latest/blog/2022/introducing-ambient-mesh/
위에는 Sidecar 방식으로 사이드 카 방식과 비교하면 아래와 같이 ztunnel을 통해 통신하는 차이를 확인할 수 있다.
출처: https://istio.io/latest/docs/ambient/architecture/data-plane/
HBONE(HTTP-Based Overlay Network)은 Istio 구성 요소 간에 사용되는 보안 터널링 프로토콜이다.
만약, 아래와 같은 네트워크 정책이 있었더라면 Ambient 모드 적용시 두번째 네트워크 정책으로 변경되어야 한다. HBONE이기에 8080 포트와 HBONE 트래픽이 지나가는 포트를 열어줘야한다.
(1) Before
1
2
3
4
5
6
7
8
9
10
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
spec:
ingress:
- ports:
- port: 9090 # 기존에는 9090만 열어줌
protocol: TCP
podSelector:
matchLabels:
app.kubernetes.io/name: my-app
(2) After
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
spec:
ingress:
- ports:
- port: 8080 # HTTP 기반이기에 8080
protocol: TCP
- port: 15008 # HBONE 트래픽을 열어주기 위한 포트
protocol: TCP
podSelector:
matchLabels:
app.kubernetes.io/name: my-app
실습
실습 환경
실습 환경은 Kind(controlplane 1대) + istio-ingressgateway(NodePort)로 구성되었으며 Istio 버전은 v1.23.2이다.
설치 진행
- Istioctl을 통해 설치 진행
1
2
3
4
export ISTIOV=1.23.2
curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl install --set profile=default -y
1
2
3
4
5
6
7
8
9
10
11
12
istioctl profile list
Istio configuration profiles:
**ambient**
default
demo
empty
minimal
openshift
openshift-ambient
preview
remote
stable
- 우리가 실습할 default 네임스페이스에 istio-proxy sidecar를 주입한다. (Label)
1
2
3
kubectl label namespace default istio-injection=enabled
namespace/default labeled
1
2
3
4
5
6
7
8
k get ns -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 5m29s enabled
istio-system Active 118s
kube-node-lease Active 5m29s
kube-public Active 5m29s
kube-system Active 5m29s
local-path-storage Active 5m25s
Ingress gateway 테스트
- 이제 Ingress gateway 실습을 위해 호스트를 지정한다.
1
2
3
4
5
6
export MYDOMAIN="dongmin.test"
echo "127.0.0.1 $MYDOMAIN" | sudo tee -a /etc/hosts
Password:
127.0.0.1 dongmin.test
1
2
3
4
5
6
docker inspect -f '' myk8s-control-plane
172.18.0.2
echo -e "172.18.0.2 dongmin.test" | tee -a /etc/hosts
172.18.0.2 dongmin.test
- 서비스 배포: Istio는 K8s에서 identity는 Service Account를 기반으로 하기에 서비스 어카운트도 같이 배포한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
cat <<EOF | kubectl 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 Gateway/VirtualService 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cat <<EOF | kubectl 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:
- "$MYDOMAIN"
gateways:
- test-gateway
http:
- route:
- destination:
host: svc-clusterip
port:
number: 80
EOF
ingressgateway를 살펴보면, 관련 설정을 Envoy에 완료한 것을 볼 수 있다.
이제 도메인으로 실제 접속해보면, 아래와 같이 정상 통신된다.
Proxy-config 확인
- 이제 proxy-config를 확인해본다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
docker exec -it myk8s-control-plane istioctl proxy-config all deploy-websrv-778ffd6947-mv2wj.default
Istio Version: 1.23.2
Istio Proxy Version: 6c72b2179f5a58988b920a55b0be8346de3f7b35
Envoy Version: 1.31.2-dev/Clean/RELEASE/BoringSSL
NAME SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
cluster/inbound|80|| 80 - inbound ORIGINAL_DST
cluster/BlackHoleCluster cluster/BlackHoleCluster - - - STATIC
cluster/InboundPassthroughCluster cluster/InboundPassthroughCluster - - - ORIGINAL_DST
cluster/PassthroughCluster cluster/PassthroughCluster - - - ORIGINAL_DST
cluster/agent cluster/agent - - - STATIC
cluster/outbound|80||istio-ingressgateway.istio-system.svc.cluster.local istio-ingressgateway.istio-system.svc.cluster.local 80 - outbound EDS
cluster/outbound|443||istio-ingressgateway.istio-system.svc.cluster.local istio-ingressgateway.istio-system.svc.cluster.local 443 - outbound EDS
cluster/outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local istio-ingressgateway.istio-system.svc.cluster.local 15021 - outbound EDS
cluster/outbound|443||istiod.istio-system.svc.cluster.local istiod.istio-system.svc.cluster.local 443 - outbound EDS
cluster/outbound|15010||istiod.istio-system.svc.cluster.local istiod.istio-system.svc.cluster.local 15010 - outbound EDS
cluster/outbound|15012||istiod.istio-system.svc.cluster.local istiod.istio-system.svc.cluster.local 15012 - outbound EDS
cluster/outbound|15014||istiod.istio-system.svc.cluster.local istiod.istio-system.svc.cluster.local 15014 - outbound EDS
cluster/outbound|53||kube-dns.kube-system.svc.cluster.local kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
cluster/outbound|9153||kube-dns.kube-system.svc.cluster.local kube-dns.kube-system.svc.cluster.local 9153 - outbound EDS
cluster/outbound|443||kubernetes.default.svc.cluster.local kubernetes.default.svc.cluster.local 443 - outbound EDS
cluster/prometheus_stats cluster/prometheus_stats - - - STATIC
cluster/sds-grpc cluster/sds-grpc - - - STATIC
cluster/outbound|80||svc-clusterip.default.svc.cluster.local svc-clusterip.default.svc.cluster.local 80 - outbound EDS
cluster/xds-grpc cluster/xds-grpc - - - STATIC
Listener는 각 서비스에 대한 요청을 받는 곳으로 아래와 같이 실제 서비스 IP에 대한 모든 Listener를 확인할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
NAME ADDRESSES PORT MATCH DESTINATION
listener/10.200.1.10_53 10.200.1.10 53 ALL Cluster: outbound|53||kube-dns.kube-system.svc.cluster.local
listener/0.0.0.0_80 0.0.0.0 80 Trans: raw_buffer; App: http/1.1,h2c Route: 80
listener/0.0.0.0_80 0.0.0.0 80 ALL PassthroughCluster
listener/10.200.1.34_80 10.200.1.34 80 Trans: raw_buffer; App: http/1.1,h2c Route: svc-clusterip.default.svc.cluster.local:80
listener/10.200.1.34_80 10.200.1.34 80 ALL Cluster: outbound|80||svc-clusterip.default.svc.cluster.local
listener/10.200.1.1_443 10.200.1.1 443 ALL Cluster: outbound|443||kubernetes.default.svc.cluster.local
listener/10.200.1.59_443 10.200.1.59 443 ALL Cluster: outbound|443||istiod.istio-system.svc.cluster.local
listener/10.200.1.73_443 10.200.1.73 443 ALL Cluster: outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
listener/10.200.1.10_9153 10.200.1.10 9153 Trans: raw_buffer; App: http/1.1,h2c Route: kube-dns.kube-system.svc.cluster.local:9153
listener/10.200.1.10_9153 10.200.1.10 9153 ALL Cluster: outbound|9153||kube-dns.kube-system.svc.cluster.local
listener/virtualOutbound 0.0.0.0 15001 ALL PassthroughCluster
...
NAME VHOST NAME DOMAINS MATCH VIRTUAL SERVICE
route/svc-clusterip.default.svc.cluster.local:80 svc-clusterip.default.svc.cluster.local:80 * /*
route/istio-ingressgateway.istio-system.svc.cluster.local:15021 istio-ingressgateway.istio-system.svc.cluster.local:15021 * /*
route/80 istio-ingressgateway.istio-system.svc.cluster.local:80 istio-ingressgateway.istio-system, 10.200.1.73 /*
route/80 svc-clusterip.default.svc.cluster.local:80 svc-clusterip, svc-clusterip.default + 1 more... /*
route/15010 istiod.istio-system.svc.cluster.local:15010 istiod.istio-system, 10.200.1.59 /*
route/15014 istiod.istio-system.svc.cluster.local:15014 istiod.istio-system, 10.200.1.59 /*
route/kube-dns.kube-system.svc.cluster.local:9153 kube-dns.kube-system.svc.cluster.local:9153 * /*
route/inbound|80|| inbound|http|80 * /*
route/ backend * /stats/prometheus*
route/ backend * /healthz/ready*
route/InboundPassthroughCluster inbound|http|0 * /*
route/InboundPassthroughCluster inbound|http|0 * /*
route/inbound|80|| inbound|http|80 * /*
엔드포인트 부분을 살펴보면, 실제 파드 엔드포인트(10.10.0.7)와 istio와 관련된 엔드포인트와 CoreDNS 관련 엔드포인트(dns port 53사용)를 확인할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NAME STATUS LOCALITY CLUSTER
endpoint/10.10.0.7:80 HEALTHY inbound|80||
endpoint/127.0.0.1:15020 HEALTHY agent
endpoint/10.10.0.6:8080 HEALTHY outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
endpoint/10.10.0.6:8443 HEALTHY outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
endpoint/10.10.0.6:15021 HEALTHY outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
endpoint/10.10.0.5:15017 HEALTHY outbound|443||istiod.istio-system.svc.cluster.local
endpoint/10.10.0.5:15010 HEALTHY outbound|15010||istiod.istio-system.svc.cluster.local
endpoint/10.10.0.5:15012 HEALTHY outbound|15012||istiod.istio-system.svc.cluster.local
endpoint/10.10.0.5:15014 HEALTHY outbound|15014||istiod.istio-system.svc.cluster.local
endpoint/10.10.0.3:53 HEALTHY outbound|53||kube-dns.kube-system.svc.cluster.local
endpoint/10.10.0.4:53 HEALTHY outbound|53||kube-dns.kube-system.svc.cluster.local
endpoint/10.10.0.3:9153 HEALTHY outbound|9153||kube-dns.kube-system.svc.cluster.local
endpoint/10.10.0.4:9153 HEALTHY outbound|9153||kube-dns.kube-system.svc.cluster.local
...
- 실제 kubectl 포트 포워딩을 통해 envoy 컨테이너 admin 페이지에 접속할 수 있다.
1
2
3
4
5
6
7
8
kubectl port-forward deployment/deploy-websrv 15000:15000 &
[1] 16270
Forwarding from 127.0.0.1:15000 -> 15000
Forwarding from [::1]:15000 -> 15000
open http://localhost:15000
Bookinfo(Sample Application) 및 istio Addon 설치
Istioctl에서 샘플로 제공해주는 bookinfo 애플리케이션을 설치해본다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kubectl apply -f /istio-$ISTIOV/samples/bookinfo/platform/kube/bookinfo.yaml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created
1
2
3
4
kubectl apply -f /istio-$ISTIOV/samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
1
2
kubectl apply -f /istio-$ISTIOV/samples/addons
kubectl rollout status deployment/kiali -n istio-system
실제 30000포트로 접속해보면, 아래와 같은 샘플 애플리케이션 페이지를 볼 수 있다.
kiali
kiali를 통해 트래픽 그래프를 확인할 수 있다.
현재는 1000개 정도의 요청을 보낸 상태인데, review를 잘 확인하면 적절하게 로드밸런싱이 되는 것을 확인할 수 있다.