[Cilium] #2์ฃผ์ฐจ (4) Hubble Flow Logs๋ฅผ Grafana๋กœ ์‹œ๊ฐํ™”ํ•˜๊ธฐ (Loki + Promtail)

Hubble Exporter

hubble observe ๋ช…๋ น์€ CLI์—์„œ ์‹ค์‹œ๊ฐ„ ํ๋ฆ„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์žฅ๊ธฐ ์ €์žฅ์„ ์œ„ํ•ด์„œ๋Š” Hubble Exporter๋ฅผ ์‚ฌ์šฉํ•ด Flow Log๋ฅผ ์™ธ๋ถ€ ์‹œ์Šคํ…œ(ํŒŒ์ผ, Kafka, Loki ๋“ฑ)์œผ๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

Exporter๋Š” hubble-relay์™€ cilium-agent ๊ฐ„ gRPC ์ŠคํŠธ๋ฆผ์„ ํ™œ์šฉํ•˜์—ฌ Flow๋ฅผ ๋ฐ›์•„์˜จ๋‹ค.

 

Cilium Hubble → Promtail → Loki → Grafana๋กœ ๋งคํŠธ๋ฆญ์„ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•ด๋ณธ๋‹ค!

 

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl get cm -n kube-system cilium-config -o json | grep hubble-export
        "hubble-export-allowlist": "",
        "hubble-export-denylist": "",
        "hubble-export-fieldmask": "",
        "hubble-export-file-max-backups": "5",
        "hubble-export-file-max-size-mb": "10",
        "hubble-export-file-path": "/var/run/cilium/hubble/events.log",

 

helm upgrade

helm upgrade cilium cilium/cilium \
  -n kube-system \
  --reuse-values \
  --set hubble.enabled=true \
  --set hubble.export.dynamic.enabled=true \
  --set hubble.export.dynamic.config.content[0].name=system \
  --set hubble.export.dynamic.config.content[0].filePath=/var/run/cilium/hubble/events-system.log \
  --set hubble.export.dynamic.config.content[0].includeFilters[0].source_pod[0]='kube_system/' \
  --set hubble.export.dynamic.config.content[0].includeFilters[1].destination_pod[0]='kube_system/'

 

hubble flow ์ €์žฅ ์œ„์น˜

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl -n kube-system get configmap cilium-config -o yaml | grep -A10 hubble-export
  hubble-export-allowlist: ""
  hubble-export-denylist: ""
  hubble-export-fieldmask: ""
  hubble-export-file-max-backups: "5"
  hubble-export-file-max-size-mb: "10"
  hubble-export-file-path: /var/run/cilium/hubble/events.log # ํ—ˆ๋ธ” ํ”Œ๋กœ์šฐ ์ €์žฅ ์œ„์น˜
  hubble-flowlogs-config-path: /flowlog-config/flowlogs.yaml
  hubble-listen-address: :4244
  hubble-metrics: dns drop tcp flow port-distribution icmp httpV2:exemplars=true;labelsContext=source_ip,source_namespace,source_workload,destination_ip,destination_namespace,destination_workload,traffic_direction
  hubble-metrics-server: :9965
  hubble-metrics-server-enable-tls: "false"
  hubble-socket-path: /var/run/cilium/hubble.sock
  hubble-tls-cert-file: /var/lib/cilium/tls/hubble/server.crt
  hubble-tls-client-ca-files: /var/lib/cilium/tls/hubble/client-ca.crt
  hubble-tls-key-file: /var/lib/cilium/tls/hubble/server.key
  identity-allocation-mode: crd

 

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -n kube-system ds/cilium -c cilium-agent -- tail -f /var/run/cilium/hubble/events.log

 

ํ˜„์žฌ ์ €์žฅ๋˜๊ณ  ์žˆ๋Š” ์ด๋ฒคํŠธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Loki ์„ค์น˜

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# helm upgrade --install loki grafana/loki-stack \
  --set grafana.enabled=true \
  -n monitoring --create-namespace
Release "loki" does not exist. Installing it now.
NAME: loki
LAST DEPLOYED: Sat Jul 26 21:52:29 2025
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
NOTES:
The Loki stack has been deployed to your cluster. Loki can now be added as a datasource in Grafana.

See http://docs.grafana.org/features/datasources/loki/ for more detail.

 

promtail ์„ค์น˜

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# helm upgrade --install promtail grafana/promtail \
  -n monitoring \
  --create-namespace \
  --set "config.clients[0].url=http://loki.monitoring:3100/loki/api/v1/push" \
  --set "extraVolumes[0].name=hubble-logs" \
  --set "extraVolumes[0].hostPath.path=/var/run/cilium/hubble" \
  --set "extraVolumeMounts[0].name=hubble-logs" \
  --set "extraVolumeMounts[0].mountPath=/var/run/cilium/hubble" \
  --set "config.scrape_configs[1].job_name=hubble" \
  --set "config.scrape_configs[1].static_configs[0].targets[0]=localhost" \
  --set "config.scrape_configs[1].static_configs[0].labels.job=hubble" \
  --set "config.scrape_configs[1].static_configs[0].labels.__path__=/var/run/cilium/hubble/events*.log"
Release "promtail" does not exist. Installing it now.
NAME: promtail
LAST DEPLOYED: Sat Jul 26 23:30:38 2025
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
***********************************************************************
 Welcome to Grafana Promtail
 Chart version: 6.17.0
 Promtail version: 3.5.1
***********************************************************************

Verify the application is working by running these commands:
* kubectl --namespace monitoring port-forward daemonset/promtail 3101
* curl http://127.0.0.1:3101/metrics

 

Promtail์„ ์‚ฌ์šฉํ•ด Hubble์˜ events.log ํŒŒ์ผ์„ Loki์— ์ „์†กํ•œ๋‹ค.

 

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl -n monitoring describe pod -l app.kubernetes.io/name=promtail | grep -A5 "Mounts"
    Mounts:
      /etc/promtail from config (rw)
      /run/promtail from run (rw)
      /var/lib/docker/containers from containers (ro)
      /var/log/pods from pods (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jvx7l (ro)
--
    Mounts:
      /etc/promtail from config (rw)
      /run/promtail from run (rw)
      /var/lib/docker/containers from containers (ro)
      /var/log/pods from pods (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-4t8m5 (ro)
--
    Mounts:
      /etc/promtail from config (rw)
      /run/promtail from run (rw)
      /var/lib/docker/containers from containers (ro)
      /var/log/pods from pods (ro)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-fzgv5 (ro)
--
    Mounts:
      /etc/promtail from config (rw)
      /run/promtail from run (rw)
      /var/lib/docker/containers from containers (ro)
      /var/log/pods from pods (ro)
      /var/run/cilium/hubble from hubble-logs (rw)
--
    Mounts:
      /etc/promtail from config (rw)
      /run/promtail from run (rw)
      /var/lib/docker/containers from containers (ro)
      /var/log/pods from pods (ro)
      /var/run/cilium/hubble from hubble-logs (rw)
--
    Mounts:
      /etc/promtail from config (rw)
      /run/promtail from run (rw)
      /var/lib/docker/containers from containers (ro)
      /var/log/pods from pods (ro)
      /var/run/cilium/hubble from hubble-logs (rw)

 

Promtail์ด Kubernetes ๋…ธ๋“œ์™€ Pod ๋กœ๊ทธ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•„์š”ํ•œ ๊ฒฝ๋กœ๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€๋กœ ๋งˆ์šดํŠธ๋œ ์„ค์ •์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

helm get values promtail -n monitoring > promtail-values.yaml

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# cat promtail-values.yaml
USER-SUPPLIED VALUES:
config:
  clients:
  - url: http://loki.monitoring:3100/loki/api/v1/push
  scrape_configs:
  - job_name: kubernetes-pods
    kubernetes_sd_configs:
    - role: pod
    pipeline_stages:
    - cri: {}
    relabel_configs:
    - action: replace
      regex: ([0-9a-z-.]+?)(-[0-9a-f]{8,10})?
      source_labels:
      - __meta_kubernetes_pod_controller_name
      target_label: __tmp_controller_name
    - action: replace
      regex: ^;*([^;]+)(;.*)?$
      source_labels:
      - __meta_kubernetes_pod_label_app_kubernetes_io_name
      - __meta_kubernetes_pod_label_app
      - __tmp_controller_name
      - __meta_kubernetes_pod_name
      target_label: app
    - action: replace
      regex: ^;*([^;]+)(;.*)?$
      source_labels:
      - __meta_kubernetes_pod_label_app_kubernetes_io_instance
      - __meta_kubernetes_pod_label_instance
      target_label: instance
    - action: replace
      regex: ^;*([^;]+)(;.*)?$
      source_labels:
      - __meta_kubernetes_pod_label_app_kubernetes_io_component
      - __meta_kubernetes_pod_label_component
      target_label: component
    - action: replace
      source_labels:
      - __meta_kubernetes_pod_node_name
      target_label: node_name
    - action: replace
      source_labels:
      - __meta_kubernetes_namespace
      target_label: namespace
    - action: replace
      replacement: $1
      separator: /
      source_labels:
      - namespace
      - app
      target_label: job
    - action: replace
      source_labels:
      - __meta_kubernetes_pod_name
      target_label: pod
    - action: replace
      source_labels:
      - __meta_kubernetes_pod_container_name
      target_label: container
    - action: replace
      replacement: /var/log/pods/*$1/*.log
      separator: /
      source_labels:
      - __meta_kubernetes_pod_uid
      - __meta_kubernetes_pod_container_name
      target_label: __path__
    - action: replace
      regex: true/(.*)
      replacement: /var/log/pods/*$1/*.log
      separator: /
      source_labels:
      - __meta_kubernetes_pod_annotationpresent_kubernetes_io_config_hash
      - __meta_kubernetes_pod_annotation_kubernetes_io_config_hash
      - __meta_kubernetes_pod_container_name
      target_label: __path__
  - job_name: hubble
    static_configs:
    - labels:
        __path__: /var/run/cilium/hubble/events*.log
        job: hubble
      targets:
      - localhost
extraVolumeMounts:
- mountPath: /var/run/cilium/hubble
  name: hubble-logs
  readOnly: true
extraVolumes:
- hostPath:
    path: /var/run/cilium/hubble
    type: DirectoryOrCreate
  name: hubble-logs

 

ํ”„๋กฌํ…Œ์ผ์— ์ ์šฉ๋œ ๊ฐ’์ด๋‹ค.

๊ทผ๋ฐ ๋‹ค์†Œ ๊ถ๊ธˆํ•œ์ ์€.. ํ”„๋กฌํ…Œ์ผ ํŒŒ๋“œ ๋‚ด๋ถ€ ํ”„๋กฌํ…Œ์ผ ์•ผ๋ฏˆ ์„ค์ • ํŒŒ์ผ ๋‚ด์— ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ปจํ”ผ๊ทธ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ... (/var/run/cilium/hubble/events*.log) 

์š”๊ฑด ๋‚ด๊ฐ€ ๋ณ„๋„๋กœ ์„ ์–ธํ•ด์„œ ํŒŒ๋“œ ๋‚ด๋ถ€ ์ปจํ”ผ๊ทธ์— ๋ฎ์–ด์”Œ์›Œ์ง€์ง„ ์•Š๊ณ  ๊ด€๋ฆฌ๋˜๋Š” ๊ฒƒ์ผ๊นŒ..? 

๊ทธ๋ผํŒŒ๋‚˜ ๋…ธ๋“œ ํฌํŠธ ์„ค์ •

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# k get po -A | grep grafana
monitoring    loki-grafana-664849db4c-gwf4r      2/2     Running   0          71s

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~kubectl patch svc loki-grafana -n monitoring -p '{"spec": {"type": "NodePort"}}'}'
kubectl get svc loki-grafana -n monitoring
service/loki-grafana patched
NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
loki-grafana   NodePort   10.96.103.176   <none>        80:30723/TCP   5m50s

 

๋…ธ๋“œ ํฌํŠธ๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋กœ์ปฌ์—์„œ ์ ‘์†ํ™•์ธํ•ด๋ณธ๋‹ค.

 

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl get secret loki-grafana -n monitoring -o jsonpath="{.data.admin-password}" | base64 --decode; echo

 

ํ—ฌ๋ฆ„์œผ๋กœ ์„ค์น˜ํ•  ๊ฒฝ์šฐ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์‹œํฌ๋ฆฟ์— ์ €์žฅ๋ผ์žˆ์œผ๋ฏ€๋กœ ๊ฐ’์„ ์ถ”์ถœํ•œ๋‹ค. ์œ„์— ๋‚˜์˜จ ๊ฐ’์„ admin ์‚ฌ์šฉ์ž์˜ ํŒจ์Šค์›Œ๋“œ๋กœ ์ž…๋ ฅํ•˜์—ฌ ๋กœ๊ทธ์ธํ•œ๋‹ค.

 

๊ทธ๋ผํŒŒ๋‚˜์—์„œ Unable to connect with Loki ์—๋Ÿฌ ๋ฐœ์ƒํ•  ๋•Œ

 

 

Helm์œผ๋กœ loki-stack์„ ๋ฐฐํฌํ–ˆ์ง€๋งŒ Grafana์—์„œ Loki Data Source๋ฅผ ์ถ”๊ฐ€ ์‹œ ๊ทธ๋ผํŒŒ๋‚˜์—์„œ ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋œจ๊ณ  ๊ทธ๋ผํŒŒ๋‚˜ ํŒŒ๋“œ์— ์•„๋ž˜์™€ ๊ฐ™์ด ๋กœ๊ทธ๊ฐ€ ๋‚จ์•˜๋‹ค.

parse error at line 1, col 1: syntax error: unexpected IDENTIFIER
 

๊ทธ๋Ÿฐ๋ฐ ํŒŒ๋“œ ๋‚ด๋ถ€์—์„œ ์ง์ ‘์ ์œผ๋กœ ๋กœํ‚ค์—๋Š” ํ†ต์‹ ์ด ๋˜์—ˆ๋‹ค.

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it -n monitoring deploy/loki-grafana -c grafana -- sh
/usr/share/grafana $ curl http://loki.monitoring:3100/ready
ready
/usr/share/grafana $ curl http://loki.monitoring:3100/loki/api/v1/labels
{"status":"success","data":["app","component","container","filename","instance","job","namespace","node_name","pod","stream"]}

 

https://github.com/grafana/grafana/issues/79846

 

Grafana Loki Integration: Health check fails when Loki is up and functional · Issue #79846 · grafana/grafana

What happened? When attempting to add a new loki datasource via grafana, I get this error in the console, and a 'failed to connect' on the webUI. logger=tsdb.loki endpoint=checkHealth pluginId=loki...

github.com

 

๋น„์Šทํ•œ ์‚ฌ๋ก€๋ฅผ ๊นƒ์—์„œ ์ฐพ์•„๋ณด๋‹ˆ ์žˆ์—ˆ๋Š”๋ฐ ๋ฒ„์ „ ์ข…์†์„ฑ์ด ๋ฌธ์ œ์˜€๋‹ค..!

loki-stack ์ฐจํŠธ๊ฐ€ ์„ค์น˜ํ•œ Grafana ๋ฒ„์ „(10.x)์ด Loki 2.9.x์™€ ํ˜ธํ™˜์„ฑ์ด ์ข‹์ง€ ์•Š์•„ Health Check๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์ด๋‹ค.

 

helm upgrade --install loki grafana/loki-stack \
  -n monitoring \
  --set grafana.enabled=true \
  --set grafana.image.tag=9.2.3
  
  
 (โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl get pods -n monitoring | grep grafana
loki-grafana-c9748bdd-wmxkk   2/2     Running   0          59s

 

๊ทธ๋ž˜์„œ ๋กœํ‚ค์™€ ํ˜ธํ™˜๋˜๋Š” ๋ฒ„์ „์˜ ๊ทธ๋ผํŒŒ๋‚˜๋กœ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œํ•˜์—ฌ ๋‹ค์‹œ ์„ค์น˜ํ•ด์ฃผ๊ณ ,

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl patch svc loki-grafana -n monitoring -p '{"spec": {"type": "NodePort"}}'
service/loki-grafana patched

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl patch svc loki -n monitoring -p '{"spec": {"type": "NodePort"}}'
service/loki patched

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# kubectl get svc -n monitoring
NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
loki              NodePort    10.96.171.35   <none>        3100:30642/TCP   51m
loki-grafana      NodePort    10.96.107.66   <none>        80:32576/TCP     118s
loki-headless     ClusterIP   None           <none>        3100/TCP         51m
loki-memberlist   ClusterIP   None           <none>        7946/TCP         51m

 

๋…ธ๋“œํฌํŠธ๋„ ๋‹ค์‹œ ์„ธํŒ…ํ•œ๋‹ค.

 

์ œ๋Œ€๋กœ ์—ฐ๊ฒฐ์ด ๋˜์—ˆ๋‹ค.

 

๊ทธ๋ผํŒŒ๋‚˜์—์„œ ์ฟผ๋ฆฌํ•˜๊ธฐ

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# curl "http://192.168.10.101:30642/loki/api/v1/labels"
{"status":"success","data":["app","component","container","filename","instance","job","namespace","node_name","pod","stream"]}

(โŽˆ|HomeLab:N/A) root@k8s-ctr:~# curl "http://192.168.10.101:30642/loki/api/v1/label/job/values"
{"status":"success","data":["hubble","kube-system/cilium-agent","kube-system/cilium-operator","kube-system/coredns","kube-system/hubble-relay","kube-system/hubble-ui","kube-system/k8s-ctr","kube-system/promtail","monitoring/grafana","monitoring/loki","monitoring/promtail"]}

 

์šฐ์„  ๋กœํ‚ค์—์„œ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๋งคํŠธ๋ฆญ์„ ๋จผ์ € ์ปฌํ•ด์„œ ํŒŒ์•…ํ•ด๋ณธ๋‹ค.

 

 

{job="hubble"}๋กœ ์ฟผ๋ฆฌํ•˜๋ฉด ๊ฒฐ๊ณผ๊ฐ’์ด ์ž˜ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.