배포 및 출시 (Shipping and Launch)
개요
자신감을 가지고 출시하세요. 목표는 단순히 배포하는 것이 아닙니다. 모니터링을 갖추고, 롤백 계획을 준비하며, 성공의 기준을 명확히 이해한 상태에서 안전하게 배포하는 것입니다. 모든 출시는 되돌릴 수 있고( reversible), 관찰 가능해야 하며(observable), 점진적으로(incremental) 이루어져야 합니다.
사용 시점
- 기능을 처음으로 프로덕션에 배포할 때
- 사용자에게 큰 변화를 출시할 때
- 데이터 또는 인프라를 마이그레이션할 때
- 베타 또는 얼리 액세스 프로그램을 시작할 때
- 위험을 수반하는 모든 배포 (사실상 모든 배포)
출시 전 체크리스트
코드 품질
- 모든 테스트 통과 (단위, 통합, E2E)
- 빌드 성공 (경고 없음)
- 린트 및 타입 검사 통과
- 코드 리뷰 완료 및 승인
- 출시 전에 해결해야 할 TODO 주석 없음
- 프로덕션 코드에
console.log디버깅문 없음 - 예상되는 실패 모드에 대한 오류 처리 존재
보안
- 코드나 버전 관리에 비밀값(secret) 없음
- 생태계의 의존성 감사(
npm audit,pip-audit,cargo audit, ...)에서 치명적 또는 높은 수준의 취약점 없음 - 모든 사용자 대상 엔드포인트에 입력 검증 존재
- 인증 및 권한 부여 검사 마련
- 보안 헤더 구성 (CSP, HSTS 등)
- 인증 엔드포인트에 속도 제한 적용
- CORS가 특정 오리진(와일드카드 아님)으로 구성됨
성능
- Core Web Vitals가 "Good" 임계값 내에 있음
- 중요 경로에 N+1 쿼리 없음
- 이미지 최적화 (압축, 반응형 크기, 지연 로딩)
- 번들 크기 예산 이내
- 데이터베이스 쿼리에 적절한 인덱스 존재
- 정적 자산 및 반복 쿼리에 캐싱 구성
접근성
- 모든 대화형 요소에 키보드 탐색 작동
- 스크린 리더가 페이지 콘텐츠와 구조 전달 가능
- 색상 대비가 WCAG 2.1 AA (텍스트 4.5:1) 충족
- 모달 및 동적 콘텐츠에 대한 포커스 관리 올바름
- 오류 메시지가 설명적이며 양식 필드와 연결됨
- axe-core 또는 Lighthouse에서 접근성 경고 없음
인프라
- 프로덕션 환경 변수 설정됨
- 데이터베이스 마이그레이션 적용됨 (또는 적용 준비 완료)
- DNS 및 SSL 구성됨
- 정적 자산에 CDN 구성됨
- 로깅 및 오류 보고 구성됨
- 헬스 체크 엔드포인트 존재 및 응답
문서화
- README에 새로운 설정 요구사항 반영
- API 문서 최신 상태 유지
- 아키텍처 결정에 대한 ADR 작성됨
- 변경 로그 업데이트됨
- 사용자 대상 문서 업데이트됨 (해당하는 경우)
피처 플래그 전략
배포와 출시를 분리하기 위해 피처 플래그 뒤에 배포하세요:
// Feature flag check
const flags = await getFeatureFlags(userId);
if (flags.taskSharing) {
// New feature: task sharing
return <TaskSharingPanel task={task} />;
}
// Default: existing behavior
return null;
피처 플래그 수명 주기:
1. OFF 상태로 배포 → 코드는 프로덕션에 있지만 비활성화
2. 팀/베타에 활성화 → 프로덕션 환경에서 내부 테스트
3. 점진적 롤아웃 → 사용자 5% → 25% → 50% → 100%
4. 각 단계별 모니터링 → 오류율, 성능, 사용자 피드백 확인
5. 정리 → 전체 롤아웃 후 플래그와 죽은 코드 제거
규칙:
- 모든 피처 플래그에는 소유자와 만료일이 있어야 함
- 전체 롤아웃 후 2주 이내에 플래그 정리
- 피처 플래그 중첩 금지 (기하급수적 조합 생성)
- CI에서 플래그의 두 상태(켜짐/꺼짐)를 모두 테스트
단계적 롤아웃
롤아웃 순서
1. 스테이징에 배포
└── 스테이징 환경에서 전체 테스트 스위트 실행
└── 중요 흐름 수동 smoke 테스트
2. 프로덕션에 배포 (피처 플래그 OFF)
└── 배포 성공 확인 (헬스 체크)
└── 오류 모니터링 확인 (새로운 오류 없음)
3. 팀에 활성화 (내부 사용자 대상 플래그 ON)
└── 팀이 프로덕션에서 기능 사용
└── 24시간 모니터링 기간
4. 카나리 롤아웃 (사용자 5% 대상 플래그 ON)
└── 오류율, 지연 시간, 사용자 행동 모니터링
└── 메트릭 비교: 카나리 vs. 기준선
└── 24-48시간 모니터링 기간
└── 모든 임계값 통과 시에만 진행 (아래 표 참조)
5. 점진적 증가 (25% -> 50% -> 100%)
└── 각 단계에서 동일한 모니터링
└── 언제든지 이전 비율로 롤백 가능
6. 전체 롤아웃 (모든 사용자 대상 플래그 ON)
└── 1주일간 모니터링
└── 피처 플래그 정리
롤아웃 결정 임계값
각 단계에서 진행, 보류 또는 롤백을 결정하려면 다음 임계값을 사용하세요:
| 메트릭 | 진행 (초록) | 보류 및 조사 (노랑) | 롤백 (빨강) |
|---|---|---|---|
| 오류율 | 기준선 대비 10% 이내 | 기준선 대비 10-100% 상회 | 기준선 대비 2배 초과 |
| P95 지연 시간 | 기준선 대비 20% 이내 | 기준선 대비 20-50% 상회 | 기준선 대비 50% 초과 |
| 클라이언트 JS 오류 | 새로운 오류 유형 없음 | 세션의 0.1% 미만에서 새 오류 | 세션의 0.1% 초과에서 새 오류 |
| 비즈니스 메트릭 | 중립적 또는 긍정적 | 5% 미만 감소 (노이즈 가능) | 5% 초과 감소 |
롤백 시점
다음 상황에서는 즉시 롤백하세요:
- 오류율이 기준선 대비 2배 이상 증가
- P95 지연 시간이 50% 이상 증가
- 사용자 보고 문제 급증
- 데이터 무결성 문제 감지
- 보안 취약점 발견
모니터링 및 관측 가능성
모니터링 항목
애플리케이션 메트릭:
├── 오류율 (전체 및 엔드포인트별)
├── 응답 시간 (p50, p95, p99)
├── 요청량
├── 활성 사용자
└── 주요 비즈니스 메트릭 (전환율, 참여도)
인프라 메트릭:
├── CPU 및 메모리 사용률
├── 데이터베이스 연결 풀 사용량
├── 디스크 공간
├── 네트워크 지연 시간
└── 큐 깊이 (해당하는 경우)
클라이언트 메트릭:
├── Core Web Vitals (LCP, INP, CLS)
├── JavaScript 오류
├── 클라이언트 관점의 API 오류율
└── 페이지 로드 시간
오류 보고
// 오류 경계 설정 및 보고
class ErrorBoundary extends React.Component {
componentDidCatch(error: Error, info: React.ErrorInfo) {
// 오류 추적 서비스에 보고
reportError(error, {
componentStack: info.componentStack,
userId: getCurrentUser()?.id,
page: window.location.pathname,
});
}
render() {
if (this.state.hasError) {
return <ErrorFallback onRetry={() => this.setState({ hasError: false })} />;
}
return this.props.children;
}
}
// 서버 측 오류 보고
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
reportError(err, {
method: req.method,
url: req.url,
userId: req.user?.id,
});
// 사용자에게 내부 정보 노출 금지
res.status(500).json({
error: { code: 'INTERNAL_ERROR', message: '문제가 발생했습니다' },
});
});
출시 후 검증
출시 후 첫 1시간 동안:
1. 헬스 엔드포인트가 200 반환 확인
2. 오류 모니터링 대시보드 확인 (새로운 오류 유형 없음)
3. 지연 시간 대시보드 확인 (성능 저하 없음)
4. 중요 사용자 흐름 수동 테스트
5. 로그가 정상적으로 출력되고 읽을 수 있는지 확인
6. 롤백 메커니즘이 작동하는지 확인 (가능하면 dry run)
에러 예산 출시 게이트
서비스의 에러 예산(서비스 SLO가 실패를 허용하는 요청 또는 시간의 비율)은 출시가 안전한지 여부를 결정합니다. 협상의 대상이 아닌 객관적인 게이트로 사용하세요:
예산 잔여 20% 초과 → 정상 출시; 면밀히 모니터링
예산 잔여 0–20% → 느린 롤아웃만 허용; 고위험 변경 금지
예산 소진 → 기능 작업 중단; 안정성에 집중
예산 재설정 → 정상 속도 재개; 회복에 기여한 수정 사항 유지
카나리 중 높은 소진율(기준선 속도보다 빠르게 예산 소모)은 위 롤아웃 임계값 표에서 보류 신호입니다. 오류율 상승과 동일하게 처리하세요.
롤백 전략
모든 배포는 실행 전에 롤백 계획이 필요합니다:
## [기능/릴리스] 롤백 계획
### 트리거 조건
- 오류율 > 기준선 2배
- P95 지연 시간 > [X]ms
- [특정 이슈]에 대한 사용자 보고
### 롤백 단계
1. 피처 플래그 비활성화 (해당하는 경우)
OR
1. 이전 버전 배포: `git revert <커밋> && git push`
2. 롤백 확인: 헬스 체크, 오류 모니터링
3. 커뮤니케이션: 팀에 롤백 알림
### 데이터베이스 고려 사항
- 마이그레이션 [X]에 롤백 있음: `npx prisma migrate rollback`
- 새 기능으로 삽입된 데이터: [보존 / 정리]
### 롤백 소요 시간
- 피처 플래그: < 1분
- 이전 버전 재배포: < 5분
- 데이터베이스 롤백: < 15분
같이 보기
- 이 체크리스트보다 먼저 모든 변경 사항이 통과해야 하는 프로젝트 전체 완료 정의(Definition of Done)는
../../references/definition-of-done.md참조 - 출시 전 보안 검사는
../../references/security-checklist.md참조 - 출시 전 성능 체크리스트는
../../references/performance-checklist.md참조 - 출시 전 접근성 확인은
../../references/accessibility-checklist.md참조 - 알림 규칙 및 SLO 기반 임계값은
observability-and-instrumentation참조
일반적인 합리화
| 합리화 | 현실 |
|---|---|
| "스테이징에서 잘 작동하니 프로덕션에서도 잘 작동할 거야" | 프로덕션은 데이터, 트래픽 패턴, 엣지 케이스가 다릅니다. 배포 후 모니터링하세요. |
| "이 기능에는 피처 플래그가 필요 없어" | 모든 기능은 킬 스위치의 이점을 누릴 수 있습니다. "단순한" 변경도 문제를 일으킬 수 있습니다. |
| "모니터링은 오버헤드야" | 모니터링이 없으면 대시보드 대신 사용자 불만으로 문제를 발견하게 됩니다. |
| "모니터링은 나중에 추가할게" | 출시 전에 추가하세요. 볼 수 없는 것은 디버깅할 수 없습니다. |
| "롤백은 실패를 인정하는 거야" | 롤백은 책임 있는 엔지니어링입니다. 망가진 기능을 출시하는 것이 실패입니다. |
| "오류율이 괜찮아 보이니 계속 출시하자" | 현재 오류율뿐만 아니라 소진율도 확인하세요. 기준선보다 빠르게 예산을 소모하는 것은 개별 임계값이 초록색이어도 보류 신호입니다. |
위험 신호
- 롤백 계획 없이 배포
- 프로덕션에 모니터링 또는 오류 보고 없음
- 빅뱅 릴리스 (한 번에 모든 것, 스테이징 없음)
- 만료일이나 소유자가 없는 피처 플래그
- 배포 후 첫 1시간 동안 모니터링하는 사람 없음
- 코드가 아닌 기억에 의존하는 프로덕션 환경 구성
- "금요일 오후니까 출시하자"
- 에러 예산이 소진되었지만 기능 작업이 계속됨
검증
배포 전:
- 출시 전 체크리스트 완료 (모든 항목 초록색)
- 피처 플래그 구성됨 (해당하는 경우)
- 롤백 계획 문서화됨
- 모니터링 대시보드 설정됨
- 팀에 배포 알림
배포 후:
- 헬스 체크 200 반환
- 오류율 정상
- 지연 시간 정상
- 중요 사용자 흐름 작동
- 로그 정상 출력
- 롤백 테스트 또는 준비 완료 확인
모든 출시된 서비스에 대해:
- 에러 예산 정책 마련: 예산이 20% 미만으로 떨어지거나 소진되었을 때 취할 조치를 알고 있음