k8s - istio!

istio

https://istio.io/latest/
https://istio.io/latest/docs/ops/deployment/architecture/ https://github.com/istio/istio
https://www.udemy.com/course/kubernetes-istio-hands-on/

MSA 환경을 구축하면서 아래와 같은 공통적인 운영 패턴문제들이 발생하는데,

  • Observability
  • TLS configuration
  • Service Discovery
  • Distributed Tracing
  • Circuit Breaking, Retry
  • Blue-Green Deploy

서비스 메시 는 이런 MSA 패턴문제를 어플리케이션으로부터 분리해서 비지니스 로직 개발에 집중할 수 있게 한다.

1

과거 istio-system 내부에선 [Pilot, Citadel, Galley] 서비스가 각각 [원격측정, 라우팅, 정책검증] 등의 책임가지고 실행되었지만,
1.5 버전부터 단순화되어 istiod(istio-daemon) 서비스로 통합되었다.

istiod 에서 작성한 정책들을 통해, 각 Podsidecar provider 를 배포하고, 서비스 메시 의 모든 in/out bound 트래픽을 관리한다.

istio 의 장점으로는 위의 모든 작업을 진행하는 동안 어플리케이션이나 Pod 의 설정 변겨 없이 위의 MSA 운영 패턴 구현이 가능하다.

Envoy

https://www.envoyproxy.io/
사이드카 provider 로 가장 유명한 프로젝트.
C++ 로 개발된 고성능 L7 프록시 서버.

Pod 의 컨테이너에선 Enovy 를 실행중이다.

Envoy 컨테이너를 [sidecar, data plane, istio-proxy] 등으로 부름

서비스 메시를 구축할 때 거의 표준으로 사용되고 있는 프로젝트이다.

istio control plan 에선 k8s 리소스 상황에 맞춰 각종 설정을 Envoy 에 적용하고 실행시키는 구조이다.

설치

istioctl, helm 을 사용하여 설치 가능.

helm repo add istio https://istio-release.storage.googleapis.com/charts
# 압축파일 다운로드, base-1.20.3.tgz 버전 설치됨
helm fetch istio/base
# 압축파일 다운로드, istiod-1.20.3.tgz 버전 설치됨
helm fetch istio/istiod

# 압축 파일 해제
tar zxvf base-*.tgz
mv base base-helm
tar zxvf istiod-*.tgz
mv istiod istiod-helm

kubectl create namespace istio-system

istio k8s CRD 설치

# base-helm
helm install istio-base -f values.yaml . -n istio-system

kubectl get crd 
# authorizationpolicies.security.istio.io
# envoyfilters.networking.istio.io
# istiooperators.install.istio.io
# peerauthentications.security.istio.io
# proxyconfigs.networking.istio.io
# requestauthentications.security.istio.io
# serviceentries.networking.istio.io
# sidecars.networking.istio.io
# telemetries.telemetry.istio.io
# virtualservices.networking.istio.io
# wasmplugins.extensions.istio.io
# ...

Istio discovery chart 설치

# istiod-helm
helm install istiod -f values.yaml . -n istio-system

kubectl get all -n istio-system                     
# NAME                         READY   STATUS    RESTARTS   AGE
# pod/istiod-bc4584967-pvpgv   1/1     Running   0          6m26s

# NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                 AGE
# service/istiod   ClusterIP   10.97.153.154   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP   6m26s

# NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/istiod   1/1     1            1           6m26s

# NAME                               DESIRED   CURRENT   READY   AGE
# replicaset.apps/istiod-bc4584967   1         1         1       6m26s

# NAME                                         REFERENCE           TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
# horizontalpodautoscaler.autoscaling/istiod   Deployment/istiod   <unknown>/80%   1         5         1          6m26s
helm ls -n istio-system
# NAME            NAMESPACE       REVISION   ...  STATUS    ...  APP VERSION
# istio-base      istio-system    1          ...  deployed  ...  1.20.3     
# istiod          istio-system    1          ...  deployed  ...  1.20.3     

istio ingress gateway controller

https://istio.io/latest/docs/setup/additional-setup/gateway/

ingress 사용하기 위해 ingress controller 를 설치했듯이,
istio gateway 를 사용하기 위해 ingress gateway controller 설치가 필요하다.

위 url 에서 요구한대로 Kubernetes YAML 기반으로 LoadBalancer, Deployment, Role, RoleBinding 생성.

LoadBalancer 의 경우 이미 nginx-ingress 가 80, 443 포트를 사용중임으로 istio-ingress 는 8080, 8443 을 사용하도록 설정.

그리고 MetalLB 를 사용해 IP 하나를 공유해서 사용중임으로 아래 annotation 지정.

# istio/gateway-controller.yaml
# ...
metadata:
  name: istio-ingressgateway
  namespace: istio-system
  annotations:
    metallb.universe.tf/allow-shared-ip: "my-lb-service"
# ...
kubectl apply -f ingress.yaml
kubectl get all -n istio-system
# NAME                                        READY   STATUS    RESTARTS   AGE
# pod/istio-ingressgateway-7c86d547c7-rdr8b   1/1     Running   0          6m47s

# NAME                           TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                         AGE
# service/istio-ingressgateway   LoadBalancer   10.99.142.173   192.168.10.228   8080:31517/TCP,8443:32630/TCP   6m47s

# NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/istio-ingressgateway   1/1     1            1           6m47s

# NAME                                              DESIRED   CURRENT   READY   AGE
# replicaset.apps/istio-ingressgateway-7c86d547c7   1         1         1       6m47s

book-info 데모 서비스

https://github.com/istio/istio/blob/master/samples/bookinfo/platform/kube/bookinfo.yaml

istio 제공 데모서비스 bookinfo.yaml 파일을 사용해 istio 의 동작 확인.
book-demo namespace 를 생성하고 istio-injection 라벨을 설정.

kubectl create namespace book-demo
kubectl label namespace book-demo istio-injection=enabled
kubectl describe ns book-demo
# Name:         book-demo
# Labels:       istio-injection=enabled
#               kubernetes.io/metadata.name=book-demo
# Annotations:  <none>
# Status:       Active

kubectl apply -f bookinfo.yaml -n book-demo
kubectl get all -n book-demo
# NAME                                 READY   STATUS    RESTARTS   AGE
# pod/details-v1-698d88b-6ppfv         2/2     Running   0          42s
# pod/productpage-v1-675fc69cf-lghct   2/2     Running   0          42s
# pod/ratings-v1-6484c4d9bb-7bt57      2/2     Running   0          42s
# pod/reviews-v1-5b5d6494f4-8h8fz      2/2     Running   0          42s
# ...

# NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
# service/details       ClusterIP   10.105.228.184   <none>        9080/TCP   42s
# service/productpage   ClusterIP   10.99.64.113     <none>        9080/TCP   42s
# service/ratings       ClusterIP   10.98.143.228    <none>        9080/TCP   42s
# service/reviews       ClusterIP   10.101.1.40      <none>        9080/TCP   42s

# NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/details-v1       1/1     1            1           42s
# deployment.apps/productpage-v1   1/1     1            1           42s
# deployment.apps/ratings-v1       1/1     1            1           42s
# deployment.apps/reviews-v1       1/1     1            1           42s
# ...

# NAME                                       DESIRED   CURRENT   READY   AGE
# replicaset.apps/details-v1-698d88b         1         1         1       42s
# replicaset.apps/productpage-v1-675fc69cf   1         1         1       42s
# replicaset.apps/ratings-v1-6484c4d9bb      1         1         1       42s
# replicaset.apps/reviews-v1-5b5d6494f4      1         1         1       42s
# ...

해당 namespace 에 생성되는 Podistio sidecar 가 같이 동작하는지 확인.

kubectl get pod/details-v1-698d88b-6ppfv -n book-demo -o=jsonpath='{.spec.containers[*].name}' | tr ' ' '\n'

# details
# istio-proxy

ratings 컨테이너에서 curl 을 통해 productpage:9080 호출, 서버가 정상동작하는지 확인

kubectl exec -n book-demo "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}' -n book-demo)" -c ratings -- curl -sS productpage:9080/productpage| grep -o "<title>.*</title>"
# <title>Simple Bookstore App</title>

kiali

https://kiali.io/ observability console for Istio with service mesh, like grafana

istio 에서 제공하는 모니터링 콘솔 어플리케이션.

istio git 에서 제공하는 에드온을 통해 kaili 를 포함해 [prometheus, jeager, grafana] 등의 서드파티 어플리케이션을 쉽게 설치하고 통합 할 수 있다.

하지만 여기선 kiali 설치를 에드온으로 진행하지 않고 helm 차트를 사용한다.
그리고 기존 k8s 에 설치해둔 prometheustempo 를 사용해 istio 와 연결한다.

에드온으로 kiali, prometheus, jeager 를 설치할 경우 아래 url 참고.
<https://github.com/istio/istio/tree/master/samples/addons/

helm repo add istio https://kiali.org/helm-charts

helm search repo kiali

# 압축파일 다운로드, kiali-server-1.80.0.tgz 버전 설치됨
helm fetch kiali/kiali-server

# 압축 파일 해제
tar zxvf kiali-server-*.tgz
mv kiali-server kiali-server-helm

kiali 의 모니터링은 기본적인 k8s APIpormetheus 를 사용해 control-plane, data-plane 에서 수집한 데이터를 기반으로 동작한다.
기존에 생성해둔 prometheus, tempo 에 접근할 수 있도록 external_services 에 설정 추가.

istio_namespace: "istio-system" # default is where Kiali is installed

auth:
  openid: {}
  openshift: {}
  strategy: "anonymous"
...
external_services:
  custom_dashboards:
    enabled: true
  istio:
    root_namespace: ""
  prometheus:
    url: "http://thanos-query-frontend.thanos.svc.cluster.local:9090/"
  tracing:
    enabled: true
    in_cluster_url: "http://tempo.tempo.svc.cluster.local:3100/"
    provider: "tempo"
    use_grpc: false
...
server:
  port: 20001
  observability:
    metrics:
      enabled: true
      port: 9090
  web_root: "/dashboards/kiali"
  web_fqdn: kiali.istio.local # nginx ingress
# base-helm
helm install kiali-server -f values.yaml . -n istio-system

kiali.istio.local hosts 파일에 등록 후 https://kiali.istio.local/dashboards/kiali url 에 접속

prometheus 통합

https://istio.io/latest/docs/ops/integrations/prometheus/

기존 설치해둔 prometheusconfig 파일에 아래와 같이 control-plan, data-plane(envoy) 을 스크래핑할 수 있도록 설정.

prometheus:
  ...
  prometheusSpec:
  ...
    additionalScrapeConfigs:
      - job_name: 'istiod' # control plan 메트릭 수집
        kubernetes_sd_configs:
        - role: endpoints
          namespaces:
            names:
            - istio-system
        relabel_configs:
        - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
          action: keep
          regex: istiod;http-monitoring
      - job_name: 'envoy-stats' # data plan 메트릭 수집
        metrics_path: /stats/prometheus
        kubernetes_sd_configs:
        - role: pod
        relabel_configs:
        - source_labels: [__meta_kubernetes_pod_container_port_name]
          action: keep
          regex: '.*-envoy-prom'

실제 모든 podenvoy 컨테이너의 ports.name 에 위 regex 에 해당되는 문자열이 설정되어있다.

kubectl get pod details-v1-698d88b-6ppfv -o=jsonpath='{.spec.containers[*].ports[*].name}' -n book-demo 
# http-envoy-prom

prometheusmetric 을 수집하고 있는 상황에서 ratings 에서 product 서비스를 호출하는 명령을 여러번 전송.

while true; \
do kubectl exec -n book-demo "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}' -n book-demo)" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"; \
sleep 0.5; done

1

tempo 통합

envoy 에서 trace 관측데이터를 전달할 때 zipkin b3 방식만 사용함으로 tempo-helmvalues.yamlzipkin 프로토콜 수신지 설정

# tempo/value.yaml
tempo:
  ...
  receiver:
  ...
    zipkin:
      endpoint: "0.0.0.0:9411"

envoy 에서도 trace 관측데이터의 수신지를 설정하기 위해 defaultConfig 를 수정

# istiod/value.yaml
meshConfig:
  enablePrometheusMerge: true
  enableTracing: true
  defaultConfig: # envoy default config
    tracing:
      zipkin:
        address: tempo.tempo.svc.cluster.local:9411
      sampling: 100.0

이제 모든 envoy 에서 위 addresstrace 데이터를 전달한다.

주의: 기존실행 envoy 를 모두 재실행 해야 위 설정이 적용됨.

kiali 에서도 tempo 에 접근할 수 있도록 설정해두었기 때문에 아래 그림처럼 trace 데이터를 확인할 수 있다.

1

Traffic

1

  • VirtualService
    트래픽 Policy, 트래픽 흐름을 제어해 카나리아 배포 같은 기능 구현 가능.
  • DestinationRule
    트래픽을 분산하기 위한 정의서.

book-info 데모서비스에서 3개 버전 review deployment 에 접근할 수 있는 service 를 생성한다.

아무런 설정을 하지 않았다면 아래 그림처럼 기본 k8s service 라우팅 규칙인 round robin 으로 동작할 것이다.

1

만약 트래픽 퍼센티지를 아래와 같이 변경하고 싶다면,
review-v1:review-v2:review-v3=0:1:1
kiali 에서 그림처럼 설정할 수 있다.

1

이때 아래와 같은 VirtualServiceDestinationRule 이 생성된다.

kind: DestinationRule
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: reviews
  labels:
    kiali_wizard: request_routing
  annotations: ~
spec:
  host: reviews.book-demo.svc.cluster.local
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
    - name: v3
      labels:
        version: v3
  trafficPolicy: ~
---
kind: VirtualService
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: reviews
  labels:
    kiali_wizard: request_routing
spec:
  hosts:
    - reviews.book-demo.svc.cluster.local
  gateways: ~
  http:
    - route:
        - destination:
            host: reviews.book-demo.svc.cluster.local
            subset: v1
          weight: 0
        - destination:
            host: reviews.book-demo.svc.cluster.local
            subset: v2
          weight: 50
        - destination:
            host: reviews.book-demo.svc.cluster.local
            subset: v3
          weight: 50
---

생성된 VirtualService, DestinationRuleistio control plane 에 전달되고, data plane 의 라우팅 규칙을 재작성 하는데 사용된다.

kiali 를 통해 생성된 istio resource yaml 을 바로 적용하는것도 좋지만, 대부분 코드 추적을 위해 직접 yaml 파일을 생성하고 적용한다.

VirtualService

  • timeout
  • retries
  • route
    • weight-base
  • mirror
kind: VirtualService
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: reviews-vs # virtual service name
spec:
  hosts: 
    - reviews.book-demo.svc.cluster.local # service DNS name
  gateways: ~
  http: # http 라우팅 규칙
    - match: # prefix 라우팅
      # IF
      - headers: # http header 에
          end-user: # end-user:admin 이 있을경우 라우팅
            exact: admin
            # regex 문법도 존재함
      # OR 
      - uri: # uri 에
          prefix: "/review"
        # AND
        header: # query 에
          - x-version: # v=v1 일 경우
            exact: v1
      route: # 조건일치 목적지
        - destination:
            host: reviews.book-demo.svc.cluster.local # service DNS name
            subset: subset-v1 # DestinationRule 정의된 subset
    
    # - match: another matching rule

    - route: # 기본 라우팅
      - destination:
          host: reviews.book-demo.svc.cluster.local # service DNS name
          subset: subset-v2 # DestinationRule 정의된 subset
        weight: 50 # weight-based routing
      - destination:
          host: reviews.book-demo.svc.cluster.local # service DNS name
          subset: subset-v3 # DestinationRule 정의된 subset
        weight: 50 # weight-based routing
      timeout: 10s  # 시간초과
      retries: # 재시도
        attempts: 3
        perTryTimeout: 2s
  • spec.http.[].route: 기본 라우팅
  • spec.http.[].match.route: 매칭 라우팅

VirtualServicematch 속성을 사용하면 프로덕션 환경에서 일반 사용자는 접근못하고 관리자만 접근 가능하도록 테스트용 서버를 동작시킬 수 있다.

이런 배포방식을 Dark Release 라고 부름

1

FaultInjection

결함을 주입해서 어플리케이션 전체에서 발생하는 문제를 테스트할 수 있다.

kind: VirtualService
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: reviews-vs # virtual service name
spec:
  hosts: 
    - reviews.book-demo.svc.cluster.local # service DNS name
  gateways: ~
  http:
    - match:
      - headers: # http header 에
          - x-version: # v=v1 일 경우
            exact: v1
      fault: # 해당 match 에 결합 주입
        delay:
          fixedDelay: 10s
          percentage:
            value: 100.0
        abort:
          httpStatus: 500
          percentage:
            value: 10.0
      route: # 조건일치 목적지
        - destination:
            host: reviews.book-demo.svc.cluster.local # service DNS name
            subset: subset-v1 # DestinationRule 정의된 subset
    
    - route: # 기본 라우팅
      - destination:
          host: reviews.book-demo.svc.cluster.local
          subset: subset-v2
        weight: 50
      - destination:
          host: reviews.book-demo.svc.cluster.local
          subset: subset-v3
        weight: 50

DestinationRule

아래와 같은 작업 수행 가능

  • load-balancer
  • circuit-breaker
kind: DestinationRule
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: reviews
spec:
  host: reviews.book-demo.svc.cluster.local # service DNS name
  subsets:
    - name: subset-v1 # subset name
      labels: # selector
        version: v1 # label name
    - name: subset-v2
      labels:
        version: v2
    - name: subset-v3
      labels:
        version: v3
  trafficPolicy: ~

Circuit Breaker

https://istio.io/latest/docs/reference/config/networking/destination-rule/#TrafficPolicy https://istio.io/latest/docs/reference/config/networking/destination-rule/#OutlierDetection

MSA 특성상 하나의 마이크로 서비스의 장애로 인해 전체 시스템 장애로 전파되는 Cacading Failure 가 발생할수 있다.

보통 Cacading Failure 를 막기위한 방법으로 Circuit Breaker 를 자주 설정하여 사용하는데, java 진영에선 resilience4j 와 같은 라이브러리를 사용한 방식이 유일했다.

istio 를 사용해 Circuit Breaker 를 구현함으로써, 라이브러리 의존성을 벗어날 수 있고, 각 서비스에서 광범위한 코딩 작업을 하지 않아도 구현이 가능하다.

테스트를 위해 calc-service 의 경우 2개 version 으로 운영중이며, 그중 하나는 임의로 500 에러를 반환하도록 설정하였다.

1

DestinationRulespec.trafficPolicy.trafficPolicy 을 추가해서 Circuit Breaker 역할을 구현

kind: DestinationRule
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: spring
  name: calc-destination-rule
spec:
  host: calc-service.spring.svc.cluster.local
  subsets:
    - name: normal
      labels:
        version: normal
    - name: poison
      labels:
        version: poison
  trafficPolicy:
    outlierDetection:
      consecutive5xxErrors: 1 # default 5, 5XX 에러발생 횟수
      interval: 10s # default 10s
      baseEjectionTime: 1m # default 30s
      maxEjectionPercent: 100 # default 10%, 모든 요청을 ejection 가능
---
# Gateway 전용 VirtualService
kind: VirtualService
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: spring
  name: calc-virtual-service-for-gateway
spec:
  http:
    - route:
        - destination:
            host: calc-service.spring.svc.cluster.local
# Circuit Breaker 설정시 정상 서비스로 라우팅하기 위해 모두 주석처리 함
#            subset: normal
#          weight: 50
#        - destination:
#            host: calc-service.spring.svc.cluster.local
#            subset: poison
#          weight: 50
  hosts:
    - calc.kube.demo.com
  gateways:
    - spring-kube-demo-gateway

5XX 에러가 한번이라도 발생하면 Circuit Breaker 가 동작되도록 설정한다.

trafficPolicy 를 삽입하면서 번개모양의 아이콘이 추가되었다.

1

테스트 결과 처음 오류가 한번 발생하면, 그 이후 1m 까지는 오류가 발생한 서비스로 라우팅되지 않는다.

while true; \
do curl -sS http://calc.kube.demo.com:8080/calculating/1/2; echo ''; sleep 0.5; done
# {"timestamp":"2024-03-21T10:19:45.455+00:00","status":500,"error":"Internal Server Error","path":"/calculating/1/2"}
# 3
# 3
# 3
# 3
# 3
# 3
# 3
# 3
# 3
# 3

주의사항으로 만약 VirtualService 에서 weight, subset 을 설정해두었다면 에러 발생시 아래와 같이 Circuit Breaker 가 동작하지만, 자체적으로 요청의 절반은 503 처리를 수행한다.

while true; \
do curl -sS greet.kube.demo.com:8080/greeting/1/2; echo ''; \
sleep 0.5; done
# 3
# 3
# {"timestamp":"2024-03-21T07:37:27.668+00:00","status":500,"error":"Internal Server Error","path":"/calculating/1/2"}
# 3
# 3
# 3
# no healthy upstream # 503 에러임
# no healthy upstream
# no healthy upstream
# 3
# no healthy upstream
# 3
# no healthy upstream

istioCircuit Breaker 기능이 라이브러리로 구성되는것 보다는 부족할 순 있지만, 장애 서비스의 요청을 우회하고 막음으로서 Cacading Failure 는 충분히 예방할 수 있다.

데모코드: https://github.com/Kouzie/spring-kube-demo

Gateway

사전에 istio ingress gateway controller 설치 필요.

Service Mesh 가장자리에서 VirtualService 까지 트래픽을 제어하는 독립형 Envoy 프록시.

istio 를 사용하기 전, 외부에서 들어오는 트래픽의 흐름은 아래와 같다.

LoadBalancer Service -> (Ingress) -> Another Service or Pod

여기서 IngressService 사이에 VirtualService 를 삽입한다 하더라도 Ingressk8s 표준 이고 VritualServiceistio CRD 이기 때문에 istio proxy 를 통해 패킷이 전달되지 않는다.

즉 외부요청을 바로 VirtualService 로 접근시키고 싶다면 Gateway 를 사용해야 한다.
아래와 같이 istio gateway 를 통해 라우팅해야 외부요청이 envoy 로 전달된다.

LoadBalancer Service -> Istio Gateway Container(Gateway) -> VirtualService

동일한 namespaceGateway 를 생성, hosts*.book.example.com 같이 와일드카드를 지정해서 라우팅할 도메인 범위를 지정.

/etc/hostsproduct.book.example.com 도메인 등록.

kind: Gateway
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: http-book-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 # gateway controller 중 label 이 istio=ingressageteway 인 pod 를 사용할 gateway 로 지정
  servers:
  - port:
      number: 8080 # load balanacer 의 port 와 매핑
      name: http
      protocol: HTTP
    hosts:
    - "*.book.example.com" # 라우팅할 hosts, 여러개 지정 가능

VirtualServieGateway 를 서로 매핑시켜 product 서비스까지 라우팅할 수 있도록 설정.

kind: DestinationRule
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: productpage
spec:
  host: productpage.book-demo.svc.cluster.local
  subsets:
    - name: v1
      labels:
        version: v1
  trafficPolicy: ~
---
kind: VirtualService
apiVersion: networking.istio.io/v1beta1
metadata:
  namespace: book-demo
  name: productpage
spec:
  hosts:
    - product.book.example.com # gateway 에서 설정한 hosts 와 매핑
  gateways: 
    - http-book-gateway # gateway 명 지정
  http:
    - route:
        - destination:
            host: productpage.book-demo.svc.cluster.local
            subset: v1
          weight: 100

1

reviews, detailsVirtualServiceL7 LB 역할을 수행하는 Gateway 를 통해 외부에서 바로 접근시킬 수 있다.

주의사항으로 Gateway 를 지정한 VirtualService 의 경우 Gateway 에서 들어온 트래픽만 처리하고 서비스들간의 트래픽에선 사용되지 않는다.
Gateway 와 서비스들간의 통신 모두 처리하고 싶다면 2개 VirtualService 를 각각 생성해야 한다.

ServiceEntry

istio 가 내부적으로 유지 관리하는 서비스 레지스트리에 항목

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: svc-entry
spec:
  hosts:
  - ext-svc.example.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  location: MESH_EXTERNAL # 서비스 레지스트리에 외부 종속성을 추가
  resolution: DNS
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: ext-res-dr
spec:
  host: ext-svc.example.com
  trafficPolicy:
    connectionPool:
      tcp:
        connectTimeout: 1s

Security

https://www.f5.com/labs/learning-center/what-is-mtls

k8s 노드를 AWS AZ 에 배치해 운영한다면 암호화 되지 않은 통신이 외부에 노출될 수 있다.
istiomTLS(mutal TLS, 상호 TLS) 기능을 사용하면 엔드포인트간 통신을 쉽게 암호화 처리할 수 있다.

기존 istio Citadel 에서 하는 작업이었으며 현재 istiod 로 통합됨.

1

그림처럼 서버와 클라이언트 상호간 인증서를 교환하며 헨드쉐이크하고, 신뢰할 수 있는 사용자의 통신만 허용시켜 Zero Trust 접근 방식을 사용할 수 있다.

모든 엔드포인트를 제어할 수 있는 폐쇄된 환경에 적합한 프로토콜이다.

PeerAuthentication

암호화 정책 설정 전, 테스트를 위해 NodePort Service 를 생성하고 review 서비스에 접근가능한지 확인

apiVersion: v1
kind: Service
metadata:
  name: reviews-nodeport
  namespace: book-demo
  labels:
    app: reviews
    service: reviews
spec:
  type: NodePort
  selector:
    app: reviews
  ports:
  - port: 9080 # 클러스터 내부에서 접근할 서비스 포트
    targetPort: 9080 # 실제 Pod의 포트
    nodePort: 30123
curl http://192.168.10.XXX:30123/reviews/0
# {"id": "0","podname": "reviews-v1-5b5d6494f4-5x82z","clustername": "null","reviews": [{  "reviewer": "Reviewer1",  "text": "An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!"},{  "reviewer": "Reviewer2",  "text": "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare."}]}%

종단간 인증정책, 워크로드에 적용하는 mTLS 모드 를 지정

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: example-peer-policy
  namespace: book-demo # 해당 namespace 안에서 mTLS 인증정책 사용
spec:
  mtls:
    # mode: PERMISSIVE # 일반 텍스트, TLS 모두 허용, default 값
    mode: STRICT # TLS 트래픽만 허용
    # mode: DISABLE # 상호 TLS 비활성화

PERMISSIVE 모드를 사용하면 istio 메시에 포함되지 않은 서비스도 암호화 되지 않은 네트워크로 통신 가능하다.

kiali 에서 security 체크박스 설정 후 엔드포인트 통신구간에 자물쇠 아이콘이 설정되었는지 확인.

1

지정 후 다시한번 NodePort Service 서비스에 접근

curl http://192.168.10.XXX:30123/reviews/0
# curl: (56) Recv failure: Connection reset by peer

데모 코드

https://github.com/Kouzie/local-k8s/tree/main/service-mash

카테고리:

업데이트: