티스토리 뷰

목차

    들어가기 전에

    처음 쿠버네티스를 공부할 때는 쿠버네티스만 하면 끝날 줄 알았습니다.

     

    하지만 인기 있는 오픈소스가 애드온이 없을 리가 없지요.

     

    한 번에 익혀야 할 지식이 너무 많아서 버거운 것이 사실입니다.

     

    또한 교육자료에서는 샘플 코드를 기준으로 가르치기 때문에 실제 환경에서 어떻게 구성해야 하는지 시행착오를 많이 겪어야 했습니다.

     

    때문에 오늘은 쿠버네티스 애드온의 Production환경 구축에 대해서 하나하나 풀어가보겠습니다.

     

    가능한 helm을 이용해서 설치합니다. helm을 먼저 설치해주시기 바랍니다.

    https://helm.sh/docs/intro/install/

     

    Installing Helm

    Learn how to install and get running with Helm.

    helm.sh

     

    이 글에서 작성할 파일의 폴더 구조는 아래와 같습니다.

     

     

    1. Jaeger

    1-1. Elasticsearch

    jaeger는 DB로서 Elasticsearch, Cassandra, Kafka를 사용할 수 있습니다. 

     

    elasticsearch.yaml

    • replicas, storage class는 자신의 환경에 맞게 설정해주세요.
    clusterName: elasticsearch
    nodeGroup: master
    
    replicas: 1
    minimumMasterNodes: 1
    
    volumeClaimTemplate:
     accessModes: ["ReadWriteOnce"]
     storageClassName: gp2
     resources:
       requests:
         storage: 10Gi

     

    1-2. jaeger

    jaeger.yaml

    apiVersion: jaegertracing.io/v1
    kind: Jaeger
    metadata:
      name: jaeger
      namespace: istio-system
    spec:
      strategy: production
      collector:
        maxReplicas: 5
        resources:
          limits:
            cpu: 100m
            memory: 128Mi
      storage:
        type: elasticsearch
        options:
          es:
            server-urls: http://elasticsearch-master.istio-system.svc.cluster.local:9200
      sampling:
        options:
          default_strategy:
            type: probabilistic
            param: 1.0

     

    1-3. Helm install Jaeger

    저는 istio-system 네임스페이스에 설치했습니다.

     

    원하는 네임스페이스에 설치하시면 되는데 다른 애드온 설치할 때 svc주소에 주의해주세요.

     

    helm repo add elastic https://helm.elastic.co
    helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
    
    helm repo update
    
    helm upgrade -i -f elasticsearch.yaml elasticsearch elastic/elasticsearch -n istio-system --wait
    helm upgrade -i jaeger-operator jaegertracing/jaeger-operator -n istio-system --wait
    kubectl apply -f jaeger.yaml

     

    2. Istio

    2-1. values.yaml

    global:
      tracer:
        zipkin:
          address: "jaeger-collector.istio-system.svc:9411" # jaeger collector 주소
    pilot:
      traceSampling: 100.0 # jaeger의 샘플링 빈도를 조절합니다. 실제 환경에 맞게 조절해주세요.

    2-2. Helm install Istio

    kubectl create namespace istio-system
    helm repo add istio https://istio-release.storage.googleapis.com/charts
    helm repo update
    helm upgrade -i  istio-base istio/base -n istio-system
    helm upgrade -i  -f values.yaml istiod istio/istiod -n istio-system --wait

     

    3. Prometheus & Grafana

    3-1. values.yaml

    Istio, prometheus, grafana, Kiali가 연동이 잘 안 돼서 고생을 많이 했었습니다.

    • storageclass는 자신의 환경에 맞게 조절해주세요
    • additionalScrapeConfigs에서 istio를 스크랩하는 설정이 들어갑니다.
    • kiali는 특정 grafana 대시보드를 요구합니다.
    namespaceOverride: "istio-system"
    
    alertmanager:
      alertmanagerSpec:
        retention: 120h
        resources:
          requests:
            memory: 400Mi
          limits:
            memory: 1Gi
        storage:
          volumeClaimTemplate:
            spec:
              storageClassName: gp2
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 10Gi
    
    # https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml
    grafana: # 메트릭 시각화
      namespaceOverride: "istio-system"
      defaultDashboardsTimezone: Asia/Seoul
      resources:
        requests:
          memory: 400Mi
        limits:
          memory: 1Gi
      persistence:
        type: pvc
        enabled: true
        storageClassName: gp2
        accessModes:
          - ReadWriteOnce
        size: 10Gi
      dashboardProviders:
        dashboardproviders.yaml:
          apiVersion: 1
          providers:
          - name: 'default'
            orgId: 1
            folder: ''
            type: file
            disableDeletion: false
            editable: true
            options:
              path: /var/lib/grafana/dashboards/default
      dashboards:
        default:
          istio-control-plane-dashboard:
            gnetId: 7645
            revision: 110
            datasource: Prometheus
          istio-mesh-dashboard:
            gnetId: 7639
            revision: 110
            datasource: Prometheus
          istio-performance-dashboard:
            gnetId: 12153
            revision: 1
            datasource: Prometheus
          istio-service-dashboard:
            gnetId: 7636
            revision: 110
            datasource: Prometheus
          istio-wasm-extension-dashboard:
            gnetId: 13277
            revision: 67
            datasource: Prometheus
          istio-workload-dashboard:
            gnetId: 7630
            revision: 110
            datasource: Prometheus
    
    kube-state-metrics: # 쿠버네티스 클러스터의 메트릭 수집
      namespaceOverride: "istio-system"
    
    prometheus-node-exporter: # 노드의 메트릭 수집
      namespaceOverride: "istio-system"
      hostRootFsMount:
        enabled: false
    
    prometheus:
      prometheusSpec:
        retention: 10d
        retentionSize: "10GB"
        replicas: 2
        resources:
          requests:
            memory: 400Mi
          limits:
            memory: 2Gi
        # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md
        storageSpec:
          volumeClaimTemplate:
            spec:
              storageClassName: gp2
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 10Gi
    
        # https://istio.io/latest/docs/ops/integrations/prometheus/#option-1-quick-start
        # https://raw.githubusercontent.com/istio/istio/release-1.7/manifests/charts/istio-telemetry/prometheus/templates/configmap.yaml
        # 형식: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config
        # istio Standard Metrics https://istio.io/latest/docs/reference/config/metrics/
        additionalScrapeConfigs:
        - job_name: 'istiod'
          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: 'istio-mesh'
          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: istio-telemetry;prometheus
    
        - job_name: 'envoy-stats'
          metrics_path: /stats/prometheus
          kubernetes_sd_configs:
            - role: pod
          # relabel_config 설정 https://grafana.com/docs/grafana-cloud/metrics-control-usage/control-prometheus-metrics-usage/usage-reduction/?src=grafana&mdm=rss
          relabel_configs:
          - source_labels: [ __meta_kubernetes_pod_container_port_name ]
            action: keep # 일치하는 대상 유지, 나머지 삭제
            regex: '.*-envoy-prom'
          - source_labels: [ __address__, __meta_kubernetes_pod_annotation_prometheus_io_port ]
            action: replace # 일치하는 label 을 replacement에 지정된 새 label 로 변경
            regex: ([^:]+)(?::\d+)?;(\d+)
            replacement: $1:15090
            target_label: __address__
          - action: labeldrop
            regex: __meta_kubernetes_pod_label_(.+)
          - source_labels: [ __meta_kubernetes_namespace ]
            action: replace
            target_label: namespace
          - source_labels: [ __meta_kubernetes_pod_name ]
            action: replace
            target_label: pod_name
    
        - job_name: 'istio-policy'
          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: istio-policy;http-policy-monitoring
    
        - job_name: 'istio-telemetry'
          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: istio-telemetry;http-monitoring
    
        - job_name: 'galley'
          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: istio-galley;http-monitoring
    
        - job_name: 'citadel'
          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: istio-citadel;http-monitoring
    
        - job_name: 'sidecar-injector'
          kubernetes_sd_configs:
          - role: endpoints
            namespaces:
              names:
              - default
              - istio-system
              - traefik
          relabel_configs:
          - source_labels: [ __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name ]
            action: keep
            regex: istio-sidecar-injector;http-monitoring
    
          # kubernetes API 스크랩
        - job_name: 'kubernetes-apiservers'
          kubernetes_sd_configs:
            - role: endpoints
              namespaces:
                names:
                  - default
          scheme: https
          tls_config:
            ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
          relabel_configs:
            - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
              action: keep
              regex: kubernetes;https
    
          # kubelet 수집
        - job_name: 'kubernetes-nodes'
          scheme: https
          tls_config:
            ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
          kubernetes_sd_configs:
            - role: node
          relabel_configs:
            - action: labelmap
              regex: __meta_kubernetes_node_label_(.+)
            - target_label: __address__
              replacement: kubernetes.default.svc:443
            - source_labels: [__meta_kubernetes_node_name]
              regex: (.+)
              target_label: __metrics_path__
              replacement: /api/v1/nodes/${1}/proxy/metrics
    
          # 컨테이너 수집
        - job_name: 'kubernetes-cadvisor'
          scheme: https
          tls_config:
            ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
          kubernetes_sd_configs:
            - role: node
          relabel_configs:
            - action: labelmap
              regex: __meta_kubernetes_node_label_(.+)
            - target_label: __address__
              replacement: kubernetes.default.svc:443
            - source_labels: [__meta_kubernetes_node_name]
              regex: (.+)
              target_label: __metrics_path__
              replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
    
          # node 정보 수집
        - job_name: 'kube-dns'
          static_configs:
            - targets: [ 'kube-dns.kube-system.svc.cluster.local:9153' ]
    
          #  서비스 수집
        - job_name: 'kubernetes-service-endpoints'
          kubernetes_sd_configs:
            - role: endpoints
          relabel_configs:
            - source_labels: [ __meta_kubernetes_service_annotation_prometheus_io_scrape ]
              action: keep
              regex: true
            - source_labels: [ __meta_kubernetes_service_annotation_prometheus_io_scheme ]
              action: replace
              target_label: __scheme__
              regex: (https?)
            - source_labels: [ __meta_kubernetes_service_annotation_prometheus_io_path ]
              action: replace
              target_label: __metrics_path__
              regex: (.+)
            - source_labels: [ __address__, __meta_kubernetes_service_annotation_prometheus_io_port ]
              action: replace
              target_label: __address__
              regex: ([^:]+)(?::\d+)?;(\d+)
              replacement: $1:$2
            - action: labelmap
              regex: __meta_kubernetes_service_label_(.+)
            - source_labels: [ __meta_kubernetes_namespace ]
              action: replace
              target_label: kubernetes_namespace
            - source_labels: [ __meta_kubernetes_service_name ]
              action: replace
              target_label: kubernetes_name

     

    3-2. Helm install prometheus

    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo update
    helm upgrade -i -f values.yaml monitoring prometheus-community/kube-prometheus-stack -n istio-system --wait

     

    4. Kiali

    4-1. values.yaml

    • auth strategy는 입맛에 맞게 설정해주세요.
    cr:
      create: true
      name: kiali-operator
      namespace: istio-system
      spec:
        auth:
          strategy: "anonymous" # 로그인 없이 kiali 접근 가능
    #      strategy: "token" # kubernetes 의 sa token 을 이용해 로그인
    #      strategy: "openid" # 타사 아이디(ex. google) 인증을 통해 로그인
    
        deployment:
          installation_tag: "Kiali in istio-system"
          view_only_mode: false
          accessible_namespaces:
          - '**'
          logger:
            # "trace", "debug", "info", "warn", "error", "fatal"
            log_level: info
            # "text", "json".
            log_format: text
            time_field_format: "2006-01-02T15:04:05Z07:00"
            log_sampler_rate: 1
    
        external_services:
          istio:
            istiod_pod_monitoring_port: 15014
            component_status:
              components:
              - app_label: istiod
                is_core: true
          prometheus:
            url: "http://monitoring-kube-prometheus-prometheus.istio-system:9090/"
            cache_enabled: true
            cache_duration: 10 # 쿼리당 캐시 만료 시간(초)
            cache_expiration: 300 # 전역 캐시 만료 시간(초)
          tracing:
            enabled: true
            use_grpc: false
            whitelist_istio_system: ["jaeger-query"]
            in_cluster_url: 'http://jaeger-query.istio-system:16686'
            url: "<traefik의 external 주소>:<jaeger entryPoint포트번호>"
          grafana:
            enabled: true
            auth:
              type: "basic"
              username: "admin"
              password: "prom-operator"
            dashboards:
              - name: "Istio Service Dashboard"
              - name: "Istio Workload Dashboard"
              - name: "Istio Mesh Dashboard"
              - name: "Istio Control Plane Dashboard"
              - name: "Istio Performance Dashboard"
              - name: "Istio Wasm Extension Dashboard"
            in_cluster_url: 'http://monitoring-grafana.istio-system/'
            url: "<traefik의 external 주소>:<그라파나 entryPoint포트번호>"
    istio_namespace: istio-system

     

    4-2. Helm install Kiali

    helm upgrade -i -f values.yaml kiali-operator kiali/kiali-operator -n kiali-operator --wait

     

    5. Traefik ingress controller

    서비스 메시인 Istio를 접하신 분들은 왜 Istio ingressgateway를 사용하지 않는지 의아하게 생각하실 수도 있습니다.

     

    처음에는 Istio만으로 행복 코딩을 했으나 맥의 M1칩에서 동작하지 않는다는 사실을 알게 되었습니다.

     

    비공식적으로 빌드된 M1용 Istio가 있지만 검증되지 않은 빌드는 사용하고 싶지 않았기에 Traefik을 도입했습니다.

     

    개발환경에서는 Traefik, 서버에서는 Istio + Traefik을 사용하는 구조이지요.

     

    Traefik은 helm을 이용해서 설치합니다.

     

    5-1. values.yaml

    • annotation 설정은 AWS 환경에서 사용하실 분만 해주시면 됩니다.
    • ports 부분의 포트는 입맛에 맞게 변경하거나 수정해주시면 됩니다.
    # https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml
    ingressRoute:
      dashboard:
        enabled: false # 대시보드를 비활성화 합니다.
    providers:
      kubernetesCRD:
        allowCrossNamespace: true # Traefik이 다른 네임스페이스의 서비스에 라우팅할 수 있도록 합니다.
    service:
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-type: nlb # AWS의 network loadbalancer를 활성화합니다. 설정하지 않으면 classic으로 생성됩니다.
    ports: # port는 외부에 개방하는 포트이며 traefik내에서 entryPoint라고 불립니다.
      preview: # blue/green 배포를 위한 포트입니다. 나중에 다시 다루겠습니다.
        port: 8888
        expose: true
        exposedPort: 8888
        protocol: TCP
      jaeger:
        port: 9991
        expose: true
        exposedPort: 9991
        protocol: TCP
      grafana:
        port: 9992
        expose: true
        exposedPort: 9992
        protocol: TCP
      prometheus:
        port: 9993
        expose: true
        exposedPort: 9993
        protocol: TCP
      kiali:
        port: 9994
        expose: true
        exposedPort: 9994
        protocol: TCP
    autoscaling:
      enabled: true
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          targetAverageUtilization: 60
      - type: Resource
        resource:
          name: memory
          targetAverageUtilization: 60

     

    5-2. Ingressroute

    kubectl get svc -n traefik

    Traefik 서비스를 확인하면 values에서 개봉한 port를 확인할 수 있습니다.

     

    이 포트를 통해서 각 애드온들에 접속하는 설정을 해봅시다.

     

    Ingressroute의 상세 설정은 링크를 참조하세요.

    https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-ingressroute

     

    Kubernetes IngressRoute - Traefik

    Traefik & Kubernetes The Kubernetes Ingress Controller, The Custom Resource Way. Configuration Examples Configuring KubernetesCRD and Deploying/Exposing Services Resource Definition# All resources definition must be declared --- apiVersion: apiextensions.k

    doc.traefik.io

     

    ingressroute/grafana.yml

    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
      name: ingress-route-grafana
      namespace: traefik
    spec:
      entryPoints:
        - grafana
      routes:
      - kind: Rule
        match: PathPrefix(`/`)
        services:
        - name: monitoring-grafana
          port: 80
          namespace: istio-system

    ingressroute/jaeger.yml

    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
      name: ingress-route-jaeger
      namespace: traefik
    spec:
      entryPoints:
        - jaeger
      routes:
        - match: PathPrefix(`/`)
          kind: Rule
          services:
            - name: jaeger-query
              namespace: istio-system
              port: 16686

    ingressroute/kiali.yml

    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
      name: ingress-route-kiali
      namespace: traefik
    spec:
      entryPoints:
        - kiali
      routes:
        - match: PathPrefix(`/`)
          kind: Rule
          services:
            - name: kiali
              namespace: istio-system
              port: 20001

     

    5-3. Helm install Traefik

    # Traefik 네임스페이스 생성
    kubectl create ns traefik
    # istio-injection 설정
    kubectl label namespace traefik istio-injection=enabled --overwrite
    # Helm 설치
    helm repo add traefik https://helm.traefik.io/traefik
    helm repo update
    helm upgrade -i -f values.yaml traefik traefik/traefik -n traefik
    # ingressroute 설치
    kubectl apply -f ingressroute/jaeger.yml
    kubectl apply -f ingressroute/kiali.yml
    kubectl apply -f ingressroute/grafana.yml

     

    6. 통합 설치 스크립트

     위에서 작성한 커맨드를 한 번에 설치하는 쉘 스크립트를 만듭시다.

     

    script/init.sh

    • repo_path는 현재 레포지토리의 절대 주소입니다.
    • helm upgrade -i 옵션이 참 편리합니다. 이미 설치되어 있다면 업데이트 아니라면 설치합니다.
    • istio-system에 jaeger, elasticsearch, prometheus, kiali를 모두 같은 네임스페이스에 설치했습니다만 다른 네임스페이스에 설치하셔도 됩니다.
    #!/bin/bash
    
    repo_path=$(git rev-parse --show-toplevel)
    
    echo "👉 네임스페이스 설치 👈"
    kubectl create namespace istio-system
    kubectl create namespace traefik
    kubectl create namespace kiali-operator
    kubectl label namespace traefik istio-injection=enabled --overwrite
    kubectl label namespace default istio-injection=enabled --overwrite
    
    echo "👉 Helm repo 추가 👈"
    helm repo add elastic https://helm.elastic.co
    helm repo add jaegertracing https://jaegertracing.github.io/helm-charts
    helm repo add istio https://istio-release.storage.googleapis.com/charts
    helm repo add traefik https://helm.traefik.io/traefik
    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo add kiali https://kiali.org/helm-charts
    
    echo "👉 Helm 업데이트 👈"
    helm repo update
    
    echo "👉 Elasticsearch 설치 👈"
    helm upgrade -i -f ${repo_path}/jaeger/elasticsearch.yaml elasticsearch elastic/elasticsearch -n istio-system --wait
    
    echo "👉 Jaeger 설치 👈"
    helm upgrade -i jaeger-operator jaegertracing/jaeger-operator -n istio-system --wait
    kubectl apply -f ${repo_path}/jaeger/jaeger.yaml
    
    echo "👉 Istio 설치 👈"
    helm upgrade -i istio-base istio/base -n istio-system --wait
    helm upgrade -i -f ${repo_path}/istio/values.yaml istiod istio/istiod -n istio-system --wait
    
    echo "👉 Traefik 설치 👈"
    helm upgrade -i -f ${repo_path}/traefik/values.yaml traefik traefik/traefik -n traefik --wait
    kubectl apply -f ${repo_path}/traefik/ingressroute/jaeger.yml
    kubectl apply -f ${repo_path}/traefik/ingressroute/kiali.yml
    kubectl apply -f ${repo_path}/traefik/ingressroute/grafana.yml
    
    echo "👉 Prometheus 설치 👈"
    helm upgrade -i -f ${repo_path}/prometheus/values.yaml monitoring prometheus-community/kube-prometheus-stack -n istio-system --wait
    
    echo "👉 Kiali 설치 👈"
    helm upgrade -i -f ${repo_path}/kiali/values.yaml kiali-operator kiali/kiali-operator -n kiali-operator --wait

     

    마무리

    지금 정리하고 보니 이렇게 간단한데 몇 주를 팀원과 고생했었습니다.

     

    인프라는 yaml과의 긴 싸움이군요.

     

    마지막 팁은 helm의 values 기본값을 확인하는 방법입니다.

    helm show values istio/istiod

    일일이 레포지토리를 찾아가지 않아도 돼서 편리합니다.

    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/07   »
    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
    글 보관함