개발 이야기2026년 3월 24일

데브옵스 맛보기 여정기

199
0

시간은 더더 빠르게 흘러 1.0.0 배포 직전으로...

드디어 12월 4일, 식후경 3.0 배포를 준비하면서 여러 인프라 문제와 개발 방향을 고민하게 되었고, 특히. 그중, 알림톡 템플릿 관리와 관련된 이야기를 정리해본다.

** 모든 코드는 예시코드입니다.

**

데브옵스 맛보기 여정기: 알림톡 시스템 개선기

시작은 템플릿 관리의 어려움으로부터...


기존 시스템의 한계

  1. Strapi 서버 접속 알림톡이나 MMS 발송을 위해 먼저 Strapi 서버에 접속해야 했다.
  2. 4500줄짜리 cron.js 탐험 엄청난 길이의 cron.js 파일에서 템플릿 코드를 찾아 수정해야 했다.
  3. 템플릿 검증 Postman으로 알리고 API 요청을 테스트하며, 템플릿이 정상적으로 동작하는지 확인해야 했다. 띄어쓰기 하나라도 틀리면 실패했다.
  4. 코드 수정 새로운 템플릿 코드를 cron.js에 직접 추가해야 했다.
  5. 서버 재시작 수정 후에는 서버를 재시작해 변경 사항을 적용해야 했다. 이런 방식은 관리와 유지보수에 비효율적일 뿐 아니라, 실수의 여지가 많았다. 새로운 개발 환경에서는 템플릿 관리와 발송을 더 단순하고 유연하게 만들고자 했다.

MongoDB와 NestJS를 활용한 개선 방향

우선 템플릿 데이터를 관리하기 위해 MongoDB를 도입하고, 이를 NestJS와 연결해 관리자 권한으로 접근할 수 있는 시스템을 설계했다. MongoDB는 템플릿 구조 변경과 동적 파라미터 처리에서 유연한 스키마를 제공했기 때문에 선택하게 되었다. Atlas 무료 티어로 비용도 최소화했다.

TypeScript

NestJS는 템플릿 생성, 수정, 삭제 API를 제공해 관리 편의성을 크게 높였다. 이렇게 템플릿 관리 로직을 cron.js에서 완전히 분리할 수 있었다.


서버리스 아키텍처와 Lambda 도입

템플릿 발송 로직은 Serverless Framework를 사용해 AWS Lambda에 배포했다. API Gateway를 통해 Lambda를 호출하고, MongoDB에서 템플릿 데이터를 가져오는 방식으로 설계했다. 발송 요청은 동적 파라미터를 처리한 뒤 알리고 API로 전달되는 구조였다.

TypeScript

Lambda와 API Gateway를 사용하면 인프라 관리 부담 없이 서버리스를 통해 손쉽게 확장할 수 있을 것으로 기대했다.


예상치 못한 IP 제한 문제와 회귀

하지만 예상치 못한 문제가 발생했다. 알리고 API는 최대 8개의 고정 IP만 허용했는데, 이미 Lambda에서 다른 작업들이 이 IP를 모두 사용하고 있었다. NAT Gateway를 도입하려 했지만, 운영 비용이 너무 높아 현실적이지 않았다.

결국 Lambda를 포기하고 EC2로 전환했다. EC2에서는 고정 IP를 자유롭게 설정할 수 있었고, 기존 NestJS 인스턴스에 Express를 통해 발송 로직을 간단히 통합했다.


최종 발송 시스템

이제 EC2에서 실행되는 Express 서버와 NestJS를 결합해 알림톡 발송 로직을 처리하게 되었다.

TypeScript

이 방식은 안정적으로 작동했으며, 비용 효율성과 확장성을 동시에 확보할 수 있었다.


결론적으로...

Lambda로 시작했던 발송 시스템은 IP 제한 문제로 인해 EC2로 전환되었다. 아쉬움은 있었지만, 결과적으로는 더 안정적이고 실용적인 구조를 만들 수 있었다. 특히 MongoDB와 NestJS 기반의 템플릿 관리 시스템 덕분에 cron.js에 종속되지 않는 더 유연한 환경을 구축했다.

이 여정을 통해 서버리스의 장단점을 배우는 동시에, 기술적 문제에 유연하게 대응하는 중요성을 다시금 느꼈다. 앞으로는 템플릿 관리뿐 아니라 cron.js의 기존 로직 자체를 NestJS로 완전히 분리하는 것을 목표로, 더욱 개선된 구조를 만들어갈 예정이다.

NestJS 서버의 무중단 배포 도입기

시작하며

알림톡 시스템을 EC2로 이전하면서, 안정적인 서비스 운영을 위해 무중단 배포 환경을 구축하게 되었다. Blue-Green 배포 전략, Docker 컨테이너화, GitHub Actions 기반의 CI/CD 등 새로운 기술들을 도입하며 많은 시행착오를 겪었다. 이 글에서는 Docker 설정부터 GitHub Actions까지 하나하나 구체적으로 정리해 보려 한다.


Docker 컨테이너화의 첫걸음

NestJS 애플리케이션을 Docker로 컨테이너화하면서 다단계 빌드(Multi-stage Build)를 적용했다. 이는 빌드와 실행 단계를 분리해 이미지 크기를 줄이고 보안을 강화하는 데 중점을 뒀다.

Dockerfile 설정

PLAIN

이 구조를 통해 실행 환경에 불필요한 빌드 파일을 제거하고 이미지 크기를 최소화할 수 있었다.


Blue-Green 배포 전략 구현

Blue-Green 배포는 두 개의 독립적인 애플리케이션 환경(Blue, Green)을 유지하며, 하나가 운영되는 동안 다른 하나를 배포하는 방식이다. 이를 통해 무중단 배포가 가능하며, 문제 발생 시 즉각 롤백이 가능하다.

Docker Compose 설정

YAML

두 컨테이너(Blue와 Green)는 동일한 설정을 공유하며, 배포 과정에서 번갈아 활성화된다. 각 컨테이너에 메모리 제한을 설정해 안정성을 확보했다.


배포 스크립트 작성

배포 과정의 자동화를 위해 Shell Script를 작성했다. 새로운 컨테이너를 배포하고 헬스 체크 후 문제가 없으면 이전 컨테이너를 종료한다.

deploy.sh

Bash

GitHub Actions를 통한 CI/CD

코드가 main 브랜치에 병합되면 자동으로 배포가 이루어지도록 GitHub Actions를 구성했다.

.github/workflows/deploy.yml

YAML

GitHub Actions는 배포 과정을 자동화하며, EC2에 SSH로 접속해 deploy.sh 스크립트를 실행한다. 이를 통해 코드 업데이트와 배포가 완전히 자동화되었다.


Portainer를 활용한 컨테이너 모니터링

운영 중인 컨테이너의 상태를 실시간으로 모니터링하고 관리하기 위해 Portainer를 도입했다.

Portainer 설정

YAML

Portainer는 직관적인 UI를 제공해 컨테이너 상태, 리소스 사용량, 로그를 실시간으로 확인할 수 있었다.


결론적으로...

Docker 기반의 Blue-Green 배포와 GitHub Actions CI/CD를 성공적으로 구축하며, 무중단 배포 환경을 완성할 수 있었다. 특히 배포 자동화와 모니터링 강화 덕분에 운영 효율성이 크게 향상되었고, 서비스 안정성도 확보할 수 있었다.

앞으로는 카나리 배포와 같은 다른 배포 전략도 도입해 다양한 시나리오에 대비하고자 한다. 또한, Portainer의 대시보드를 커스터마이징하고 로그 집중화 시스템을 구축해 운영 효율성을 더욱 높일 계획이다. 이번 여정은 Docker와 CI/CD의 강력함을 체감하는 좋은 경험이었다.

4o