로그 집계

중앙 집중식 로그 수집, 저장, 분석 시스템 구축


중앙 집중식 로그 수집, 저장, 분석 시스템 구축

목표: 분산 시스템의 로그를 효과적으로 수집하고 분석할 수 있는 수준


📚 로그 집계 개요

아키텍처

graph TB
    subgraph "로그 수집"
        APP["📦 Application"] -->|"stdout"| AGENT["🚚 Log Agent"]
        SYS["💻 System"] -->|"syslog"| AGENT
    end
    
    subgraph "로그 처리"
        AGENT -->|"전송"| BUFFER["📦 Buffer"]
        BUFFER -->|"처리"| PARSER["🔧 Parser"]
    end
    
    subgraph "로그 저장"
        PARSER -->|"저장"| STORE["🗄️ Storage"]
    end
    
    subgraph "로그 분석"
        STORE -->|"검색"| SEARCH["🔍 Search"]
        STORE -->|"시각화"| VISUAL["📊 Visualization"]
    end

🚚 수집 에이전트

Fluentd

# fluentd.conf
<source>
  @type tail
  path /var/log/containers/*.log
  pos_file /var/log/fluentd-docker.pos
  tag kubernetes.*
  <parse>
    @type multi_format
    <pattern>
      format json
      time_key time
      time_format %Y-%m-%dT%H:%M:%S.%NZ
    </pattern>
    <pattern>
      format regexp
      expression /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
    </pattern>
  </parse>
</source>

<filter kubernetes.**>
  @type kubernetes_metadata
</filter>

<match kubernetes.**>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
  logstash_prefix k8s-logs
  <buffer>
    @type file
    path /var/log/fluentd-buffers/kubernetes.system.buffer
    flush_mode interval
    retry_type exponential_backoff
    flush_thread_count 2
    flush_interval 5s
    retry_forever false
    retry_max_interval 30
    chunk_limit_size 2M
    queue_limit_length 8
    total_limit_size 500M
  </buffer>
</match>

Filebeat

# filebeat.yml
filebeat.inputs:
- type: container
  paths:
    - /var/log/containers/*.log
  processors:
    - add_kubernetes_metadata:
        host: ${NODE_NAME}
        matchers:
        - logs_path:
            logs_path: "/var/log/containers/"

output.elasticsearch:
  hosts: ['elasticsearch:9200']
  index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"

setup.kibana:
  host: "kibana:5601"

logging.level: info

Fluent Bit

# fluent-bit.conf
[INPUT]
    Name              tail
    Tag               kube.*
    Path              /var/log/containers/*.log
    Parser            docker
    DB                /var/log/flb_kube.db
    Mem_Buf_Limit     5MB
    Skip_Long_Lines   On
    Refresh_Interval  10

[FILTER]
    Name                kubernetes
    Match               kube.*
    Kube_URL            https://kubernetes.default.svc:443
    Kube_CA_File        /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    Kube_Token_File     /var/run/secrets/kubernetes.io/serviceaccount/token

[OUTPUT]
    Name            es
    Match           *
    Host            elasticsearch
    Port            9200
    Logstash_Format On
    Logstash_Prefix k8s-logs

🗄️ 저장소

Elasticsearch

# elasticsearch.yml
cluster.name: logging-cluster
node.name: ${HOSTNAME}
path.data: /usr/share/elasticsearch/data
path.logs: /usr/share/elasticsearch/logs
network.host: 0.0.0.0
discovery.type: single-node
xpack.security.enabled: false

# 인덱스 템플릿
PUT _index_template/logs
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs-policy",
      "index.lifecycle.rollover_alias": "logs"
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "level": { "type": "keyword" },
        "message": { "type": "text" },
        "service": { "type": "keyword" },
        "host": { "type": "keyword" }
      }
    }
  }
}

Loki (경량 대안)

# loki-config.yml
auth_enabled: false

server:
  http_listen_port: 3100

ingester:
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 5m
  chunk_retain_period: 30s

schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 168h

storage_config:
  boltdb:
    directory: /tmp/loki/index
  filesystem:
    directory: /tmp/loki/chunks

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h

📊 시각화

Kibana

# kibana.yml
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://elasticsearch:9200"]

Grafana + Loki

# datasources.yml
apiVersion: 1
datasources:
  - name: Loki
    type: loki
    url: http://loki:3100
    jsonData:
      maxLines: 1000

🔍 로그 분석

검색 쿼리

# 기본 검색
kubernetes.pod.name: "my-app-*"

# 로그 레벨
level: "ERROR"

# 시간 범위
@timestamp:[now-1h TO now]

# 복합 쿼리
kubernetes.namespace.name: "production" AND level: "ERROR"

# 정규식
message: /exception|error|failed/

LogQL (Loki)

# 기본 선택
{job="kubernetes-pods"}

# 레이블 필터
{job="kubernetes-pods", namespace="production"}

# 라인 필터
{job="kubernetes-pods"} |= "error"
{job="kubernetes-pods"} != "debug"
{job="kubernetes-pods"} |~ "err.*or"

# 파서
{job="kubernetes-pods"} 
  | json 
  | level="error" 
  | line_format "{{.message}}"

# 집계
sum(rate({job="kubernetes-pods"} |= "error" [1m])) by (namespace)

📋 체크리스트

  • 로그 에이전트 선택
  • 수집 설정
  • 파서 구성
  • 저장소 설정
  • 인덱스 템플릿
  • 보관 정책
  • 시각화 도구
  • 검색 쿼리
  • 알림 설정
  • 성능 튜닝

🔗 관련 노트

  • 02-04-모니터링-스택 — 메트릭 모니터링
  • 03-07-분산추적 — 분산 추적
  • 03-06-로깅-EFK-스택 — Kubernetes 로깅

마지막 업데이트: 2026-06-01