Promtail의 지원 종료(2026년 3월 예정)로 Grafana의 새 에이전트 Alloy로 전환해야 합니다. Alloy는 로그, 메트릭, 트레이스를 한곳에서 수집하며, 컴포넌트 기반의 유연한 파이프라인을 제공합니다. 이 글에서는 Helm Chart를 사용해 쿠버네티스에 Alloy를 배포하고, Loki로 로그를 전송하는 방법을 실습 기반으로 설명합니다.
Promtail과 Alloy의 차이점
- Promtail: Loki 전용 로그 수집기, 2026년 3월 지원 종료.
- Alloy: 로그, 메트릭, 트레이스 통합 수집 가능. 컴포넌트 기반 아키텍처로 확장성과 유연성 제공.
- 주요 장점: 단일 에이전트로 다양한 관측 데이터 처리, 성능 최적화, 커뮤니티 중심 개발.
쿠버네티스에 Alloy 배포하기 (Helm Chart)
1. Helm 저장소 추가
Grafana Helm Chart 저장소를 추가하고 최신화합니다.
bash
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
2. Alloy Helm Chart 설치
monitoring 네임스페이스에 Alloy를 설치합니다. ConfigMap으로 Alloy 설정 파일을 전달합니다.
bash
helm install alloy grafana/alloy \
--namespace monitoring --create-namespace \
-f values.yaml
Alloy 설정의 컴포넌트 연결과 Loki 전송
Alloy 설정의 컴포넌트 연결과 Loki 전송
그림 관계를 글로 읽기
- local.file_match node_logs가 /var/log/syslog 대상을 loki.source.file node_logs의 targets로 넘긴다.
- loki.source.file이 읽은 노드 로그를 loki.write default로 forward_to 한다.
- discovery.kubernetes pod가 찾은 대상을 discovery.relabel pod_logs가 받는다.
- relabel 결과(output)가 loki.source.kubernetes pod_logs의 targets가 된다.
- Pod 로그는 loki.process pod_logs로 forward_to 된다.
- loki.process pod_logs가 cluster 정적 라벨을 붙여 loki.write로 보낸다.
- loki.source.kubernetes_events cluster_events가 클러스터 이벤트를 loki.process cluster_events로 보낸다.
- loki.process cluster_events가 라벨을 붙여 loki.write로 보낸다.
- loki.write default가 endpoint url(http://loki:3100/loki/api/v1/push)로 전송한다.
3. values.yaml 설정 예시
values.yaml에 아래 Alloy 설정 파일을 ConfigMap으로 마운트합니다.
yaml
configMap:
enabled: true
create: true
name: alloy-config
file: alloy.yaml
config:
alloy.yaml: |
logging {
level = "info"
format = "logfmt"
}
loki.write "default" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
}
// local.file_match discovers files on the local filesystem using glob patterns
local.file_match "node_logs" {
path_targets = [{
__path__ = "/var/log/syslog",
job = "node/syslog",
node_name = sys.env("HOSTNAME"),
cluster = "your-cluster-name",
}]
}
// loki.source.file reads log entries from files
loki.source.file "node_logs" {
targets = local.file_match.node_logs.targets
forward_to = [loki.write.default.receiver]
}
// discovery.kubernetes finds scrape targets from Kubernetes resources
discovery.kubernetes "pod" {
role = "pod"
}
// discovery.relabel rewrites the label set of input targets
discovery.relabel "pod_logs" {
targets = discovery.kubernetes.pod.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
action = "replace"
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
action = "replace"
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
action = "replace"
target_label = "container"
}
rule {
source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
action = "replace"
target_label = "app"
}
rule {
source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"]
action = "replace"
target_label = "job"
separator = "/"
replacement = "$1"
}
rule {
source_labels = ["__meta_kubernetes_pod_uid", "__meta_kubernetes_pod_container_name"]
action = "replace"
target_label = "__path__"
separator = "/"
replacement = "/var/log/pods/*$1/*.log"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_id"]
action = "replace"
target_label = "container_runtime"
regex = "^(\\S+):\\/\\/.+$"
replacement = "$1"
}
}
// loki.source.kubernetes tails logs from Kubernetes containers
loki.source.kubernetes "pod_logs" {
targets = discovery.relabel.pod_logs.output
forward_to = [loki.process.pod_logs.receiver]
}
// loki.process applies processing stages to logs
loki.process "pod_logs" {
stage.static_labels {
values = {
cluster = "your-cluster-name",
}
}
forward_to = [loki.write.default.receiver]
}
// loki.source.kubernetes_events tails Kubernetes events
loki.source.kubernetes_events "cluster_events" {
job_name = "integrations/kubernetes/eventhandler"
log_format = "logfmt"
forward_to = [loki.process.cluster_events.receiver]
}
// loki.process for cluster events
loki.process "cluster_events" {
forward_to = [loki.write.default.receiver]
stage.static_labels {
values = {
cluster = "your-cluster-name",
}
}
stage.labels {
values = {
kubernetes_cluster_events = "job",
}
}
}
설정 적용 가이드:
your-cluster-name을 실제 클러스터 이름(예:production,us-east-1)으로 교체하세요.- Loki URL(
http://loki:3100/loki/api/v1/push)이 환경에 맞는지 확인하세요.
Alloy Config 설명
logging: Alloy의 로깅 수준과 형식을 설정.loki.write: Loki로 로그를 전송.local.file_match&loki.source.file:/var/log/syslog에서 노드 로그를 수집.discovery.kubernetes&discovery.relabel: Pod 메타데이터를 기반으로 로그 수집 대상과 라벨을 설정.loki.source.kubernetes: Pod 로그를 수집.loki.source.kubernetes_events: 클러스터 이벤트를 수집.loki.process: 로그에 라벨을 추가하여 Loki로 전송.
실습 및 디버깅
-
배포 확인:
bashkubectl -n monitoring get pods -l app.kubernetes.io/name=alloyAlloy Pod가
Running상태인지 확인하세요. -
로그 점검:
bashkubectl -n monitoring logs -l app.kubernetes.io/name=alloy오류가 있다면, config 문법이나 Loki 연결 문제를 확인하세요.
-
Loki 로그 확인:
Grafana Explore에서{cluster="your-cluster-name"}쿼리로 로그가 수집되는지 확인하세요.

마무리
Alloy는 Promtail을 대체하며, 노드 로그, Pod 로그, 클러스터 이벤트를 한곳에서 수집할 수 있습니다. Helm Chart와 이 글의 config를 활용하면 빠르게 설정할 수 있습니다. 테스트 환경에서 실습한 뒤 Grafana 대시보드로 로그를 시각화해 보세요.