Docker Compose로 보는 결합도
docker-compose 선언에서 의존성·상태 위치·네트워크 경계를 읽어 시스템 결합도와 운영 위험을 드러내는 방법
요약 (5–7줄)
docker-compose는 실행 스크립트가 아니라 시스템의 결합도를 드러내는 설계도다.
서비스 의존성, 상태 저장소, 네트워크 경계, 운영 포인트가 한 파일에 노출된다.
Compose를 읽으면 “어디가 붙어 있고, 어디서 터질 수 있는지”가 보인다.
이 강의 아키텍처는 데이터 흐름 관점에서 Twitter → Kafka → Elastic → Query/Web로 요약된다.
stateful 컴포넌트와 stateless 서비스를 분리하지 못하면 확장·복구가 동시에 무너진다.
로컬 compose와 클라우드 배포는 형태만 다를 뿐, 설계 판단은 그대로 이전된다.
1. 정의
Docker Compose 기반 시스템 결합도란
컨테이너 선언만으로 드러나는 의존성 그래프·상태 위치·운영 개입 지점의 밀도다.
Compose는 “어떻게 띄우는가”가 아니라
“무엇이 무엇에 묶여 있는가”를 보여준다.
2. 직관
코드 없이 compose만 봐도 다음 질문에 답할 수 있어야 한다.
- 이 시스템의 중심(state)은 어디인가?
- 하나가 죽으면 무엇이 같이 죽는가?
- 확장은 어디서 막히는가?
답이 안 나오면 설계가 숨겨진 것이다.
3. 작동원리: Compose가 드러내는 네 가지
3.1 의존성 그래프
depends_on은 시작 순서만 보장- 런타임 의존성은 네트워크/환경변수로 드러남
3.2 상태 저장소
- volume이 붙은 컨테이너 = stateful
- volume 없는 컨테이너 = 교체 가능(stateless)
3.3 네트워크 경계
- 동일 네트워크 = 암묵적 신뢰
- 네트워크 분리 = 경계 명시
3.4 운영 포인트
- env/secret/healthcheck/restart
- 장애 시 사람이 개입할 지점이 노출됨
4. 데이터 흐름으로 본 전체 아키텍처
이 강의의 핵심 흐름은 다음 한 줄이다.
Twitter → Kafka → Elasticsearch → Query/Web
- 입력: 외부 이벤트(트윗)
- 버퍼: Kafka (시간축)
- 투영: Elasticsearch (읽기 최적화)
- 제공: Query/Web API
Compose에서 이 흐름이 컨테이너 연결로 보이지 않으면,
아키텍처는 문서에만 존재한다.
5. Stateful vs Stateless 분리 기준
5.1 Stateful 컴포넌트
- Kafka
- Elasticsearch
- Redis
- Keycloak
- Database
특징:
- 볼륨 필수
- 복구 비용 큼
- 단순 재시작 위험
5.2 Stateless 서비스
- API
- Consumer
- Query 서비스
특징:
- 볼륨 없음
- 수평 확장 가능
- 장애 시 교체
Compose에서 이 둘이 섞이면
확장과 복구가 동시에 불가능해진다.
6. 트레이드오프
- 장점: 구조 가시성, 로컬 재현성, 빠른 피드백
- 비용: 실제 운영과의 차이, 단일 호스트 한계
Compose는 운영 대체재가 아니라
설계 검증 도구다.
7. 로컬 Compose vs 클라우드 배포
바뀌는 것
- 스케줄링
- 네트워크 구현
- 스토리지 제공 방식
- 시크릿 관리
그대로인 것
- 서비스 경계
- 데이터 흐름
- 상태 위치
- 신뢰 경계
클라우드로 가도 설계가 좋아지지는 않는다.
Compose에서 나쁜 설계는 그대로 증폭된다.
8. 운영 관점 필수 체크
8.1 환경변수
- 기본값 존재?
- 민감정보 분리?
8.2 시크릿
- git에 노출?
- env로 주입?
8.3 볼륨
- 백업 전략?
- 권한 설정?
8.4 헬스체크
- 프로세스 생존 vs 기능 정상?
- 의존성 반영?
8.5 재시작 정책
- always vs on-failure
- 무한 재시작 위험?
9. 실무 함정 → 해결 패턴
| 함정 | 결과 | 해결 패턴 |
|---|---|---|
| 모든 서비스 한 네트워크 | 침투 확산 | 네트워크 분리 |
| 상태 서비스 자동 재시작 | 데이터 손상 | 수동 개입 |
| env에 시크릿 | 유출 | secret 분리 |
10. 최소 예시
10.1 Toy 예시: 최소 Compose
- 서비스 A (API)
- 서비스 B (Consumer)
- 브로커 (Kafka)
구조:
- A → Kafka → B
- Kafka만 볼륨 보유
- A/B는 언제든 교체
이 구조가 확장 가능한 최소 단위다.
10.2 실무 예시: “나중에 터질 문제” 점검표 (12)
1) stateful 서비스에 restart: always?
2) Kafka/ES 단일 인스턴스?
3) 볼륨 백업 경로 없음?
4) 네트워크 하나로 통합?
5) 내부 서비스 외부 포트 노출?
6) 시크릿 env 평문?
7) healthcheck 없음?
8) depends_on에 의존한 안정성?
9) 리소스 제한 없음?
10) 로그 볼륨 미분리?
11) 시간대/로케일 불일치?
12) 로컬 전용 설정 하드코딩?
11. 오해/실수 3개 + 교정
1) “Compose는 개발용” → 설계 검증용
2) “depends_on이면 안전” → 시작 순서만 보장
3) “로컬은 대충” → 문제는 로컬에서 이미 보임
12. 판단 기준
사용해야 할 때
- 아키텍처 학습/검증
- 데이터 흐름 점검
- 장애 시나리오 리허설
쓰지 말아야 할 때
- 실제 프로덕션 운영
- 고가용성 요구
- 멀티 호스트 스케줄링
13. 재학습 체크리스트 (10–14)
- 데이터 흐름이 한 눈에 보이는가?
- stateful/stateless가 분리돼 있는가?
- 볼륨이 필요한 곳에만 있는가?
- 네트워크 경계가 명확한가?
- 내부 서비스가 외부에 노출되지 않았는가?
- 시크릿이 코드/compose에 없는가?
- 헬스체크가 의미를 가지는가?
- 재시작 정책이 위험하지 않은가?
- 리소스 제한이 설정됐는가?
- 로그 수집 경로가 분리됐는가?
- 장애 시 수동 개입 지점이 보이는가?
- 클라우드 이전 시 그대로 가져갈 수 있는가?
