로그인 회원가입
모두인포
전체IT경제사회생활스포츠시사여행연애

Nginx Ingress + Argo Rollouts 실제 Canary Traffic 제어와 Prometheus·Grafana·Loki·Tempo·GitHub Actions GitOps 자동화

lmkfox · 2026-09-22 · 조회 3
Nginx Ingress + Argo Rollouts 실제 Canary Traffic 제어와 Prometheus·Grafana·Loki·Tempo·GitHub Actions GitOps 자동화
Nginx Ingress + Argo Rollouts 실제 Canary Traffic 제어와 Prometheus·Grafana·Loki·Tempo·GitHub Actions GitOps 자동화 1. 들어가며 Kubernetes에서 Canary Deployment를 구현할 때 가장 중요한 질문은 다음과 같다. "Canary Pod를 만들었는데 실제 사용자 트래픽을 어떻게 10%만 보내는가?" 단순히 Kubernetes Service를 두 개 만드는 것만으로는 충분하지 않다. 예를 들어 다음과 같이 만들었다고 하자. fastapi-stable fastapi-canary Service가 두 개 존재한다고 해서 자동으로 다음과 같은 트래픽이 만들어지는 것은 아니다. Stable 90% Canary 10% 실제 HTTP 요청을 다음과 같이 제어하려면 Traffic Routing이 필요하다. Nginx Ingress | +-----------+-----------+ | | v v Stable Canary 90% 10% 그리고 Canary의 상태를 Prometheus로 검사한다. Canary | +--> HTTP 5xx | +--> P95 Latency | +--> Request Rate | v Prometheus | v Argo Rollouts 정상이면: 10% ↓ 25% ↓ 50% ↓ 100% 문제가 발생하면: Canary | v Prometheus Analysis | v FAILED | v Argo Rollouts Abort | v Stable 100% 이번 글에서는 이 과정을 실제 Kubernetes 환경에서 구현할 수 있도록 구성한다. 2. 최종 아키텍처 이번 실습의 전체 구조는 다음과 같다. Developer | git push | v GitHub Application | v GitHub Actions | +---------+---------+ | | v v Test/Build Docker Image | v Container Registry | v GitOps Repository | v Argo CD | v Kubernetes Cluster | v Argo Rollouts | Traffic Routing | v Nginx Ingress | +--------------+--------------+ | | v v Stable Canary v1.0 v1.1 | | +--------------+--------------+ | v FastAPI | +-------------+-------------+ | | v v PostgreSQL Redis Observability FastAPI | +---- Metrics ----> Prometheus ----> Grafana | +---- Logs -------> Loki ----------> Grafana | +---- Traces -----> Tempo ---------> Grafana Canary Verification Argo Rollouts | v Prometheus Analysis | +---- 5xx | +---- P95 | v PASS / FAIL | +---- PASS ----> Next Weight | +---- FAIL ----> Abort 3. 이번 프로젝트의 핵심 목표 이번에는 단순히 Canary를 배포하는 것이 목적이 아니다. 다음 6가지를 모두 연결한다. 1. 실제 Traffic Split 10% 25% 50% 100% 2. Canary 전용 Metrics Canary HTTP Request Canary HTTP 5xx Canary P95 3. Prometheus 자동 검증 5xx < 1% P95 < 500ms 4. Grafana 운영 Dashboard Stable Canary 5xx P95 Traffic 5. Loki / Tempo 장애 분석 Metrics | +--> Logs | +--> Traces 6. GitHub Actions → GitOps 자동화 Code Push | v GitHub Actions | v Docker Image | v GitOps values.yaml | v Argo CD 4. 왜 Nginx Ingress Traffic Routing이 필요한가? 일반적인 Kubernetes Service는 기본적으로 Pod 집합에 트래픽을 분산한다. 예를 들어: Service | +-- Pod 1 +-- Pod 2 +-- Pod 3 +-- Pod 4 하지만 Canary에서는 다음과 같은 의도가 필요하다. Stable | +-- 90% Canary | +-- 10% 이것은 단순한 Replica 수와 다른 개념이다. 예를 들어 Stable Pod 9개와 Canary Pod 1개를 만들었다고 해서 정확히 HTTP 요청의 90%와 10%가 보장되는 것은 아니다. 따라서 HTTP Layer에서 Traffic Weight를 제어해야 한다. 5. Argo Rollouts와 Nginx Ingress의 역할 각 구성요소의 역할을 구분하면 이해하기 쉽다. Argo Rollouts "몇 %를 Canary로 보낼 것인가?" Nginx Ingress: "실제 HTTP 요청을 어느 Service로 보낼 것인가?" Prometheus: "Canary가 정상인가?" Grafana: "운영자가 현재 상태를 어떻게 볼 것인가?" Loki: "무슨 오류가 발생했는가?" Tempo: "어느 구간에서 시간이 오래 걸렸는가?" Argo CD: "Git에 정의된 상태를 Kubernetes에 반영한다." GitHub Actions: "코드를 테스트하고 Image를 만든다." 6. Kubernetes 환경 준비 예제에서는 다음 Namespace를 사용한다. kubectl create namespace app kubectl create namespace monitoring kubectl create namespace argocd 확인: kubectl get namespace 7. Nginx Ingress Controller Nginx Ingress Controller가 Kubernetes Cluster에 설치되어 있어야 한다. 확인: kubectl get pods -A | grep ingress 예: ingress-nginx-controller-xxxxx Service 확인: kubectl get svc -n ingress-nginx 외부 IP 또는 NodePort를 통해 HTTP 요청이 Ingress Controller까지 도착해야 한다. 8. FastAPI Application 간단한 FastAPI Application을 사용한다. from fastapi import FastAPI from prometheus_fastapi_instrumentator import Instrumentator app = FastAPI() Instrumentator().instrument(app).expose(app) @app.get("/") def root(): return { "version": "v1.0", "message": "Hello Kubernetes" } @app.get("/health") def health(): return { "status": "ok" } Canary 버전에서는 응답을 다음처럼 변경한다. @app.get("/") def root(): return { "version": "v1.1", "message": "Hello Canary" } 이렇게 하면 실제 Traffic이 어느 버전으로 들어가는지 쉽게 확인할 수 있다. 9. 중요한 Canary Metric 설계 여기서 매우 중요한 부분이 있다. 단순히 다음과 같이 Metrics를 수집하면: http_requests_total Stable과 Canary의 Metrics가 섞일 수 있다. 그러면 Prometheus가 다음을 계산할 때 문제가 발생한다. 전체 Application 5xx 우리가 원하는 것은: Canary만의 5xx 따라서 Pod에 명확한 Label을 추가한다. Stable: metadata: labels: app: fastapi rollouts-pod-template-hash: stable version: stable Canary: metadata: labels: app: fastapi version: canary 실제 Argo Rollouts에서는 Pod Template Hash 등의 동적 label을 활용하는 방식이 더 적절하다. 핵심은 다음과 같다. Stable Metrics | +---- version="stable" Canary Metrics | +---- version="canary" 10. Prometheus Metrics 예 FastAPI에서 다음 Metrics를 노출한다고 하자. http_requests_total http_request_duration_seconds_bucket Prometheus에서 다음과 같이 확인할 수 있다. http_requests_total Canary만 확인: http_requests_total{ app="fastapi", version="canary" } Stable: http_requests_total{ app="fastapi", version="stable" } 11. Stable Service apiVersion: v1 kind: Service metadata: name: fastapi-stable namespace: app spec: selector: app: fastapi ports: - name: http port: 8000 targetPort: 8000 하지만 이 Service는 모든 FastAPI Pod를 선택할 수 있다. 따라서 실제 Rollouts 환경에서는 Argo Rollouts가 Service selector를 관리하도록 구성하는 것이 중요하다. 12. Canary Service apiVersion: v1 kind: Service metadata: name: fastapi-canary namespace: app spec: selector: app: fastapi ports: - name: http port: 8000 targetPort: 8000 Argo Rollouts가 Stable/Canary ReplicaSet을 구분할 수 있도록 Rollout과 Service를 함께 구성한다. 13. Rollout 기본 구조 apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: fastapi namespace: app spec: replicas: 6 revisionHistoryLimit: 3 selector: matchLabels: app: fastapi template: metadata: labels: app: fastapi spec: containers: - name: fastapi image: ghcr.io/example/fastapi:v1.0 ports: - name: http containerPort: 8000 readinessProbe: httpGet: path: /health port: http initialDelaySeconds: 5 periodSeconds: 5 livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 10 periodSeconds: 10 14. Nginx Ingress와 Rollout 연결 Argo Rollouts에서 Nginx Ingress Traffic Routing을 사용하도록 지정한다. strategy: canary: canaryService: fastapi-canary stableService: fastapi-stable trafficRouting: nginx: stableIngress: fastapi-ingress steps: - setWeight: 10 - pause: duration: 5m - setWeight: 25 - pause: duration: 5m - setWeight: 50 - pause: duration: 10m - setWeight: 100 여기서 중요한 부분은: trafficRouting: nginx: stableIngress: fastapi-ingress 이다. 이 설정을 통해 Argo Rollouts가 Nginx Ingress의 Canary 설정을 조정할 수 있다. 15. Ingress 구성 Ingress는 Stable Service를 기본 Backend로 사용한다. apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: fastapi-ingress namespace: app spec: ingressClassName: nginx rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: fastapi-stable port: number: 8000 처음에는 모든 트래픽이 Stable로 간다. 100% Stable 16. Canary 10% 새로운 버전이 배포된다. Argo Rollouts: - setWeight: 10 그러면 Nginx Ingress가 Canary Weight를 반영하도록 변경된다. 개념적으로: Nginx Ingress | +--------+--------+ | | v v Stable Canary 90% 10% | | v v v1.0 v1.1 이제 실제 사용자 요청의 일부가 Canary로 전달된다. 17. 실제 Traffic 확인 예를 들어 다음 명령을 반복한다. for i in {1..100}; do curl -s http://api.example.com/ echo done 결과를 보면: v1.0 v1.0 v1.1 v1.0 v1.0 v1.1 ... 대략 Canary 요청이 10% 수준으로 나타날 수 있다. 단, 짧은 테스트에서 정확히 10개가 나온다는 의미는 아니다. Traffic Weight는 장기적인 요청 분포를 기준으로 이해해야 한다. 18. Canary 25% Prometheus 검증 결과가 정상이라면: 10% | v 25% Argo Rollouts: - setWeight: 25 Traffic: Stable 75% Canary 25% 구조: Nginx Ingress | +--------+--------+ | | v v Stable Canary 75% 25% 19. Canary 50% 다음 단계: - setWeight: 50 결과: Stable 50% Canary 50% 이 단계에서는 Canary에 상당히 많은 실제 요청이 전달되므로 문제가 있다면 더욱 빠르게 감지할 수 있다. 20. Canary 100% 최종 단계: - setWeight: 100 결과: Stable 0% Canary 100% Canary가 최종 Production 버전이 된다. v1.0 | | 0% | v v1.1 | | 100% | v Production 21. Canary 자동 검증 이제 중요한 부분을 추가한다. 각 단계에서 Prometheus를 통해 Canary 상태를 확인한다. 검증 기준: HTTP 5xx < 1% P95 < 500ms 예를 들어: Canary 10% 5xx = 0.2% P95 = 180ms PASS 그러면: 10% ↓ 25% 22. Canary 5xx PromQL Canary만 계산하도록 한다. sum( rate( http_requests_total{ app="fastapi", version="canary", status=~"5.." }[5m] ) ) / sum( rate( http_requests_total{ app="fastapi", version="canary" }[5m] ) ) 결과: 0.002 이면: 0.2% 이다. 23. Canary P95 PromQL Histogram Metric을 사용한다. histogram_quantile( 0.95, sum( rate( http_request_duration_seconds_bucket{ app="fastapi", version="canary" }[5m] ) ) by (le) ) 결과: 0.18 이면: 180ms 이다. 24. AnalysisTemplate apiVersion: argoproj.io/v1alpha1 kind: AnalysisTemplate metadata: name: fastapi-canary-analysis namespace: app spec: metrics: - name: canary-error-rate interval: 1m count: 3 failureLimit: 1 successCondition: result[0] < 0.01 provider: prometheus: address: http://prometheus.monitoring:9090 query: | sum( rate( http_requests_total{ app="fastapi", version="canary", status=~"5.." }[5m] ) ) / sum( rate( http_requests_total{ app="fastapi", version="canary" }[5m] ) ) - name: canary-p95 interval: 1m count: 3 failureLimit: 1 successCondition: result[0] < 0.5 provider: prometheus: address: http://prometheus.monitoring:9090 query: | histogram_quantile( 0.95, sum( rate( http_request_duration_seconds_bucket{ app="fastapi", version="canary" }[5m] ) ) by (le) ) 25. Rollout에 Analysis 연결 strategy: canary: canaryService: fastapi-canary stableService: fastapi-stable trafficRouting: nginx: stableIngress: fastapi-ingress steps: - setWeight: 10 - pause: duration: 5m - analysis: templates: - templateName: fastapi-canary-analysis - setWeight: 25 - pause: duration: 5m - analysis: templates: - templateName: fastapi-canary-analysis - setWeight: 50 - pause: duration: 10m - analysis: templates: - templateName: fastapi-canary-analysis - setWeight: 100 이제 배포 흐름은 다음과 같다. 10% | +--> Prometheus | | | +--> PASS | v 25% | +--> Prometheus | | | +--> PASS | v 50% | +--> Prometheus | | | +--> PASS | v 100% 26. 실패하면 어떻게 되는가? 예를 들어 Canary 25%에서: 5xx = 4.2% P95 = 1.8s 기준: 5xx < 1% P95 < 500ms 따라서: Analysis | v FAILED Argo Rollouts: Abort Traffic: Canary 25% | X | v Stable 100% 27. 중요한 Abort 동작 Abort 이후에는 단순히 Pod를 삭제하는 것보다 Traffic을 Stable로 복귀시키는 것이 중요하다. Before Stable 75% Canary 25% Abort: Stable 100% Canary 0% 사용자는 다시 Stable 버전을 사용한다. 28. Grafana Dashboard 구성 Grafana에서는 최소한 다음 Panel을 구성하는 것을 권장한다. +---------------------------------------------------+ | FastAPI Canary Dashboard | +---------------------------------------------------+ | | | Canary Traffic 25% | | | +---------------------------------------------------+ | | | Stable RPS 820 req/s | | Canary RPS 270 req/s | | | +---------------------------------------------------+ | | | Canary 5xx 0.42 % | | | +---------------------------------------------------+ | | | Canary P95 210 ms | | | +---------------------------------------------------+ | | | Stable P95 180 ms | | | +---------------------------------------------------+ | | | Canary Pods 2 | | Stable Pods 4 | | | +---------------------------------------------------+ 29. Canary Request Rate Grafana에서 다음 PromQL을 사용할 수 있다. sum( rate( http_requests_total{ app="fastapi", version="canary" }[5m] ) ) Stable: sum( rate( http_requests_total{ app="fastapi", version="stable" }[5m] ) ) 두 값을 하나의 Graph에서 비교하면 Canary Traffic 변화를 볼 수 있다. 30. Canary 5xx Dashboard 100 * sum( rate( http_requests_total{ app="fastapi", version="canary", status=~"5.." }[5m] ) ) / sum( rate( http_requests_total{ app="fastapi", version="canary" }[5m] ) ) 단위는 Percentage로 설정한다. 예: 0.25% 31. Canary P95 Dashboard histogram_quantile( 0.95, sum( rate( http_request_duration_seconds_bucket{ app="fastapi", version="canary" }[5m] ) ) by (le) ) Grafana Unit: seconds (s) 또는 적절한 시간 단위로 표시한다. 32. Loki 연동 Canary 장애가 발생하면 Metrics만 보는 것으로 끝내면 안 된다. Grafana에서 Loki를 조회한다. 예: {namespace="app", app="fastapi", version="canary"} ERROR: {namespace="app", app="fastapi", version="canary"} |= "ERROR" HTTP 500: {namespace="app", app="fastapi", version="canary"} |= "500" 33. Canary 로그의 장점 Stable과 Canary 로그를 분리하면 매우 유용하다. Stable INFO request completed INFO database query completed Canary: ERROR database timeout ERROR redis connection timeout ERROR HTTP 500 따라서: Canary Metric | v 5xx 증가 | v Loki | v Canary ERROR Log 형태로 빠르게 장애를 추적할 수 있다. 34. Tempo Tracing FastAPI에 OpenTelemetry를 적용하면 Request Trace를 Tempo로 보낼 수 있다. 개념: Client | v Ingress | v FastAPI | +------ Redis | +------ PostgreSQL Trace: Trace ID | +-- FastAPI 1.2s | +-- Redis 20ms | +-- PostgreSQL 1.1s 이런 식으로 어느 구간에서 지연이 발생하는지 확인할 수 있다. 35. OpenTelemetry 구조 FastAPI | | OpenTelemetry SDK v OTel Collector | v Tempo 운영 환경에서는 애플리케이션에서 Tempo로 직접 보내기보다 OpenTelemetry Collector를 중간에 두는 구조가 관리하기 좋다. FastAPI | v OpenTelemetry Collector | v Tempo 36. Metrics → Logs → Traces 연결 가장 중요한 운영 패턴이다. 예를 들어 Grafana에서: Canary 5xx = 5% 를 발견한다. 그 다음: 5xx | v Loki | v ERROR Log | v Trace ID | v Tempo | v PostgreSQL 이렇게 연결한다. 즉: Prometheus | | "문제가 발생했다" v Loki | | "무슨 오류인가?" v Tempo | | "어디에서 발생했는가?" v Root Cause 37. GitHub Actions 전체 구조 이제 CI/CD를 연결한다. Developer | v git push | v GitHub | v GitHub Actions | +-- Test | +-- Build | +-- Security Scan | +-- Push Image | +-- Update GitOps 38. Docker Image Tag 이미지는 Git Commit SHA를 사용하는 것을 권장한다. 예: ghcr.io/example/fastapi: 8f4d92c 또는: ghcr.io/example/fastapi: sha-8f4d92c 이렇게 하면 어떤 Commit에서 만들어진 이미지인지 추적하기 쉽다. 39. GitHub Actions Build name: Build Application on: push: branches: - main jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout uses: actions/checkout@v4 - name: Login GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build Image run: | docker build \ -t ghcr.io/example/fastapi:${{ github.sha }} . - name: Push Image run: | docker push \ ghcr.io/example/fastapi:${{ github.sha }} 40. GitOps Repository 자동 수정 이제 중요한 단계다. Build가 끝나면 GitOps Repository의: values.yaml 을 변경한다. 기존: image: tag: "8f4d92c" 새 버전: image: tag: "9ab1234" GitHub Actions가 이 파일을 변경하고 Commit한다. 41. GitOps Repository Checkout GitHub Actions에서는 GitOps Repository를 별도로 Checkout할 수 있다. - name: Checkout GitOps uses: actions/checkout@v4 with: repository: example/k8s-gitops token: ${{ secrets.GITOPS_TOKEN }} path: gitops 여기서: GITOPS_TOKEN 은 GitOps Repository를 수정할 수 있는 권한이 필요하다. 실제 운영에서는 장기 PAT보다 GitHub App 또는 적절한 단기 인증 방식을 검토하는 것이 좋다. 42. values.yaml 변경 예: - name: Update Image Tag run: | sed -i \ "s/^ tag:.*/ tag: \"${GITHUB_SHA}\"/" \ gitops/environments/prod/values.yaml 확인: cat gitops/environments/prod/values.yaml 결과: image: repository: ghcr.io/example/fastapi tag: "9ab1234..." 43. Git Commit - name: Commit GitOps run: | cd gitops git config user.name "github-actions" git config user.email "github-actions@github.com" git add environments/prod/values.yaml git commit \ -m "Deploy fastapi ${GITHUB_SHA}" git push 이제 전체 흐름이 완성된다. Application Git | v GitHub Actions | v Docker Image | v GitOps Repository | v Argo CD 44. GitOps Repository 변경 예: Before image: tag: v1.0 GitHub Actions 실행 후: After image: tag: 9ab1234 Git Commit: Deploy fastapi 9ab1234 Argo CD가 변경을 감지한다. Git | | changed v Argo CD | v OutOfSync | v Sync 45. Argo CD Sync Argo CD: GitOps | v Helm | v Kubernetes Manifest | v Argo Rollout 새로운 Image: v1.1 이 적용된다. 46. 실제 전체 배포 흐름 최종적으로 다음과 같은 흐름이 만들어진다. Developer | | git push v GitHub Repository | v GitHub Actions | +---------+---------+ | | v v Test Docker Build | v Registry | v GitOps Repo | v Argo CD | v Argo Rollouts | v Nginx Ingress | +-------------+-------------+ | | v v Stable Canary 90% 10% | | +-------------+-------------+ | v Users 47. 10% 단계 Argo Rollouts | v setWeight: 10 | v Nginx Ingress | +---+---+ | | 90% 10% | | Stable Canary Prometheus: 5xx = 0.2% P95 = 180ms 결과: PASS 48. 25% 단계 Stable 75% Canary 25% Prometheus: 5xx = 0.3% P95 = 210ms 결과: PASS 49. 50% 단계 Stable 50% Canary 50% Prometheus: 5xx = 0.4% P95 = 230ms 결과: PASS 50. 100% 단계 Stable 0% Canary 100% Deployment 완료. v1.1 | v Production 51. 장애 발생 시나리오 이번에는 v1.2에 문제가 있다고 가정한다. GitHub: v1.1 | v v1.2 GitHub Actions: PASS GitOps: v1.2 Argo CD: Sync Canary: 10% 그런데 Canary에서 DB Query가 느려진다. Prometheus: P95 = 1.9s 기준: P95 < 500ms Analysis: FAILED Argo Rollouts: ABORT Traffic: Stable 100% Canary 0% 52. 장애 분석 Grafana에서: Canary P95 | v 1.9s Loki: {namespace="app", app="fastapi", version="canary"} |= "timeout" 결과: ERROR PostgreSQL query timeout Tempo: FastAPI | +-- PostgreSQL | +-- 1.7s 최종적으로 PostgreSQL Query 문제임을 확인할 수 있다. 53. GitOps 상태와 Runtime 상태의 관계 여기서 매우 중요한 운영 개념이 있다. GitOps: Desired State Kubernetes: Actual State Argo Rollouts: Runtime Progressive Delivery 따라서: Git | | Desired State v Argo CD | v Kubernetes | v Argo Rollouts | v Runtime Traffic 이 구조를 이해해야 한다. 54. 자동 Abort 이후 Git은 어떻게 되는가? 예를 들어 GitOps에는: image: tag: v1.2 가 들어 있다. Canary가 실패해서 Abort되었다고 하자. Runtime: Stable v1.1 Canary v1.2 | X 하지만 Git은 여전히: v1.2 를 가리키고 있을 수 있다. 따라서 운영 정책을 별도로 정해야 한다. 방법 1 Runtime Abort만 하고 Git은 유지. Git = v1.2 Runtime = v1.1 방법 2 GitOps Repository도 자동으로 이전 버전으로 Revert. Git v1.2 | v Git v1.1 Production 환경에서는 이 둘의 의미를 명확하게 구분해야 한다. 55. GitHub Actions에서 자동 Rollback을 직접 수행하면 안 되는 이유 GitHub Actions가 Kubernetes에 직접: kubectl rollout undo 를 실행하도록 만들 수도 있다. 하지만 GitOps 구조에서는 권장되지 않는다. 왜냐하면: Git | +-- v1.2 Kubernetes | +-- v1.1 처럼 상태가 달라질 수 있기 때문이다. GitOps에서는 가능한 한: Git | v Argo CD | v Kubernetes 흐름을 유지하는 것이 중요하다. 56. Production 권장 구조 Production에서는 다음처럼 역할을 분리하는 것이 좋다. GitHub Actions CI 담당 - Test - Build - Scan - Push Image - GitOps 변경 Argo CD CD 담당 - Sync - Drift Detection - Self Heal Argo Rollouts Progressive Delivery 담당 - Canary - Traffic Weight - Analysis - Abort Prometheus 자동 상태 판단 Grafana 운영자 Dashboard Loki Log 분석 Tempo Trace 분석 이렇게 하면 각 시스템의 책임이 명확하다. 57. Canary Traffic Dashboard 실제 운영 Dashboard에서는 다음을 한 화면에 보여주는 것이 좋다. +------------------------------------------------------+ | CANARY DEPLOYMENT | +------------------------------------------------------+ | | | Rollout Status Progressing | | Current Weight 25% | | | +------------------------------------------------------+ | Stable Traffic 75% | | Canary Traffic 25% | | | +------------------------------------------------------+ | Canary 5xx 0.31% | | Threshold 1.00% | | | +------------------------------------------------------+ | Canary P95 220ms | | Threshold 500ms | | | +------------------------------------------------------+ | Canary Pods 2 | | Stable Pods 4 | | | +------------------------------------------------------+ 이 Dashboard만 봐도 현재 배포 상태를 빠르게 파악할 수 있다. 58. 운영자가 장애를 분석하는 순서 실제 장애가 발생하면 다음 순서가 유용하다. 1단계 Grafana 확인 5xx 증가? P95 증가? Traffic 이상? 2단계 Prometheus 확인 Canary만 문제인가? Stable도 문제인가? 3단계 Loki 확인 ERROR Exception Timeout Database Redis 4단계 Tempo 확인 어느 Span이 느린가? 5단계 Kubernetes 확인 kubectl get pods -n app kubectl get rollout -n app kubectl describe rollout fastapi -n app 6단계 Argo Rollouts 확인 kubectl argo rollouts get rollout fastapi -n app 7단계 필요하면 Abort kubectl argo rollouts abort fastapi -n app 59. 전체 장애 대응 구조 User | v Ingress | v Canary | v FastAPI | +----------+----------+ | | | v v v Metrics Logs Traces | | | v v v Prometheus Loki Tempo | | | +----------+----------+ | v Grafana | v Operator | v Argo Rollouts | v Abort | v Stable 60. 최종 GitHub Actions Pipeline 최종적으로 GitHub Actions는 다음 구조가 된다. git push | v Checkout | v Unit Test | v Docker Build | v Security Scan | v Push Registry | v Checkout GitOps | v Update values.yaml | v Git Commit | v Git Push Argo CD는: GitOps Change | v Argo CD | v Sync Argo Rollouts는: New Version | v 10% | v Analysis | v 25% | v Analysis | v 50% | v Analysis | v 100% 61. 최종 완성 구조 모든 내용을 하나로 합치면 다음과 같다. Developer | | git push v GitHub Application | v GitHub Actions | +--------------+--------------+ | | v v Test Docker Build | v Container Registry | v GitOps Repo | v Argo CD | v Argo Rollouts | +---------+---------+ | | v v Stable Canary 90% 10% | | +---------+---------+ | v Nginx Ingress | v Users Observability FastAPI | +---- Metrics ----> Prometheus | | | v | Analysis | | | v | PASS / FAIL | +---- Logs -------> Loki | | | v | Grafana | +---- Traces -----> OTel Collector | v Tempo | v Grafana 62. 가장 중요한 핵심 이번 실습에서 반드시 기억해야 할 것은 다음이다. 첫 번째. Service 두 개 != Traffic Split 실제 Canary Traffic을 제어하려면 Traffic Routing이 필요하다. 두 번째. Canary Metric != 전체 Metric Canary 전용 label 또는 다른 안정적인 식별 기준을 사용해 Canary 상태만 측정해야 한다. 세 번째. Prometheus 는 단순 모니터링 도구가 아니라 Argo Rollouts의 자동 배포 검증에도 사용할 수 있다. 네 번째. Grafana 는 사람이 전체 상태를 확인하는 Dashboard 역할을 한다. 다섯 번째. Loki 는 Metric만으로 알 수 없는 실제 오류 내용을 확인한다. 여섯 번째. Tempo 는 하나의 Request가 어느 서비스 또는 Database 구간에서 느려졌는지 추적한다. 일곱 번째. GitHub Actions 는 Kubernetes에 직접 배포하기보다는 Application Build와 GitOps Repository 변경을 담당하게 만들 수 있다. 여덟 번째. Argo CD 는 Git을 Kubernetes의 Desired State로 연결한다. 아홉 번째. Argo Rollouts 는 실제 Runtime에서 Canary Traffic을 단계적으로 증가시키고 Prometheus Analysis 결과에 따라 다음 단계로 진행하거나 Abort할 수 있다. 63. 최종 운영 흐름 결국 우리가 만드는 시스템은 다음 한 줄로 표현할 수 있다. Code → GitHub Actions → Docker Image → GitOps → Argo CD → Argo Rollouts → Nginx Ingress → 10% → Prometheus → 25% → Prometheus → 50% → Prometheus → 100% → Production 장애가 발생하면: Canary | v Prometheus | +---- 5xx 증가 | +---- P95 증가 | v Analysis Failed | v Argo Rollouts Abort | v Stable 100% | +---- Loki → 오류 로그 | +---- Tempo → 장애 Trace | v Grafana → 운영자 분석 이 구조가 완성되면 단순한 Kubernetes 배포를 넘어 Progressive Delivery + GitOps + Observability 기반의 실제 운영형 DevOps/SRE 플랫폼을 직접 구축한 것이 된다. 64. 다음 단계 이제 이론적으로 필요한 구성은 거의 모두 연결되었다. 다음 실전 단계에서는 위 YAML을 단순 예제로 보는 것이 아니라 실제로 다음 순서대로 구축하면 된다. 1. Kubernetes Cluster ↓ 2. Nginx Ingress Controller ↓ 3. Argo CD ↓ 4. Argo Rollouts ↓ 5. Prometheus + Grafana ↓ 6. Loki ↓ 7. OpenTelemetry Collector + Tempo ↓ 8. FastAPI + PostgreSQL + Redis ↓ 9. Helm Chart ↓ 10. Nginx Ingress Traffic Routing ↓ 11. Canary 10 → 25 → 50 → 100 ↓ 12. Prometheus Analysis ↓ 13. Grafana Dashboard ↓ 14. Loki / Tempo 장애 분석 ↓ 15. GitHub Actions ↓ 16. GitOps 자동 변경 ↓ 17. Argo CD 자동 Sync ↓ 18. Canary 자동 Abort 테스트 최종 목표는 정상 배포 테스트와 고의적인 장애를 발생시키는 실패 배포 테스트를 모두 수행하는 것이다. 예를 들어 Canary v2에서 의도적으로 HTTP 500을 발생시키면: GitHub Push ↓ GitHub Actions ↓ Docker Image ↓ GitOps ↓ Argo CD ↓ Argo Rollouts ↓ Canary 10% ↓ HTTP 5xx 증가 ↓ Prometheus Analysis FAILED ↓ Argo Rollouts ABORT ↓ Stable 100% ↓ Loki에서 ERROR 확인 ↓ Tempo에서 문제 Trace 확인 ↓ Grafana에서 전체 상황 확인 여기까지 직접 성공하면 CI/CD → GitOps → Canary → Observability → 자동 장애 대응이라는 하나의 완성된 Kubernetes 운영 플랫폼을 구축한 것으로 볼 수 있다.

댓글

아직 댓글이 없습니다.

로그인 후 댓글을 남길 수 있습니다.