분산 배포를 위한 개발
Source: Dev.to
모범 사례 및 고려 사항
소개
이 글의 아이디어는 연초에 제가 프로젝트 시작 시 고려해야 할 요소에 관한 글을 올린 뒤, 클라우드 환경을 배우기 시작한 동료들과 이야기를 나누면서 떠올랐습니다.
애플리케이션은 이제 클라우드 공급자(AWS, Azure, GCP)든, Kubernetes 같은 오케스트레이터든, 관리형 서비스든, 서버리스 함수든, 혹은 온‑프레미스 분산 인프라든, 분산된 환경에 배포되는 경우가 많습니다.
이러한 분산 환경을 대상으로 하는 애플리케이션 개발은 여러 가지 특수한 측면을 고려해야 합니다.
다음은 탄력적이고 확장 가능한 분산 애플리케이션을 개발하기 위한 핵심 실천 항목 및 고려 사항 목록입니다.
이 글에서는 주로 장기 실행 서비스에 대한 고려 사항을 다룹니다. 대부분의 내용은 서버리스 함수와 이벤트 기반 애플리케이션에도 동일하게 적용됩니다.
동일 서비스를 위한 다수의 일회성 인스턴스
여러 복제본, 하나의 목표
가장 중요한 고려 사항은 애플리케이션이 동시에 여러 인스턴스가 실행될 수 있는 환경에서도 정상적으로 동작하도록 설계되어야 한다는 점입니다. 즉, 한 인스턴스가 다른 인스턴스와 충돌하지 않아야 하며, 작업 중복을 피해야 합니다. 애플리케이션은 로컬 상태나 특정 인스턴스에 종속적인 리소스에 의존해서는 안 됩니다. 이러한 요소들은 인스턴스 간 또는 재시작 시에 보장되지 않을 수 있기 때문입니다.
수평 확장(인스턴스 추가)이나 복원력(실패한 인스턴스 재시작)을 위해 인스턴스 수는 실제 혹은 예상 부하, 시간 등에 따라 변합니다. 따라서 애플리케이션은 충돌 없이 다수의 인스턴스를 동시에 처리할 수 있어야 합니다.
또한 대부분 자동으로 시작될 가능성이 높으므로, 설계 및 구현 단계에서 이러한 점을 염두에 두어야 합니다.
로드 밸런서 / 리버스 프록시 뒤의 아키텍처
서비스 센터의 콜 분배기와 같이: 각 요청은 요청 내용에 따라 청구, 지원, 계정 등 적절한 부서로 전달됩니다.
대부분의 경우, 애플리케이션 인스턴스는 로드 밸런서(트래픽 분산 장치) 뒤에 배포됩니다. 로드 밸런서는 들어오는 트래픽을 여러 인스턴스에 고르게 분배합니다.
**스티키 세션(sticky sessions)**을 사용하면 로드 밸런서가 동일한 인스턴스로 재요청을 라우팅하도록 할 수 있습니다. 하지만 초기 처리를 담당한 인스턴스가 더 이상 사용 가능하지 않을 수도 있습니다(스케일‑다운, 업데이트 등) 혹은 로드 밸런서가 스티키 세션을 지원하지 않을 수도 있습니다. 이런 경우 애플리케이션은 이전 요청을 처리하지 않은 상태에서도 요청을 받아 처리할 수 있어야 합니다.
현대 아키텍처에서는 로드 밸런서 혹은 API 게이트웨이가 요청에 따라 서로 다른 서비스로 라우팅하기도 합니다:
- 경로 기반 라우팅:
/api/users→ 사용자 서비스,/api/orders→ 주문 서비스 - 호스트 기반 라우팅:
api.example.com→ API,static.example.com→ 정적 리소스 - 헤더 또는 API 버전 기반 라우팅:
X-Client: mobile혹은Accept: application/vnd.company.v2+json - 메서드 또는 포트 기반 라우팅(드물게), 기술적 제약에 따라
개발 측면에서의 의미는 로컬 세션 상태에 대한 가정을 피해야 한다는 것입니다. 요청이 다른 서비스나 인스턴스로 전달될 수 있기 때문에, 여러 서비스에 걸쳐 요청을 추적할 수 있도록 상관관계 ID를 전파하는 것이 매우 유용합니다.
설정 외부화
설정을 외부화하는 것은 전화기에 SIM 카드를 삽입하는 것과 같습니다: 동일한 기기지만 네트워크에 맞게 설정이 바뀝니다. SIM을 교체하면 Bell, Vidéotron, Orange 등 공급자를 바꿀 수 있지만, 전화기 자체는 바뀌지 않습니다.
애플리케이션 코드를 재컴파일하지 않고도 파라미터를 변경할 수 있도록 설정을 코드와 분리하는 것이 핵심입니다. 가장 흔한 방법은 환경 변수를 사용하는 것입니다. 자세한 내용은 12‑factor app (Config 섹션)을 참고하세요.
클라우드 공급자들은 설정 외부화를 위한 서비스를 제공합니다:
- AWS Systems Manager Parameter Store
- Azure App Configuration
- GCP Secret Manager
또는 Consul, etcd, Spring Cloud Config와 같은 자체 설정 서비스를 배포할 수도 있습니다. 이 경우 애플리케이션이 해당 서비스에서 설정을 읽어오도록 구현해야 합니다.
선택은 배포 전략에 따라 달라집니다. 단일 클라우드 공급자, 다중 공급자, 혹은 향후 공급자를 교체할 가능성을 고려한다면 공급자에 종속되지 않는 솔루션을 선택해 vendor lock‑in을 방지하는 것이 좋습니다.
Feature flag와 동적 설정
Feature flag는 코드를 재컴파일하거나 재배포하지 않고도 기능을 켜고 끌 수 있게 해줍니다(애플리케이션이 런타임에 이를 지원하도록 설계된 경우). 주요 활용 사례는 다음과 같습니다:
- 점진적 배포: 새로운 기능을 전체 사용자 중 일부 비율 혹은 특정 그룹에만 활성화
- A/B 테스트: 기능의 여러 버전을 동시에 시험
- Kill switch: 문제가 발생한 기능을 즉시 비활성화
- 환경별 기능: 개발 혹은 QA 환경에서는 활성화하고, 프로덕션에서는 비활성화
LaunchDarkly, Unleash, Split.io, AWS AppConfig 등과 같은 도구를 사용해 Feature flag를 관리할 수 있습니다.
비밀 관리
비밀번호, API 키, 인증서와 같은 비밀을 코드나 버전 관리되는 설정 파일에 직접 저장해서는 안 됩니다. 대신 비밀 관리 서비스를 이용하세요:
- AWS Secrets Manager
- Azure Key Vault
- GCP Secret Manager
- Kubernetes Secrets(휴지 상태 암호화 활성화)
- HashiCorp Vault
- SOPS(설정 파일 암호화용)
이들 솔루션은 다음을 제공합니다: 저장 및 전송 중 비밀 암호화, 세분화된 접근 제어, 자동 비밀 회전, 접근 감사 로그 등.
작업 파일 또는 업로드 파일 백업
클라우드에서 로컬 디스크에 쓰는 것은 카페 테이블에 메모를 남겨두는 것과 같습니다: … (텍스트가 불완전합니다).