서론
얼마 전 상용배포 과정에서 서버 장애가 여러 번 발생했다.
체크리스트 점검이 미흡했던 것도 사실이지만, 어떤 형태의 실수가 있더라도 서버 가용성을 유지할 수 있는 방법을 조사해보기로 했다.
본론
현재 상황
현재 우리 팀에서는 AWS의 Elastic Beanstalk과 Code Pipeline 을 주축으로 사용하여 배포하고 있다.
깃허브의 상용 브랜치에 작업이 머지되면 codepipeline의 첫번째 단계가 trigger 되고, 빌드 단계를 거쳐 빈스톡에 배포된다.
빌드 단계에서 데이터베이스 마이그레이션이 함께 실행되어 코드 배포 전에 데이터베이스 스키마가 변경될 수 있도록 하고 있다.
빈스톡 배포는 rolling with additinonl batch 로 설정되어 다운타임 없이 변경사항을 배포하고 있다.
지금 사용중인 인프라를 점검해보기로 했다.
1. Elastic Beanstalk 을 살펴보기
rolling with additinonl batch 의 경우 deploy batch size를 추가 설정할 수 있는데, 기존에는 100%로 되어있었다.
즉 기존 인스턴스만큼의 추가 인스턴스를 띄운 뒤, 헬스체크를 통과하면 전부 교체되는 방식이다.
이것을 25~50% 로 변경할 경우, 배포에 걸리는 총 시간은 늘어나지만, 잘못된 코드가 배포되더라도 설정한 비율 만큼의 인스턴스가 반복적으로 교체되며 완전히 배포되기 때문에, 그 과정에 해당 인스턴스를 종료할 수도 있고, 전체 서비스에 미치는 영향이 적다.
이외에, 빈스톡 환경을 복제하여 복제한 환경(그린 환경, 블루그린배포)에 배포한 뒤에 테스트를 거쳐 실제 환경과 트래픽을 교체하는 방법 [링크], Canary 배포와 Immutable (변경불가)배포 옵션도 있다.
Elastic Beanstalk를 사용한 블루/그린 배포 - AWS Elastic Beanstalk
이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.
docs.aws.amazon.com
2. Code Pipeline 의 phase 를 재구성해보기
데이터 베이스 변경을 빌드 단계에서 별도의 단계로 분리하여 특화된 알림을 설정할 수도 있고, 실제 서비스에 반영되는 것임을 명시함으로써 개발자가 직접 적절한 모니터링을 시작할 수 있도록 할 수 있다.
3. AWS의 다른 서비스를 활용하기
배포 전 코드빌드에서 또는 위의 그린 환경 등에서 서버의 최소한의 동작(DB 연결, 클라이언트 생성 등)을 테스트하는 로직을 실행하도록 buildspec yml 파일에 해당 내용을 추가할 수 있다. 특히 이 때 필요한 환경변수를 코드빌드 자체의 환경변수 설정에 추가하는 것이 아니라 시크릿매니저를 사용하면, 코드빌드에 설정된 변수가 운영환경에 설정되지 않는 것과 같이 찾아내거나 예상하기 힘든 원인으로 인한 장애를 줄일 수 있을 것이다.
4. AI 를 활용하기
이번 장애의 원인 중 하나는 수십만 건의 로우를 가진 테이블에 컬럼을 추가하는 마이그레이션 파일이었다. 이에 테이블에 컬럼을 추가하거나 외래키, 인덱스 생성시 online ddl 여부, chunked update를 검토하거나, 블루그린 배포를 제안하는설정을 깃헙 제미나이 리뷰봇에 추가하는 의견이 있었다.
5. github action 의 workflow 활용하기
먼저 PR 디스크립션의 템플릿에 공통 배포 점검 리스트를 적용하고, main 브랜치에 병합하려는 PR 의 경우 모두 체크되었는지를 확인하는 yml 파일을 만들어 적용할 수 있다. 이 단계를 통과하지 못하면 병합 버튼이 enable 되지 않도록 설정할 수도 있을 것이다.
name: Checklist Validator
on:
pull_request:
types: [opened, edited, synchronize, reopened]
jobs:
checklist:
if: github.event.pull_request.base.ref == 'subgraph'
runs-on: ubuntu-latest
steps:
- name: Check PR checklist
uses: actions/github-script@v7
with:
script: |
const body = context.payload.pull_request.body || "";
const unchecked = body.match(/- \[ \]/g);
if (unchecked) {
core.setFailed(`❌ 체크리스트 ${unchecked.length}개가 완료되지 않았습니다.`);
} else {
core.info("✅ 모든 체크리스트가 완료되었습니다.");
}'배운 것들 > 회고' 카테고리의 다른 글
| 2025년 회고: 중니어가 되어가는 과정 (2) | 2026.01.16 |
|---|---|
| 왜 내 개발 일정은 밀릴까.. (2) | 2025.10.23 |