C4 Container 다이어그램: 예제와 함께 보는 완벽 가이드 - Archyl Blog

C4 컨테이너 다이어그램(C4 모델 레벨 2)은 시스템의 배포 가능한 빌딩 블록을 보여줍니다: 웹 앱, API, 데이터베이스, 큐. 이 가이드는 컨테이너 다이어그램이 무엇인지, 무엇이 들어가야 하는지, 완전하게 작성한 예제, 흔한 실수, 그리고 코드와 동기화 상태를 유지하는 방법을 설명합니다.

C4 Container 다이어그램: 예제와 함께 보는 완벽 가이드

시스템을 위해 단 하나의 아키텍처 다이어그램만 그릴 수 있다면, 컨테이너 다이어그램으로 하세요. 이것은 C4 모델의 레벨 2이며, 실무에서는 네 가지 레벨 중 가장 많이 사용됩니다 — 엔지니어링 팀이 실제로 빌드하고, 배포하고, 운영하는 것들, 즉 웹 앱, API, 데이터베이스, 메시지 브로커에 직접 대응되기 때문입니다.

이 가이드는 좋은 C4 컨테이너 다이어그램을 만드는 데 필요한 모든 것을 다룹니다: 그것이 무엇인지(그리고 무엇이 아닌지 — 아니요, C4 컨테이너는 Docker 컨테이너가 아닙니다), 무엇이 들어가야 하는지, 전형적인 SaaS 제품에 대해 완전하게 작성한 예제, 대부분의 컨테이너 다이어그램을 망치는 실수들, 그리고 수동으로 만들거나 코드베이스에서 생성하는 방법까지.

C4 모델 자체가 완전히 처음이라면, 먼저 C4 모델 완벽 가이드부터 읽고 여기로 돌아오세요.

C4 Container 다이어그램이란 무엇인가?

컨테이너 다이어그램은 Simon Brown이 만든 C4 모델의 레벨 2입니다. System Context 다이어그램에서 시스템을 나타내던 하나의 상자 안으로 확대하여, 그 안의 상위 수준 기술 빌딩 블록을 드러냅니다.

C4 용어에서 컨테이너는 개별적으로 배포 가능하거나 실행 가능한 모든 단위입니다: 코드를 실행하거나 데이터를 저장하고, 자체 프로세스에서 실행되며(또는 자체 스토리지 생명주기를 가지며), 원칙적으로 시스템의 나머지 부분과 독립적으로 배포될 수 있는 것입니다.

그 정의는 다음과 같은 것들을 포괄합니다:

  • 사용자의 브라우저에서 실행되는 싱글 페이지 애플리케이션(React, Vue, Angular)
  • 서버 사이드 웹 애플리케이션(Next.js, Rails, Django)
  • 모바일 애플리케이션(iOS 앱, Android 앱)
  • 백엔드 API 서비스(Go API, Node.js 서버, Spring Boot 서비스)
  • 데이터베이스(PostgreSQL, MongoDB, MySQL)
  • 캐시(Redis, Memcached)
  • 메시지 브로커 또는 큐(Kafka, RabbitMQ, SQS)
  • 백그라운드 워커 또는 예약된 작업 프로세스
  • 파일 또는 블롭 저장소(S3 버킷, MinIO)
  • 서버리스 함수(AWS Lambda, Cloud Functions)

판별 기준은 간단합니다: 자체 프로세스에서 실행되거나 자체 데이터를 보유하는가? 하나의 바이너리로 컴파일된 두 개의 Go 패키지는 동일한 컨테이너에 속합니다. 독립적으로 배포되는 두 개의 서비스는 두 개의 컨테이너입니다 — 같은 리포지토리를 공유하더라도 말입니다.

간결한 참조 정의는 용어집의 컨테이너 다이어그램 항목을 참고하세요.

C4 컨테이너는 Docker 컨테이너가 아닙니다

이것이 가장 흔한 혼동 지점이므로 명시적으로 정리하겠습니다.

C4 모델은 Docker의 주류 채택보다 앞서며, C4에서 "컨테이너"라는 단어는 더 넓은 의미입니다: 시스템의 런타임 수준 빌딩 블록입니다. Docker와의 겹침은 우연적이고 부분적입니다:

  • C4 컨테이너는 Docker 컨테이너 안에서 실행될 수도 있습니다. 당신의 Go API는 아마 그럴 것입니다.
  • C4 컨테이너는 평범한 OS 프로세스, 브라우저 탭, 모바일 앱, 또는 관리형 클라우드 서비스로 실행될 수도 있습니다. 그중 어느 것도 Docker 컨테이너가 아닙니다.
  • 하나의 Docker 컨테이너가 여러 개의 C4 컨테이너를 호스팅할 수도 있습니다(개발 이미지에서 앱과 임베드된 데이터베이스). 비록 그것은 드문 경우이지만요.

달리 말하면: Docker 컨테이너는 패키징 및 배포 기술입니다. C4 컨테이너는 아키텍처적 추상화입니다. Chrome에서 실행되는 React SPA는 C4 컨테이너이며 결코 Docker 컨테이너가 되지 않을 것입니다. RDS PostgreSQL 인스턴스는 C4 컨테이너이며 Docker는 어디에도 보이지 않습니다.

C4 다이어그램에서 어떤 상자에 "컨테이너"라는 레이블을 붙일 때, 당신은 "이것은 내 시스템의 개별적으로 실행 가능하거나 배포 가능한 부분이다"라고 말하는 것입니다 — 그 이상은 아닙니다.

컨테이너 다이어그램에 들어가야 하는 것

좋은 컨테이너 다이어그램은 정확히 세 가지 범주의 정보를 보여줍니다:

1. 컨테이너 그 자체

시스템 경계 안의 모든 배포 가능하거나 실행 가능한 단위로, 각각 그 이름, 책임, 그리고 기술 선택으로 레이블이 붙습니다: "Order Service (Go)", "Session Cache (Redis)", "Web App (React SPA)". 기술 레이블은 장식이 아닙니다 — 그것은 다이어그램 가치의 절반입니다. 신입 엔지니어나 플랫폼 팀이 열두 개의 리포지토리를 열지 않고도 시스템을 추론할 수 있게 해주는 것이 바로 그것입니다.

2. 관계와 프로토콜

컨테이너 사이의 화살표로, 각각 무엇이 어떻게 흐르는지로 레이블이 붙습니다: "주문을 읽고 씀 (SQL)", "이벤트를 발행함 (AMQP)", "API를 호출함 (HTTPS/JSON)". 통신 프로토콜은 이 레벨에서 중요합니다. 왜냐하면 운영 관심사 — 네트워크 정책, 지연 시간 예산, 재시도 의미, 실패 모드 — 를 좌우하기 때문입니다.

3. 직접적인 컨텍스트

컨텍스트 다이어그램의 사용자와 외부 시스템을 가장자리에 두어, 독자가 요청이 시스템에 어떻게 들어오고 나가는지 볼 수 있게 합니다. 그것들을 자세히 다시 문서화하지는 않습니다. 그것들은 앵커입니다.

이 다이어그램은 누구를 위한 것인가?

컨테이너 다이어그램의 대상 독자는 기술적입니다: 팀에 합류하는 개발자, 구조적 결정을 내리는 아키텍트, 그리고 배포·모니터링·용량을 계획하는 운영/플랫폼 엔지니어입니다. "이 두 서비스가 데이터베이스를 공유해야 할까?" 또는 "Redis가 다운되면 무엇이 깨질까?" 같은 대화가 실제로 일어나는 레벨입니다. 비기술 이해관계자는 대신 컨텍스트 다이어그램을 보고 있어야 합니다.

들어가서는 안 되는 것

  • 내부 모듈, 클래스, 패키지 — 그것들은 컴포넌트 다이어그램(레벨 3)에 있습니다
  • 로드 밸런서, VPC, Kubernetes 노드 같은 인프라 세부 사항 — 그것들은 배포 다이어그램에 속합니다
  • 모든 미세 상호작용 — 관계가 아키텍처적으로 의미 있지 않다면, 빼두세요

컨테이너 다이어그램 예제: SaaS 웹 제품

가상의 SaaS 제품 — 웹 기반 청구서 작성 도구 "InvoiceHub" — 에 대한 완전한 컨테이너 다이어그램 예제를 만들어 봅시다. 이 형태(SPA + API + 데이터베이스 + 캐시 + 워커 + 큐)는 실제 웹 제품의 상당 부분을 설명하므로, 아마 직접 응용할 수 있을 것입니다.

컨테이너

컨테이너 기술 책임
Web Application React SPA 고객이 청구서를 작성하고 보내는 데 사용하는 UI
API Application Go (Fiber) 비즈니스 로직, 인증, SPA가 소비하는 REST API
Database PostgreSQL 계정, 청구서, 결제의 기록 시스템
Cache Redis 세션 저장 및 청구서 요약의 핫패스 캐싱
Message Queue RabbitMQ 느린 작업(PDF 렌더링, 이메일)을 API 요청에서 분리
Background Worker Go 큐 메시지 소비: PDF 렌더링, 이메일 전송, 결제 상태 동기화

관계

[Customer] --> [Web Application (React SPA)] : Uses (HTTPS)
[Web Application] --> [API Application (Go)] : Makes API calls (HTTPS/JSON)
[API Application] --> [Database (PostgreSQL)] : Reads/writes invoices and accounts (SQL/TCP)
[API Application] --> [Cache (Redis)] : Reads/writes sessions and cached summaries (RESP)
[API Application] --> [Message Queue (RabbitMQ)] : Publishes invoice.created, email.requested (AMQP)
[Background Worker (Go)] --> [Message Queue] : Consumes jobs (AMQP)
[Background Worker] --> [Database (PostgreSQL)] : Updates job and payment status (SQL/TCP)
[Background Worker] --> [Email Service (SendGrid)] : Sends invoice emails (HTTPS/REST)
[API Application] --> [Payment Gateway (Stripe)] : Creates payment links, receives webhooks (HTTPS/REST)

이 다이어그램이 알려주는 것

그 목록을 다시 읽어보고, 그것이 얼마나 많은 구체적인 엔지니어링 질문에 답하는지 주목하세요:

  • 상태는 어디에 사는가? 두 곳입니다: PostgreSQL(영속적)과 Redis(휘발성). 세션이 Redis 재시작 후에도 살아남는지 논쟁해 본 적이 있다면, 다이어그램이 그 질문을 가시화합니다.
  • 실패의 폭발 반경은 무엇인가? 워커와 API는 데이터베이스를 공유합니다. RabbitMQ가 다운되면 청구서는 여전히 생성되지만 이메일은 큐에 쌓입니다 — 설계상 그렇게 되도록 한 것입니다.
  • 신뢰 경계는 무엇인가? SPA는 신뢰할 수 없는 클라이언트 기기에서 실행됩니다. 그것이 할 수 있는 모든 것은 API의 인증을 거칩니다.
  • 운영이 실행해야 하는 것은 무엇인가? 여섯 가지, 그 프로토콜과 함께. 그것이 당신의 모니터링 체크리스트이자 대략 당신의 docker-compose 파일입니다.

신입 개발자는 이것을 2분 안에 흡수할 수 있습니다. 그것이 바로 C4 모델 레벨 2의 핵심입니다.

흔한 컨테이너 다이어그램 실수

대부분의 컨테이너 다이어그램은 몇 가지 예측 가능한 방식 중 하나로 실패합니다.

컨테이너와 컴포넌트 혼동하기

컨테이너 다이어그램에 "OrderController", "InvoiceRepository", "AuthMiddleware"가 보인다면, 한 레벨 너무 깊이 확대한 것입니다. 그것들은 컴포넌트 — 컨테이너 내부의 내부 빌딩 블록 — 이며 레벨 3 컴포넌트 다이어그램에 속합니다. 판별 기준: 그것이 독자적으로 배포되거나 실행될 수 있는가? 리포지토리 클래스는 그럴 수 없습니다. 각 다이어그램을 하나의 줌 레벨에 유지하세요. 레벨을 섞는 것이 읽을 수 없는 다이어그램을 만드는 가장 빠른 방법입니다.

데이터 저장소 누락하기

팀은 종종 코드를 작성한 것들만 그리고, 데이터베이스, 캐시, 큐도 컨테이너라는 것을 잊습니다. 데이터 저장소가 없는 컨테이너 다이어그램은 아키텍트와 운영 엔지니어가 가장 필요로 하는 정보를 정확히 숨깁니다: 상태가 어디에 사는지, 무엇이 공유되는지, 무엇이 단일 장애 지점인지. 시스템이 PostgreSQL, Redis, S3를 사용한다면, 셋 다 다이어그램에 들어갑니다.

런타임 구조 대신 배포를 그리기

컨테이너 다이어그램은 인프라 다이어그램이 아닙니다. 로드 밸런서, Kubernetes 파드, 오토스케일링 그룹, 가용 영역, 복제본 수는 배포 관심사입니다 — C4에는 그것들을 위한 별도의 보조 배포 다이어그램이 있습니다. 컨테이너 다이어그램은 "논리적 런타임 조각은 무엇이고 그들이 어떻게 통신하는가?"에 답하지, "몇 개의 인스턴스가 어디서 실행되는가?"에 답하지 않습니다. 세 개의 복제본을 실행한다고 동일한 "API" 상자 세 개를 그리는 것은 정보가 아니라 노이즈를 더합니다.

레이블이 없거나 모호한 관계

그냥 "사용함"이라고만 적힌 화살표는 다이어그램의 잠재력을 낭비합니다. "API를 호출함 (HTTPS/JSON)", "주문 이벤트를 발행함 (AMQP)", "세션을 읽고 씀 (RESP)" — 동사와 프로토콜이 그림을 문서로 바꿉니다.

썩게 내버려 두기

가장 치명적인 실수는 다이어그램 위에 있지도 않습니다. 18개월 전에 그린, 이후 네 개의 서비스로 분할한 모놀리스를 여전히 보여주는 컨테이너 다이어그램은 모든 새로운 독자를 적극적으로 오도합니다. 노후화된 아키텍처 문서는 없는 것보다 나쁩니다 — 그것이 바로 다이어그램을 코드와 동기화 상태로 유지하는 것이 그것이 얼마나 예쁜지보다 더 중요한 이유입니다.

컨테이너 다이어그램 만드는 법

수동으로

탄탄한 컨테이너 다이어그램을 한 시간 안에 만들 수 있습니다:

  1. 컨텍스트 다이어그램에서 시작하기. 사용자와 외부 시스템을 가장자리에 둡니다.
  2. 배포 가능한 단위 나열하기. 리포지토리, docker-compose 파일, 클라우드 콘솔을 살펴보세요. 자체 프로세스로 실행되거나 데이터를 저장하는 모든 것이 후보입니다.
  3. 데이터 저장소를 명시적으로 추가하기. 데이터베이스, 캐시, 큐, 블롭 스토리지.
  4. 관계 그리기. 통신하는 각 컨테이너 쌍에 대해, 동사구와 프로토콜이 붙은 화살표를 추가합니다.
  5. 기술 레이블 붙이기. 모든 상자에 이름과 기술을.
  6. 팀과 함께 검토하기. 이것이 촉발하는 토론("잠깐, 워커가 Stripe와 직접 통신한다고?")은 보통 다이어그램 자체보다 더 가치가 있습니다.

어떤 도구로도 됩니다 — Structurizr, C4 확장이 있는 PlantUML, draw.io, 심지어 화이트보드. 표기법은 내용과 그것을 최신으로 유지하는 규율보다 훨씬 덜 중요합니다.

Archyl로

수동 접근법에는 하나의 구조적 약점이 있습니다: 그것은 스냅샷을 포착하는데, 소프트웨어는 가만히 있지 않습니다. Archyl은 컨테이너 다이어그램에 반대 방향에서 접근합니다 — 코드로부터 모델을 도출합니다:

  • 코드베이스로부터의 AI 디스커버리. 리포지토리를 연결하면 Archyl의 AI 디스커버리가 코드 구조, 설정, 의존성 매니페스트를 분석하여 초안 C4 모델 — 시스템, 컨테이너, 컴포넌트, 그리고 그것들 사이의 관계 — 을 제안합니다. 기억에 의존해 상자를 그리는 대신 제안을 검토하고 승인합니다.
  • 표류 탐지가 정직하게 유지해 줍니다. 모델이 존재하면, Archyl은 문서화된 컨테이너를 코드베이스가 실제로 보여주는 것과 지속적으로 비교하고 표류 점수를 드러냅니다. 누군가 서비스를 분할하거나 RabbitMQ를 Kafka로 교체하면, 6개월 후의 혼란스러운 온보딩 세션이 아니라 대시보드로부터 알게 됩니다.
  • Architecture as Code. 텍스트를 선호하시나요? 전체 C4 모델 — 컨테이너, 기술, 관계 — 을 YAML로 정의하고, 코드와 함께 버전 관리하면, Archyl이 인터랙티브 다이어그램을 렌더링합니다. 다이어그램 변경은 다른 모든 것과 마찬가지로 풀 리퀘스트를 거칩니다.

어느 쪽이든 목표는 동일합니다: 오늘 정확하고 동시에 다음 분기에도 여전히 정확한 컨테이너 다이어그램.

FAQ

C4 컨테이너는 Docker 컨테이너와 같은가요?

아니요. C4 컨테이너는 아키텍처적 추상화입니다: 웹 앱, API, 데이터베이스, 메시지 브로커 같은, 시스템의 개별적으로 배포 가능하거나 실행 가능한 모든 단위입니다. Docker 컨테이너는 패키징 기술입니다. 많은 C4 컨테이너가 마침 Docker 컨테이너로 배포되지만, 그렇지 않은 것도 많습니다 — React SPA는 브라우저에서 실행되고, 모바일 앱은 폰에서 실행되며, 관리형 데이터베이스는 클라우드 서비스로 실행됩니다. 같은 이름은 불행한 역사적 우연입니다.

C4 모델 레벨 2는 무엇인가요?

C4 모델의 레벨 2는 컨테이너 다이어그램입니다. 하나의 소프트웨어 시스템(레벨 1 컨텍스트 다이어그램의 단일 상자) 안으로 확대하여 그 안의 배포 가능한/실행 가능한 단위, 그 기술 선택, 그리고 통신에 사용하는 프로토콜을 보여줍니다. 컨텍스트 다이어그램(레벨 1)과 컴포넌트 다이어그램(레벨 3) 사이에 위치합니다.

컨테이너 다이어그램은 몇 개의 컨테이너를 보여줘야 하나요?

엄격한 규칙은 없지만, 15-20개의 컨테이너를 넘어서면 가독성이 빠르게 떨어집니다. 시스템에 정말로 더 많다면, 뷰를 분할하세요: 하위 시스템마다 컨테이너 다이어그램 하나씩, 또는 관련 컨테이너를 시각적으로 그룹화하세요. 수백 개라면, 아마 여러 시스템을 문서화하고 있는 것이며 컨텍스트 레벨에서 연결된 별도의 C4 모델이 필요합니다.

마이크로서비스는 각각 별도의 컨테이너여야 하나요?

네 — 정의상 그렇습니다. 독립적으로 배포 가능한 각 서비스는 자체 컨테이너이며, 서비스별 데이터베이스를 따른다면 각 서비스의 데이터베이스도 함께입니다. 이것은 또한 유용한 냄새 테스트이기도 합니다: 당신의 "마이크로서비스"가 프로세스를 공유하거나 독립적으로 배포할 수 없어서 별도의 컨테이너로 그릴 수 없다면, 그것은 분산 모놀리스일 수 있습니다.


컨테이너 다이어그램을 그리는 대신 생성할 준비가 되셨나요? Archyl을 무료로 사용해 보고 몇 분 안에 코드베이스로부터 C4 모델을 얻으세요. C4 시리즈를 계속 탐색하세요: C4 모델이란 무엇인가? 완벽 가이드 | C4 System Context 다이어그램 가이드 | C4 Component 다이어그램 가이드.