Loki 쿠버네티스 세팅

Alli_Eunbi·2023년 8월 15일
2
  • 사전 준비
    💡 k8s 클러스터에 네임스페이스 모니터링(monitoring)이 있어야 함.
    💡 helm이 설치되어 있어야 함.

Log 수집기가 필요한 이유

Kubernetes에서는 기본적으로 로그가 각 Pod의 생명주기 동안만 유지됩니다. 하지만 단일 Pod의 수명보다 오래 로그를 보관하기 위해 로그 집계(log aggregation)를 사용합니다. 이는 여러 원본으로부터 수집된 로그를 하나의 위치에 저장하여 문제가 발생한 후에도 쉽게 분석할 수 있도록 합니다. ELK 스택 (Elasticsearch, Logstash, Kibana)은 로그 집계를 위한 인기있는 솔루션이지만, 더 가볍고 간단한 솔루션인 Loki를 선택했습니다. (또한 아래 설명되는 수평적 확장 기능 또한 Loki를 선택한 이유입니다)

Grafana Labs에서 개발한 Loki는 수평적으로 확장 가능하고 고가용성이 뛰어난 멀티테넌트 로그 집계 시스템으로, Prometheus에서 영감을 받아 개발되었습니다. Loki는 서로 다른 형식의 다양한 원본으로부터 쉽게 로그를 수집하고, 객체 스토리지를 통해 확장 가능한 영속성을 제공합니다.


Loki Distributed 선택 이유

Loki를 설치하고 관리하는 데 사용되는 Kubernetes의 Helm 차트들 중 두 개는 "loki-stack"과 "loki-distributed"입니다. 이 두 차트의 차이점은 다음과 같습니다.

1. loki-stack:

"loki-stack" Helm 차트는 Loki를 단일 노드로 구성하여 배포하는 방법을 제공합니다. 이는 기본적인 Loki 설치를 위해 사용되며, 로그 수집, 저장 및 검색을 단일 노드에서 처리합니다. 이 단일 노드는 다수의 컨테이너로 구성되어 Loki 서버, Prometheus, Grafana 및 Prometheus 메트릭 저장소를 모두 단일 클러스터에 배포합니다. 이 단순한 배포 방식은 개발 및 테스트 용도로 적합할 수 있습니다.

2. loki-distributed:

"loki-distributed" Helm 차트는 Loki를 분산 환경에서 배포하기 위해 설계되었습니다. 이 차트는 Loki의 구성 요소들을 다수의 노드로 분산시키고, 데이터를 보다 효율적으로 처리하고 처리 능력을 확장할 수 있도록 도와줍니다. 분산된 Loki를 사용하면 대량의 로그를 처리하는 데 더 적합하며, 고가용성과 확장성을 갖추기 위해 다양한 구성을 가능하게 합니다.

요약하면, loki-stack은 단일 노드로 Loki를 설치하는 데 사용되며, 간단한 테스트 및 개발 환경에서 유용합니다.

반면 loki-distributed는 Loki를 분산 환경으로 배포하여 대규모 로그 처리 및 고가용성이 필요한 경우에 적합합니다.

현재 저희 서비스는 개발 클러스터와 운영 클러스터 두개로 구성되어 있으며, 한 클러스터당 많은 MSA 서버가 가동되는 것을 감안하여, loki-distributed를 사용하는 것으로 결정했습니다.

Loki 배포를 위해 kube-stack 수정 배포

  • helm에 grafana repository 설치
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
  • 복붙한 values.yaml의 수정사항은 아래와 같음.
    prometheus:
      prometheusSpec:
        serviceMonitorSelectorNilUsesHelmValues: false
        serviceMonitorSelector: {}
        serviceMonitorNamespaceSelector: {}
    
    grafana:
      sidecar:
        datasources:
          defaultDatasourceEnabled: true
      additionalDataSources:
        - name: Loki
          type: loki
          url: http://loki-loki-distributed-query-frontend.monitoring:3100
  • 배포 명령어
    helm upgrade --install prom prometheus-community/kube-prometheus-stack -n monitoring --values values.yaml

Loki 배포 전략

1. Promtail

  • Promtail 설정을 위한 promtail-values.yaml 파일 생성(아래 복붙)
    #promtail-values.yaml
    config:
      serverPort: 8080
      clients:
        - url: http://loki-loki-distributed-gateway/loki/api/v1/push
  • 배포 명령어
    helm upgrade --install promtail grafana/promtail -f promtail-values.yaml -n monitoring 

2. Loki

  • 배포
    helm upgrade --install loki grafana/loki-distributed -n monitoring -f values.yaml

각 컴포넌트의 역할은 아래와 같습니다.


1. Promtail: 로그를 LoadBalancer로 전달합니다.
2. LoadBalancer: 로그를 Distributor로 전달합니다.
3. Distributor: 주된 역할은 로그를 배치하고 유효성을 검사하는 것입니다. 유효한 청크는 배치로 분할되어 다른 Ingestor로 전달됩니다. Distributor는 상태를 유지하지 않으므로 확장이 용이합니다. Distributor는 Ingestor로부터 작업을 받는 것이 최종적으로 책임입니다.
4. Ingestor: Loki에서 가장 중요한 구성 요소입니다. 검증 과정 중 Distributor는 로그 라인이 너무 길지 않고 타임스탬프가 너무 오래되지 않았는지 확인합니다.
5. Chunks: Ingestor는 로그의 스트림을 받아 Chunks로 패킹하고, 이후 장기 저장소로 전달하는 책임을 지닙니다. 높은 가용성을 위해 일반적으로 Kubernetes 클러스터 내에서 여러 개의 Ingestor를 실행합니다.
6. Chunks 장기 저장: Chunks는 다음과 같은 경우 장기 저장소로 전달됩니다.
- 현재 청크가 용량에 도달한 경우 (구성 가능한 값).
- 현재 청크가 일정 시간 동안 업데이트되지 않은 경우.
- 플러시가 발생한 경우 - 즉, 특정 시간이 경과하고 로그가 자동으로 전달됩니다.

이러한 구성 요소들을 조합하여 Loki는 로그를 효율적으로 수집하고 분산하여 장기 저장소에 보관하는데 사용됩니다. Distributor와 Ingestor는 특히 Loki의 핵심 부분이며, Distributor는 Ingestor로부터 로그 작업을 받아들이고, Ingestor는 로그를 청크로 변환하고 장기 저장소로 전달하는 역할을 담당합니다.


에러 헨들링

1. memberlist 에러

failed: failed to create memberlist: Failed to get final advertise address: no pri
vate IP address found, and explicit IP not provided"

level=error ts=2022-06-11T08:11:00.753914179Z caller=loki.go:384 msg="module failed" module=memberlist-kv error="invalid service state: Failed, expected: Running, failure: service failed: failed to create memberlist: Failed to get final advertise address: no private IP address found, and explicit IP not provided"

위의 에러의 경우, loki-distributed helm차트의 values.yaml을 수정없이 기본값으로 사용하여 배포 했을 경우 발생합니다.

Loki 설정 파일에서 "memberlist bind address"를 명시적으로 Pod의 IP 주소로 설정해줘야 합니다.

  • memberlist란?

    Loki에서의 Memberlist는 서비스 검색 및 클러스터 구성을 위한 내부 통신 메커니즘입니다. Loki는 가볍고 분산된 로그 집계 시스템이며, 다양한 컴포넌트 간에 로그 및 메타데이터를 효율적으로 전달하기 위해 Memberlist를 사용합니다.

    Memberlist는 HashiCorp의 Serf 라이브러리에서 영감을 받은 Gossip 프로토콜을 기반으로 합니다. Gossip 프로토콜은 분산 시스템에서 노드들 간에 정보를 효율적으로 전파하는 방법을 제공합니다. 이는 Loki의 컴포넌트들이 서로의 존재를 알고, 클러스터 내에서 새로운 노드를 발견하고 상태를 동기화하는 데 사용됩니다.

    Memberlist를 통해 Loki의 다양한 컴포넌트들은 서로의 IP 주소와 포트 번호를 알 수 있으며, 로그 데이터와 메타데이터를 주고받을 수 있습니다. 각 Loki Pod는 고유한 IP 주소를 가지고 있으며, Memberlist를 통해 서로를 발견하고 통신할 수 있게 됩니다.

  • Memberlist의 주요 특징은 다음과 같습니다:

    1. Gossip 프로토콜: Memberlist는 Gossip 프로토콜을 사용하여 정보를 효율적으로 전파합니다. 이를 통해 노드들은 서로와 상태를 주기적으로 동기화하고 클러스터의 변화를 감지할 수 있습니다.

    2. 구성의 유연성: Loki의 설정 파일에서 Memberlist의 bind address를 명시적으로 설정할 수 있으며, 이를 통해 각 Pod는 특정 IP 주소에 바인딩하여 통신합니다.

    3. 서비스 검색 및 동적 확장: Memberlist를 사용하면 Loki 클러스터는 동적으로 새로운 노드를 검색하고 추가할 수 있으며, 서비스의 확장에 유연하게 대응할 수 있습니다.

    4. 가볍고 분산: Memberlist는 가벼우면서도 분산 시스템에서 효과적인 서비스 검색 및 노드 간 통신을 제공합니다.

      이렇게 Memberlist를 사용하여 Loki는 높은 가용성과 확장성을 갖춘 로그 집계 시스템으로 동작합니다. 다양한 Loki 컴포넌트들은 Memberlist를 통해 서로를 알고, 로그 데이터를 효율적으로 수집하고 저장하는데 활용됩니다.

  1. values.yaml의 모든 extraEnv에 아래와 같이 추가 합니다.

    extraEnv: 
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
  2. values.yaml의 모든 extraArgs에 아래와 같이 추가 합니다.

    extraArgs: 
        - -config.expand-env=true

에러 참조)

Gossip-ring / memberlist - no private IP address found

2. no such file or directory 에러

open /var/loki/chunks/ZmFrZS80MzA4NDcyMTQyNmE1YjI1OjE4OWQyMTNiYjEwOjE4OWQyOGEyZjkzOmNmMDViNjli: no such file or directory

loki-distributed는 multi-pod로 운영되고 있고, 파일 시스템 저장소를 사용하면 여러 파드가 동일한 볼륨에 액세스해야 하므로 데이터는 메모리에 캐시되어있는 한만 조회 가능합니다.

예를 들어, loki 수집기 서버의 메모리에 로그 데이터가 캐시되어 있지 않는 경우, loki의 쿼리 서버는 로그 데이터를 찾지 못해 위와 같은 에러를 발생시킵니다.
file-system: local-storage를 사용하는 경우 빈번하게 발생하므로, s3로 저장소를 이관해야합니다.

// 이쪽 세팅 보고 맞춰줘야 함.
loki:
  config: |
    compactor:
      shared_store: s3
    schema_config:
      configs:
      - from: "2020-05-15"
        index:
          period: 24h
          prefix: index_
        object_store: s3
        schema: v11
        store: boltdb-shipper
    server:
      http_listen_port: 3100
    storage_config:
      boltdb_shipper:
        active_index_directory: /var/loki/index
        cache_location: /var/loki/cache
        cache_ttl: 168h
        shared_store: s3
      aws:
        bucketnames: {bucket-name} // 버킷 이름
        s3: s3://{region} //AWS region

storageConfig를 위와 같이 변경하면 에러가 해결 됩니다.

에러 관련 참조 문서)

https://github.com/grafana/helm-charts/issues/1111

전체 참조 문서)

Loki - Access logs the smart way

profile
BACKEND

1개의 댓글

comment-user-thumbnail
2023년 8월 15일

감사합니다

답글 달기