잡담

이코에코(Eco²) 2025 새싹톤 본선 진출 후일담

mango_fr 2025. 11. 29. 14:48

이코에코가 181팀 중 6위로 본선 진출을 확정했다🎉🎉 본선은 12.01-12.02로 DDP 아트홀 1관에서 진행된다.

순위 선정은 작성한 기획서와 첨부한 GitHub를 바탕으로 참여자 + 심사자 투표로 결정됐다.
좋아요 수를 보면 알겠지만 참여자 투표에선 그렇게 썩 좋은 점수를 받진 못했으나, 심사자 투표의 가점을 크게 받은 모양이다.
마감 이틀 전까지만 해도 좋아요 6개로 181팀 중 181위를 달리고 있었지만 댓글 공세로 지수반등을 보인 게 총합 19개였다.
기획서 자체는 프론트, 디자인, AI 분들 모두 공을 많이 들이셔서 퀄이 높은 덕에 심사위원 점수에서 가점을 많이 받은 듯싶다.
난 기획서..에서 큰 비중은 없었고 깃허브에서 Codex + Claude와 공격적인 인프라 구축을 이어가던 중이었다.
참여 팀이 181팀으로 꽤 많은데 다수가 새싹이라는 부트캠프 수강생들처럼 보인다.
 
새싹은 원래부터 알고 있던 부트캠프였다.
전 직장에 입사했을 때쯤 소개를 받았던 전여친이 새싹 부트캠프 데이터 분석 과정을 수강 중이기도 했어서..쩝
주최는 서울시지만 해커톤 운영을 데이콘이 맡아서 그런지 의외로 현업 및 연구 쪽 종사자 분들도 꽤 참여했다.
기대보다 높은 등수로 본선에 진입해서 시연이 잘 풀린다면 수상을 노려보고 싶은 맘이다.

 
14-nodes K8s 클러스터 + GitOps 파이프라인 + API 개발까지 걸린 기간은 32일이다.
결국 띄워낸 29 어플리케이션 리소스 All-Sync + Healthy.. 안정화 일정이 계속 밀려서 식은땀을 빼면서 올렸다..
마지막 주는 눈뜨면 Codex 5.1이랑 개발하고, 쓰러지듯 자고 무한 반복이었다.
백엔드 + 인프라 팀원은 나 한 명이긴 했지만 Claude + GPT와 함께 작업해서 솔로 작업 같은 기분은 안 난다.
기능별로 브랜치 분기해서 로컬 docke-compose로 테스트 -> 병합 -> 배포를 반복하다가 기한이 촉박해진 후부터는 develop 브랜치에 작업한 이후 배포 환경으로 올리는 방식으로 사이클을 줄였다.

GitOps에서 시간을 많이 쓰기도 했고, 셀프 메이드 클러스터 환경에 API를 정상 동작시키는 과정에서 병목이 터졌다.
주로 많이 터졌던 건 DB 부트스트랩이었다. 단순히 컬럼만 있는 스키마는 SQLAlchemy로 충분히 생성 가능했다.
그러나 캐릭터, 주소처럼 미리 쌓아둔 정보를 필요로 하는 스키마의 경우는 얘기가 달랐다.
CSV로 초기 정보들을 쌓아두고 클러스터의 DB에 주입하는 과정에서 권한 문제가 자주 터졌다.
DB 부트스트랩을 담당하는 job을 앱과 동일한 Sync에 태운 채로 진행하면 DB 작업이 어긋나는 즉시 degraded 상태에 빠진다.
심지어 K8s의 job은 수행을 완료할 때까지 state가 Progressing에서 나아가지 않는다. 일종의 배포 데드락이라 볼 수 있다.
더불어 컴퓨터 시스템 중 가장 느린 파트는 보조 메모리인 스토리지며, 그중 쓰기 작업은 말할 것도 없다.
여기서 파일 크기가 조금만 커져도 병목이다. PostSync로 배치하면 그나마 상황이 나아진다.
App 배포 플로우 이후에 수행이 되니 DB 부트스트랩과 앱의 배포가 디커플링 된다. (물론 동작은 다른 얘기다.)
DB 부트스트랩을 PostSync로 빼고, kustomize secret으로 DB 계정에 적합한 권한을 위임하니 진전이 보였다.
다른 스키마 주입 작업들도 동일한 방식으로 진행해 해결했으나.. 마이그레이션과 부트스트래핑의 경우 더 나은 방안이 있을 거라 여긴다.

정말 폭력적인 커밋과 PR, 토큰 소모량이다. 회사에서 이랬다면 난 이미 맞아죽었겠지만.. 또 이런 거 해보려고 공모전하는 거 아니겠나 하하

 
초기 포스팅을 보니 Ansible 위주의 클러스터 구축엔 토큰 6억개 남짓 소모했더라.
Ansible 최소화, GitOps(현황은 Operator보다 Helm-charts의 비중이 높다.), 7개 도메인 API까지 올리니 총 40억개를 소모했다.
기능별 병합 겸 후반 작업 브랜치인 develop을 기준으로 보면 555,148 ++487,064--로 실제 클러스터에 반영된 코드는 68,000자 남짓이다. Cursor 위주로 작업을 이어왔고 초안 작성 -> 피처별 로직 개발 -> 리팩토링 -> 배포 -> 버그 픽스 순으로 진행했다.
인프라와 파이프라인 파트의 경우 저 과정에 Helm-charts 및 Operator 오픈소스 조사, 선정, 테스트가 초안 작성에 포함됐다.

코드 작성 외에 시스템 디버깅 및 클러스터 진단에도 LLM을 기용했다. Cursor의 경우 sandbox 제한을 풀면 터미널 상의 모든 동작이 허용되기 때문에 LLM들에게 적합한 키 혹은 스크립트를 전달하면 클러스터 디버깅도 가능하다. 그러나 헤매고 루프를 도는 경우도 상당히 많기 때문에 사용자가 개입해 길잡이 역할은 해줘야 한다.

오작동 사례 중 하나로는 Redis를 Operator와 CRD/CR로 구축하는 시도를 했을 당시로 Redis 파드들이 Degraded되어 진행이 되지 않았던 적이 있다.
주 원인은 해당 파드에 PVC(gp3)가 할당되지 않았던 이슈로, 이코에코 K8s에 관련 드라이버가 설치되지 않아 지속적인 다운이 발생했었다. 결국 알맞은 드라이버를 pvc 스펙으로 명시해 설치한 이후로는 정상 동작했다.
이를 밝히는데 꽤 오랜 시간(3시간 남짓)이 걸렸던 걸로 기억한다. LLM이 클러스터에 붙어 정보를 수집하다가 동일한 작업에서 루프를 도는 경우가 상당히 많이 관측됐다.
이 과정에서 Redis Operator+CR/CRD는 Redis Helm-charts로 교체됐다. 관련 내용은 이코에코 트러블슈팅 문서에 기록돼있으니 참고하면 감사하겠다.

총 토큰 사용량을 보면 소모 토큰 19.1억개로 GPT 5.1 Codex의 사용 비중이 가장 높다.
순전히 경험적인 감이나, Claude는 초반부 코드 생산성이 높지만 원인을 파고 들어가는 시스템 디버깅에서 성능이 상당히 낮았다.
5.1 Codex는 리팩토링과 시스템 디버깅에서 Claude보다 만족스러운 사용 경험을 줘, 코드 베이스가 쌓일수록 Codex 쪽으로 기울었다. 가격도 GPT 5.1 Codex가 Claude 4.5 Sonnet보다 10배 가량 싸기 때문에 후반엔 GPT 5.1 Codex로 모델을 고정해 작업을 이어왔다.
Gemini 3.0 Pro는 의외로 프로젝트의 맥락을 잘 잡지 못했다. 몇 번 시도한 이후로는 초안 작성 혹은 논의에만 이따금씩 활용하고 이코에코 코드베이스엔 접근하지 못하게 했다.
 
커밋 데이터를 보면 짐작이 가겠지만 실제 작성한 코드에 비해 클러스터에 반영된 코드의 비중은 12-13%다.
아키텍처 구축 및 사전 리서치 때 생산성을 폭발적으로 낸 후 특정 도메인을 기반으로 리팩토링, 조사를 반복하며 나은 선택지를 도출, 해당 구조를 전체 도메인 서버에 적용하는 방식으로 진행했다.

 
그 결과를 확인할 수 있는 지점은 Kustomize Overlays 패턴 (base, dev, prod)와 FastAPI 서버들의 레이어드 아키텍처다.
Kustomize의 Overlays 패턴에 대한 얘기는 이코에코 인프라 구축기 #02에서 확인할 수 있다.
개발 진행에 있어서 가장 공을 많이 들인 지점은 GitOps, 병목이었던 지점은 Auth다.
회원 기반 서비스가 전제다 보니, 모든 API는 Auth에 의존하게 된다. Auth를 업데이트하는 동안 서버가 다운되면 유저들에게 API에 접근할 권한을 줄 방도가 없다. 다른 서버들이 물리적으로 살아있어도 사실상 유저들이 접근할 수가 없으니,, 클러스터가 얼어버린다.
로컬 도커에선 테스트용으로 Auth 기능을 끄는 옵션도 넣었었지만.. 단순 API 기능 개발할 때를 제외하고는 크게 활용한 적은 없다.
이코에코 배포 클러스터의 경우 시스템 복잡도와 세팅이 로컬에선 재현이 불가능할 만큼 다른 환경이라.. 로컬 테스트의 중요도가 떨어졌다. docker-compose로 Auth와 RDB+Cache, 대상 도메인을 함께 올리는 조합이 클러스터와 가장 유사했지만 완전히 일치하진 않는다.
예를 들어 scan 기능을 e2e로 테스트해야하는 경우 로그인-> 이미지 업로드 -> 스캔 -> 캐릭터 발급 -> 유저 정보 확인까지 auth, my, scan, character, image 도메인을 올리고 DB 부트스트랩까지 해줘야 해서.. 오히려 배포 환경 분리가 손이 덜 가는 상황이었다. 도메인 서버 개발기, 리팩토링, 배포 및 테스트 과정 등의 수기는 다음 포스팅에서 서술할 예정이다.


서술했듯 개발 병목은 dev / prod의 분리가 배포 환경에서 이뤄지지 않은 데서 발생한 이슈다. 코드 베이스의 경우 dev와 prod가 분기되어 있지만 배포된 클러스터는 dev 단일로 운용했다. 분리를 진행하지 않았던 근거는 비용 측면도 있지만(Blue-Green의 경우 dev/prod 환경 분리를 운용할 경우 비용이 x2가 된다.) 한 달 남짓한 기간에 클러스터를 두 곳으로 나눠서 운용하는 선택지는 그다지 매력적인 옵션이 아니었다.
파이프라인 혹은 API 기능 개발 속도를 저하시킬 수 있다고 판단했으나.. Auth 병목을 생각하면 조삼모사 같은 면이 없지 않아 있다.
클러스터 안정화가 늦춰져서 이제 본선 첫날을 포함하면 3일 정도밖에 안 남았는데 프론트 쪽에선 연동 시도를 거의 못했다..
프론트는 Vercel로 올리지만, 백엔드는 EC2 / Route53 / ALB 등 self-managed K8s임에도 AWS 의존도가 높았던 상황이라 두 파트가 꽤 이질적인 상태에서 작업을 했다. 이전엔 헤더에 JWT를 담는 방식으로 인증/인가 서버를 만들다가 이번엔 JWT를 쿠키에 담아 OAuth2.0을 구현한지라 브라우저 정책 맞추기 까다로웠다.
 
쿠키가 보안이 강한 저장소지만 그만큼 브라우저 측의 쿠키 발급 정책도 까다롭다. 도메인이 다르면 쿠키 발급을 허가하지 않는다.
Cross-domain을 쓰면 또 Credential에 제약이 생기는 둥 사실상 도메인이 일치된 구성을 브라우저 측에서 강제하는 환경이다.
이전엔 Nginx를 앞단에 두고 프론트 측을 클러스터 안으로 포함시켜서 해결했으나, 이번엔 내가 프론트 쪽이 사용하는 스택들을 잘 모르기도 하고, 이미 내 스택으로도 벅찬 상황이었기에 Route53만 앞에 세우는 걸로 마무리지었다. 인프라가 준프로덕션 레벨의 스택이라 버거운 면도 있었지만.. 무엇보다 메인 서버 개발로 FastAPI를 쓰는 건 이번이 처음이기도 해서 여유가 0에 가까웠다.
기존 Vercel 도메인으론 쿠키가 담기지 않기에 우선 Route53 레코드로 등록을 해두고(frontend.dev.growbin.app) 다음 홉을 Vercel로 잡아서 해결했다. 이렇게 되니 프론트가 배포된 상태에서 밖에 테스트를 못하는 상황이 발생했다.

개발 초중반에 쓰던 docker-compose로 로컬 테스트 환경을 달라는 프론트 측 요청이 있긴 했지만..
이게 도커로 Redis, Postgres, Auth 등 각 요소를 묶어 올리다가 도커 내에서 포트나 통신 이슈가 발생하면 dockerfile 땜질하거나, 파드에 직접 붙어서 시스템 디버깅(실무에선 절!대!까진 아니지만 전혀 권장하는 방식은 아니다.)하는 등의 잔수고가 강제되는 테스트 환경이라 솔직히 프론트에서 수행하기 어렵다고 판단하긴 했다. 결국 프론트에서 동일한 도메인의 테스트용 Vercel 서브 주소를 두개 더 올리는 대신, 백엔드에선 커스텀 헤더로 프론트 주소를 기록하고 이를 기반으로 리다이렉팅 주소를 분기해, 프론트엔드 dev / prod 배포 환경 분리를 완료했다.

좌: 본선까지의 구조 [2025.12.02], 우: 현재 구조[2025.12.13]. East-West를 K8s Ingress 대신 Istio 리소스(GW, Envoy Sidecar)가 맡도록 변경됐다.

 
너무 반복해서 지겨울 법한 시스템 구조도다. MQ가 빠진 걸 제외하면 초기 구상대로 개발을 완료했다.
개발 전 항상 이런 구조도를 짜고, 시스템을 구상하는 시점까지만 보면 거의 입개발에 가까운 구성처럼 보이나..
학부 때부터 지금까지 참여한 사이드 프로젝트들은 모두 초기 구상대로 배포 및 e2e 시연까지 완성한 이력이 있는 지라 나를 믿고 지르는 편이다.  솔직한 심정으론.. 그냥 목표를 높게 잡고 구르면서 배우는 편에 가깝다.
위 구조도는 트래픽 흐름을 중점으로 풀었다. ALB가 ingress의 주소를 획득해 TG에 등록하는 과정과 이를 기반으로 목적지 Pod까지 패킷을 전달하는 과정을 담고 있다. 자주 설명한 내용이니 반복하지는 않겠다. 이와 관련된 기록은 인프라 구축기 #04에 남겨뒀다.
각 도메인 서비스별로 노드 하나를 담당하고, Auth를 제외하면 도메인별 의존성이 크지 않기 때문에 하나의 서버가 다운되더라도 클러스터가 다운되는 일은 없다. MQ 도입 직전인 구조로 EDA로 전환을 앞둔 상황이라 보면 좋다.
공모전이 끝나면 dev/prod 환경 분리를 진행한 후, MQ 전환 및 DB 분리 작업에 착수할 예정이다.
EDA 전에 Auth의 의존도를 낮추는 작업이 선행될 수 있다. Nginx가 그리워지는 건 정말 오랜만이다..

그렇지만 실제 작업엔 Nginx Controller 대신 서비스메쉬를 쓸 예정이다. 관련 고도화는 재취준 중 에너지가 차면 시도해볼 듯 싶다.

 
가장 공이 많이 들어간 GitOps 파이프라인이다. Terraform / Ansible은 부트스트랩 이후엔 사용되지 않는다.
develop / main 브랜치에 push 혹은 PR이 발생하면 CI가 트리거 되며 APP과 Manifest 별로 Lint/Render 테스트를 진행한다.
GitHub와 Docker Hub에서 변경사항이 발생하면 ArgoCD root-app이 이를 감지해 클러스터에 자동 배포하는 구조다.
태그 이름이 latest라 실시간 감지가 잘 안 이뤄질 때도 있다. 이럴 땐 ArgoCD Web UI나 Cli로 트리거해주면 잘 반영된다.
태그명부터 배포 전략까지 GitOps 파트도 개선할 부분이 조금 남아있다.
배포 전략은 도입해야겠다 싶은 게 3-5분이면 자동 Sync가 되긴 해도 수동 트리거가 필요할 때가 은근 많다.
Canary 혹은 Blue-Green 중 하나를 정해서 환경 분리와 병행으로 진행될 듯싶다.
 

 
 
API들 기능 구현은 완료됐다. 도메인별로 엔드포인트가 많진 않다. 3-5개 사이?
특별한 점은 없고 공통 RDMS + Cache를 쓰는 MSA다. 현재는 스키마만 도메인별로 나눠진 상태로 MQ가 도입되면 DB도 도메인별로 분리가 될 구조다. 백엔드 측 주기능은 인증/인가, 사용자 위치 기반 주변 재활용 센터 안내, Scan 결과에 따른 캐릭터 매칭 및 보상 지급이다. 앱 기능 자체는 LLM Text/Vision Classification 파이프라인이 메인이기에 백엔드 API는 그렇게 비중이 크진 않다. 전반적으로 앱의 형태를 짜주는 포지션에 가깝다. LLM 분류 성능은 사용자에 가까운 내 입장에선 꽤 좋다. 분류 적합 기준이 까다로워서 캐릭터 보상이 잘 트리거가 안될 정도다. AI 담당자분께서 JSON 주입, YAML 분류체계, txt 프롬프트만으로 Rule-based Retrieval 파이프라인을 구성했는데도 성능이 상당하다. 토큰값이 싸지고 추론 시간이 줄면 '비즈니스 로직을 LLM한테 위임하고 프롬프트만 주입하는 시대도 오려나..' 싶다.
본선에서 프론트+백 연동이 잘 마무리되기를 바란다. 너무 늦게 끝나서 면목이 없지만..
12월 1일에 상황 봐서 연동 각이 안 나온다 싶으면 Cursor를 써서 붙으면 e2e는 가능할 듯싶다.
수상하면 좋고.. 아니더라도 큰 문제는 없다. 이제부터 이코에코는 내 인프라+BE 실험용으로 마개조될 일만 남았다. 잘 됐으면 좋겠다. 흐흐
 

docs

현재 제공 중인 API 문서들은 아래와 같다.
1. Auth - 인증인가 서버, JWT 쿠키 사용, OAuth2.0 기반 간편 로그인(구글, 카카오, 네이버)
2. My - 유저 서버, 마이페이지 정보 노출 및 유저 스키마 보유
3. Chat - GPT 5.1 Vision 특화 Lite Rag 파이프라인 활용, 분리수거용 챗봇, 이미지 인식 가능
4. Scan - GPT 5.1 Vision 특화 Lite Rag 파이프라인 활용, 3단계 레이어로 폐기물 분류, 평가, 개선안 제공
5. Character - 캐릭터 보상 시스템, 분리 배출물과 매칭되는 13종 캐릭터 지급, Scan과 연동되어 작동
6. Loation - 사용자 위치 정보를 기반으로 주변 제로웨이스트 샵과 재활용 센터 안내, keco/제로웨이스트 정보 사용
7. Image - 이미지 업로드 서버, CDN + S3에 사용자가 제공한 이미지를 업로드
 
배포 클러스터에서 정상 동작 중이다. 아마 공모전까지는 추가 기능 확장 및 고도화보다 안정화에 집중할 듯 싶다. 업무가 아닌 사이드 프로젝트로 K8s 클러스터를 다루는 건 처음이라 긴장되지만 최소 현장 시연, 안정성이 높다면 해커톤 참여자들의 실시간 사용도 가능한 수준까지 엮어둘 예정이다.