Search
📄

Come2us #3 - Infra & DevOps BluePrint

Date
2025/11/30
Category
Goorm
Tag
Architect
Goorm
 Part: Infra & DevOps
목차

1. 개요

프로젝트명: COME2US (Sprint #3)
목표:
ECS 기반 2차 아키텍처를 Kubernetes(EKS) 기반으로 확장
GitOps 기반 선언적 배포 구조 정립 (GitHub Actions + ArgoCD)
서비스 메시에 Istio 도입하여 보안(mTLS)·트래픽 제어·관찰성 확립
Helm 기반 Kubernetes Manifest 템플릿화
Kafka(MSK) 기반 이벤트 시스템을 결제(Payment) 서비스 중심으로 부분 도입
인프라 자동화는 Terraform 중심으로 유지
Istio를 활용한 Canary 배포 전략 도입
Karpenter 기반 자동 노드 프로비저닝 도입
핵심 구성 계층
계층
주요 구성 요소
Network Layer
VPC, Subnet(Public/App/Data), NAT, LB, Route53
Compute Layer
EKS, NodeGroup, Karpenter
Service Layer
Spring Boot Microservices, Istio, Envoy Sidecar, Helm
Data Layer
RDS(PostgreSQL), Redis, MSK(Kafka), S3
DevOps Layer
GitHub Actions(CI), ArgoCD(CD), Terraform, Helm
Observability Layer
CloudWatch, Prometheus, Grafana, Loki, Tempo(Tracing)

2. 시스템 아키텍처 요약

아키텍처 다이어그램

주요 변경점 요약 (ECS → EKS 전환)

영역
2차 프로젝트 (기존)
3차 프로젝트 (변경 버전)
컨테이너 오케스트레이션
ECS Fargate
EKS + Karpenter
배포 체계
Jenkins + Terraform
GitHub Actions(CI) + ArgoCD(CD)
서비스 디스커버리
Eureka
K8s Service + Istio Mesh
트래픽 라우팅
Spring Cloud Gateway
Istio Ingress Gateway + Envoy
App 설정 관리
Config Server
Helm Values + ConfigMap/Secret
이벤트 시스템
-
Kafka(MSK) 도입 (결제 서비스, 로그 파이프라인)
관찰성
CloudWatch 중심
Prometheus + Grafana + Loki + Tempo
배포 전략
Blue/Green
Canary Deployment (Istio 기반)

3. 네트워크 구조

2차 프로젝트와 동일한 2-AZ 구성
Public, Private(Application), Private(Database) Subnet을 분리하여 트래픽 및 보안 계층화
기존과 동일
Istio Ingress Gateway는 LoadBalancer Service이며, AWS NLB 생성
모든 서비스 간 통신은 Envoy Sidecar를 통해 처리
구분
역할
구성 계획
Public Subnet
외부 노출용 리소스
- ALB(Grafana, ArgoCD) - NLB(Istio Ingress Gateway) - NAT
Private Subnet(Application)
내부 서비스
EKS Worker Node
Private Subnet(Database)
데이터 리소스
RDS, Redis, MSK
Routing
IGW / NAT
Outbound → NAT
DNS
Route53 + ACM
HTTPS 통신 기반 인증서 관리

4. 애플리케이션 계층

구성 요소

요소
설명
EKS Cluster
모든 MSA 서비스의 런타임 환경
NodeGroup + Karpenter Autoscaling
On-demand 최소 구성 + Karpenter 통한 Autoscaling
Pod / Deployment / Service
내부 서비스들은 ClusterIP를 통해 노출
Istio (Service Mesh)
mTLS, Traffic Splitting, Routing, Circuit Breaker
Envoy Sidecar
Pod 간 통신 프록시
Helm Charts
Microservice 템플릿 관리
ArgoCD
GitOps 기반 지속적 배포(CD)

서비스 흐름

Client → Route53 → Istio Ingress Gateway → Envoy Sidecar → K8s Service → Microservice Pod → RDS / Redis / MSK(Kafka) → Envoy Sidecar → Istio Ingress Gateway → Client 응답
Plain Text
복사

5. 데이터 계층

기존과 동일한 데이터베이스를 유지하며, MSK(Kafka)를 도입하여 이벤트 기반 메시징 처리
구성요소
설계 의도
RDS (PostgreSQL)
Multi-AZ 구성 (Writer: AZ-a, Standby: AZ-b, Reader 다중 구성)
Redis (ElastiCache)
- Session Redis (세션 + 비영속 데이터 저장소) - Cache Redis (캐시 저장소)
MSK (Kafka)
- 결제(Payment) 서비스 적용 - 로그 파이프라인 적용
S3
- 이미지 저장소 및 정적 오브젝트 저장 - VPC Endpoint 통한 사설 연결 구성

6. 이벤트 기반 아키텍처 - MSK

MSK(Kafka)는 결제 승인 결과를 비롯한 주문·상품·쿠폰 서비스 간 SAGA 보상 트랜잭션을 구현하기 위한 핵심 메시징 플랫폼으로 사용한다.
본 프로젝트에서는 결제 서비스 중심의 부분 도입을 시작으로, 점진적으로 EDA를 확장한다.

6.1 도입 배경

목적
설명
SAGA 보상 트랜잭션 처리
결제 승인 실패 시 주문/재고/쿠폰 원복 처리
서비스 간 강결합 제거
동기 HTTP 호출 제거 → 비동기 메시지 기반 통신
장애 전파 차단
외부 서비스 실패가 주문 서비스까지 전파되지 않도록 격리

6.2 이벤트 흐름

결제 승인 성공 흐름

1.
payment-service → payments-paid 발행
2.
order-service consume → 주문 상태 PREPARING 로 변경

결제 승인 실패(보상 흐름)

1.
payment-service → payments-failed 발행
2.
order-service consume → 주문·쿠폰 원복 (idempotent)
3.
order-service → orders-failed 발행
4.
product-service consume → 재고 롤백

6.3 Topic 설계

이벤트
Topic 명
발행 주체
소비 주체
결제 승인 성공
payments-paid
payment-service
order-service
결제 승인 실패
payments-failed
payment-service
order-service
주문 보상 실패
orders-failed
order-service
product-service

6.4 Kafka 클러스터 구성

항목
이유
Broker 개수
3개
Quorum(2) 확보, 고가용성
Partition 수
3개
Broker 수의 배수 → Leader 분산
Replica 수
3개
장애 시에도 메시지 유실 방지
보관 기간
7일
비정상 이벤트 재처리 대비

6.5 Consumer Group 전략

서비스별 1 Consumer Group
주문(Rebalancing) 문제를 줄이고 안정적인 메시지 처리를 위해
order-service-group, product-service-group 형태로 구성
같은 그룹 내에서는 메시지 병렬성 = Partition 수
현재 Partition=3 → 3개 인스턴스까지 병렬 처리 가능
Exactly Once 보장
Consumer는 메시지를 처리 성공 시 명시적으로 Commit
실패 시 Commit하지 않고 DLQ로 이동 → 재처리 가능

6.6 DLT (Dead Letter Topic)

Kafka에서 Consumer가 메시지 처리에 실패할 경우, 해당 메시지는 DLT(Dead Letter Topic)
으로 이동하며 재처리 또는 수동 복구를 위한 근거 데이터로 사용된다.

DLT 적용 포인트

실패 위치
DLT 활용 이유
order-service (payments-failed 처리 실패)
주문/쿠폰 원복 실패 시 반드시 재처리 필요
product-service (orders-failed 처리 실패)
재고 원복 실패 시 비즈니스 장애 유발

DLT 메시지 스키마

1) payments.failed 처리 실패 이벤트
필드
내용
orderId
주문 ID
paymentKey
PG 결제 키
errorSource
order-service or product-service
errorCode
내부 에러 코드
errorMessage
오류 메시지2) orders-failed 처리 실패
timestamp
실패 발생 시각
2) orders.failed 처리 실패 이벤트
필드
내용
orderDetailId
주문 상세 ID
optionValueId
옵션 ID
quantity
원복해야 하는 수량
paymentKey
PG 결제 키
errorSource
order-service or product-service
errorCode
내부 에러 코드
errorMessage
오류 메시지

DLT 활용 전략

1.
DLT Consumer를 통한 자동 재처리
일시적 장애(잠깐의 DB 락, 네트워크 지연 등)는 재처리 시 성공 가능
주문/재고 시스템 데이터 정합성을 위해 반드시 필요
2.
운영자 수동 재처리
구조적 장애(논리적 오류, 스키마 문제 등)는 수동 조치 필요
3.
DLT 모니터링
Grafana / CloudWatch에서 DLT 적재량을 모니터링해 운영 장애 조기 감지
특정 Topic의 DLT 증가 = 특정 서비스 장애로 볼 수 있음

6.7 멱등성(Idempotency) 전략

중복 메시지 처리 및 중복 결제 실행 방지를 위한 멱등성 처리 전략.

1) 결제하기 API 멱등성 – Toss Idempotency-Key

클라이언트에서 UUIDv4 기반 명등키 Idempotency-Key 생성 및 전달
토스페이먼츠가 서버 내부적으로 멱등 처리
ALREADY_PROCESSED_PAYMENT 응답 시 → 보상 트랜잭션 실행 금지

2) Consumer 멱등성

Kafka 메시지는 At-Least-Once가 기본이므로 동일 메시지가 중복 전달될 가능성 존재
Consumer는 DB 상태 기반 멱등성 체크 필요
예시 (order-service):
if (order.status == FAILED) return if (order.status == PREPARING) return
Java
복사

6.8 Producer 발행 실패 처리

방안 1) Transactional Outbox Pattern

DB 업데이트 + Event 저장을 하나의 트랜잭션으로 묶어 원자성 보장
장점:
Kafka 장애에도 데이터 유실 없음
재처리 가능

방안 2) 발행 실패 재시도 테이블 + 스케줄러

publishStatus = FAILED 마킹
스케줄러가 1분 간격 재시도
Exponential Backoff 적용 가능

6.9 PENDING 장기 체류 주문 스케줄러

결제 지연·외부 서비스 오류로 인해 5분 이상 PENDING 상태로 남아있는 주문 정리 로직

실행 전략

스케줄 주기: 1분
타임아웃 기준: 5분

처리 방식

1.
5분 이상 PENDING 주문 조회
2.
주문 상태 FAILED로 변경
3.
쿠폰 / 재고 롤백 요청 발행
4.
DB 업데이트 후 Kafka에 보상 이벤트 발행

개선 방안

1.
외부 시스템 호출을 비동기 이벤트 기반으로 전환 (최적 방식)
주문 서비스는 DB 업데이트 + Kafka 이벤트 발행으로 작업 종료
product/payment 서비스가 토픽을 구독하여 자체적으로 롤백 실행
응답 대기 시간이 없으므로 안정성 + 성능 개선
2.
청크 처리 (대량 주문 대비)
PENDING 주문을 전체 조회하지 않고 chunk 단위로 처리
시스템 부하 감소
실패 시 특정 chunk만 재처리 가능

7. CI/CD 파이프라인

GitOps 파이프라인 다이어그램

GitHub Actions (CI)

Lint → Build → Test → Docker Build → ECR Push
Helm values 업데이트

ArgoCD (CD)

GitOps Repo 상태를 기준으로 EKS 상태 자동 동기화
Health/Sync 자동 관리
Helm-Based Release 관리
데이터 보존을 위한 EBS Volume 또는 EFS Volume 마운트 고려
ArgoCD는 GitOps 기반의 stateless 운영 모델을 사용하므로 별도의 EBS/EFS 마운트 불필요
ArgoCD는 Kubernetes 리소스를 Git 저장소를 통해 재생성할 수 있으므로, EKS 클러스터 재생성 시에도 Git 상태를 기준으로 전체 상태 복구 가능

8. 배포 전략 - Canary

우선적으로는 Istio VirtualService 기반의 수동 Canary 방식으로 운영

도입 배경

Blue/Green 대비 더 안전한 점진적 배포 제공
Istio VirtualService 기반 트래픽 분할 가능
서비스 안정성 확보를 위한 점진적 검증
GitOps 기반 배포 이력 보존

8.1 배포 흐름

1.
신규 버전 배포
2.
DestinationRule을 통한 v1/v2 Subset 정의
3.
VirtualService 기반 Canary 트래픽 설정
v1: 90%, v2: 10%
4.
Grafana + Tempo + Loki 기반 모니터링
Latency/Error, Log, Trace
5.
오류 시 Rollback
v1 = 100%
6.
정상 동작 시 트래픽 확대
10 → 30 → 50 → 100

8.2 Canary 배포 단계

단계
트래픽 비율
수행 항목
성공 기준
Phase 0
0% → 10%
신규 버전(v2) 배포, VirtualService weight 10% 적용
Pod Ready 100%, 오류 없음
Phase 1
10% → 30%
주요 API 응답 검증
Latency 증가 < 200ms, Error Rate < 1%
Phase 2
30% → 50%
실제 사용자 트래픽 점진적 반영
5xx < 0.3%, Business Error < 1%
Phase 3
50% → 100%
전체 트래픽 전환
Pod 안정화, 로그 이상 없음

8.3 Canary 실패 기준 (Rollback 조건)

Rollback은 즉시 VirtualService를 Stable(v1)로 전환하여 처리한다.
분류
조건
HTTP 오류율
5xx 비율 3% 이상 (1분 평균)
Latency 증가
평균 응답속도 200ms 이상 증가
애플리케이션 오류율
Business Error 1% 이상
Readiness 실패
신규 Pod Ready 실패
리소스 임계치
CPU > 80%, Memory > 85%

8.4 구성 요소

요소
역할
Deployment (v1/v2)
버전별 Pod
DestinationRule
Subset 정의 (labels 기반)
VirtualService
트래픽 비율 조정
Envoy Sidecar
실제 트래픽 분배 수행
ArgoCD Sync
GitOps 기반 자동 배포

8.5 고려사항 (Manual Canary 운영 관점)

항목
설명
Observability
Grafana / Loki / Tempo 통합 필요
Sticky Session
세션 일관성 확보가 필요한 API에 대한 Session Redis 호환성 검증 필요
테스트 자동화 필요성
Canary 단계별 검증을 위한 k6/JMeter 등의 API Test 구성 고려
Resource Impact
v1/v2 동시 운영으로 인한 Pod 수 증가 → HPA/Karpenter
향후 확장성
현재는 프로젝트 기간 고려하여 수동 Canary 운영 방식 적용 향수 Auto Rollback을 도입할 경우 Argo Rollouts + AnalysisTemplate 기반 확장

9. 오토스케일링 전략

9.1 Pod Autoscaling (HPA)

9.1.1 HPA 정책 기준

CPU 사용률 > 70%
Memory 사용률 > 75%
Target Metric 기반 자동 확장
Canary 배포시 v1 + v2 Pod 동시 존재 고려
Karpenter Node 생성 시간을 고려한 최소 Replica 버퍼 전략 적용

9.1.2 서비스별 HPA minReplicas 버퍼 전략

Karpenter의 Node Provisioning 시간동안 기존 Pod가 과부하되지 않도록 최소 Replica를 여유있게 유지한다.
서비스 유형
트래픽 특성
초기 구성 minReplica 버퍼
Gateway (Ingress)
외부 요청 집중, Latency 민감
평시 Pod의 150%
Order / Payment
Latency 민감, 장애 영향 큼
130~150%
Product
높은 조회 빈도
120~130%
User
일반 API
120%
AI
중요도 낮음, 사용량 적음
100~110%

9.1.3 서비스별 HPA 설정

서비스
Min~Max
특징
Gateway (Ingress)
3~6
요청 집중 구간, 안정성 중요
User/Product
2~10
조회 중심, 트래픽 변동폭 큼
Order/Payment
2~5
주문/결제 중심, 안정성 중요
AI
1~2
최소 유지

9.1.4 Requests / Limits

임시 - GPT 추천값 / 추후 모니터링 반영 조정
서비스
CPU Request
CPU Limit
Memory Request
Memory Limit
Gateway
250m
500m
512Mi
1Gi
User/Product
200m
400m
256Mi
512Mi
Order
200m
500m
512Mi
1Gi
Payment
300m
600m
512Mi
1Gi
AI
100m
300m
256Mi
512Mi

9.2 NodeAutoscaling (Karpenter)

Karpenter를 도입하여 자동 Node Provisioning을 목표로 함

9.2.1 Karpenter 도입 배경

문제
설명
ECS / 기존 EKS의 한계
Pod 증가 시 NodeGroup의 scale-out 속도가 느림
고정 노드 비용 발생
항상 Node를 유지해야 해서 비용 증가
Canary 배포 시 Pod 일시 증가
Canary 실행 시 v1+v2 Pod 동시 운영 → 노드 부족 발생
트래픽 변동성
Product, Order 서비스의 트래픽 변동 폭이 큼

9.2.2 Karpenter 동작 흐름

HPA가 Pod 증가 → 기존 Node capacity 부족 → Pod Pending 발생 → Node Provisioning (Karpenter) → Pod Scheduling 완료 → 트래픽 감소 → Idle Node 발생 → Idle Node 자동 제거 (Consolidation)
Plain Text
복사

9.2.3 Autoscaling 고려사항

Karpenter Provisioning 시간동안 기존 Pod의 과부화 방지를 위한 minReplicas 버퍼 적용
Canary 배포 시 v1/v2 Replica 동시 증가 → Karpenter 즉각 확장 필수
트래픽 감소 시 Consolidation을 통해 비용 최소화
Pod 요청(Request)이 낮게 잡히면 과도한 확장 발생하므로 적절한 Request 필요
Spot Instance 사용 고려

10. Observability

10.1 구성요소

계층
구성 요소
역할
Metrics
Prometheus
애플리케이션·Istio·Node 메트릭 수집
Logs
Fluentbit → Loki
stdout 로그 수집 및 저장
Tracing
Envoy / Spring Boot OTel → OTel Collector → Tempo
분산 트레이싱 저장
Dashboard
Grafana
Metrics / Logs / Tracing 시각화
Infra Logs
CloudWatch Logs
Node, Control Plane, EKS Infra 로그 저장

10.2 Metrics 수집 흐름

10.2.1 애플리케이션 / 서비스 메트릭

Spring Boot Actuator의 /actuator/prometheus 활용
Prometheus Operator를 사용하여 메트릭 수집
서비스별 ServiceMonitor를 통해 Scrape
데이터 흐름:
Application Pod (/actuator/prometheus) → ServiceMonitor → Prometheus → Grafana
Plain Text
복사

10.2.2 Istio (Envoy) 메트릭

Istio Telemetry v2 활성화
Prometheus가 Istio의 Envoy Proxy를 Scrape
ServiceMonitor 활용
Envoy SideCar → Prometheus (ServiceMonitor) → Grafana (Istio Dashboard)
Plain Text
복사

10.2.3 Node / 시스템 메트릭

구성요소
kube-state-metrics
node-exporter (PodMonitor 활용)
수집 지표
CPU / Memory
Pod 상태
Node 상태 / Disk I/O
네트워크 등 인프라 자원 상태 모니터링

10.3 Logs 수집 흐름

구성 요소

FluentBit DaemonSet
Loki
S3

로그 흐름

Container stdout/stderr → Fluentbit → Loki → S3 → Grafana
Plain Text
복사

Fluentbit 주요 필터

JSON Log Parser
Level 필터

10.4 Tracing 수집 흐름

Tracing은 Envoy(네트워크 레벨) + Application(비즈니스 레벨) 모두 수집하며, OTel Collector를 거쳐 Tempo에 저장

10.4.1 Envoy → Tempo(Zipkin)

1.
Envoy가 Zipkin 포맷으로 Trace 생성
Istio Proxy(Envoy)는 Zipkin 포맷 Trace를 기본 지원
Ingress Gateway, Sidecar 모두 Span 생성
2.
OTel Collector가 Zipkin 포맷 수신
Collector의 Zipkin Receiver가 Envoy에서 보낸 데이터를 수신
내부적으로 OTLP로 변환 → Tempo로 Export
3.
Collector에서 Tempo로 Export
데이터 흐름
Envoy (Zipkin) → OTel Collector (zipkin receiver) → OTel Collector (otlp exporter) → Tempo → Grafana
Plain Text
복사

10.4.2 Application → Tempo (OTLP)

Java 서비스를 OpenTelemetry Java Agent로 구성하여 OTLP/gRPC로 Trace 전송
Application (OTLP → grpc) → OTel Collector (otlp receiver) → Tempo (otlp exporter) → Grafana
Plain Text
복사

10.4.3 End-to-End 트레이싱

Envoy Span과 Application Span은 동일 Trace ID를 공유하여 하나의 전체 트랜잭션 흐름으로 결합된다.

11. 고가용성 & 장애 복구 전략

EKS Multi-AZ NodeGroup 운영
RDS Multi-AZ Failover
Redis Multi-AZ
ArgoCD Rollback
S3 Versioning
Terraform 기반 인프라 re-provision

12. 비용 관리 전략

항목
전략
EKS
NodeGroup 온디맨드 최소 유지 + Karpenter 자동 확장
Node
Consolidation으로 Idle Node 최소화
NAT Gateway
Dev/Stage 최소 구성
CloudWatch Logs
15일 보관
Redis
ClusterMode Off
MSK
결제 서비스 중심 최소 구성
ECR
Private ECR 사용