티스토리 뷰

카테고리 없음

Alloy+Loki+Grafana

자바바라 2025. 9. 13. 13:41

Helm으로 Loki + Grafana + Alloy(=Grafana Agent) 

1) 개요(한줄)

Helm으로 loki-stack(storage), grafana, grafana-agent(DaemonSet) 설치 → Grafana에 Loki/Prometheus datasource 프로비저닝 → 대시보드(네임스페이스 기반, 로그+메트릭 연계) 적용 → 알람 룰 등록.

2) Helm 리포지터리 추가 & 공통 명령

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

3) Loki (loki-stack) 설치 권장 values (loki-values.yaml)

주요 포인트: persistence, compactor, 라벨 인덱싱(네임스페이스/ pod / container), retention 설정.

# loki-values.yaml
loki:
  persistence:
    enabled: true
    size: 50Gi
  config:
    table_manager:
      retention_deletes_enabled: true
      retention_period: 168h   # 7 days, 필요시 늘려라
    ingester:
      wal:
        enabled: true
    schema_config:
      configs:
        - from: 2020-10-24
          store: boltdb-shipper
          object_store: filesystem
          schema: v11
          index:
            prefix: index_
            period: 24h

# 필요시 클러스터가 크면 boltdb-shipper + s3 등 외부 오브젝트스토어 권장

설치:

helm install loki grafana/loki-stack -f loki-values.yaml --namespace monitoring --create-namespace

 

4) Grafana 설치 권장 values (grafana-values.yaml)

포인트: admin 비밀번호, persistence, datasource & dashboard provisioning(사이드카) 설정.

# grafana-values.yaml
persistence:
  enabled: true
  size: 10Gi

adminPassword: "StrongAdminPwd123!"

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
      - name: Loki
        type: loki
        url: http://loki.monitoring.svc.cluster.local:3100
        access: proxy
        isDefault: false
      - name: Prometheus
        type: prometheus
        url: http://prometheus.monitoring.svc.cluster.local:9090
        access: proxy
plugins: []

sidecar:
  dashboards:
    enabled: true
    label: grafana_dashboard
  datasources:
    enabled: true
    label: grafana_datasource

설치:

helm install grafana grafana/grafana -f grafana-values.yaml --namespace monitoring

참고: Dashboard 파일은 ConfigMap으로 올리고 grafana_dashboard 라벨을 달면 Grafana가 자동으로 로드함. (내가 이미 만든 대시보드 JSON은 Canvas에 있으니, 그걸 가져와 ConfigMap으로 올려도 됨)

 

5) Grafana Agent (Alloy 역할) DaemonSet 설치값 (agent-values.yaml)

목표: 모든 노드에서 로그(=journal, /var/log/*) + 메트릭(노드 메트릭) 수집해 Loki/Prometheus로 전송.

# agent-values.yaml (간단 형태)
agent:
  enabled: true
  config:
    server:
      log_level: info

    metrics:
      global:
        scrape_interval: 15s
      receivers:
        - prometheus
      processors: []
      exporters:
        - prometheus_remote_write:
            url: http://prometheus.remote-write.endpoint:9201 # optional

    logs:
      loki:
        - url: http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push

    sources:
      journal:
        forward_to: [loki]
      files:
        - paths: ["/var/log/syslog", "/var/log/messages", "/var/log/*.log"]
          labels:
            job: syslog

daemonset:
  enabled: true
  hostNetwork: false
  volumes:
    - name: varlog
      hostPath:
        path: /var/log
    - name: journal
      hostPath:
        path: /var/log/journal

설치(예: grafana/agent chart 사용):

helm install grafana-agent grafana/agent -f agent-values.yaml --namespace monitoring

운영환경에서는 Agent에 RBAC, serviceAccount, 최소권한(읽기 전용)만 부여하고, 로그 읽기 성능을 고려해 batching/bootsize 설정을 조정하자.

 

6) Grafana에 대시보드/데이터소스 자동 프로비저닝 (권장)

  • Datasource는 Helm values로 이미 등록했음.
  • Dashboard는 ConfigMap으로 JSON 올리고 grafana_dashboard: "1" 라벨 달아두면 Grafana sidecar가 자동으로 임포트.
  • 예: cm-grafana-dashboard-namespace.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-dashboard-namespace
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  k8s-namespace-monitoring.json: |-
    <여기에 dashboard JSON 내용>

(주의: 내 만든 JSON은 이미 Canvas에 있으니 그것을 복사해서 넣어라.)

7) 모범사례(벤치마크) — 최적 스택 & 설정 요약

  1. Retention: 로그는 기본 7일, 중요 시스템은 30~90일 (비용 고려)
  2. Index 라벨 관리: Loki에 인덱스할 라벨 최소화(예: namespace, pod, container, app) — 너무 많은 라벨은 비용 폭주
  3. Grafana provisioning: datasources + dashboards 자동 프로비저닝 (ConfigMap + sidecar)
  4. 알림(Alerts): Prometheus Alertmanager로 CPU/Memory/PVC(>85%)/PodReady결핍/CrashLoopBackOff 등 알림 구현
  5. 보안: Grafana + Loki 통신은 내부 네트워크에서만, 외부 접근은 OAuth/LDAP/Reverse proxy로 제어
  6. 모니터링 범위: 메트릭(Prometheus) + 로그(Loki) + 트레이스(옵션) 연계 — 문제파악 속도 3배 향상
  7. Resource Limits: Loki ingester/querier와 Grafana에 적절한 CPU/RAM 요청·제한 지정
  8. PVC Size & IOPS: Loki 인덱스/객체스토어 수준에 따라 IOPS 높은 스토리지 사용 권장

8) 최선의 대시보드(권장 셋) — 벤치마킹 요소

내가 네임스페이스 모니터링 기반으로 최적화할 때 넣는 것들(짧게):

  • Namespace Overview: CPU%, Memory%, PVC% (Gauge) + Top-5 파드 (Bar)
  • Namespace Trends: CPU/Memory 시계열(1h/24h/7d)
  • Pod Health: Ready/Running/Pending/CrashLoop(테이블 + 색상)
  • PVC Details: 사용량, inodes, growth-rate, 알림 임계치
  • Logs Quick-Find: Loki query 템플릿(예: {namespace="$namespace"} |= "error" | json)
  • Replica Health: Deployment spec vs ready (Alert 적용)
  • Node / System Logs: Node별 journal 에러 카운트(주간)
  • OS Inventory: (Exporter 필요) Pod별 OS 라벨 테이블 — 드릴다운 가능
  • SLA Dashboard: 중요 서비스 실패율, Job 실패율, 응답시간(가능하면 APM 연동)

각 패널에 Threshold + 색상(녹/노/적) 적용. Alert rule은 Prometheus Alertmanager로 분리.

 

9) Alerts(예시) — PrometheusRule snippets

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: k8s-alerts
  namespace: monitoring
spec:
  groups:
  - name: k8s.rules
    rules:
    - alert: HighNamespaceCPU
      expr: (sum(rate(container_cpu_usage_seconds_total{namespace=~".+"}[5m])) by (namespace)) / (sum(kube_pod_container_resource_limits_cpu_cores{namespace=~".+"}) by (namespace)) * 100 > 90
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "CPU > 90% in namespace {{ $labels.namespace }}"

 

10) 배포 체크리스트 (롤아웃 전)

  • PVC (Loki/Grafana) 프로비저닝 완료
  • RBAC/ServiceAccount 권한 최소화 설정
  • Grafana admin 비밀 안전하게 저장(secrets)
  • 로그 라벨 설계(어떤 라벨을 인덱싱할지 결정)
  • 대시보드 프로비저닝(파일 준비)
  • 알림 채널(Slack/Email) 구성

 

  •  helm install (loki-values.yaml, grafana-values.yaml, agent-values.yaml, dashboard ConfigMaps, PrometheusRule)
  • Grafana (네임스페이스 전체 대시보드, Pod OS 리스트, Replica Health, PVC Monitoring)
  • 배포 후 테스트 쿼리 & 알람 시뮬레이션 스크립트
# Loki + Grafana + Alloy (Grafana Agent)

아래 파일들을 그대로 저장 후 Helm/`kubectl apply -f`
간단 설명 + 설치/테스트 커맨드까지 포함.

---

## 1) loki-values.yaml
```yaml
loki:
  persistence:
    enabled: true
    size: 50Gi
  config:
    table_manager:
      retention_deletes_enabled: true
      retention_period: 168h
    ingester:
      wal:
        enabled: true
    schema_config:
      configs:
        - from: 2020-10-24
          store: boltdb-shipper
          object_store: filesystem
          schema: v11
          index:
            prefix: index_
            period: 24h
ingester:
  lifecycler:
    ring:
      kvstore:
        store: inmemory

# 필요시 외부 오브젝트스토어(S3/GCS)로 변경 권장
```

---

## 2) grafana-values.yaml
```yaml
persistence:
  enabled: true
  size: 10Gi

adminPassword: "StrongAdminPwd123!"

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
      - name: Loki
        type: loki
        url: http://loki.monitoring.svc.cluster.local:3100
        access: proxy
        isDefault: false
      - name: Prometheus
        type: prometheus
        url: http://prometheus.monitoring.svc.cluster.local:9090
        access: proxy
        isDefault: true

sidecar:
  dashboards:
    enabled: true
    label: grafana_dashboard
  datasources:
    enabled: true
    label: grafana_datasource
```

---

## 3) grafana-agent-values (agent-values.yaml)
```yaml
daemonset:
  enabled: true
  hostNetwork: false
  tolerations: []

config:
  server:
    log_level: info

  logs:
    scrape_configs:
      - job_name: system_journal
        journal:
          path: /var/log/journal
        relabel_configs: []
        labels:
          job: systemd-journal

      - job_name: syslog
        static_configs:
          - targets: [localhost]
            labels:
              job: syslog
              __path__: /var/log/syslog

    clients:
      - url: http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push

  metrics:
    scrape_configs:
      - job_name: node_exporter
        static_configs:
          - targets: ['localhost:9100']

# hostPath volumes handled in DaemonSet manifest by chart
```

---

## 4) Helm 설치 명령 (순서)
```bash
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

# 1) Loki
helm install loki grafana/loki-stack -f loki-values.yaml --namespace monitoring --create-namespace

# 2) Grafana
helm install grafana grafana/grafana -f grafana-values.yaml --namespace monitoring

# 3) Grafana Agent (Alloy 역할)
helm install grafana-agent grafana/agent -f agent-values.yaml --namespace monitoring
```

---

## 5) Dashboard ConfigMap 예제 (자동 프로비저닝용)
- 아래 ConfigMap 3개를 만들어 Grafana sidecar가 로드하게 함.
- 파일명 예: cm-dashboard-namespace.yaml, cm-dashboard-pod-os.yaml, cm-dashboard-replica-pvc.yaml

### a) cm-dashboard-namespace.yaml (Namespace 종합 대시보드)
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-dashboard-namespace
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  k8s-namespace-monitoring.json: |-
    {
      "id": null,
      "title": "K8s Namespace Monitoring - Best Practice",
      "schemaVersion": 39,
      "version": 1,
      "timezone": "browser",
      "templating": { "list": [ { "name": "namespace", "type": "query", "query": "label_values(kube_pod_info, namespace)", "datasource": "Prometheus", "multi": true, "includeAll": true } ] },
      "panels": [
        { "type": "row", "title": "Overview", "collapsed": false },
        { "title": "Namespace CPU %", "type": "gauge", "targets": [{ "expr": "(sum(rate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container!~\"POD|\"}[5m])) by (namespace)) / (sum(kube_pod_container_resource_limits_cpu_cores{namespace=\"$namespace\"}) by (namespace)) * 100", "refId": "A" }], "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{"color":"green","value":0},{"color":"orange","value":70},{"color":"red","value":80}] } } } },
        { "title": "Namespace Memory %", "type": "gauge", "targets": [{ "expr": "(sum(container_memory_usage_bytes{namespace=\"$namespace\",container!~\"POD|\"}) by (namespace)) / (sum(kube_pod_container_resource_limits_memory_bytes{namespace=\"$namespace\"}) by (namespace)) * 100", "refId": "B" }], "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{"color":"green","value":0},{"color":"orange","value":70},{"color":"red","value":80}] } } } },
        { "title": "Namespace PVC %", "type": "gauge", "targets": [{ "expr": "(sum(kubelet_volume_stats_used_bytes{namespace=\"$namespace\"}) by (namespace)) / (sum(kubelet_volume_stats_capacity_bytes{namespace=\"$namespace\"}) by (namespace)) * 100", "refId": "C" }], "fieldConfig": { "defaults": { "thresholds": { "mode": "absolute", "steps": [{"color":"green","value":0},{"color":"orange","value":70},{"color":"red","value":85}] } } } },
        { "title": "Top 5 Pods CPU in Namespace", "type": "bargauge", "targets": [{ "expr": "topk(5, sum(rate(container_cpu_usage_seconds_total{namespace=\"$namespace\",container!~\"POD|\"}[5m])) by (pod))", "refId": "D" }] }
      ]
    }
```

### b) cm-dashboard-pod-os.yaml (Pod별 OS 리스트)
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-dashboard-pod-os
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  k8s-pod-os.json: |-
    {
      "id": null,
      "title": "Pod OS Inventory",
      "schemaVersion": 38,
      "version": 1,
      "panels": [
        {
          "type": "table",
          "title": "Pod → OS",
          "gridPos": {"x": 0, "y": 0, "w": 24, "h": 12},
          "targets": [{ "expr": "k8s_container_os_issue_info", "format": "table", "instant": true }],
          "transformations": [{ "id": "labelsToFields", "options": {} }],
          "options": { "showHeader": true }
        }
      ]
    }
```

### c) cm-dashboard-replica-pvc.yaml (Replica / PVC 건강 대시보드)
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-dashboard-replica-pvc
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  k8s-replica-pvc.json: |-
    {
      "id": null,
      "title": "Replica & PVC Health",
      "schemaVersion": 39,
      "version": 1,
      "panels": [
        { "title": "Deployment Spec vs Ready", "type": "timeseries", "targets": [ { "expr": "sum(kube_deployment_spec_replicas{namespace=~\"$namespace\"}) by (deployment,namespace)", "refId": "A"}, { "expr": "sum(kube_deployment_status_replicas_ready{namespace=~\"$namespace\"}) by (deployment,namespace)", "refId": "B" } ] },
        { "title": "PVC Usage List", "type": "table", "targets": [ { "expr": "kubelet_volume_stats_used_bytes", "format": "table", "instant": true } ], "transformations": [{ "id": "labelsToFields", "options": {} }] }
      ]
    }
```

---

## 6) Prometheus Alert Rule 예시 (PrometheusRule CRD)
```yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: k8s-health-rules
  namespace: monitoring
spec:
  groups:
  - name: k8s.rules
    rules:
    - alert: NamespaceHighCPU
      expr: |
        (sum(rate(container_cpu_usage_seconds_total{container!~"POD|"}[5m])) by (namespace))
        /
        (sum(kube_pod_container_resource_limits_cpu_cores) by (namespace)) * 100 > 90
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "CPU usage >90% in namespace {{ $labels.namespace }}"

    - alert: PVCUsageHigh
      expr: (sum(kubelet_volume_stats_used_bytes) by (namespace)) / (sum(kubelet_volume_stats_capacity_bytes) by (namespace)) * 100 > 85
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "PVC usage >85% in namespace {{ $labels.namespace }}"
```

---

## 7) 배포/적용 명령 모음
```bash
# 1) values 파일로 Helm 설치
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install loki grafana/loki-stack -f loki-values.yaml --namespace monitoring --create-namespace
helm install grafana grafana/grafana -f grafana-values.yaml --namespace monitoring
helm install grafana-agent grafana/agent -f agent-values.yaml --namespace monitoring

# 2) Dashboard ConfigMap 적용 (sidecar가 자동 임포트)
kubectl apply -f cm-dashboard-namespace.yaml
kubectl apply -f cm-dashboard-pod-os.yaml
kubectl apply -f cm-dashboard-replica-pvc.yaml

# 3) Alert Rule 적용 (PrometheusOperator 필요)
kubectl apply -f prometheusrule.yaml
```

---

## 8) 테스트 & 검증 스크립트 (C)
### a) Loki 수집 확인
```bash
# Grafana Agent가 로그를 보냈는지 확인
kubectl logs -n monitoring -l app.kubernetes.io/name=grafana-agent --tail 200
# Loki가 수신했는지 확인 (샘플 쿼리)
kubectl exec -n monitoring svc/loki -c loki -- curl -s "http://localhost:3100/loki/api/v1/query?query={job=\"systemd-journal\"}" | jq .
```

### b) Prometheus 메트릭 수집 확인
```bash
# prometheus가 있다면
kubectl port-forward -n monitoring svc/prometheus 9090:9090 &
# 브라우저에서 http://localhost:9090 에 접속 후 PromQL 입력
# 예: sum(rate(container_cpu_usage_seconds_total[5m])) by (namespace)
```

### c) Grafana 대시보드 확인
- Grafana 서비스 접속 (port-forward 또는 LoadBalancer)
  ```bash
  kubectl port-forward -n monitoring svc/grafana 3000:80 &
  # 브라우저에서 http://localhost:3000 (admin / StrongAdminPwd123!)
  ```
- 좌측 메뉴 → Dashboards → Manage 에서 자동로드된 대시보드 확인

### d) 알람 시뮬레이션
- CPU alert 테스트: 임의로 부하 생성
  ```bash
  kubectl run -n default loadgen --image=busybox --restart=Never -- sh -c "while true; do dd if=/dev/zero of=/dev/null bs=1M count=1024; sleep 0.1; done"
  ```
- Prometheus에 메트릭 반영 후 Alertmanager에서 경보 확인

---

## 9) 모범사례 팁 (짧게)
- Loki 라벨은 최소화: namespace,pod,container,app
- Logs retention은 비용과 규정 고려해서 세팅
- Grafana dashboard는 provisioning으로 배포(버전관리)
- Alert은 for 조건(예: 5m 이상)으로 일시적 스파이크 방지
- Agent(=Alloy)의 리소스 limit 설정 필수

---

 

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