AI

[GitAIOps로 인프라 구성하기] 4. 모니터링 구성하기

Hanhorang31 2026. 7. 12. 23:16
 

앞으로 4주간 온라인 모각코를 통해 스터디한 내용을 업로드할 예정입니다.

모각코란 모여서 각자 코딩의 준말로, CloudNet@ 가시다님과 함께 책 하나를 돌파하는 스터디입니다.

이번 모각코는 책, AI 시대에 개발자가 알아야 할 인프라 구성 배포 with 클로드 코드 를 기반으로 진행합니다.

 

 

모니터링 구성 이유

구성한 서비스가 잘 돌아가고 있는 지 확인이 필요합니다.

이번 장에서는 모니터링 시스템(메트릭&로깅)을 구축하고, 알람을 구성하겠습니다.

트레이스는 뒤 8장에서 구현 예정입니다.

 

 

 

구성

  • 4.2 메트릭 모니터링 (Prometheus + Grafana)
  • 4.3 로그 수집 (Loki + Fluent Bit)
  • 4.4 알림 설정

 

 

 

클러스터 내 모니터링 도구 확인

 클러스터에서 뭐가 돌아가고 있는지 어떻게 알지?
 kube-state-metris이랑 node-exporter 차이가 뭐야?

 

 

 

프로메테우스 + 그라파나 설치

저자의 지침에 따라 프로메테우스와 그라파나를 설치합니다.

그라파나에는 애플리케이션(notifliex) 대시보드를 구성합니다.

Prometheus랑 Grafana 설치해줘 3장과 마찬가지로 어떤 지침을 통해서 진행하는지, 어떤 명령어를 실행했는지 표로 정리해서 알려줘

(참고) 지침

# 4.2 메트릭: Prometheus + Grafana

## 사전 조건
- ArgoCD 설치 완료 (ch3.2)
- `shared/resource-budget.md` 확인: kube-prometheus-stack은 **Prometheus 100m + Grafana 50m + Alertmanager 25m + operator 25m + kube-state-metrics 10m = ~210m** CPU를 추가한다.

> ⚠️ **ch6 대비 리소스 주의**: 여기서 설치하는 관측 가능성 스택은 ch6에서 CSI DaemonSet(240m)이 추가될 때 CPU 부족의 원인이 된다. ch6 진입 전에 Prometheus/Grafana/Alertmanager의 CPU requests를 5m으로 축소해야 하므로, 여기서 설정하는 값은 임시적이라는 점을 인지한다.

## 실행 지침

### 단계 1: kube-prometheus-stack 설치

`kube-prometheus-stack`은 Prometheus + Grafana + Alertmanager + Prometheus Operator + kube-state-metrics + node-exporter를 한 번에 묶어 설치하는 Helm 차트다. 50개가 넘는 리소스(Deployment, StatefulSet, Service, ConfigMap, CRD)를 직접 작성하지 않아도 되고, 차트 인자(`-f helm-values/...`)만으로 일관된 튜닝이 가능하다. 컴포넌트 간 ServiceMonitor·PrometheusRule 연결도 차트가 알아서 묶는다.

```bash
kubectl create namespace monitoring
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install kube-prometheus prometheus-community/kube-prometheus-stack \
  -n monitoring -f helm-values/kube-prometheus.yaml
```

`helm-values/kube-prometheus.yaml` 파일을 생성한다. e2-small 노드에 맞게 리소스를 조정:
- Prometheus: requests 100m/256Mi
- Grafana: requests 50m/128Mi
- Alertmanager: requests 25m/64Mi

### 단계 2: Grafana UI 접속

```bash
kubectl port-forward svc/kube-prometheus-grafana -n monitoring 3000:80
```

브라우저에서 `http://localhost:3000` 접속 (ID: admin, PW: `kubectl get secret`으로 확인).

### 단계 3: Notiflex 대시보드 생성

Grafana에 Notiflex 전용 대시보드를 ConfigMap으로 생성한다:
- Pod CPU/Memory 사용량
- HTTP 요청 수
- Pod 재시작 횟수

## 트러블슈팅

### Pod Pending (CPU 부족)
kube-prometheus-stack은 5개 이상의 컴포넌트를 배포한다. e2-medium 2노드에서 ArgoCD(~500m)와 함께 설치하면 CPU requests가 빠듯해진다.
→ `helm-values/kube-prometheus.yaml`에서 requests를 축소한다.
→ 그래도 Pending이면 `kubectl describe pod  -n monitoring`으로 원인 확인.

### Prometheus StatefulSet 리소스 변경이 반영 안 됨
Prometheus CR의 `spec.resources`를 변경해도 기존 StatefulSet이 자동으로 업데이트되지 않을 수 있다.
→ StatefulSet을 삭제하면 Prometheus Operator가 새 스펙으로 재생성한다:
```bash
kubectl delete statefulset prometheus-kube-prometheus-prometheus -n monitoring
```

### ch6 진입 전 CPU 축소 방법
ch6에서 CSI DaemonSet이 240m CPU를 차지한다. 사전에 관측 가능성 스택을 축소한다:
```bash
# Prometheus CR 직접 패치
kubectl patch prometheus kube-prometheus-prometheus -n monitoring \
  --type merge -p '{"spec":{"resources":{"requests":{"cpu":"5m"}}}}'
# 반영 안 되면 StatefulSet 삭제 → operator가 재생성
kubectl delete statefulset prometheus-kube-prometheus-prometheus -n monitoring

# Grafana — JSON patch 사용 (multi-container이므로 인덱스로 지정)
# 컨테이너 순서 확인: kubectl get deploy kube-prometheus-grafana -n monitoring -o jsonpath='{.spec.template.spec.containers[*].name}'
# 보통 0: grafana-sc-dashboard, 1: grafana-sc-datasources, 2: grafana
kubectl patch deployment kube-prometheus-grafana -n monitoring \
  --type=json -p='[{"op":"replace","path":"/spec/template/spec/containers/2/resources/requests/cpu","value":"5m"}]'

# Operator — resources 섹션이 없을 수 있으므로 add op 사용
kubectl patch deployment kube-prometheus-kube-prom-operator -n monitoring \
  --type=json -p='[{"op":"add","path":"/spec/template/spec/containers/0/resources","value":{"requests":{"cpu":"5m"}}}]'

# Alertmanager
kubectl patch alertmanager kube-prometheus-alertmanager -n monitoring \
  --type merge -p '{"spec":{"resources":{"requests":{"cpu":"5m"}}}}'
```

> ⚠️ **`--type merge` 실패**: Grafana Deployment처럼 multi-container Pod에 strategic merge patch를 쓰면 `"spec.template.spec.containers[0].image: Required value"` 에러가 발생한다. 컨테이너를 특정하려면 image 필드도 포함해야 하기 때문. **`--type=json`으로 컨테이너 인덱스를 직접 지정**하면 이 문제를 피할 수 있다.

> ⚠️ **resources 섹션 미존재**: operator 등 일부 Deployment는 resources 섹션 자체가 없다. 이 경우 `"op":"replace"`는 실패하고 `"op":"add"`로 경로를 생성해야 한다.

## 💬 질문해보기

> "Prometheus 말고 메트릭 수집 도구는 뭐가 있어? Datadog, New Relic 같은 SaaS와 비교하면?"

 

 

 

애플리케이션 HTTP 요청 수 누락 확인

계측을 위해 애플리케이션 코드 어디를 수정했는지 알려주고, 프로메테우스에서 지표 수집을 위해 무엇을 했는 지, 그라파나 대시보드에는 어떻게 구성했는 지 알려줘

 

  • 이름 추가 이유 ?
  • 이게 없으면 serviceMonitor가 무시함?

→ 기가막히게 추가되었다.

 

 

Loki + Fluent Bit 설치

로깅 시스템을 구성하겠습니다.

Loki랑 Fluent Bit 설치해줘

(참고) 지침

# 4.3 로깅: Loki + Fluent Bit

## 사전 조건
- Prometheus + Grafana 설치 완료 (ch4.2) — Grafana에서 Loki 데이터소스를 추가하여 로그를 조회한다.

## 실행 지침

### 단계 1: Loki 설치

```bash
helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki -n monitoring -f helm-values/loki.yaml
```

`helm-values/loki.yaml` — SingleBinary 모드, 최소 리소스:
- deploymentMode: SingleBinary
- `loki.useTestSchema: true` (schema_config 자동 생성, 없으면 설치 실패)
- `loki.storage.type: filesystem` + `loki.storage.bucketNames` (최신 chart에서 필수, 없으면 "Please define loki.storage.bucketNames.chunks" 에러)
- 리소스: requests 10m/128Mi
- `grafana.datasource.isDefault: false` (기본값 true. Prometheus가 이미 default이므로 두면 Grafana 재시작 시 "multiple datasources marked as default" 에러. ch8.2 Tempo 추가 시점에 표면화되므로 이 단계에서 선제적으로 false 고정)

### 단계 2: Fluent Bit 설치

```bash
helm install fluent-bit grafana/fluent-bit -n monitoring -f helm-values/fluent-bit.yaml
```

Loki로 로그를 전송하도록 output 설정.

### 단계 3: Grafana에서 로그 조회

Grafana → Explore → Loki 데이터소스 선택 → `{namespace="notiflex"}` 쿼리.

## 트러블슈팅

### "You must provide a schema_config for Loki"
Loki helm chart 최신 버전은 `schema_config` 명시를 요구한다. `useTestSchema: true`가 빠지면 Loki Pod이 기동 즉시 이 에러 메시지로 CrashLoopBackOff에 빠진다. `helm-values/loki.yaml`에 다음 옵션을 추가한다:
```yaml
loki:
  useTestSchema: true
```
이 옵션은 기본 schema_config를 자동 생성한다. 단계 1의 helm-values 작성 단계에서 누락하지 않도록 주의한다.

### Fluent Bit 차트 deprecated 경고
`helm install fluent-bit grafana/fluent-bit` 실행 시 "WARNING: This chart is deprecated" 경고가 출력된다.
→ 현재는 정상 동작하므로 무시해도 된다. 공식 대안은 https://github.com/fluent/helm-charts 의 `fluent/fluent-bit` 차트이다.

## 💬 질문해보기

> "Loki 말고 로그 수집 시스템은 뭐가 있어? ELK(Elasticsearch)와 비교하면?"
  • deploymentMode: SingleBinary → 단일 파드에서 실행되는 모드
  • loki.useTestSchema: true → 테스트 스키마 구성

(참고) Loki Value

deploymentMode: SingleBinary

loki:
  useTestSchema: true
  storage:
    type: filesystem
    bucketNames:
      chunks: chunks
      ruler: ruler
      admin: admin
  auth_enabled: false
  # 기본값 3 — SingleBinary 1개(replicas:1)로는 "at least 2 live replicas required" 에러가 남
  commonConfig:
    replication_factor: 1

singleBinary:
  replicas: 1
  resources:
    requests:
      cpu: 10m
      memory: 128Mi

read:
  replicas: 0
write:
  replicas: 0
backend:
  replicas: 0

chunksCache:
  enabled: false
resultsCache:
  enabled: false

gateway:
  enabled: false

grafana:
  datasource:
    isDefault: false

로그 스크랩 확인

fluentbit가 어느 로그를 가져가는 지 어떻게 알아?

(참고) fleunt bit Value

# 이 파일은 [Output](Loki 연결)과 리소스만 오버라이드한다.
# [INPUT](어느 로그 파일을 읽을지)과 [FILTER](kubernetes 메타데이터 추가)는
# 여기서 지정하지 않았으므로 차트 기본값이 그대로 적용된다:
#   [INPUT]  Path /var/log/containers/*.log   (모든 컨테이너 로그, 필터링 없음)
#   [FILTER] Name kubernetes                  (namespace/pod/labels 메타데이터 부착)
# 실제 렌더링된 전체 설정은 클러스터의 ConfigMap에서 확인 가능:
#   kubectl get configmap fluent-bit-fluent-bit-loki -n monitoring -o jsonpath='{.data.fluent-bit\.conf}'

loki:
  # 기본값은 "${RELEASE}-loki" (릴리즈명이 fluent-bit이라 "fluent-bit-loki"가 됨 — 우리 Loki 서비스명과 다름)
  # 이 helm-values 없이는 fluent-bit이 존재하지 않는 서비스로 로그를 보내려다 실패한다
  serviceName: loki
  servicePort: 3100
  # 기본값 /api/prom/push는 구버전 push API(레거시). 최신 Loki 표준 경로로 명시
  servicePath: /loki/api/v1/push

resources:
  requests:
    cpu: 25m
    memory: 32Mi

 

(트러블슈팅) Loki 데이터소스 조회 불가 및 로깅 확인 불가

처음 필자의 그라파나에서 데이터소스와 로깅 확인이 불가하여 트러블 슈팅을 시켰습니다.

→ 문제 원인 분석 및 해결까지 잘 됩니다.

 

 

알람 구성하기

문제가 생기면 자동으로 알람 구성할 수 있나?

→ GItOps 목적으로 YAML로 관리할 수 있는 PromethuRule + AlertManager로 알람 구성을 권고함( 저자 지침)

(참고) 지침

# 4.4 알림 설정

## 사전 조건
- Prometheus + Grafana 설치 완료 (ch4.2) — PrometheusRule CRD가 존재해야 한다.

## 실행 지침

### 단계 1: PrometheusRule 생성

`k8s/monitoring/pod-restart-alert.yaml`을 생성한다:

```yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: pod-restart-alert
  namespace: monitoring
  labels:
    release: kube-prometheus
spec:
  groups:
    - name: notiflex-alerts
      rules:
        - alert: PodRestartTooMany
          expr: increase(kube_pod_container_status_restarts_total{namespace="notiflex"}[5m]) > 2
          for: 1m
          labels:
            severity: warning
          annotations:
            summary: "Pod {{ $labels.pod }} 재시작 과다"
            description: "5분 내 {{ $value }}회 재시작"
```

> ⚠️ `labels.release: kube-prometheus`가 없으면 Prometheus가 이 규칙을 로드하지 않는다. Helm release 이름과 일치해야 한다.

### 단계 2: 알림 테스트

Pod을 강제 재시작하여 알림이 발생하는지 확인:
```bash
kubectl delete pod -l app=notiflex-api -n notiflex
```

### 단계 3: 커밋

변경 사항을 커밋하고 푸시한다.

## 💬 질문해보기

> "PrometheusRule로 알림을 설정하는 것과 Grafana Alert를 쓰는 것은 뭐가 달라? 알림 채널은 어떤 걸 쓸 수 있어? Slack, PagerDuty 연동은 어떻게 해?"

PromethrusRule + AlertManager 는 따로 설치해야 하나?  어떻게 설치한거고 알람을 구성한거야?

→ 이미 존재했고 알람 설정은 CRD를 통해 구성 가능함

# k8s/monitoring/pod-restart-alert.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule       # ← CRD 타입
metadata:
  labels:
    release: kube-prometheus   # ← 이게 없으면 무시됨 (ServiceMonitor 때와 같은 패턴)
spec:
  groups:
    - name: notiflex-alerts
      rules:
        - alert: PodRestartTooMany
          expr: increase(kube_pod_container_status_restarts_total{namespace="notiflex"}[5m]) > 2
          for: 1m

 

 

알람 구성

슬랙에 연동시키고 싶은데 어떻게 해?

→ 지침 가이드대로 슬랙에서 Web URL을 클로드 코드에게 던져주면, 클로드 코드가 알람 테스트까지 진행합니다. 연동은 잘 되네요. 원리를 확인하겠습니다.

 슬랙 알람이 왔어 이거 웹  URL을 어디에 추가해서 연동한 거지 알려줘
  • URL이 민감정보로 인식하여 Git에 올리지 않고 K8s Secret 생성하여 마운트하였다.

 

 

소감

무섭다. 지침 외 사항에 대해 트러블슈팅도 하고, 상황이 달라짐에 따라 유연성있게 대처한다.

필자는 Sonnet 5 모델을 사용하였는데 DevOps 일자리 위기가 느껴진다…

AI를 통해 조금 더 민첩하게 대신하지 않을까 라는 생각이 든다.

좋은 경험이였다.