이건우 · Geonwoo Lee
Cloud Infrastructure

문제가 생기면 데이터와 인프라 흐름부터 확인합니다.

Cloud Infrastructure Engineer

AWS와 Kubernetes 인프라를 코드로 세우고, 그 위에서 AI 기능이 실제로 동작하는지 데이터 흐름까지 따라가 확인하여 문제를 해결해본 경험이 있습니다. 로그·이벤트로 원인을 좁혔고, 고친 뒤에는 같은 기준으로 다시 재어 비교했습니다.

01 / 프로젝트

프로젝트

담당 역할과 주요 결과를 소개합니다. 상세 페이지에는 선택 기준, 검증 결과와 한계를 정리했습니다.

5인 팀 프로젝트

Mealplanning

식비 예산과 사용자 행동 데이터를 기반으로 레시피·상품 추천과 AI 기능을 연결한 5인 팀 프로젝트입니다.

  • 15개 LLM 후보를 누적 1,750건 평가 기록으로 비교하고 기능별 모델을 선정했습니다.
  • 동일 275건에서 Guardrail 통과 건수를 166건에서 247건으로 개선했습니다.
  • 추천 노출·행동 이벤트의 session_id 누락을 전달 경로에서 확인하고 수정했습니다.

확인 자료 · 당시 비교표 / 수정 전후 실측 / 데이터 흐름 조사

개인 Retrieval / RAG PoC · 개발 평가

RAG Retrieval PoC

경험에 대한 질문에서 근거를 찾고, 답변 가능한 범위와 거절 조건을 나눠 확인한 개인 실험입니다.

  • BM25 검색과 답변 허용 범위를 판단하는 규칙을 분리했습니다.
  • 별도 평가(holdout)의 첫 실패를 분석하고, 검색 설정을 유지한 v2를 확정했습니다.
  • 개발 평가 결과와 아직 확인하지 못한 일반화 범위를 구분했습니다.

확인 자료 · 확정한 설정 / 개발 평가 / 남은 검색 실패

개인 상황판 · 자동화/운영

디딤

취업 준비에 필요한 것을 한 화면에 모은 개인 상황판입니다.
취업 공고 수집, 분석, 학습 및 학습기록, 메일 요약 및 분류, 알림 등의 다양한 개인 기능들을 이 한 페이지에서 관리할 수 있습니다.

  • 여섯 가지 요구를 여섯 개의 도구가 아니라 하나의 면으로 만들었습니다.
  • 메일 화면을 채우는 도구는 메일함을 읽기 전용으로만 다룹니다.
  • 테스트 281개가 전부 통과하는 상태에서 29가지를 찾아 고쳤습니다.

확인 자료 · 훼손 실험 / 집계 정합성 / 재현 빌드

인프라 실습

02 / Incident & Runbook

트러블슈팅

증상에서 원인을 좁힌 과정과 조치 결과를 정리했습니다. 조사를 마치지 못한 사례는 확인된 사실과 남은 가설을 구분했습니다.

Runbookgeonu.site HTTPS 인증서가 발급되지 않아 카카오톡에서 링크가 열리지 않던 문제 DNS는 정상이었고 GitHub이 커스텀 도메인 인증서를 발급하지 않은 상태였습니다. GitHub PagesDNSTLSLet's Encrypt

문제

카카오톡에서 geonu.site 링크를 누르면 보안상의 이유로 열리지 않았습니다. 데스크톱 브라우저에서는 경고를 넘기면 접속돼서 바로 드러나지 않았습니다.

확인 순서

  1. DNS부터 확인했습니다. apex A 레코드는 GitHub Pages IP 4개(185.199.108~111.153)를 정확히 가리켰고, www CNAME도 정상이었습니다. 리졸버 두 곳에서 같은 값이 나왔습니다.
  2. CAA 레코드가 발급을 막는 경우가 있어 조회했지만 레코드 자체가 없었습니다. apex에 CNAME이 잘못 들어간 것도 아니었습니다.
  3. 인증서를 직접 받아봤습니다. openssl s_client로 확인한 subject가 CN=*.github.io였고, SAN 목록에 geonu.site가 없었습니다.
  4. GitHub Pages API를 조회하니 https_certificate 객체 자체가 없었습니다.

원인

DNS 문제가 아니라 GitHub 쪽에서 커스텀 도메인 인증서 발급이 끝나지 않은 상태였습니다. 그래서 기본 와일드카드 인증서가 그대로 제시됐고, 호스트명이 맞지 않아 TLS 연결이 실패했습니다. 카카오톡 인앱 브라우저는 이 경우 우회 선택지 없이 차단합니다.

조치

DNS는 손대지 않았습니다. GitHub Pages 설정에서 커스텀 도메인을 지웠다가 다시 등록해 인증서 발급을 새로 걸었고, 발급이 끝난 뒤 Enforce HTTPS를 켰습니다.

결과

https://geonu.site가 HTTP/2 200으로 응답하고, Pages API의 인증서 상태가 approved, https_enforced가 true로 바뀌었습니다. 저장소 전체에 http:// 참조는 0건이라 혼합 콘텐츠 문제는 없었습니다.

다시 겪는다면 — 브라우저가 열린다고 HTTPS가 정상인 것은 아닙니다. 인증서의 SAN에 도메인이 들어 있는지부터 보면 DNS 조사 범위를 좁힐 수 있습니다.
기여 범위 — 문제 발견·설정 변경·결과 확인: 본인 · 진단 명령 실행·분석 보조: AI 도구
IncidentMealplanning 추천 노출·행동 이벤트의 session_id가 전달되지 않아 학습 label이 0건이던 문제 조회한 44건이 전부 비어 있었고, 값을 따라가 전달이 끊긴 지점을 찾았습니다. PostgreSQLSQLFrontend데이터 흐름

문제

추천이 화면에 노출된 기록은 쌓이는데, 개인화 랭킹 학습에 필요한 긍정 label이 한 건도 만들어지지 않았습니다.

확인 순서

  1. 모델을 다시 학습시키기 전에 학습 SQL의 join 조건과 실제 저장된 이벤트를 대조했습니다.
  2. 노출과 행동을 잇는 키 값을 조회하니 44건이 전부 비어 있었습니다. label이 0건이면 재학습해도 결과가 같으므로 모델이 아니라 값의 경로를 봤습니다.
  3. Frontend의 세션 생성 → API 요청 본문 → 이벤트 저장 → 학습 데이터 순서로 각 구간에서 값이 실려 있는지 확인했습니다.

원인

백엔드 요청 모델에는 필드가 있었지만 Frontend가 요청 본문에 값을 싣지 않아 저장 시점부터 비어 있었습니다. 학습 SQL은 그 키로 조인하므로 한쪽이 비어 있으면 조인되지 않습니다.

조치

전달 경로를 수정하고, 수정 후 이벤트가 실제로 값을 갖고 저장되는지와 학습 데이터가 연결되는지를 다시 확인했습니다.

결과

끊겨 있던 노출과 행동의 연결이 복구돼, 이후 쌓이는 데이터부터는 label이 생성될 수 있는 상태가 됐습니다.

한계 — 이미 지나간 기간의 label은 복구할 수 없어 데이터가 다시 쌓이기를 기다려야 했습니다. 확인 범위는 조회한 44건의 키 누락과 전달 경로입니다.
기여 범위 — 발견·원인 분석·수정: 본인
확인 경로 정리 보기 →
Decision NoteMealplanning 정상 응답이 검증 단계에서 막히던 문제 같은 275건을 다시 재서 통과 건수를 166건에서 247건으로 늘렸습니다. LLMGuardrail프롬프트재측정

문제

응답 내용은 문제가 없는데 검증 단계에서 막히는 경우가 반복됐습니다. 막히면 템플릿 답변으로 대체되므로 사용자가 보는 답의 품질이 떨어졌습니다.

확인 순서

  1. 모델을 바꾸자는 판단으로 가기 전에 실패한 케이스를 모아 다시 봤습니다.
  2. 상당수가 환각이 아니라 사용자가 질문에 쓴 재료와 금액을 그대로 되풀이한 것이었고, 검증 로직이 그것을 근거 없는 내용으로 오판하고 있었습니다.

원인

근거로 인정하는 범위에 사용자 질문이 빠져 있었습니다. 「8천원」 같은 한글 수사 표현도 숫자와 이어지지 않았습니다.

조치

근거 문자열에 사용자 질문 원문과 한글 수사를 숫자로 편 정규화 결과를 함께 넣도록 처리 방식을 바꿨습니다. 모델은 교체하지 않았습니다.

결과

같은 275건 평가 세트를 다시 돌려 통과가 166건에서 247건으로 늘었습니다(약 60% → 90%). 문자열 구성만 바꾼 변경이라 LLM 호출은 늘지 않았습니다.

한계 — 근거로 인정하는 범위를 넓힌 만큼, 사용자가 잘못된 전제를 질문에 담으면 그것이 근거로 통과할 여지가 생깁니다. 수정 후에도 남은 실패는 모르는 것을 지어내는 유형에 몰려 있었습니다.
기여 범위 — 오탐 의심 제기·재측정 요구·채택: 본인 판단
실측 문서 보기 → 기록 전문 보기 →
Incident프로젝트 종료 후 점검 파드는 Running인데 새 배포만 실패하던 상태 주기적 점검이 실패 신호를 내고 있었지만 그 실패에는 알림이 없었습니다. KubernetesRegistry배포관측
프로젝트 종료 후 점검 — 프로젝트가 끝난 뒤 실행 환경을 살펴보며 확인한 사례입니다. 프로젝트 기간 중 대응한 장애가 아닙니다.

문제

워크로드는 정상으로 보이는데 새 배포만 실패했습니다. 파드 상태와 재시작 횟수만 보면 이상이 없었습니다.

확인 순서

  1. 기존 파드가 왜 멀쩡한지부터 봤습니다. 노드에 남아 있던 이미지로 계속 실행되고 있었고 재시작도 0이었습니다.
  2. 실패가 언제 드러나는지 좁혔습니다. 레지스트리 접근이 필요한 순간, 즉 새 배포나 재스케줄링에서만 실패했습니다.
  3. 주기적으로 도는 점검이 이미 실패 신호를 만들고 있었는데, 그 실패 자체에는 알림이 걸려 있지 않아 아무도 모르고 있었습니다.

원인

레지스트리에 닿지 못하는 상태였고, 캐시된 이미지 덕분에 겉으로는 정상처럼 보였습니다.

결과 / 배운 점

파드가 Running인 것과 새 배포가 가능한 것은 다릅니다. 현재 상태가 정상인 것과 다음 변경을 수행할 수 있는 것은 별개이고, 둘 다 운영 상태의 일부입니다. 점검 실패를 대응으로 연결하려면 알림 경로도 함께 확인해야 합니다.

기여 범위 — 종료 후 개인 점검: 본인 · 클러스터 구축·운영: 팀
Mealplanning 상세에서 보기 →
IncidentMealplanning 한 카테고리만 매일 새벽에 실패하는데 작업은 성공으로 기록되던 문제 실행 시간 15.4초를 단계별로 분석하고, 로컬 측정 35회와 대조했습니다. 크롤러Playwright관측 공백로그

문제

매일 새벽 3시 30분에 도는 수집 작업에서 첫 카테고리 하나만 사흘 연속 아무것도 못 가져왔습니다. 그런데 작업 자체는 실패 건수 0으로 기록돼 성공처럼 보였습니다.

확인 순서

  1. 실패한 실행의 소요 시간 15.4초를 성분으로 나눴습니다. 대기 루프가 구조상 최소 15초를 차지하므로, 페이지를 여는 데 쓴 시간은 아무리 커도 0.4초 미만이었습니다.
  2. 정상일 때와 비교했습니다. 같은 클러스터의 정상 파드는 0.62초, 프로덕션과 같은 브라우저로 로컬에서 35회 재보니 전부 0.49~0.95초였습니다. 페이지가 무거워 그 아래로 내려갈 수 없는 구조였습니다.
  3. 총 소요가 정상 셸의 대기 루프 단독보다도 짧았습니다. 매 폴링마다 도는 요소 개수 조회가 훨씬 쌌다는 뜻이고, 곧 받은 문서가 작았다는 뜻입니다.

원인 범위

그 시각 첫 요청이 받은 것이 평소의 카테고리 페이지가 아니라 앱 번들이 붙지 않은 작은 문서였다는 정황까지 좁혔습니다. 다만 그 응답의 실제 HTTP 상태와 종류는 확보하지 못해 무엇이었는지는 확정하지 않았습니다. 차단·오류 페이지가 유력한 후보였습니다. 네트워크 지연이나 파드 축출, DNS 재시작 같은 후보는 근거가 맞지 않아 기각 목록에 남겼습니다.

조치

응답의 종류를 구분하지 못하게 한 관측 공백은 코드에 있었습니다. 페이지 이동의 응답 객체를 버려서 HTTP 상태코드가 로그에 남지 않았고(브라우저 자동화는 4xx·5xx에 예외를 던지지 않습니다), 렌더 대기 함수의 반환값도 버려서 「한 장도 렌더되지 않음」과 「렌더는 됐지만 파싱이 0」이 구분되지 않았습니다. 이 관측 공백을 조사 기록으로 남겼습니다.

결과 / 배운 점

부분 실패를 성공으로 적으면 다음 사람이 같은 조사를 처음부터 다시 합니다. 실패 건수만 보지 않고 기대 수량 대비 실제 수집량을 함께 보는 편이 안전합니다. 조사 내내 클러스터는 읽기만 했고 변경은 로컬에서만 재현했습니다.

한계 — 차단 페이지 정황까지 좁혔지만 외부 응답 본문을 직접 확보하지는 못해, 원인을 단정하지 않고 정황과 기각 근거를 함께 적었습니다.
기여 범위 — 조사·원인 좁히기·기록: 본인 · 크롤러 운영: 팀
Decision NoteMealplanning 영수증 OCR 방식을 고를 때 성공 기준을 먼저 정한 이유 실물 13장을 5개 방식에 같은 조건으로 통과시키고, 지표의 한계를 함께 적었습니다. OCRVision비용지표 정의

문제

영수증을 찍어 품목과 금액을 자동으로 넣으려면 감열지 인쇄와 구겨진 종이에서도 구조화된 결과가 나와야 했습니다. 어떤 방식이 맞는지 미리 알 수 없었습니다.

확인 순서

  1. 무엇을 성공으로 셀지부터 정했습니다. 합계 정합 — 추출한 품목 금액의 합이 영수증 총액과 맞으면 성공입니다.
  2. 같은 지표의 한계도 같이 적었습니다. 품목이 한두 개인 영수증은 쉽게 통과하고, 총액을 못 읽으면 품목이 맞아도 실패로 처리됩니다. 즉 절대 수치는 무르고 방식 간 상대 순위만 견고합니다.
  3. 실물 13장을 5개 방식에 통과시켰습니다. 다운스케일, 재시도, 타임아웃을 모두 고정했습니다.

결과

경량 비전 모델이 합계 정합 기준 13장 중 12장이었고 실행 오류가 없었습니다. 추론 옵션을 켠 상위 모델은 더 낫지 않으면서 비용이 수십 배였고, 로컬 엔진은 구조화 출력 자체가 나오지 않았습니다.

조치

경량 비전 모델을 채택하고, 사용자가 결과를 확인·수정하는 단계를 앞에 둬서 인식 오류를 사람이 보정할 수 있게 했습니다.

한계 — 13장은 작은 표본이고 품목명과 가격의 개별 정오는 따로 검증하지 않았습니다. 그래서 「인식 정확도」라고 쓰지 않고 합계 정합 기준이라고 적습니다. 영수증 원본은 개인정보라 로컬에만 두고 Git에 올리지 않았습니다.
기여 범위 — 비교 착수·성공 기준 정의·한계 명시·채택: 본인 판단
비교 결과 보기 →

03 / Skills

주요 기술 영역

01

Infrastructure

Linux · Network · Cloud · Kubernetes

02

Observability

Metrics · Logs · Events · Troubleshooting

03

Automation

Python · IaC · Repetitive operations

04

AI / ML Systems

Evaluation · Data flow · Serving · Reliability