본문 바로가기
k3s

Grafana + Prometheus + Loki로 k3s 모니터링 구축하기

by 밍슈_ 2026. 4. 28.

나는 항상 서버 모니터링 시스템을 구축하는것에 대한 생각에 잡혀 있었다. 그래서 이번에는 클라우드 서버에 하는것이 아닌 홈서버를 구축해서 마음껏 서버 설정을 할 수 있도록 했다. 쿠버네티스를 사용해보고 모니터링도 해보고 로드밸런싱도 해보며 공부도 하고 공부한 것을 적용 시키는 것을 목적으로 서버 설정을 하고 있다.

이 글은k3s 클러스터와 서버 전체를 모니터링하는 시스템을 구축한다. Prometheus로 지표를 수집하고, Loki로 로그를 수집하며, Grafana로 시각화 한다.


모니터링 스택 구성

Prometheus     → 숫자/지표 수집 (CPU, 메모리, 요청수 등)
Loki           → 로그 수집 (Pod 로그, 서버 로그)
Grafana        → 시각화 대시보드
Promtail       → 로그 수집 에이전트 (Pod → Loki)
node-exporter  → 서버 리소스 수집
kube-state-metrics → k3s Pod 상태 수집

왜 이 조합인가?

Prometheus + Loki + Grafana = PLG 스택
→ 모두 Grafana Labs에서 만든 도구
→ 서로 호환성 최고 ✅
→ 모두 무료 오픈소스 ✅
→ k3s 환경에 최적화 ✅

ELK 스택(Elasticsearch + Logstash + Kibana)과 비교하면:

  • ELK: 강력하지만 무겁고 리소스 많이 사용
  • PLG: 가볍고 홈 서버에 적합

1단계: 네임스페이스 생성

네임스페이스가 없으면 상당히 불편하다. 약간 프로그램들이 모여있을만한 펜션? 방을 하나 만들어준다고 생각하자.

kubectl create namespace monitoring

2단계: Helm 레포지토리 추가

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

Helm을 사용하는 이유

Helm은 쿠버네티스용 패키지 매니저예요. apt install 처럼 복잡한 쿠버네티스 앱을 명령어 몇 줄로 설치할 수 있다.

Nginx Ingress Controller를 설치할 때 Traefik의 hostPort 설정 문제를 해결하려다 Helm을 처음 사용했고, 이후 모니터링 스택 설치에도 활용했다.


3단계: Prometheus 설치

helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
  -n monitoring \
  --set grafana.enabled=false \
  --set alertmanager.enabled=false

grafana.enabled=false 인 이유

kube-prometheus-stack에 Grafana가 포함되어 있지만 별도로 설치하는 게 더 유연하게 관리할 수 있어서 비활성화했다.

설치되는 컴포넌트:

prometheus-operator     → Prometheus 관리
prometheus             → 지표 수집/저장
kube-state-metrics     → k3s Pod 상태 수집
node-exporter          → 서버 리소스 수집

4단계: Loki 설치

처음 시도 (실패)

# deprecated 버전 → Grafana와 호환성 문제
helm upgrade --install loki grafana/loki-stack ...

오류:

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

loki-stack은 더 이상 업데이트되지 않는 구버전이라 최신 Grafana와 호환이 되지 않았다.

해결: 최신 Loki 설치

cat <<EOF > /tmp/loki-values.yaml
deploymentMode: SingleBinary
loki:
  auth_enabled: false
  commonConfig:
    replication_factor: 1
  storage:
    type: filesystem
singleBinary:
  replicas: 1
read:
  replicas: 0
write:
  replicas: 0
backend:
  replicas: 0
EOF

helm upgrade --install loki grafana/loki \
  -n monitoring \
  -f /tmp/loki-values.yaml \
  --set loki.useTestSchema=true

SingleBinary 모드를 선택한 이유

Loki는 여러 배포 모드가 있어요:

  • SimpleScalable: 여러 노드 클러스터용
  • SingleBinary: 단일 노드용 ✅ (우리 환경에 적합)

단일 노드 홈 서버라 SingleBinary가 가장 적합.


5단계: Grafana 설치

helm upgrade --install grafana grafana/grafana \
  -n monitoring \
  --set adminPassword='비밀번호' \
  --set persistence.enabled=true \
  --set persistence.size=2Gi

persistence.enabled=true 인 이유

이 옵션을 켜면 Grafana 설정, 대시보드, 사용자 정보가 PVC에 영구 저장된다. 끄면 Pod 재시작 시 모든 설정이 초기화된다.


6단계: Promtail 설치

Promtail은 각 Pod의 로그를 수집해서 Loki로 전송하는 에이전트예요.

처음 시도 (실패)

helm upgrade --install promtail grafana/promtail \
  -n monitoring \
  --set config.lokiAddress=http://loki-gateway.monitoring.svc.cluster.local:80/loki/api/v1/push

설치는 됐지만 로그가 Loki에 들어오지 않았다.

문제 원인 발견

kubectl exec -n monitoring daemonset/promtail -- cat /etc/promtail/promtail.yaml | grep url
# url: http://loki-gateway/loki/api/v1/push  ← namespace 누락!

--set 옵션이 제대로 적용되지 않았어요.

해결: values 파일로 설정

cat <<EOF > /tmp/promtail-values.yaml
config:
  clients:
    - url: http://loki-gateway.monitoring.svc.cluster.local:80/loki/api/v1/push
EOF

helm upgrade promtail grafana/promtail \
  -n monitoring \
  -f /tmp/promtail-values.yaml

Pod 재시작으로 로그 확인

Promtail은 이미 읽은 로그 위치(Offset)를 기억해서 기존 로그는 전송하지 않았다. Pod을 재시작하면 새 로그가 생성되어 확인할 수 있다.

kubectl rollout restart deployment/nestjs-dev -n backend-dev

7단계: Cloudflare Tunnel에 Grafana 추가

sudo nano /etc/cloudflared/config.yml
ingress:
  - hostname: dev.도메인.cloud
    service: http://10.43.24.216:3000
  - hostname: api.도메인.cloud
    service: http://10.43.49.113:3000
  - hostname: grafana.도메인.cloud
    service: http://10.43.188.85:80  ← Grafana ClusterIP
  - service: http_status:404
cloudflared tunnel route dns 도메인-tunnel grafana.도메인.cloud
sudo systemctl restart cloudflared

8단계: Grafana 데이터소스 설정

Prometheus 연결

Connections → Data sources → Add → Prometheus

URL: http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090

Loki 연결

처음에 http://loki.monitoring.svc.cluster.local:3100 으로 시도했지만 실패

Unable to connect with Loki

해결: loki-gateway를 통해 연결

URL: http://loki-gateway.monitoring.svc.cluster.local:80

loki-gateway는 Loki 앞단의 nginx 프록시로 실제 연결 포인트이다.


9단계: 대시보드 임포트

Grafana → Dashboards → Import

ID이름데이터소스

15661 Kubernetes 클러스터 Prometheus
1860 Node Exporter (서버 리소스) Prometheus
13639 Loki 로그 대시보드 Loki

10단계: 서버 PC 로그 수집

k3s 외부 서버 자체 로그를 수집하려면 Promtail을 서버에 직접 설치해야 한다. 생각해보면 맞는말

curl -LO https://github.com/grafana/loki/releases/download/v3.5.1/promtail-linux-amd64.zip
unzip promtail-linux-amd64.zip
sudo mv promtail-linux-amd64 /usr/local/bin/promtail
sudo chmod +x /usr/local/bin/promtail

설정 파일:

# /etc/promtail-host/config.yml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions-host.yaml

clients:
  - url: http://10.43.34.107:80/loki/api/v1/push  # loki-gateway ClusterIP

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

  - job_name: auth
    static_configs:
      - targets: [localhost]
        labels:
          job: auth
          host: servername
          __path__: /var/log/auth.log

  - job_name: journald
    journal:
      max_age: 12h
      labels:
        job: journald
        host: servername
    relabel_configs:
      - source_labels: ['__journal__systemd_unit']
        target_label: unit

svc.cluster.local DNS를 못 쓰는 이유

서버 호스트는 k3s 클러스터 외부이므로 svc.cluster.local DNS가 동작하지 않는다. 대신 loki-gateway의 ClusterIP를 직접 사용해야 한다.

kubectl get svc -n monitoring | grep loki-gateway
# 10.43.34.107

systemd 서비스 등록:

sudo systemctl enable promtail-host
sudo systemctl start promtail-host

Grafana에서 로그 조회

Explore → Loki

{job="syslog"}              → 서버 시스템 로그
{job="auth"}                → SSH 접속 로그
{job="journald"}            → systemd 서비스 로그
{namespace="backend-dev"}   → Nest.js 개발 서버 로그
{namespace="database"}      → PostgreSQL 로그

수집 중인 전체 로그 목록

kubectl exec -n monitoring deployment/grafana -- wget -qO- \
  'http://loki-gateway.monitoring.svc.cluster.local:80/loki/api/v1/label/job/values'

출력:

{
  "data": [
    "auth",
    "backend-dev/nestjs-dev",
    "cert-manager/cert-manager",
    "database/postgres-dev",
    "database/postgres-prod",
    "database/postgres-backup",
    "journald",
    "kube-system/coredns",
    "monitoring/grafana",
    "monitoring/prometheus",
    "syslog"
  ]
}

그라파나 대시보드로 본 쿠버네티스 상태

메뉴가 직관적이라서 한번씩 들어가서 본다면 어떤 기능들을 위한 페이지인지 알 수 있다.

'k3s' 카테고리의 다른 글

cert-manager로 SSL 인증서 자동 발급하기  (0) 2026.04.27
k3s에 PostgreSQL 배포하기  (0) 2026.04.25
k3s 설치 - 경량 쿠버네티스 시작하기  (0) 2026.04.25