Istio Service Mesh


Istio

1. Istio service mesh

Istio Architecture

Istio는 컨트롤 플레인과 데이터 플레인으로 나뉜다.

  • 컨트롤 플레인은 트래픽 라우팅을 위해 프록시를 관리하고 구성하는 역할을 담당한다.
  • 데이터 플레인은 사이드카로 배포된 일련의 지능형 프록시(Envoy)로 구성되며 이러한 프록시는 마이크로서비스 간의 모든 네트워크 통신을 중개하고 제어한다. 또한 모든 메시 트래픽에 대해 텔레메트리 정보를 수집하고 보고한다.

istio-architecture001.png

Istio Component

  • Envoy
    Istio는 Envoy 프록시를 이용합니다. Envoy는 서비스 메시의 모든 서비스에 대한 모든 Inbound/Outbound 트래픽에 대해 중개하는 고성능 Proxy 입니다. Envoy 프록시는 데이터 플레인 트래픽과 상호작용하는 유일한 Istio 컴포넌트이다.
    Envoy 프록시는 사이드카 패턴으로 배포되며 논리적으로 Envoy의 아래의 다양한 build-in 기능으로 서비스를 논리적으로 보강한다.
    • Dynamic service discovery
    • Load balancing
    • TLS termination
    • HTTP/2 and gRPC proxies
    • Circuit breakers
    • Health checks
    • Staged rollouts with %-based traffic split
    • Fault injection
    • Rich metrics

    Envoy 프록시에서 사용할 수 있는 Istio 기능 및 작업은 다음과 같습니다.

    • 트래픽 제어 기능: HTTP, gRPC, WebSocket, TCP 트래픽 에 대해서 다양한 라우팅 규칙을 통해 세분화된 트래픽 제어 시행
    • 네트워크 복원력 기능: Setup retries, Fail-over, Circuit breakers, Fault injection
    • 보안 및 인증 기능: 보안 정책, 접근 제어, 속도 제한을 시행
  • Istiod
    Istiod provides service discovery, configuration and certificate management.

    Istiod는 트래픽 동작을 제어하는 high level 라우팅 규칙을 Envoy 전용 구성으로 변환하여 런타임에 사이드카에 전파한다. Pilot 플랫폼별 서비스 검색 메커니즘을 추상화하여 Envoy API를 준수하는 모든 사이드카가 사용할 수 있는 표준형식으로 합성한다.
    Istiod 보안은 build-in identity 및 자격 증명 관리를 통해 강력한 서비스 간 및 최종 사용자 인증을 지원합니다. Istio를 사용하여 서비스 메시에서 암호화되지 않은 트래픽을 업그레이드할 수 있습니다. 운영자는 Istio를 사용하여 상대적으로 불안정한 계층 3 또는 계층 4 네트워크 식별자 대신 서비스 ID를 기반으로 정책을 시행할 수 있습니다. 또한 Istio의 인가 기능을 사용하여 서비스에 액세스할 수 있는 사용자를 제어할 수 있습니다. Istiod는 인증 기관(CA) 역할을 할 수 있으며 데이터 플레인에서 안전한 mTLS 통신을 허용하는 인증서를 생성합니다.


2. Install Istio

Istio를 설치하는 방법에는 여러가지 방법이 있고 istioctl과 helm을 통한 설치방법을 소개하지만 여기서는 Helm을 이용하기로 한다. Helm의 values파일을 변경하여 필요한 값을 Customize하여 사용하기 위해서다.

2.1. Install with istioctl

Install Download

curl -L https://istio.io/downloadIstio | sh -
cd istio-1.19.3
cp bin/istioctl /usr/local/bin

Install

istioctl install --set profile=demo -y
istioctl uninstall --set profile=demo -y

Injection Configuration

kubectl label namespace default istio-injection=enabled

Deploy the sample application

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml


2.2. Install with helm

base-values.yaml
istiod-values.yaml
gateway-values.yaml

gateway-values.yaml
ingress-gateway를 위해

  1. Service(NLB)의 설정파일 실제 Listener로 설정될 포트는 서비스 포트이며 타겟 포트로 설정될 포트는 Gateway 서버포트와 일치해야 한다.
  2. 헬스체크에 대해서는 고민이 필요하다. 15021 포트로 헬스체크를 하면 istio-ingressgateway 파드 자체에 대한 헬스체크는 가능하나 backend 서비스에 자체에 대한 헬스체크는 불가능하다. 만약 traffic-port로 변경할 경우 healthcheck-path 값을 통해 backend 중 하나에는 트래픽을 보낼 수 있지만 여러 서비스로는 보낼 수 없다. 그래서 traffic-port를 tcp로 변경하고 traffic-port로 설정하면 각 서비스에 대한 헬스체크가 가능하다(path는 제외하였지만).
service:
  # Type of service. Set to "None" to disable the service entirely
  type: LoadBalancer
  ports:
  # - name: status-port
  #   port: 15021
  #   protocol: TCP
  #   targetPort: 15021
  # - name: https
  #   port: 443
  #   protocol: TCP
  #   targetPort: 10012
  # 실제 트래픽 전달을 위해 사용 하는 포트 (awssdk)
  - name: https
    port: 443
    protocol: TCP
    targetPort: 80
  # 실제 트래픽 전달을 위해 사용 하는 포트 (bookinfo)
  - name: http
    port: 8080
    protocol: TCP
    targetPort: 8080
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-name: k8s-istiosys-ingressgateway
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-subnets: subnet-02e6d788fad8afdcf, subnet-020255d69e8c814da #az1-extelb, az3-extelb
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    service.beta.kubernetes.io/aws-load-balancer-attributes: load_balancing.cross_zone.enabled=true
    service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:ap-northeast-2:558846430793:certificate/250015a4-4753-4a97-b536-88a6e6aaaf73
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
    
    # SET 1
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: http
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "15021"  # traffic-port "15021"
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-path: /healthz/ready
    # SET 2
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: tcp
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: traffic-port  # traffic-port "15021"

    service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: "2"
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3"
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "20"
    service.beta.kubernetes.io/aws-load-balancer-security-groups: sg-0f94ae1a6d9ba9d69
    service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: auto-delete=no
  loadBalancerIP: ""
  loadBalancerSourceRanges: []
  externalTrafficPolicy: ""
  externalIPs: []
  ipFamilyPolicy: ""
  ipFamilies: []

설정한 파일을 가지고 총 3개의 Helm 차트를 설치한다.

  1. istio-base
    • CRD, WebhookConfiguration 등이 설치된다.
  2. istiod
  3. istio-ingressgateway
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
kubectl create namespace istio-system

helm upgrade -i istio-base istio/base -n istio-system -f /Users/bys/workspace/kubernetes/istio/bys-dev-eks-main/helm/base-values.yaml
helm upgrade -i istiod istio/istiod -n istio-system -f /Users/bys/workspace/kubernetes/istio/bys-dev-eks-main/helm/istiod-values.yaml
helm upgrade -i istio-ingressgateway istio/gateway -n istio-system -f /Users/bys/workspace/kubernetes/istio/bys-dev-eks-main/helm/gateway-values.yaml


2.2. Istio object

  • Gateway
    Gateway는 송/수신 HTTP/TCP 연결을 받는 서비스 메시의 edge에서 동작하는 로드밸런서를 설명한다. 즉, 노출해야하는 port, protocol, 로드밸런서에 대한 SNI 구성을 설정한다. 아래의 Gateway 명세는 로드밸런서의 L4-L6 속성을 설명한다.
    (Gateway의 포트 설정은 istio-ingressgateway로 배포된 proxy 서버의 타겟포트와 일치해야하는데, 그 타겟포트로 도 했을 때의 Gateway 맵핑으로 이해하면 이후 라우팅 동작은 Gateway와 연결된 VirtualService에서 정의한다고 이해하면 된다)
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-gateway
  namespace: some-config-namespace
spec:
  selector:
    app: my-gateway-controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - uk.bookinfo.com
    - eu.bookinfo.com
    tls:
      httpsRedirect: true # sends 301 redirect for http requests
  - port:
      number: 443
      name: https-443
      protocol: HTTPS
    hosts:
    - uk.bookinfo.com
    - eu.bookinfo.com
    tls:
      mode: SIMPLE # enables HTTPS on this port
      serverCertificate: /etc/certs/servercert.pem
      privateKey: /etc/certs/privatekey.pem
  - port:
      number: 9443
      name: https-9443
      protocol: HTTPS
    hosts:
    - "bookinfo-namespace/*.bookinfo.com"
    tls:
      mode: SIMPLE # enables HTTPS on this port
      credentialName: bookinfo-secret # fetches certs from Kubernetes secret
  - port:
      number: 9080
      name: http-wildcard
      protocol: HTTP
    hosts:
    - "*"
  - port:
      number: 2379 # to expose internal service via external port 2379
      name: mongo
      protocol: MONGO
    hosts:
    - "*"
  • VirtualService
    트래픽 라우팅에 영향을 미치는 설정이다. VirtualService는 host를 통해 목적지 주소를 지정하며 트래픽 라우팅 집합을 정의한다. route.destination.subset은 DestinationRule에 선언된 서비스 subset의 이름을 참조하여 식별되어야 합니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews-route
spec:
  hosts:
  - reviews.prod.svc.cluster.local
  http:
  - name: "reviews-v2-routes"
    match:
    - uri:
        prefix: "/wpcatalog"
    - uri:
        prefix: "/consumercatalog"
    rewrite:
      uri: "/newcatalog"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v2
  - name: "reviews-v1-route"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: reviews.prod.svc.cluster.local
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

이 외에도 기타 여러 설정 등을 통해 추가적인 Traffic 제어가 가능하다.


2.3. Kiali dashbaord

Istio 메시의 시각화를 위해 사용할 수 있다. 추후 Sample을 배포하고 흐름을 볼 수 있도록 미리 설치를 진행한다.

Install Kiali

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.21/samples/addons/kiali.yaml

istioctl dashboard kiali


2.4 Deploy Sample Application

kubectl label namespace default istio-injection=enabled

## Deploy sample Deployments, Services 
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

## Deploy sample Gateway, VirtualService
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

정상적으로 배포가 되었는지 확인하기 위한 작업

export INGRESS_NAME=istio-ingressgateway
export INGRESS_NS=istio-system

kubectl get svc "$INGRESS_NAME" -n "$INGRESS_NS"

export INGRESS_HOST=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
export INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="http")].port}')

export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

curl http://$GATEWAY_URL/productpage
# watch -n 1 curl -o /dev/null -s -w %{http_code} $GATEWAY_URL/productpage


2.5 Deploy Application(개인용)

기존의 존재하던 Application에 Gateway, VirtualService 추가 구성.

awssdk-gateway

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: awssdk-gateway
  namespace: aws
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
    istio: ingressgateway # use istio default controller
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "istio-awssdk.bys.digital"

awssdk-virtual-service

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: awssdk-virtual-service
  namespace: aws
spec:
  hosts:
    - "*"
  gateways:
    - awssdk-gateway
  http:
    - match:
        - uri:
            prefix: /storage
      route:
        - destination:
            host: awssdk-storage-dev-svc.aws.svc.cluster.local
            port:
              number: 10011
    - match:
        - uri:
            prefix: /iam
      route:
        - destination:
            host: awssdk-iam-dev-svc.aws.svc.cluster.local
            port:
              number: 10012
curl -v https://istio-awssdk.bys.digital/storage/v2/s3/buckets
curl -v https://istio-awssdk.bys.digital/iam/v2/sts/id



10. Troubleshooting

1. Kiali 구성 시, 기존 Prometheus 연결

Kiali dashboard를 사용하기 위해서는 prometheus 구성이 필수이지만 기존 prometheus가 설치된 경우 istio-system에 존재하지 않기 때문에 주소를 등록해주어야 한다.
kiali ConfigMap의 external_services에 custom 설치된 prometheus URL을 추가하여 설정한다.

# kubectl edit cm kiali -n istio-system

......
      external_services:
        custom_dashboards:
          enabled: true
        istio:
          root_namespace: istio-system
        tracing:
          enabled: false
        prometheus:
          url: http://prometheus-server.prometheus.svc.cluster.local/
2. Envoy Access Logging

Gateway, VirtualService 등을 구성하고 503 오류가 발생하여 istio-ingressgateway에서 발생한 오류인지 혹은 각 서비스 Envoy 프록시에서 발생한 오류인지를 확인하려고 kubectl logs 커맨드를 사용하였으나 Access 로그가 보이지 않았다.
Envoy access log를 활성화 하기 위해서는 아래의 Telemetry를 배포한다.

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system
spec:
  accessLogging:
    - providers:
      - name: envoy




Tag: [ istio  servicemesh  ]