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