프로젝트
회사에서 맡은 일과 그 전에 한 프로젝트입니다. 과정은 각 글에 자세히 적었습니다.
회사에서 맡은 일
self-hosted Sentry
세무 데이터를 외부 클라우드로 보낼 수 없어서, 에러 수집 서버를 사내망 안에 직접 세웠다.
- Docker Compose로 개발 서버를 세우고 Keycloak SSO와 HTTPS 리버스 프록시를 붙였다. 도메인을 붙이자 터진 CSRF 오류를 여섯 단계에 걸쳐 풀었다.
- 에러가 나면 Slack으로 알림이 가게 했다. 사내로 들어오는 콜백이 필요한 기능 세 가지는 일부러 접고 알림만 남겼다.
- 모바일 앱이 보내는 이벤트 수집 경로만 별도 서브도메인으로 외부에 열고, 관리 화면은 내부망에 그대로 뒀다.
- 리플레이 용량을 DB가 아니라 파일시스템에서 직접 재서 디스크 여유를 판단했다.
관련 글
사내 모니터링 콘솔
인수받은 레거시 콘솔이다. SVN 커밋이 곧 운영 배포이고 스테이징이 없으며, 나는 서버에 들어갈 수 없다.
- 켜 두는 대시보드가 20~30분마다 로그아웃되던 원인을 찾았다. 실시간 스트리밍(SSE)이 세션 갱신 요청을 멈추게 한 것이었다. 로컬에 전체 스택을 띄워 재현하고, 재연결 8번 동안 세션이 유지되는 걸 확인한 뒤 배포했다.
- 코드만 있고 꺼져 있던 Slack 알림을 운영에 켰다. 그 과정에서 2주 전 내 커밋이 남긴 회귀를 찾았고, 운영 DB 상태를 로컬에 복제해 검증한 마이그레이션으로 고쳤다.
- 인수 전에는 로그인 루프를 급히 다른 realm으로 우회했다가 원래 realm으로 되돌렸다. 커밋이 곧 배포인 곳이라 커밋이 여섯 번 필요했다.
관련 글
리버스 프록시로 realm별 접근제어
Keycloak 하나에 realm이 여럿일 때, 리버스 프록시만으로 realm마다 내부와 외부 노출을 다르게 할 수 있는지 확인하는 과제였다.
- whoami 백엔드를 뒤에 세워 프록시가 볼 수 있는 것(도메인, 경로, 헤더)과 못 보는 것(토큰 안의 정보)의 경계를 확인했다.
- 실습용 Keycloak 앞에 규칙을 걸어 공개 realm 200, 내부 realm 403, master 403을 확인했다.
- 끝이 슬래시인 location에서 nginx가 301을 먼저 보내 deny를 건너뛰는 우회를 찾아 규칙을 고쳤다.
- 서버 권한 없이 응답 코드만으로 운영 프록시 구조를 추정해 보고했고, 6일 뒤 재검증에서 그 결론을 스스로 뒤집었다.
관련 글
사내 코딩 어시스턴트 (TabbyML)
망분리 때문에 Copilot 같은 외부 코딩 어시스턴트를 쓸 수 없어서, 사내망 안에서 도는 도구를 세웠다.
- GPU 없는 서버에서 Tabby가 CUDA를 찾다 재시작을 반복했다. 임베딩까지 사내 Ollama 서버로 넘겨서 띄웠다.
- VS Code, IntelliJ, Eclipse에서 자동완성과 채팅이 되는 걸 확인하고, 팀원이 가이드만 보고 설치할 수 있게 했다.
- 파일럿 온보딩 가이드를 쓰면서, 예측되는 함정은 트러블슈팅 절이 아니라 설치 단계 안에 바로 적었다.
관련 글
그 전에 한 프로젝트
모여볼 (moball)
KBO 경기를 중계하는 펍을 지도에서 찾는 서비스. 펍 조회와 필터 도메인, KBO 크롤러, 자동 배포를 맡았다. 8개 축 필터를 쿼리 하나로 처리했고, 크롤러는 파싱에 실패해도 예정 경기 데이터가 지워지지 않게 UPSERT 규칙을 짰다. 배포하는 동안만 러너 IP 하나를 보안 그룹에 열고 끝나면 반드시 닫는다.
BangCheck
매물을 보러 갈 때 쓰는 체크리스트 서비스. 체크리스트 도메인 설계, 운영 버그 추적, GitHub Actions와 EC2 자동 배포를 맡았다. 두 번째 저장마다 나던 409를 Hibernate ActionQueue의 flush 순서까지 따라가 찾았다.
Shopping Mall API
의류 쇼핑몰 백엔드(REST API 19개)를 혼자 설계하고 구현했다. 장바구니 조회의 N+1을 쿼리 22개에서 1개로 줄였고, Hibernate Statistics 테스트로 측정해 회귀하면 바로 잡히게 했다.
EKS GitOps 인프라
CI/CD, GitOps, 모니터링을 맡았고 Terraform은 팀원과 페어로 했다. Jenkins에서 ECR을 거쳐 ArgoCD로 가는 배포 흐름을 만들고, 모니터링을 호스트, 컨테이너, 애플리케이션, 쿠버네티스 네 층으로 나눴다. 학습용 EC2 메모리 안에서 돌려야 해서 Spinnaker 대신 ArgoCD를 골랐다.