Hybrid Multi-Cloud · Observability 대표 프로젝트 · 4인 팀

AX 환경을 위한 ERP 솔루션 기반
멀티 하이브리드 클라우드 인프라 자동화 & Observability 체계 구축

AI가 수요를 예측하고 발주를 추천하는 식품 유통 ERP를 받치는 인프라입니다.
누가 무엇을 건드렸는지, 어디에 부하가 걸리는지, 요청 하나가 어디서 느려지는지를 확인하기 쉽게 구축했습니다.

기간 26.04.01 ~ 26.06.26 구성 AWS 멀티리전 + Azure DR 범위 보안과 감사, 인프라 모니터링, 애플리케이션 관측
AWSAzureTerraform EKSHelmPrometheus GrafanaFluent BitOTel · X-Ray CloudTrailLambdaGlue / Athena IRSABedrock
3
직접 설계한 레포
39
커스텀 패널
60+
트러블슈팅 해결
100%
담당 레포 IaC
개선 성과 누락 → 매일비용 알림 3차 재설계 24h → 8h장애 기록 공백 단축 끊김 → 4노드분산 추적 전 구간 연결

00 — Docs & Demo

프로젝트 자료 & 데모 영상

핵심 기능이 실제로 동작하는 모습을 편집한 1분 20초 영상입니다. 구조와 구현 근거, 구현 화면, 트러블슈팅 등은 아래 섹션에 있습니다.

프로젝트 시연: 데모 영상 💡 세부 동작을 자세히 보시려면 0.75배속 재생을 추천합니다

포트폴리오 정리 자료: PDF

📋 AX 환경 ERP 기반 멀티 하이브리드 클라우드 인프라 & Observability ⬇ PDF 다운로드 ↗ 새 탭에서 크게 보기

PDF를 불러올 수 없습니다. 아래 버튼으로 다운로드해서 확인해 주세요.

⬇ PDF 다운로드
📚 팀 전체 발표 자료: 풀버전 PDF펼치면 담당 발표 파트부터 열립니다
프로젝트 전 영역(앱, AI, 인프라, 관측) 맥락 참고용 전체 슬라이드 ⬇ 전체 PDF 다운로드 ↗ 새 탭에서 크게 보기
↓ 웹페이지 계속 보기: 01 개요부터

01 — Overview

프로젝트 개요 & 목표

AI가 수요 예측과 발주 추천까지 맡는 ERP, 곧 AX 환경입니다.
이를 안정적으로 운영하기 위한 하이브리드 멀티클라우드 위에 로그와 메트릭, 추적 3축을 올렸습니다.

문제

냉동식품 ERP에는 재고와 주문, 현장 센서가 얽혀 있습니다. 여기에 Bedrock 기반 AI까지 붙습니다. 장애가 어디서 시작됐는지 추적하기 어렵습니다. 콘솔 클릭으로 만든 인프라는 멀티 PC와 팀 협업 환경에서 재현이 어렵고, 비용과 보안 사고는 사후에야 발견됐습니다.

접근

로그와 메트릭, 추적 3축은 각각 가장 잘 맞는 도구에 붙였습니다. 대시보드와 알람, 데이터소스까지 jsonencode로 코드화했습니다.

02 — Architecture

아키텍처 구성

AWS 멀티리전을 메인, Azure를 재해복구 백업으로 두고 EKS와 관측 3축, IoT 파이프라인을 하나의 그림으로 이었습니다.

StockOps 하이브리드 멀티클라우드 아키텍처 다이어그램

AWS 서울 · 오하이오 멀티리전에 Azure DR을 붙인 구조입니다

AWS · ap-northeast-2

서울 (메인)

EKS seoul-cluster Grafana/Prometheus 호스트, ALB+ACM HTTPS, IoT/보안/비용 파이프라인

AWS · us-east-2

오하이오 (확장)

EKS 클러스터 + Prometheus 메트릭 수집(PodMonitor) · 내부 NLB로 노출 → VPC 피어링으로 서울 Grafana가 직접 쿼리

Azure · Korea Central

재해복구 (DR)

CloudTrail 로그 Blob 백업(하루 3회) · Function → Log Analytics → Monitor Workbook 페일오버 대시보드

영역별 상세 아키텍처: 보안 · 인프라 · 관측

03 — Observability

로그 · 메트릭 · 추적 3축 설계

"무엇이" "얼마나" "어디서" 느려졌는가는 서로 다른 질문입니다. 질문마다 가장 잘 맞는 도구를 붙였습니다. 로그와 메트릭, IoT는 하나의 Grafana로 모으고 추적은 X-Ray에서 요청 단위로 따라갑니다.

📜

Logs · 무슨 일이

Fluent Bit → CloudWatch

앱 stdout
Fluent Bit (DaemonSet)
CloudWatch Log Group (api, ai)
Grafana 검색어 · 레벨 변수

WHY서비스별(api/ai)로 로그 그룹을 나누고, 검색어와 레벨 변수로 여러 로그그룹을 한 번에 필터링해 콘솔보다 빠른 통합 뷰를 만들었습니다.

📈

Metrics · 얼마나

Prometheus → Grafana

/actuator/prometheus · /metrics
ServiceMonitor (30s)
kube-prometheus-stack
Grafana 대시보드 (코드화)

WHYSpring Boot는 Actuator로, FastAPI는 instrumentator로 지표를 냅니다. JVM 힙은 물론 Bedrock 장애 때 폴백을 트리거하는 회로차단기 상태까지 수치로 잡습니다.

🔎

Traces · 어디서

OTel → ADOT → X-Ray

OTel SDK (api, ai)
ADOT Collector (OTLP 4317/4318)
AWS X-Ray
Service Map · Waterfall

WHY요청 하나가 보안필터와 컨트롤러, DB를 지나 api에서 ai-module까지 흐르는 구간을 ms 단위로 쪼개 병목을 짚어냅니다.

+ IoT 센서
IoT Core Firehose (15m) S3 Glue 카탈로그 · 파티션 프로젝션 Athena Grafana
온도, 습도, 기압, PM2.5, PM10, 도어, 재실 7종 MSCK 불필요

04 — Dashboards

Grafana 대시보드 5종 · 39개 커스텀 패널

데이터소스별로 나눠 붙인 커스텀 대시보드로, 패널 정의 전체가 Terraform 코드입니다.

🏭 StockOps 인프라 현황Prometheus

13 panels

노드 CPU/메모리 게이지Running/Failed/Pending Pods네트워크 송수신Pod 재시작서비스별 Pod 상태
📈 StockOps 애플리케이션 메트릭Prometheus

9 panels  ·  api 6 + ai 3

처리량 · 에러율 · 응답시간JVM 힙HikariCPBedrock 회로차단기AI p95 · 캐시적중률
🌡️ StockOps IoT 센서 현황Athena

7 panels

온도습도기압PM2.5 · PM10도어 · 재실
🛡️ StockOps WAF 보안 로그CloudWatch

7 panels  ·  Multi-Region WAF

총 차단(BLOCK)총 탐지(count 모드)공격 소스 IP Top 10룰별 건수
📜 StockOps 애플리케이션 로그CloudWatch

3 panels

API 로그AI 로그WARN/ERROR 필터

+ Node Exporter · K8s Cluster/Pod 공식 템플릿 대시보드 연동

실제 운영 화면

05 — Distributed Tracing

분산 추적: 요청 하나를 ms 단위로 분해

OTel SDK가 심은 컨텍스트를 ADOT Collector가 모아 X-Ray로 보냅니다. 질문 하나가 Bedrock 대화에서 Prophet 예측을 거쳐 RDS까지 이어지는데, 이 체인이 단일 trace 4노드로 잡힙니다. 계측된 HTTP 클라이언트가 W3C traceparent를 전파하기 때문입니다. 아래는 수집한 트레이스를 재구성한 waterfall입니다.

client stockops-api ai-module Database
total ≈ 1.66s
인증 · 보안필터
(Spring Security)
120ms
컨트롤러 · 요청검증
90ms
api → ai-module
원격 호출
500ms
prophet 수요예측
(ai-module)
690ms
DB 조회 · 결과 적재
260ms

디버깅 기록. prophet을 직접 부르는 generate 경로의 trace가 빌드 회귀로 끊겨 ai 세그먼트의 부모가 전부 dangling 처리되고, 한 trace에 세그먼트가 220개씩 쌓였습니다. 소스는 정상인데 배포 이미지에 계측 fix가 빠진 빌드 산출물 ↔ 소스 불일치였습니다. 같은 ai를 부르되 계측된 HTTP 클라이언트를 타는 Bedrock 어시스턴트 경로로 우회하자 개별 트레이스가 4노드로 깔끔하게 이어졌습니다. 두 경로의 차이는 결국 "HTTP 클라이언트가 계측됐는가"였고, 그것을 끝까지 추적해 우회 경로를 찾아냈습니다. 추적이 붙자 예측 계산에 690밀리초, 원격 호출에 500밀리초가 쓰인다는 게 숫자로 드러났습니다.

AWS X-Ray Trace Map과 세그먼트 타임라인 구현 화면
측정값X-Ray Trace Map: 클라이언트 → stockops → ai-module → DB 노드 연결과 bedrock-assistant-converse 세그먼트 타임라인. 어시스턴트 경로의 구간별 분해로 이 경로의 병목이 Bedrock LLM 추론임을 정량 확인 (위 워터폴의 수요예측 경로와는 별개 트레이스)

06 — Implementation

구현 4개 영역

관측에서 시작해 배포 자동화와 보안 감사, 비용 거버넌스까지 운영을 지탱하는 네 영역을 직접 설계하고 구현했습니다.

01 관측 체계 (Observability 3축) siseon-infra-monitoringsiseon-observability

로그와 메트릭, 추적 3축을 공식 템플릿 없이 SDK 계측부터 대시보드 코드까지 직접 짰습니다.

  • kube-prometheus-stack을 Helm과 Terraform으로 배포했습니다. Prometheus와 Grafana, Alertmanager가 한 번에 구성됩니다
  • Grafana 대시보드 전체를 jsonencode로 코드화했습니다(GitOps). 노드 게이지부터 서비스 상태까지 한 화면에 모았습니다
  • 앱 메트릭은 Spring Boot /actuator/prometheus와 FastAPI /metrics에서 ServiceMonitor(30초 주기)로 걷습니다. 처리량과 에러율, 응답시간은 물론 Bedrock 회로차단기 상태까지 걷습니다
  • 분산 추적은 OTel에서 ADOT Collector를 거쳐 X-Ray로 보냅니다. 요청별로 보안필터와 DB 구간을 waterfall로 분석합니다
  • IoT 센서 데이터는 S3에 쌓고 Glue 카탈로그와 Athena 파티션 프로젝션(2026–2030)을 거쳐 Grafana로 보냅니다
  • Alertmanager 알람 4종을 Gmail SMTP로 보내고, blackhole로 EKS 컨트롤플레인 노이즈를 눌렀습니다. k6 부하 테스트로 대시보드와 알람을 검증했습니다
02 배포 자동화 (IaC / GitOps) 3개 레포 공통

콘솔 수작업 없이 terraform apply 한 번으로 같은 관측 환경이 재현됩니다.

  • S3 Remote Backend를 레포별 키로 분리해 멀티 PC tfstate 동기화 문제를 풀었습니다
  • 레포 간 배포 순서를 설계했습니다. security를 먼저 올리고 observability, infra-monitoring 순으로 이어집니다
  • Helm 차트를 helm_release로 선언적 관리 · ServiceMonitor CRD 의존성을 -target 단계 배포로 해결
  • Grafana 권한은 Node Role 대신 IRSA로 줬습니다. ServiceAccount에 IAM Role을 직접 붙여 서비스별 권한을 따로 분리했습니다
  • 관측 노출을 NLB → ALB + ACM으로 전환해 grafana.siseon.live HTTPS 제공
03 보안 / 감사 siseon-security

콘솔 로그인과 리소스 삭제가 실시간 Teams 알림으로 잡히고, 감사 로그는 Azure로 이중 백업됩니다.

  • CloudTrail 로그가 CloudWatch와 Subscription Filter를 거쳐 Lambda로 가고, Power Automate를 통해 Teams로 실시간 전달됩니다. 콘솔 로그인과 리소스 삭제를 채널별로 나눠 보냅니다. AWS 서비스 자동작업은 sourceIPAddress로 걸러 노이즈를 줄였습니다
  • 재해복구는 S3의 CloudTrail 로그를 Azure Blob으로 하루 3회 백업합니다. 동기화 주기를 하루 1회에서 3회로 당겨 장애 시점 기록 공백을 24시간에서 8시간으로 줄였습니다. Azure Function과 Log Analytics를 거쳐 Monitor Workbook 페일오버 대시보드까지 이어집니다
  • 멀티클라우드 SSO: Azure Entra ID → AWS SAML Federation (Azure Free 플랜 한계를 IdP 방향 전환으로 우회)
  • S3 Lifecycle로 로그 보관 비용을 줄였습니다. 30일이 지나면 IA로, 90일이면 Glacier로 옮기고 365일에 삭제합니다
  • WAF 멀티리전 로그를 Grafana 보안 대시보드로 모았습니다
04 비용 거버넌스 siseon-security 내 비용 모듈

비용 알림 누락의 근본 원인을 3차 재설계로 해결해, 매일 전일 사용 비용을 확인합니다.

  • "알림이 안 온다"의 근본 원인을 좇아 비용 모니터링을 3차에 걸쳐 재설계한 최종안은 EventBridge와 Lambda, Cost Explorer API로 매일 09시에 전일 사용 비용을 직접 조회해 임계값을 넘으면 Teams로 보냅니다
  • 서울 단일 리전을 오하이오까지 확장하자 예상 비용이 월 48달러에서 126달러로 2.6배가 됐습니다. 임계값을 그에 맞춰 현실화했습니다
1차와 2차 시도의 한계와 우회 의사결정: 재설계 과정 펼쳐 보기

1차

CloudWatch Billing Alarm
(us-east-1) → SNS → Lambda

크로스리전 Lambda Permission 실패. Billing은 us-east-1 전용

2차

AWS Budgets DAILY
→ SNS → Lambda

동일 ALARM 상태면 재발송이 없어 첫날만 알리고 이후에는 알림이 오지 않습니다

3차 · 현재

EventBridge + Lambda
+ Cost Explorer API

매일 KST 09:00 전일 사용 비용을 직접 조회 → 상태 개념 없이 임계값 초과 시 Teams 발송

멀티리전 비용 $48 → $126.5 일 임계값 $8 월 임계값 $135 크로스리전 제약 → 글로벌 서비스로 우회

07 — Tech Stack

핵심 적용 기술

IaC / GitOps

TerraformS3 Remote BackendHelmhelm_release

Container

Amazon EKSKubernetesIRSAALB + ACM

Metrics

PrometheusGrafanaServiceMonitorAlertmanagerPromQL

Logs / Traces

Fluent BitCloudWatch LogsOpenTelemetryADOTAWS X-Ray

Data / IoT

IoT CoreFirehoseGlueAthena파티션 프로젝션

Security / Cost

CloudTrailLambdaEventBridgeCost ExplorerWAF

Azure (Multi-Cloud)

Blob StorageFunctionsLog AnalyticsMonitor WorkbookEntra ID (SAML)

관측 대상 앱

ReactSpring BootFastAPIRedisresilience4jBedrockk6

08 — Troubleshooting

장애 대응 & 트러블슈팅

3개 레포에 걸쳐 60여 건을 기록했고, 그중 분류별 대표 사례를 문제와 원인, 해결 순서로 정리했습니다.

관측

전 패널 "No data" + connection refused

Prometheus가 OOMKilled. WAF 로그와 멀티리전 trace 볼륨으로 메모리 부족. limit을 512Mi → 1.5Gi로 상향해 정상화

배포

Grafana 503 Service Unavailable (간헐)

ALB 헬스체크 경로 /가 302 리다이렉트 → 타깃 unhealthy. healthcheck-path: /api/health로 변경

관측

Grafana CrashLoopBackOff

sidecar와 커스텀 데이터소스 중복 등록 충돌 → defaultDatasourceEnabled=false

관측

ServiceMonitor가 Service를 못 찾음

selector는 Deployment가 아닌 Service metadata label을 봄 → Service에 app=stockops-api 라벨 추가

관측

AI 캐시 적중률이 idle에서 NaN/0%

increase()의 0/0=NaN 문제를 누적 ratio PromQL로 안정화

관측

Bedrock 회로차단기 패널이 파드별 중복 표시

max() 집계로 단일 시리즈화. "한 파드라도 open이면 위험"으로 통합

배포

NLB가 pending / internal로 생성

서브넷 kubernetes.io/role/elb 태그 추가 + aws-load-balancer-scheme: internet-facing 어노테이션

배포

Load Balancer Controller IAM 권한 부족

DescribeListenerAttributes 등 누락 액션을 LBC 정책에 보강

배포

ServiceMonitor CRD가 plan 단계에 없음

클린 배포 시 CRD 미존재 → -target=helm_release로 먼저 설치 후 전체 apply

배포

Helm 릴리스 state 충돌로 apply 실패

helm uninstall + terraform state rm 후 재배포로 정합성 복구

배포

Grafana가 EC2 IMDS 자격증명을 못 가져옴

IRSA로 ServiceAccount에 IAM Role을 직접 연결해 근본 해결

추적

X-Ray Service Map에 서비스 간 화살표가 안 생김

실제 분산 호출 + 시드 데이터(15일치 수요 이력)가 있어야 4노드 생성됨을 규명

추적

generate 경로의 trace가 끊김 (빌드 회귀)

계측 미반영 이미지 → Bedrock 어시스턴트 경로로 우회해 4노드 정상 트레이스 확보

추적

Athena named query를 Terraform으로 자동화 불가

aws_glue_catalog_table 리소스로 전환해 apply 한 번에 테이블 등록

보안

Teams 웹훅이 갑자기 중단

O365 커넥터 종료 → Power Automate HTTP 트리거로 알림 파이프라인 재구축

보안

보안 알림이 누락됨

CloudWatch Alarm은 상태 변화가 없으면 발송하지 않음 → Subscription Filter → Lambda 실시간 감지로 전환

비용

AWS Budgets가 동일 상태에서 재발송 안 함

EventBridge + Cost Explorer API로 매일 전일 비용을 강제 체크

비용

크로스리전 Lambda Permission 실패

글로벌 서비스(Budgets)로 우회해 리전 종속성 제거

관측

WAF 공격 시도가 대시보드에 안 보임

룰이 count 모드라 ALLOW로 기록됨 → BLOCK 패널 + count-mode 룰 파싱 패널 2개로 분리

위는 대표 사례이고, 전체 60여 건은 각 레포의 troubleshooting 문서에 기록해 뒀습니다.

← 포트폴리오로 돌아가기