새소식

Kubernetes

[Study 7주차] 쿠버네티스 Service Mesh - Istio 기능 & Bookinfo 실습

  • -

CoudNet@ 팀의 가시다님께서 리딩하시는 KANS Study (Kubernetes Advanced Networking Study) 7주차 스터디 내용 정리

 

저번 글에 이어서 서비스 메시 Istio 대해 알아보겠습니다.
이번에는 이스티오 공식 문서에 있는 데모 어플리케이션인 Book Info 를 배포한 후 이스티오의 동작을 이해해보겠습니다.

 

 

1. Book Info 어플리케이션

 

이스티오 실습을 위한 데모 마이크로서비스 어플리케이션입니다.

Productpage, reviews, ratings, details 의 4개의 마이크로서비스로 구성되어 있습니다.

출처:  https://istio.io/latest/docs/examples/bookinfo/

 

Book info 어플리케이션의 동작방식

 

1. ProductPage 페이지에서 요청

2. 도서 리뷰를 보여주는 Reviews 서비스와 도서 상세 정보를 보여주는 Details 서비스에 접속

3. ProductPage 는 ReviewsDetails 결과 응답

4. Reviews 서비스는 v1, v2, v3 세 개의 버전이 있고 v2, v3 버전의 경우 Ratings 서비스에 접속하여 도서에 대한 5단계 평가 응답

5. v1 Review 는 Rating 이 없고, v2 Review 는 검은색 별로 Ratings 표시, v3 Review는 색깔이 있는 별로 Ratings 표시

 

 

1.1. Book Info 어플리케이션 배포

 

실습환경은 이전 글에서 구성한 서버를 이용합니다.
이스티오가 설치된 서버에서 실행합니다.


Book info Yaml 파일은 아래와 같습니다.

# Copyright Istio Authors
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

##################################################################################################
# This file defines the services, service accounts, and deployments for the Bookinfo sample.
#
# To apply all 4 Bookinfo services, their corresponding service accounts, and deployments:
#
#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
#
# Alternatively, you can deploy any resource separately:
#
#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews # reviews Service
#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews # reviews ServiceAccount
#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3 # reviews-v3 Deployment
##################################################################################################

##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: details
  labels:
    app: details
    service: details
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-details
  labels:
    account: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: details-v1
  labels:
    app: details
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: details
      version: v1
  template:
    metadata:
      labels:
        app: details
        version: v1
    spec:
      serviceAccountName: bookinfo-details
      containers:
      - name: details
        image: docker.io/istio/examples-bookinfo-details-v1:1.20.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: ratings
  labels:
    app: ratings
    service: ratings
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: ratings
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-ratings
  labels:
    account: ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ratings-v1
  labels:
    app: ratings
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ratings
      version: v1
  template:
    metadata:
      labels:
        app: ratings
        version: v1
    spec:
      serviceAccountName: bookinfo-ratings
      containers:
      - name: ratings
        image: docker.io/istio/examples-bookinfo-ratings-v1:1.20.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: reviews
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-reviews
  labels:
    account: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v1:1.20.1
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
  labels:
    app: reviews
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v2
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v2:1.20.1
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v3
  labels:
    app: reviews
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v3
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v3:1.20.1
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: productpage
  labels:
    app: productpage
    service: productpage
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: productpage
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-productpage
  labels:
    account: productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9080"
        prometheus.io/path: "/metrics"
      labels:
        app: productpage
        version: v1
    spec:
      serviceAccountName: bookinfo-productpage
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.20.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
      volumes:
      - name: tmp
        emptyDir: {}
---

 

# Book info 설치
ISTIOV=1.23.2
echo $ISTIOV
kubectl apply -f ~/istio-$ISTIOV/samples/bookinfo/platform/kube/bookinfo.yaml

# 해당 서버에서 접속 테스트
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>"

 

 

 

 

1.2. Book Info 어플리케이션 접속 구성 및 확인

 

Istio Gateway & VirtualService 배포

 

- 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

 

# Gateway & VirtualService 배포
kubectl apply -f ~/istio-$ISTIOV/samples/bookinfo/networking/bookinfo-gateway.yaml

# Gateway & VirtualService 정보 확인
kubectl get gw,vs
istioctl proxy-status

 

 

외부 접속 테스트

  • k3s-s 서버에서 접속
export IGWHTTP=$(kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[1].nodePort}')

# Control Plane
curl -s http://localhost:$IGWHTTP/productpage
# Node 1번
curl -s http://192.168.10.101:$IGWHTTP/productpage
# Node 2번
curl -s http://192.168.10.102:$IGWHTTP/productpage

 

  • Local PC 에서 접속
curl -v -s $MYDOMAIN:$IGWHTTP/productpage

 

 

  • testpc 에서 접속
curl -s $MYDOMAIN:$IGWHTTP/productpage | grep -o "<title>.*</title>"

 

 

브라우저를 통한 접근 확인

 

echo -e "http://$MYDOMAIN:$IGWHTTP/productpage"

# http://www.kimalarm.com:32251/productpage

 



2. 이스티오 모니터링

 

Kiali 를 통해 이스티오를 연동하여 시각화 대시보드를 구성할 수 있습니다.
저희는 데모 환경이므로, kiali / Prometheus / Grafana / Jaeger 를 한 번에 설치했습니다.

 

 

2.1. 모니터링 도구 구성

 

# 샘플 애드온 디렉토리 구조 확인
tree ~/istio-$ISTIOV/samples/addons/

# 출력 화면
/root/istio-1.23.2/samples/addons/
├── README.md
├── extras
│   ├── prometheus-operator.yaml
│   ├── skywalking.yaml
│   └── zipkin.yaml
├── grafana.yaml
├── jaeger.yaml
├── kiali.yaml
├── loki.yaml
└── prometheus.yaml
# 도구 설치
kubectl apply -f ~/istio-$ISTIOV/samples/

 

각 도구별 노드포트 구성

 

편의를 위해 노드포트로 접근을 허용해줍니다.

# Kiali 서비스
kubectl patch svc -n istio-system kiali -p '{"spec":{"type":"NodePort"}}'
KIALINodePort=$(kubectl get svc -n istio-system kiali -o jsonpath={.spec.ports[0].nodePort})
echo -e "KIALI UI URL = http://$(curl -s ipinfo.io/ip):$KIALINodePort"

 

 

# Grafana 서비스
kubectl patch svc -n istio-system grafana -p '{"spec":{"type":"NodePort"}}'
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"

 

 

# Prometheus 서비스
kubectl patch svc -n istio-system prometheus -p '{"spec":{"type":"NodePort"}}'
PROMENodePort=$(kubectl get svc -n istio-system prometheus -o jsonpath={.spec.ports[0].nodePort})
echo -e "Prometheus URL = http://$(curl -s ipinfo.io/ip):$PROMENodePort"

 

 

이스티오와 엔보이 메트릭이 수집되고 있는 것을 알 수 있습니다.

 

 

2.2. Kiali 대시보드 둘러보기

 

방금 구성한 Kiali 에서 시각화 대시보드를 확인해봅니다.
혹시 아무런 그래프가 그려지지 않으면, 우측 상단에 시간을 늘려주거나 서버에 트래픽을 흘려보내면 됩니다.

# testpc 서버에서 진행
while true; do curl -s $MYDOMAIN:$IGWHTTP/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 1; don

 

 

Security 정보 확인

 

Security 탭을 누르면 우측 패널에 인증에 대한 정보가 나옵니다.



3. Traffic Management

 

서비스 메시 이스티오의 다양한 네트워크 제어 기능을 살펴보겠습니다.

 

3.1. Request Routing

 

Request Routing 은 의도한 바로 네트워크 라우팅을 설정할 수 있는 기능입니다.

# 기본 Destination Rule 적용
cd ~/istio-$ISTIOV/samples/bookinfo/networking
tree

# 기본 DestinationRule 적용
kubectl apply -f destination-rule-all.yaml

 

 

reviews v1 으로만 통신 설정

 

해당 VirtualService Yaml 내용입니다.

 

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
spec:
  hosts:
  - productpage
  http:
  - route:
    - destination:
        host: productpage
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: details
spec:
  hosts:
  - details
  http:
  - route:
    - destination:
        host: details
        subset: v1
---
# istio vs(virtualservices) 확인
kubectl get vs
NAME          GATEWAYS               HOSTS             AGE
bookinfo      ["bookinfo-gateway"]   ["*"]             44m

# 모든 마이크로서비스에 대해 v1 의 서브셋(subset) 에 전송되게 virtualservices 적용
kubectl apply -f virtual-service-all-v1.yaml

 

해당 설정 적용 후, reviews 서비스에 대해 v1 로만 트래픽이 흐르는 것을 알 수 있습니다.

 

reviews v2 으로만 통신 설정

 

match 의 exact 를 사용해 값이 완전히 일치되는 값만 별도의 destination 라우팅을 설정할 수 있습니다.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1

 

jason 유저에 대해서는 v2 로 이동하게 설정합니다.

 

kubectl apply -f virtual-service-reviews-test-v2.yaml

 

Book Info 웹페이지에서 jason 으로 로그인 합니다. (비밀번호는 아무거나 입력해도 로그인 가능)
jason 로그인 성공 시, reviews v2 에 해당하는 검은 별 리뷰 화면이 출력됩니다.

 

 

Kiali 대시보드에서도 v2 로 흐르는 트래픽이 캡쳐됩니다.

 

 

 

3.2. Fault Injection

 

Fault Injection 은 의도적으로 서비스를 지연 시키거나 중단하는 것입니다.

 

jason 유저는 7초 지연 발생, 그외 사용자는 정상 연결

 

jason 유저에 대해 7초의 지연 시간을 발생 시키는 설정입니다.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      delay:
        percentage:
          value: 100.0
        fixedDelay: 7s
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1

 

kubectl apply -f virtual-service-ratings-test-delay.yaml

 

jason 유저로 로그인을 시도해봅니다.

7초 이상 로그인이 지연되었기 때문에, 실패 응답을 반환합니다.

 

 

kiali 대시보드에서 해당 트래픽에 문제가 있는 것을 알 수 있습니다.

 

 

jason 유저는 500 에러 발생, 그외 사용자는 정상 연결

 

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      abort:
        percentage:
          value: 100.0
        httpStatus: 500
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1

 

kubectl apply -f virtual-service-ratings-test-abort.yaml

 

jason 유저로 로그인 시도 시, reviews 서비스에 오류가 발생한 것을 확인할 수 있습니다.

 



4. Istio 보안

 

보안이 강한 회사에서는 제로 트러스트 정책을 기반으로 보안 거버넌스를 수립할 것입니다.


제로 트러스트는 아무도 신뢰할 수 없으며,

사내 내부자들 또한 악의적인 공격을 할 수 있다는 가정하에 최소한의 권한과 세밀한 통제를 지속적으로 수행하는 보안 활동을 의미합니다.

 

 

4.1. mTLS Authentication

 

Istio 는 기본적으로 mtls (상호 인증) 방식의 통신을 하기 때문에 보안 효율성을 높일 수 있습니다.

출처 : https://istio.io/latest/docs/concepts/security/

* TLS

- 암호화를 통한 인증, 통신 기밀성 제공

 

* mTLS
- 서버측도 클라이언트측에 대한 인증서 확인 및 액세스 권한 확인

 

kiali 대시보드에서 본 mtls 정보

 

Authentication 방식

 

* Permissive Mode
- 일반 텍스트 트래픽과 상호 TLS 트래픽을 동시에 허용

 

* Strict Mode
- 상호 TLS 트래픽만 허용

 

 

4.2. Authorization

출처 : https://istio.io/latest/docs/concepts/security/

 

서버 측 Envoy 프록시에서 인바운드 트래픽에 대한 액세스 제어가 가능합니다.
AuthorizationPolicy 리소스를 통해 권한을 부여(Allow) 하거나 거절(Deny) 할 수 있습니다.

 

Authorization 방식

 

- Implicit enablement : 인증 미적용 시 모든 요청 허용
- AuthorizationPolicy 는 허용(Allow), 거부(Deny), 사용자 지정(Custom) 등의 동작
- 정책 적용 우선 순위는 Custom - Deny - Allow 순으로 적용



5. Istio 트래픽 흐름

 

이렇게 다양한 기능을 제공하고 편리한데, 이스티오 도입을 주저하게 만드는 이유는 바로 트래픽 성능 저하 때문일 것입니다.
이전 글의 첫 단락에서도 다뤘지만 서비스 메시가 없는 환경에서 어플리케이션 간 통신은 파드와 파드가 Direct 통신입니다.

 

서비스 메시가 생기게 되면서 Proxy 가 해당 네트워크 패킷을 가로채 통신을 하게 되는데, 이 때문에 네트워크 지연이 발생합니다.

 

 

해당 아키텍처는 외부 트래픽이 파드로 들어왔을 때 트래픽의 흐름을 보여주는 그림입니다.
참고해야할 점은 저 경로를 왕복으로 지나가야 실제 엔드유저가 응답을 받을 수 있다는 것입니다.

그렇기 때문에 단순한 서비스 구조라면 Istio 가 꼭 필요한 지 한 번 생각해봐야될 것입니다.

 


 

 

이번에 서비스 메시를 공부하면서 이스티오의 동작 방식에 대해 많은 공부를 할 수 있었습니다.
양이 방대하여 아직 부족한 부분이 너무 많은데, 시간 날 때마다 틈틈히 공부해야될 것 같습니다.

Contents

포스팅 주소를 복사했습니다