앞으로 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를 통해 조금 더 민첩하게 대신하지 않을까 라는 생각이 든다.
좋은 경험이였다.
'AI' 카테고리의 다른 글
| [GitAIOps로 인프라 구성하기] 3. 배포 파이프라인 구성하기 (0) | 2026.07.12 |
|---|---|
| [GitAIOps로 인프라 구성하기] 2. 환경 구성 (0) | 2026.07.05 |
| [GitAIOps로 인프라 구성하기] 1. 스터디 소개 (0) | 2026.07.05 |
| SRE Incident Response Agent 와 기능 개발 (0) | 2026.04.20 |
| EKS 최적화 보고서 기능 개발(보안 편) (0) | 2026.04.12 |