서비스 세 개를 운영하며 배포와 검수를 자동화하기

세 서비스를 운영하며 배포와 서류 검수를 자동화하고 협업 문서를 정리했다.

5분 분량 #AWS #CI/CD #OCR 이 글의 방문자 수

릴리스할 때마다 SSH로 서버에 들어가 컨테이너를 재시작했다. 동아리 운영 서비스를 만들던 초기에는 이렇게 배포했다.

이후 4인 개발팀을 이끌며 동아리 운영 서비스, 학력 인증 기반 커뮤니티, 흡연구역 지도를 개발하고 운영했다. 세 서비스의 누적 가입자는 2026년 3월 기준 22,000명을 넘었다. 서비스 성격은 달랐지만 배포나 서류 검수처럼 반복해서 손이 가는 일은 비슷했다.

서로 다른 세 서비스

동아리 운영 서비스에는 예약과 승인, 카카오톡·이메일·푸시 알림을 붙였다. 세 서비스 중 가장 오래 운영했고, 배포 방식을 바꿔 나간 것도 이 서비스부터였다.

학력 인증 기반 커뮤니티는 학교 인증을 거친 사용자가 참여하는 서비스였다. 웹 MVP는 3개월, 모바일 앱은 2개월 만에 만들었다. 인증 서류를 안전하게 보관하고 빠르게 검토하는 일이 필요했다.

흡연구역 지도는 전 세계 흡연구역을 찾아볼 수 있는 서비스였다. 2개월 만에 MVP를 만들었고, 5개 언어와 실시간 번역, 지도 클러스터링을 적용했다.

직접 접속하던 배포를 자동으로

처음에는 GitHub Actions와 Docker, Elastic Beanstalk를 연결했다. master에 머지하면 이미지를 빌드하고 새 버전을 올리도록 했다. 배포에 실패하면 이전 이미지로 돌아간다.

Elastic Beanstalk는 클라우드 인프라 경험이 많지 않았을 때 시작하기 좋은 선택이었다. 다만 운영하면서 세부 설정을 바꾸려니 .ebextensions 같은 전용 설정에 의존하는 부분이 많았다. 계속 켜 두는 EC2 인스턴스의 비용도 고려해야 했다. 이후에는 ECS Fargate로 옮겼다.

기존 환경을 한 번에 내리지는 않았다. 옆에 ECS 서비스를 띄운 뒤 Route53 가중치로 트래픽을 20% → 50% → 100% 순서로 옮겼다. 각 단계에서 24시간 이상 상태를 확인했다.

첫 배포에서는 환경변수 24개가 전부 빠져 있었다. Elastic Beanstalk 설정에 넣으면 주입되던 값을 ECS에서는 Task Definition에 직접 지정해야 했다. 이전을 마치고 기존 환경을 종료할 때는 연결된 RDS까지 삭제하려는 동작이 있었지만, 삭제 보호 설정이 막아 줬다.

GitHub Actions에서 쓰던 장기 접근 키도 없애고 OIDC로 임시 권한을 받도록 바꿨다. Auto Scaling 정책과 Task Role 기반 인증은 추가로 정리할 부분으로 남았다.

학교 인증 서류를 한 장씩 보던 일

학력 인증 커뮤니티에서는 인증이 언제 끝나느냐는 문의가 들어올 때마다 사람이 서류를 확인하고 있었다. 이 과정을 OCR → LLM 필드 추출 → 비교 → 자동 승인으로 연결했다. 텍스트 추출에는 CLOVA OCR, 필드 추출에는 Bedrock 모델을 썼다.

신뢰도 점수가 0.9 이상인 경우에만 자동 승인하고, 그 아래는 사람이 검토하도록 했다. 확실하게 처리할 수 있는 서류를 먼저 넘기고 애매한 것에 검수 시간을 쓰는 방식이었다.

운영 중 예외도 하나씩 처리했다. OCR API가 504를 반환하면 실패 결과를 모아 다시 처리할 수 있게 했다. PDF 첫 장만 읽다가 도장을 놓치는 경우가 있어 기본으로 두 장까지 읽도록 바꿨다. 모델이 JSON을 코드 블록으로 감싸서 반환할 때는 파싱 전에 이를 제거했다.

인증 서류와 위치정보 다루기

인증 서류는 스토리지 접근 권한과 별도로 암호화했다. AWS KMS 데이터 키와 AES-GCM을 사용하고 복호화는 서버에서만 하도록 했다. 파일·계좌·HMAC처럼 용도가 다른 데이터에는 KMS 키도 나눠 사용했다.

흡연구역 지도에서는 위치정보 이용 사실을 남기는 감사 로그를 만들었다. 누가 언제 어떤 목적으로 위치정보를 사용했는지 남기되, 구체적인 위도·경도는 넣지 않았다. 로그에 필요한 내용과 굳이 보관하지 않아도 되는 좌표를 구분한 것이다. 먼저 조회 함수 하나에 적용했고 나머지 경로로 확대하는 작업은 남겨 뒀다.

같이 운영할 수 있도록 남긴 것

제품을 만들면서 고객, 기획자와 계속 요구사항을 맞췄다. 고객을 인터뷰한 기획자를 통해 피드백을 받기도 했다. 논의한 내용에 맞춰 개발 범위와 기술 방향을 정했다.

팀에서는 채용 기준과 면접 질문도 정리했다. 개발자 인턴 평가표에는 코드 리뷰 기준, 직접 구현한 범위, AI 도구를 사용하는 방법을 묻는 질문을 넣었다. 도구가 만든 결과를 그대로 쓰는지, 한계를 이해하고 검토하는지를 구분해서 보려고 했다.

동아리 운영 서비스에는 GraphQL 서버·클라이언트 구성과 타입·훅 자동 생성 방법을 문서로 남겼다. 빌드와 실행, 코드 생성, 린트·포맷 명령도 정리했다. 다국어 작업에서는 한국어 원문과 번역 키를 넣어 5개 언어의 JSON을 만들되, 한국어 원문은 AI가 바꾸지 않도록 했다.

배포와 검수를 자동화하는 일 옆에는 실행 방법과 예외 처리를 정리하는 일이 늘 같이 있었다. 자동으로 처리되는 단계와 사람이 확인할 지점이 모두 보여야 함께 운영할 수 있었다.

키보드 단축키