“인프라가 무너지면 *비즈니스가 *무너진다.”*

그러나 *무너지는 순간코드가 *고장난 순간아니다. 대부분은 *배포 직후 다. 그래서 *배포 파이프라인관측 체계같은 무게설계 되어야 한다.

이 글은 온프레미스 K3s 6 노드 HA 클러스터 (control-plane × 3 + worker × 3, 74 vCPU / 126 GB / 9 TB+) 위에서 65+ 개 ArgoCD ApplicationGitOps 단일 소스무중단 배포 / 관측 / 백업 / 게이트 하는 5 개 축실제 운영 설계 를 정리한다. 2026-06-07 이사갈 (40 vCPU CPU 깡패) 합류 + HA 3 replica + podAntiAffinity각 핵심 서비스가 *3 노드에 *spread 되어 노드 1 개 fail 에도 *downtime 0.


TL;DR

GitOps(ArgoCD)“클러스터 상태 = Git 상태” 라는 단 한 줄의 약속컴파일러처럼 강제 한다. 그 위에 (1) 3 - pillar 관측 (ELK + Prometheus + Tempo), (2) 이중 백업 (Velero + 14 개 pg_dump CronJob), (3) 품질 게이트 (Playwright E2E + 외부 도메인 검증), (4) 운영 관제 (Telegram 실시간 알림), (5) 인프라 자가 운영 (K3s HA + NFS + Registry mirror + frp + SOPS)5 개 축얹어야 진짜 무중단 운영가능 해진다. 코드 1 줄production 까지 가는 모든 좌석안전벨트있어야 한다는 철학 이다.


0. 왜 *GitOps 인가문제의식

0.1 “누가 *언제 *무엇을 *바꿨나”추적되지 않는 클러스터

전통적인 kubectl apply 운영은 3 가지 문제반복 된다.

  1. Drift — 실수로 kubectl edit 한 변경이 Git 에 안 남는다. 다음 사람이 Git 만 보고 클러스터를 복원 하면 그 변경이 사라진다.
  2. Audit gap누가 / 언제 / 왜git log 가 아니라 *kubectl history흩어져 있다.
  3. Rollback 불확실성 — 이전 manifest 가 어디 있었는지명확하지 않다. 재배포가 *재현 가능 하지 않다.

0.2 GitOps 의 *단 한 줄 약속

클러스터 상태 = helm-deploy 리포의 *master 브랜치 상태*

이 약속 하나로 위 3 가지 문제 가 동시에 해결 된다.

  • 변경은 *반드시 PR / commit 으로 — drift 0
  • git log = audit log누가 / 언제 / 왜영구 기록
  • rollback = git revert재현 가능

1. 축 1 — 3-Pillar 통합 관측 (Logs + Metrics + Traces)

1.1 관측의 *3 기둥

시스템의 *건강말로물으면 *시스템은 *대답하지 않는다. 수치 / 흔적 / 진술물어야 한다.

기둥 질문 대표 도구
메트릭 (Metrics) “얼마나 *어떻게 *돌고 있나?” (CPU, QPS, latency) Prometheus + Grafana
로그 (Logs) “무슨 일이 *언제 *일어났나?” (텍스트 이벤트) Fluent-bit + Elasticsearch + Kibana
트레이스 (Traces) “한 요청이 *어느 서비스를 *거쳐 *어디서 *느려졌나?” (span chain) Tempo

1.2 Fluent-bit DaemonSet — *모든 노드의 *모든 컨테이너 stdout

# argocd-applications/elk/03-fluent-bit.yaml — 핵심만
kind: DaemonSet
spec:
  template:
    spec:
      containers:
        - name: fluent-bit
          volumeMounts:
            - name: varlog
              mountPath: /var/log
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
  • DaemonSet모든 노드에 1 개씩 자동 배포. 새 노드 합류 시 수동 작업 없음
  • 컨테이너 stdout/stderrKubernetes metadata (namespace, pod, labels)함께 ES 로 적재
  • Kibana 에서 namespace = settlement-prod AND log ~ “ERROR” 같은 cross-pod 검색

1.3 Prometheus 32 개 PrometheusRule — *알림은 *코드처럼 *버전 관리

monitoring-prodkube-prometheus-stack 위에 32 개의 PrometheusRuleGit 으로 관리 된다.

# cluster-ops/pod-restart-alert-rule.yaml — 패턴 예시
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
spec:
  groups:
    - name: pod-restart
      rules:
        - alert: PodRestartingFrequently
          expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Pod  restarted >3 times in 15m"

규칙의 *3 가지 가치:

  1. PR 리뷰 가능 — 알림이 왜 이 임계치인지commit message남는다
  2. 환경별 분기 — staging 은 완화, prod 는 엄격 으로 value override
  3. 재현 가능클러스터 재구축Git apply 한 번 이면 알림 체계 복원

1.4 Tempo — *MSA 의 *끊어진 호출 chain 잇기

[Client] → gateway → order-service → payment-service → (Kafka) → settlement-service
            span A      span B           span C                       span D
                                                          ^ Kafka 가 끊는 듯 보이는데
                                                            traceparent header propagation 으로 connect
  • settlement-service 같은 이벤트 기반 MSA 에서 주문 → 결제 → 정산전체 흐름한 trace ID추적
  • 어느 span 에서 *p99 가 *튀는지Grafana Tempoflame graph즉시 보인다

Grafana 에서:

  • 메트릭 그래프튀는 지점클릭그 시간대의 로그 (ES) / 그 시간대의 trace (Tempo)
  • Tempo span 에서 exception 보임 → 클릭그 pod 의 로그 (ES)

한 사고가 *터지면 3 도구 사이 점프 횟수 = 1 ~ 2 번 으로 근본 원인 까지 내려간다.


2. 축 2 — 이중 백업 (Form × Medium × Restore unit)

2.1 왜 *이중 인가 — 직교 설계의 *원칙

단일 백업 은 *침해 / 부패 / 인적 실수하나에만 *대응 한다. 직교 한 두 가지겹치면 *둘 다 *동시터지지 않는 한 복원 가능.

내 클러스터는 3 차원이 직교 하도록 이중화 했다.

차원 Velero 백업 pg_dump CronJob
형태 (Form) 물리 (PV 스냅샷, K8s 리소스 manifest) 논리 (SQL dump)
매체 (Medium) 오프사이트 R2 로컬 PVC + R2 sync
복원 단위 (Restore unit) 클러스터 / 네임스페이스 단일 DB / 테이블

클러스터 전체 손실 — Velero 로 namespace 채로 *복원. → 단일 DB 의 *논리적 부패 (잘못된 UPDATE) — pg_dump 로 해당 DB 만 시점 복원. → 서로의 *부재 시나리오덮어준다.

2.2 Velero 일·시간 단위 오프사이트 백업

# 매일 03:00 KST 풀 백업, 매시간 incremental
velero schedule create daily-full \
  --schedule="0 3 * * *" \
  --include-namespaces='*-prod' \
  --ttl 720h0m0s   # 30 일 보존

velero schedule create hourly-pv \
  --schedule="0 * * * *" \
  --include-resources=pvc,pv \
  --ttl 168h0m0s   # 7 일 보존
  • 03:00클러스터 전체 *조용한 시간
  • 오프사이트 R2온프레미스 NAS 만 *터지는 *지역 사고 에서도 복원 가능

2.3 14 개 pg_dump CronJob — *namespace 별 *논리 백업

# charts/pg-backup/values.yaml
schedule: "0 2 * * *"     # 매일 02:00 KST (Velero 03:00 보다 1 시간 앞)
timezone: "Asia/Seoul"
retention:
  days: 30                 # local PVC 30 일 보존

핵심 설계 결정:

  • namespace 별 1 개 CronJob — 14 개 namespace × 1 = 14 개. blast radius 격리
  • Velero (03:00) 보다 1 시간 앞pg_dump 의 *결과물 .sqlVelero PV 스냅샷에 포함 되도록
  • retention 30 일지난 한 달 안 *언제든 *시점 복원
  • LimitRange 호환memory request==limit, cpu ratio ≤ 4crypto-prod 같은 *제한 namespace 에서도 반려 없이 *돌도록 튜닝

2.4 백업의 *복원 시간 (RTO) 검증

백업 은 *복원 해 본 적 없 으면 *백업 이 아니다.

분기별 1 회 staging 클러스터에 Velero restore + pg_dump 적용수동 테스트. RTO 측정 해서 Grafana 에 *수치로 기록.


3. 축 3 — 품질·안정성 게이트 (Pre + Post deploy)

3.1 배포 *직후터지는 사고가장 많다

CI 의 *단위테스트통과해도 frontend 가 *production CDN 에서 깨질 수 있다. 프론트 빌드 시점에 *NEXT_PUBLIC_API_URL틀려서 https://localhost:8080번들 되는 사고 같은 것들.

배포 후 *실제 사용자가 *보는 도메인외부에서 *검증 해야 한다.

3.2 Playwright E2E — *배포 전 *유저 시나리오 자동화

// settlement/frontend/playwright.config.ts 패턴
export default defineConfig({
  testDir: './e2e',
  use: {
    baseURL: process.env.E2E_BASE_URL ?? 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 14'] } },
  ],
});
  • PR 게이트 — main merge 전 주요 user flow (로그인 → 주문 → 결제 → 정산 조회) 자동 실행
  • Trace 자동 캡쳐 — 실패 시 영상 + DOM snapshotActions artifact남는다

3.3 배포 *후 외부 도메인 가용성 검증*

# uptime-kuma-prod.yaml 로 배포한 Uptime Kuma 의 모니터
- type: http
  name: settlement-frontend
  url: https://settlement.example.com
  interval: 60  # 1 분 주기
  acceptedStatusCodes: ['200-299']
  expectedKeyword: '정산 대시보드'   # 빌드 산출물 마커
  • acceptedStatusCodes 만 보지 않고 body keyword 까지 검증200 이지만 *빈 화면 인 사고 차단
  • frp tunnel 을 거쳐 외부 인터넷 에서 진짜 사용자 시점 으로 fetch

3.4 왜 *내부 신호 (API 200, Argo Healthy) 만으로는 부족 한가

ArgoCD 가 Healthy = Synced 라고 말해도:

  • 외부 CDN 캐시옛 버전 일 수 있다
  • frontend 빌드 ARG틀려 번들이 *깨졌어도 서버 응답은 *200
  • Kafka 가 *백로그 *쌓고 있어 DB 쓰기 가 *오래된 데이터

외부 도메인 의 *real bytes 까지 검증 해야 진짜 배포 성공.


4. 축 4 — 운영 관제 (Telegram 실시간 알림 파이프라인)

4.1 알림의 *3 채널 분리

채널 용도 임계
#infra-critical PV / etcd / NFS / 노드 down 즉시 호출
#deploy ArgoCD sync, Image Updater 이벤트 알리지만 *호출 X
#cronjob-fail 14 개 pg_dump + 기타 CronJob 실패 오늘 안에 *대응

모든 알림이 *한 채널에 *섞이면 진짜 critical 이 *묻힌다. 분리 가 *운영자 의 *정신 건강지킨다.

4.2 Alertmanager → Telegram webhook 흐름

# monitoring-prod 의 alertmanager values
receivers:
  - name: telegram-infra-critical
    webhook_configs:
      - url: 'https://api.telegram.org/bot/sendMessage'
        send_resolved: true
route:
  receiver: telegram-deploy
  routes:
    - matchers: ['severity="critical"']
      receiver: telegram-infra-critical
  • severity 라벨PrometheusRule 정의 시점에 *분기
  • send_resolved: true복구 메시지도 *수신. “끝났는지” 가 *명확

4.3 CronJob 실패 전용 룰 — *왜 *별도 인가

# cluster-ops/cronjob-failed-alert-rule.yaml
- alert: CronJobFailed
  expr: kube_job_failed{job_name=~".+-pg-backup-.+"} > 0
  for: 1m
  annotations:
    summary: "Backup job  failed"
  • 백업 실패 는 *오늘 안에 *발견 해야 한다. 내일 *터지면 *어제 백업이 없다
  • CronJob 은 *재시도가 *기본 이라 사람이 *모르고 *지나갈 수 있는 유일한 알림

4.4 알림의 *피드백 루프

알림이 *너무 *시끄러우면 운영자가 *읽지 않는다. 너무 *조용하면 진짜 사고 가 *묻힌다.

분기별 알림 통계 리뷰false positive 비율 > 30% 인 룰은 임계치 조정 또는 삭제. Git 으로 관리 되므로 PR 으로 검토 가능.


5. 축 5 — 인프라 자가 운영 (K3s HA + 4 가지 핵심 인프라)

5.1 K3s HA (etcd 3 voter + worker 3) — *control-plane 1 대 죽어도 *클러스터 살아 있음

실제 6 노드 토폴로지 (2026-06-13 기준):

노드 사양 역할 tier 주요 워크로드
르무엘 (lemuel) 4 vCPU / 32 GB control-plane + etcd (leader) management news-pipeline, judge-engine, GitHub Actions runner
루이스 (louise) i7-8565U 8 vCPU / 16 GB worker worker market-feed (C++), orderbook-matcher (Rust), settlement/sparta replica 1
데이비드 (david) 6 vCPU / 16 GB worker (모니터링) worker kube-prometheus-stack, Loki, settlement/sparta replica 2
일원 (ilwon) 12 vCPU / 32 GB / NVMe 457 GB + 4 TB HDD + 1 TB SSD control-plane + etcd storage postgres / storage 풀, ASAT, lowshopping
솔로몬 (solomon) 4 vCPU / 15 GB / Intel DC S3700 SSD control-plane + etcd storage-backup backup 전용 + etcd quorum
이사갈 (isagal) 40 vCPU / 15 GB / 3.6 TB SSD worker (CPU 깡패) worker settlement/sparta replica 3, frp self-host, 확장 워크로드

총합 : 74 vCPU / 126 GB RAM / 9 TB+ 스토리지

  • etcd 3 voter quorum (르무엘 / 일원 / 솔로몬) — 2 대만 *살아 있으면 클러스터 의사 결정 *계속 가능
  • 이사갈은 worker onlyetcd 멤버 *아님 (합류 시 orphan Learner 멤버 제거 정리 완료 2026-06-07)
  • worker 3 대 (louise / david / isagal) — podAntiAffinity preferredsettlement / sparta 등 핵심 서비스 replicas=3 이 *3 노드에 *spread 됨. 노드 1 개 fail → 2/3 ready 유지 → downtime 0
  • tier 라벨 분리 — david 는 monitoring 전용 tier, 일원/솔로몬은 storage tier운영 부하가 *관측·etcd 를 *압살하지 않도록

핵심 변곡점 timeline:

날짜 사건 의미
2026-05-12 SQLite → embedded etcd 마이그레이션 (18 분 다운타임으로 30+ ArgoCD 앱 모두 보존) 단일 마스터 → 진짜 HA 전환
2026-06-06 솔로몬 etcd 디스크 SSD 이전 (Intel DC S3700) etcd p99 latency 극적 개선 — 저전력 노드 의 I/O 병목 해소
2026-06-07 이사갈 합류 (40 vCPU CPU 깡패) 클러스터 capacity 1.6 배 확장, HA 3 spread 가능
2026-06-07 Velero node-agent OOM fix (mem 512Mi → 2Gi + KOPIA_PARALLEL_FILE_READS=2) 백업 신뢰성 회복
2026-06-08 frp self-host 추가 — Cloudflare Tunnel 의 self-host 카운터파트 외부 의존 감소 + 5 PR 디버깅 학습
2026-06-08 settlement / sparta HA 정책 적용 (replicas=3 + podAntiAffinity preferred) 각 핵심 서비스 가 *3 노드에 spread
  • 마스터 추가 시 *반드시 동기화/etc/rancher/k3s/config.yamltop-level cluster-dnskubelet-arg.cluster-dns 둘 다 *같은 값 (169.254.20.10). 한쪽만 두면 DNS 어긋남

5.2 NFS Storage — *공유 PV 의 *단순한 진리

  • nfs-server 차트 — 한 노드에 NFS 서버 + 모든 노드에 mount
  • Velero 백업 본 / 빌드 artifact / 공유 정적 자산common bucket
  • CSI driver 같은 *복잡함 없이 단일 마운트 포인트대부분의 *공유 스토리지 요구 해결

5.3 Private Registry Mirror — *DockerHub rate-limit / 외부 의존 차단

# K3s registries.yaml
mirrors:
  docker.io:
    endpoint:
      - "https://registry.internal:5000"
  ghcr.io:
    endpoint:
      - "https://registry.internal:5000"
  • DockerHub anonymous rate-limit (100 pulls / 6h)영구 회피
  • 외부 registry 장애 시에도 *내부 이미지 *재배포 가능
  • 이미지 가 *내부에 *캐시pull 속도 *상승

5.4 frp Tunnel — *외부에서 내부 서비스로의 *안전한 통로

[Public DDNS / SaaS]  →  [frp server (외부 VPS)]  →  [frp client (내부 K3s)]  →  [Service]
  • 내부 서비스 (Kibana, Grafana, ArgoCD UI)NAT 뒤에 두면서도 외부 합법 접근 만 *허용
  • 공유기 포트 포워딩 / 고정 IP 없이도 production 도메인 운영

5.5 SOPS-Operator — *암호화된 시크릿을 *Git 에 둔다

# secrets/settlement-postgres.sops.yaml — 일부 (암호화된 상태로 commit)
apiVersion: v1
kind: Secret
data:
  password: ENC[AES256_GCM,data:...]
sops:
  age:
    - recipient: age1...
  • Git 에 *암호화된 상태로 *commitaudit trail 보존 + 복호화 키 없는 사람은 못 읽음
  • 클러스터 의 *SOPS-Operator런타임에 *복호화일반 Secret 으로 *변환
  • 복호화 키 (age private key)클러스터에만 *존재, Git 에는 *없음

5.6 5 가지 인프라의 *공통 철학

외부 SaaS 의 *editable knob최소화 하고, Git 으로 *재현 가능self-managed 인프라로 집중.

  • 외부 의존 ↓ — DockerHub / SaaS 가 터져도 *우리는 *살아 있다
  • Git 단일 소스재구축 가능, audit 가능
  • 복잡함 ↓NFS / etcd / frp / SOPS — 각각 *단순하고 *오래된 *기술

6. 운영 플레이북 — *내가 *매일 *클러스터 를 *움직이는 방법

6.1 진입점 — *root-app 의 *App-of-Apps 패턴

# root-app.yaml — 클러스터의 *유일한 *수동 apply 대상*
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root-app
spec:
  source:
    repoURL: https://github.com/MyoungSoo7/helm-deploy
    targetRevision: master
    path: argocd-applications
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
  • root-app 자체 만 kubectl apply -f root-app.yaml 수동 1 회
  • 그 후로는 root-app 이 *argocd-applications/ 디렉터리 의 *모든 Application CR자동 sync
  • prune: true — Git 에서 파일을 *지우면 *클러스터에서도 *제거
  • selfHeal: true수동 kubectl edit drift발생하면 *Git 상태로 *되돌림

6.2 새 앱 추가 — *4 단계 *고정 절차

# 1. 차트 작성
mkdir -p charts/myapp/templates
$EDITOR charts/myapp/Chart.yaml charts/myapp/values.yaml charts/myapp/values-prod.yaml

# 2. Application CR 추가 (기존 academy-prod.yaml 패턴 복사)
cp argocd-applications/academy-prod.yaml argocd-applications/myapp-prod.yaml
$EDITOR argocd-applications/myapp-prod.yaml   # path, namespace 만 바꿈

# 3. 시크릿 (필요 시)
$EDITOR /tmp/myapp-secret.yaml                 # 평문 작성
sops --encrypt --in-place /tmp/myapp-secret.yaml
mv /tmp/myapp-secret.yaml secrets/myapp-secret.sops.yaml

# 4. push — ArgoCD 가 알아서 sync
git add . && git commit -m "feat(myapp): add app" && git push

수동으로 kubectl apply 하는 일이 *없다. 모든 클러스터 변경 = git push.

6.3 앱 폐기 — *git rm 한 줄

git rm argocd-applications/myapp-prod.yaml
git commit -m "chore(myapp): retire" && git push
# root-app 의 prune: true 가 cascade 로 namespace · PVC · Service 모두 정리

6.4 시크릿 수정 — *SOPS 의 마법

sops secrets/settlement-postgres.sops.yaml
# → 에디터 가 *평문으로 *열리고*
# → 저장 시 *자동으로 *다시 *암호화*
git add -u && git commit -m "chore(secrets): rotate settlement-postgres" && git push
  • Git 에는 *항상 *암호화된 상태 만 *commit
  • 복호화 키 (age private key)클러스터 의 *SOPS-Operator 만 *보유Git 에는 *없음

6.5 수동 디버깅 — *마스터에서 sudo kubectl

# lemuel 마스터에 SSH
ssh -p 2652 lemuel
sudo kubectl get pods -A | grep -v Running
sudo kubectl logs -n settlement-prod deploy/order-service --tail=200
sudo kubectl describe pod -n settlement-prod order-service-xxx
  • /etc/rancher/k3s/k3s.yaml 권한 때문에 sudo 필수
  • 수동 변경은 *금지selfHeal: trueGit 으로 되돌림

6.6 ArgoCD UI — *육안 모니터링

  • argocd.example.com외부 frp 로 노출
  • 65+ 개 Application 의 *Health × Sync 매트릭스 한 화면
  • Out-of-sync 노랑 / Degraded 빨강알람보다 *먼저 *보일 때가 많다

6.7 내 *하루 *운영 패턴

시간 행동
아침 ArgoCD UI / Grafana 대시보드 / Telegram 알림 history 5 분 스캔
작업 시 helm-deploy 의 PR 로 변경 (직접 push 도 가능 하지만 PR 권장)
알림 시 Telegram → Kibana / Grafana 점프 → 근본 원인 까지 *5 분 내 도달 목표
주간 false positive 알림 통계 리뷰 → 룰 조정 PR
분기 Velero restore + pg_dump 복원 staging 검증

“하지 않는 일”명확: kubectl apply 수동 / kubectl edit 직접 변경 / 평문 시크릿 commit / 클러스터에서 *수동 helm install.


7. 통합 아키텍처 — *5 개 축이 *어떻게 *겹치나

[Developer commits code]
    ↓
[GitHub Actions]  → 이미지 빌드 + ghcr push  ← Playwright E2E 게이트 (축 3)
    ↓
[ArgoCD Image Updater]  → helm-deploy 자동 commit (축 1)
    ↓
[ArgoCD] watches helm-deploy → cluster sync  ← Self-heal + Prune (축 1)
    ↓
[K3s 6 node HA]                              ← etcd quorum (축 5)
  ├ Pod scheduling
  ├ NFS / Registry / frp                     ← 인프라 자가 운영 (축 5)
  └ Pod start
    ↓
[Fluent-bit DaemonSet]    → ES               ← 로그 (축 1)
[Prometheus + Tempo]      → Grafana           ← 메트릭 / 트레이스 (축 1)
    ↓
[Alertmanager]            → Telegram          ← 운영 관제 (축 4)
    ↓
[Uptime Kuma]             → 외부 도메인 검증   ← 배포 후 게이트 (축 3)
    ↓
[Velero + 14 pg_dump CronJob]                ← 이중 백업 (축 2)

핵심 통찰:

  • 5 개 축은 *독립아니라 직교 한다. 각자 다른 차원위험덮는다.
  • 코드 1 줄production 까지 가는 모든 좌석안전벨트있어야 한다.

8. 운영 경험에서 얻은 *3 가지 교훈

8.1 “Healthy 가 *Healthy 가 *아니다”

ArgoCD 가 *Healthy 라고 말해도 외부 사용자 가 *못 보면 그것은 *Unhealthy 다.

  • 내부 신호 (kube_pod_status_ready, argocd app health) 와 외부 신호 (Uptime Kuma 의 body keyword) 를 둘 다 *측정
  • 둘이 *동시에 *green 일 때만 *진짜 *healthy

8.2 “백업은 *복원해 본 적 없으면 *백업이 아니다”

  • 분기별 staging 클러스터에 *Velero restore + pg_dump 복원 수동 검증
  • RTO 측정 결과Grafana 에 *수치로 *남긴다팀이 *기대치를 *공유

8.3 “알림은 *시끄러우면 *읽히지 않는다”

  • severity 별 채널 분리infra-critical / deploy / cronjob-fail
  • 분기별 *false positive 비율 리뷰> 30% 룰은 *조정 또는 *삭제
  • 알림 룰도 *Git 으로 *PR 리뷰

9. 결론 — *GitOps + 통합 관측 의 *진짜 가치

코드를 짜는 것은 *쉽다. 그 코드 가 *production 에서 *영원히 *돌게 하는 것어렵다.

GitOps 와 통합 관측 체계는 그 어려움5 개 축 으로 나눠 *분담 시킨다.

무엇을 없애 주는가
1. 3-pillar 관측 “어디서 무엇이 *왜 *느린지 모름”불안
2. 이중 백업 “되돌릴 수 없음”공포
3. 품질 게이트 “내가 *모르는 *사이 *깨졌나”의심
4. 운영 관제 “뭔가 *터졌는데 *나만 *모르나”고립감
5. 인프라 자가 운영 “외부 SaaS 가 *우리 운명쥐고 있다”통제 불능

→ 이 5 가지 가 동시에 충족 되어야 운영자가 *밤에 *잠을 잘 수 있다. 그리고 그것이 *production 운영 의 *진짜 KPI 다.


부록 — 사용 기술 한 줄 요약

분류 도구
GitOps ArgoCD (App-of-Apps), ArgoCD Image Updater
Cluster K3s v1.35+, embedded etcd 3 voter, 6 노드 (control-plane × 3 + worker × 3)
Manifest Helm 3, Kustomize 패치
Logs Fluent-bit (DaemonSet), Elasticsearch (ECK), Kibana
Metrics kube-prometheus-stack, 32 PrometheusRule, Grafana
Traces Grafana Tempo
Backup Velero (off-site R2), pg_dump CronJob × 14
Quality gate Playwright E2E, Uptime Kuma (외부 도메인 검증)
Alerting Alertmanager → Telegram (3 채널 분리)
Self-managed infra NFS Server, Private Registry Mirror, frp Tunnel, SOPS-Operator
Secrets SOPS + age, Git 에 암호화 상태로 *commit

“운영의 *모든 변경Git 으로 *간다. 모든 *수치대시보드로 *간다. 모든 *사고Telegram 으로 *간다. 모든 *상태복원 가능 하다.”* — 이것이 5 개 축이 *그리는 *세계 다.