Cloud Infrastructure Portfolio

김진호

고치기 전에 먼저 측정하는 클라우드 엔지니어입니다. 단일 VM에서 p95 응답이 17초까지 늘어난 서비스를 부하 테스트로 병목을 증명한 뒤 GCP 3-Tier로 전환해 2.3초로 줄였고, 장애 시 접속이 끊기는 대신 안내 페이지가 뜨도록 DNS Failover를 구성했습니다.

김진호 프로필 사진
17s → 2.3sk6 p95 응답 시간
55%1,000 VU 동시 부하 시 CPU
3단계단일 VM에서 멀티클라우드까지
AWS SAASolutions Architect Associate

Looper 클라우드 인프라

AI 기반 일정 관리 플랫폼 클라우드 인프라 담당

2025.04 - 2025.08

AI 추론과 일반 API가 한 인스턴스에서 자원을 다투며 응답이 지연되던 구조를, 부하 테스트로 병목을 먼저 증명한 뒤 단계적으로 분리했습니다.

GCP AWS Terraform Docker / Docker Compose GitHub Actions k6 Cloud DNS Grafana
단일 VM (MVP) API, AI 추론, DB가 한 인스턴스에 공존. 추론 부하가 일반 API 응답을 끌어내림.
GCP 3-Tier 역할별 분리, Global HTTPS LB와 Instance Group 오토스케일 도입, DB를 별도 VPC로.
멀티클라우드 웹은 AWS, AI는 GCP 내부 전용. 클라우드별 DNS와 IAM 경계 분리.

측정으로 전환 근거를 만든 뒤 3-Tier로 이동

  • k6로 부하를 걸어 추론 요청이 들어올 때 일반 API가 함께 지연되는 것을 먼저 확인했습니다. 구조를 바꾸자는 주장에 근거를 붙이는 것이 목적이었습니다.
  • Global HTTPS Load Balancer와 Instance Group 오토스케일을 두고, DB를 별도 VPC로 분리해 트랜잭션 경로와 추론 경로가 자원을 다투지 않게 했습니다.
  • Terraform 초안을 작성해 서브넷, 인스턴스, IAM을 코드로 정의하고 동일 구성을 반복 재현할 수 있게 했습니다.
  • k6 결과를 InfluxDB로 보내 Grafana에서 응답 시간과 병목 구간을 시각화했습니다.
검증된 지표 17s → 2.3s k6 기준 p95 응답 시간. 1,000 VU 동시 부하에서도 CPU 약 55% 유지, 일정 API 오류는 재발하지 않았습니다.

장애 중에도 사용자에게 화면을 남기기

  • 점검이나 장애 때 접속이 그냥 끊기면 사용자는 서비스가 사라진 것으로 받아들입니다. Cloud DNS의 정책 기반 라우팅과 HTTP Health Check를 묶어 Failover를 구성했습니다.
  • 대체 경로는 Cloud Storage에 올린 정적 점검 페이지입니다. Backend Bucket으로 붙여 HTTPS로 서비스했기 때문에, 애플리케이션이 죽어 있어도 안내는 계속 뜹니다.
  • 정적 페이지를 택한 이유는 장애 상황에서 살아 있어야 하는 구성 요소를 최소로 줄이는 것이었습니다.
확인된 동작 접속 차단 없음 장애와 점검 시 연결 실패 대신 안내 페이지가 노출됩니다.

재부팅하면 죽어 있던 GPU 모델 서버 자동 복구

  • Terraform으로 GPU VM을 만들었는데, 첫 부팅에서는 CUDA 커널 모듈이 올라오지 않아 torch.cuda.is_available()False를 반환하고 nvidia-smi도 실패했습니다. IaC로 인스턴스를 만드는 것과 그 안이 쓸 수 있는 상태가 되는 것은 다른 문제였습니다.
  • FastAPI 모델 서버를 nvidia/cuda:12.1.1-cudnn8-ubuntu22.04 기반으로 컨테이너화하고, torch.cuda.is_available()nvidia-smi 이중 체크로 GPU 인식 여부를 확인했습니다.
  • 인스턴스 메타데이터의 startup-script에 docker-compose up -d를 등록해, 재부팅 이후에도 모델 서버가 스스로 복구되게 했습니다.
  • 여기서 얻은 것은 IaC의 경계였습니다. 프로비저닝은 코드로 되지만 OS 부팅 순서와 커널 로딩은 그 밖에 있고, 원격 세션이 끊기는 순간을 전제로 설계해야 합니다.
해결 방식 부팅 시 자동 기동 startup-script와 docker-compose로 재부팅 후 수동 개입 없이 모델 서버 복구.

복잡한 연결 대신 단순한 경계를 택한 멀티클라우드

  • GPU 효율은 GCP, 웹과 관리형 서비스 생태는 AWS가 유리해 AI는 GCP 내부 전용, 웹은 AWS로 나눴습니다. 모델 서버는 외부에 노출하지 않았습니다.
  • Cross-Cloud 연결로 VPN, NAT, DNS Relay를 검토했지만 내부 API 호출 방식으로 단순화했습니다. 신입 한 명이 유지보수할 수 있는 복잡도인지가 기준이었습니다.
  • 클라우드별로 DNS 구성을 분리하고, IAM과 VPC 접근 범위를 최소 권한으로 좁혀 통신 경계를 명확히 했습니다.
  • GCP에서 만든 Terraform 자산을 AWS 전환에도 재사용해 특정 클라우드에 묶이는 정도를 줄였습니다.
  • 배포와 CI/CD, 컨테이너화, kubeadm 및 EKS 설계 검토, k6 테스트, 단계별 전환 게이트(성능, 가용성, 보안)를 Cloud-Wiki에 문서로 남겼습니다.
설계 판단 내부 API 호출 VPN과 NAT 대신 단순한 구조를 택해 유지보수 비용과 보안 경계를 함께 확보.
역할 구분
팀 구성 (본인 주도 아님)

Calico와 VXLAN Overlay로 GCP와 AWS 양쪽 Kubernetes를 프라이빗 IP로 연결해 모델 호출을 내부 통신으로 처리한 구성은 팀에서 진행했습니다.

본인 담당

전환 이후 운영 안정화와 모니터링, 복구 포지션을 맡았고 단계별 전환 로드맵을 정리했습니다. 위 01 항목들이 직접 설계하고 적용한 범위입니다.

Open Source

Uvicorn / httptools HTTP/2 h2c 파서 버그

2025.05

타 팀에서 겪던 원인 불명의 오류를 함께 추적해 업스트림 파서 버그로 규명하고 패치안을 제출했습니다.

Uvicorn httptools / llhttp Spring Boot 3.2 RestClient FastAPI RFC 7230
  • 증상: 타 팀에서 Spring Boot 3.2 RestClient로 FastAPI를 호출할 때 원인 불명의 422 Unprocessable Entity가 발생했습니다. 같은 요청을 ngrok으로 우회하면 정상 동작해 재현 조건부터 불명확했습니다.
  • 원인: Java 21 HttpClient는 평문 HTTP에서 Upgrade: h2c를 기본 전송합니다. Uvicorn은 이 업그레이드를 무시하지만 httptools 파서가 upgrade 상태에 머물러 on_body 콜백이 호출되지 않고 본문이 유실됐습니다. 서버가 업그레이드를 무시하고 진행하도록 허용한 RFC 7230 §6.7 위반입니다.
  • 기여: llhttp_resume_after_upgrade()로 HTTP/1.1 파싱을 재개하는 Cython 패치안과 재현 테스트를 첨부해 httptools에 이슈를 등록했습니다.
  • 결과: Uvicorn 디스커션에 리포트한 뒤 Java 17 HttpClient와 vLLM 등 서로 다른 환경의 개발자 3명이 동일 증상을 독립 확인, 메인테이너(Kludex)가 공식 이슈 #2722로 등록했습니다.
진단 경로
422 Unprocessable Entity 증상. 검증 오류를 가리켜 직렬화 문제로 오인하게 만듭니다
Upgrade: h2c 기본 전송 Java 21 HttpClient, 평문 HTTP 구간에서만
파서가 upgrade 상태 유지 httptools (llhttp), on_body 미호출
RFC 7230 §6.7 위반 근본 원인. 설정 문제가 아닌 버그로 확정

클라이언트에서 C 파서 바인딩까지 3개 계층을 내려가 상태머신 버그로 확정

Java HttpClient는 평문 HTTP에서만 Upgrade: h2c를 보냅니다. TLS를 종료한 뒤 내부망에서 평문으로 서비스 간 호출을 주고받는 구성이 정확히 그 조건입니다. 같은 요청이 프록시를 거칠 때 정상 동작한 것도 게이트웨이가 업그레이드 헤더를 걷어내기 때문이고, 경로를 직접 호출로 단순화하는 순간 드러납니다.

내부 API 호출 구조를 택할 때 클라이언트의 프로토콜 협상 기본값까지 확인해야 한다는 것을 이 건으로 배웠습니다.

AWS 운영 경험

판단과 회고

측정이 없으면 전환을 설득할 수 없습니다

3-Tier 전환에서 가장 먼저 한 일은 아키텍처 그림이 아니라 k6 부하 테스트였습니다. 추론 부하가 일반 API를 끌어내리는 것을 숫자로 보여준 다음에야 구조를 바꿀 근거가 생겼습니다. 지금도 인프라를 건드리기 전에 무엇을 측정할지부터 정합니다.

IaC는 인스턴스까지, 그 안은 별개입니다

Terraform으로 GPU VM을 만들어도 CUDA 커널 모듈이 올라오지 않으면 모델은 뜨지 않습니다. 프로비저닝과 실행 가능 상태는 다른 문제이고, 원격 세션이 끊기는 순간을 전제로 startup-script 같은 복구 경로를 미리 넣어두어야 합니다.

유지보수할 수 있는 복잡도를 고릅니다

Cross-Cloud 연결에 VPN과 NAT, DNS Relay를 검토했지만 내부 API 호출로 단순화했습니다. Waither에서 인프라 규모에 맞지 않는 MSA 분리가 어떤 비용을 만드는지 겪은 뒤로, 동작하는 구조보다 감당할 수 있는 구조를 먼저 봅니다.

변경은 합의와 권한 설계가 먼저입니다

인프라 구조가 사전 논의 없이 변경되며 제 IAM 권한이 삭제된 일이 있었습니다. 프로젝트를 위해 새 구조를 빠르게 파악하고 운영과 복구를 맡았지만, 이후 기술 도입과 권한 분배 기준을 문서로 고정했습니다. 권한 관리는 기술이 아니라 합의의 문제였습니다.

Skills

Cloud Platform
GCP AWS Cloud DNS / Route 53 Cloud Storage / S3 Lambda IAM / VPC
IaC & Delivery
Terraform Docker / Compose GitHub Actions Kubernetes
Observability & Testing
k6 Grafana Prometheus Loki / Tempo OpenTelemetry InfluxDB
Backend
Java 17 / 21 Spring Boot 3.2 FastAPI PostgreSQL Redis Kafka

진한 표시는 직접 설계하고 운영한 범위입니다. Kubernetes는 팀이 구성한 환경에서 운영과 복구를 담당한 수준입니다.

Credentials

Certificates

  • AWS Certified Solutions Architect - Associate
  • 정보처리기사 (한국산업인력공단)
  • SQL 개발자 SQLD (한국데이터산업진흥원)
  • OPIc IH (Intermediate High)

Education & Training

  • 카카오테크 부트캠프 클라우드 네이티브 과정 (2025.02 - 08)
  • 상명대학교 컴퓨터과학과 (2019.03 - 2025.08 졸업)
  • 전공 4.0 / 4.5, 전체 3.84 / 4.5
  • 펄어비스 Backend Developer 인턴 (2026.01 - 02)