왜 모노레포에 Dev Containers가 필요할까
여러 서비스가 한 저장소에 모여 있는 모노레포에서는 언어와 실행 환경이 제각각이라 개발자마다 셋업 시간이 달라집니다. 서비스별 devcontainer.json과 Compose 패턴을 쓰면 팀 전체가 같은 개발 환경을 빠르게 재현할 수 있습니다.
프로젝트가 커질수록 “어떤 Node 버전이죠?”, “DB는 어디에 붙나요?” 같은 질문이 반복되고, 로컬 충돌로 디버깅 시간이 길어집니다. Dev Containers는 코드와 함께 환경을 버전 관리하므로, 변경 이력에 맞춰 안전하게 개발 환경을 동기화할 수 있습니다.
이 글은 모노레포에서 서비스마다 devcontainer.json을 두고, docker-compose로 공용 의존성(DB, 메시지 브로커 등)을 묶는 기본 패턴을 소개합니다. 처음 적용하는 분도 바로 실습할 수 있도록 최소 구성과 폴더 구조, 실무 체크포인트를 단계적으로 설명합니다.
> 안티패턴: 모노레포 루트에 단일 devcontainer만 두고 모든 서비스를 한 컨테이너에 넣으면 빌드 시간과 이미지 크기가 불필요하게 커지고 격리가 무너집니다. 서비스 단위로 분리하고 공용 리소스만 Compose로 공유하세요.
서비스별 devcontainer.json과 Compose 패턴, 무엇을 어떻게 나누나
모노레포에서는 각 서비스가 서로 다른 런타임과 확장을 요구합니다. 서비스 폴더마다 devcontainer.json을 두고, 공용 인프라는 docker-compose로 루트에서 묶으면 충돌 없이 재현 가능한 환경을 만들 수 있습니다.
예를 들어 apps/api는 Node 18과 Redis를, apps/web은 Node 20과 브라우저 디버거를 씁니다. 각 서비스 컨테이너는 자기 런타임만 담고, DB·브로커·캐시는 루트 compose로 공용 네트워크에 올립니다.
- devcontainer.json(서비스별): 필요한 이미지/확장, 포트, 작업 디렉터리처럼 “개발자 도구” 정의
- docker-compose.yml(루트): postgres, redis 같은 “공용 의존성”과 네트워크 정의
- 연결 방식: 서비스 컨테이너가 compose의 서비스 이름(hostname)으로 DB에 접속
아래는 구조를 이해하기 위한 예시입니다. 서비스는 가볍게, 공용 인프라는 루트에서 일관되게 관리합니다.
repo/
docker-compose.yml # postgres, redis 등 공용
apps/
api/.devcontainer/devcontainer.json
web/.devcontainer/devcontainer.json
> 팁: 모든 것을 한 컨테이너에 몰아넣는 구성은 이미지가 비대해지고 빌드 속도가 느려집니다. 서비스별로 분리하면 캐시가 잘 활용되어 로컬 반복 빌드 비용이 줄어듭니다.
모노레포 DevContainer 적용 요약
모노레포 루트에 공용 docker-compose를 두고, 각 서비스 폴더에 devcontainer.json을 둡니다. 서비스별 컨테이너를 분리하면 같은 환경을 안정적으로 재현할 수 있습니다.
- /docker-compose.yml: postgres, redis, 네트워크
- /apps/api/.devcontainer/devcontainer.json: API 개발 컨테이너
- /apps/web/.devcontainer/devcontainer.json: Web 개발 컨테이너
- 공용 .env(선택): DB 사용자·비밀번호 등 공통 변수
각 서비스 devcontainer는 공용 의존성(postgres, redis)에만 붙도록 최소 설정으로 유지합니다. 아래는 API용 devcontainer.json과 루트 compose 핵심 예시입니다.
// apps/api/.devcontainer/devcontainer.json
{
"name": "api-dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18",
"workspaceFolder": "/workspaces/apps/api",
"runServices": ["postgres", "redis"],
"dockerComposeFile": ["../../../docker-compose.yml"],
"service": "api",
"forwardPorts": [3000],
"postCreateCommand": "npm ci"
}
# docker-compose.yml (root)
version: "3.9"
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
ports: ["5432:5432"]
redis:
image: redis:7
ports: ["6379:6379"]
api:
image: mcr.microsoft.com/devcontainers/javascript-node:18
volumes:
- ./:/workspaces
working_dir: /workspaces/apps/api
depends_on: [postgres, redis]
networks:
default: {}
포인트는 api 컨테이너가 같은 compose 네트워크를 쓰고, DB_HOST를 postgres처럼 서비스 이름으로 지정하는 것입니다. 외부 포트는 forwardPorts만 최소로 엽니다.
최종 체크리스트입니다.
- DB/캐시 호스트: DB_HOST=postgres, REDIS_HOST=redis
- 공용 서비스 기동: runServices로 자동 실행
- 볼륨/경로: 루트 -> /workspaces, workspaceFolder 일치
- 확장/툴: 서비스별로만 설치
- 포트: 내부 통신은 네트워크, 외부는 forwardPorts 최소화
> 팁: 모든 서비스를 하나의 devcontainer.json에 통합하면 빌드가 느려지고 충돌이 늘 수 있습니다. 서비스별 devcontainer + 루트 compose로 분리해 관리하세요.
흔한 실수와 선택 기준 한눈에 정리
모노레포에서 Dev Containers를 쓸 때 가장 흔한 실수는 루트 하나에 모든 개발 도구와 인프라를 몰아넣는 것입니다. 서비스별 devcontainer.json은 “런타임/도구”, 루트 compose는 “공용 의존성”으로 경계를 나누세요.
> 안티패턴: 각 서비스 devcontainer.json에 postgres, redis까지 같이 올리는 구성. 컨테이너가 늘수록 빌드/캐시가 불안정해지고, 서비스 간 포트·네트워크 충돌이 잦습니다.
선택 기준은 단순합니다. 서비스가 독립 배포 단위이거나 Node/Java 버전이 다르면 devcontainer를 분리하고, DB·브로커·캐시는 루트 compose로 공유합니다.
로컬만 필요한 임시 툴(예: mailhog)은 루트에 두고, 팀 전원이 동일해야 하는 확장/디버거는 각 서비스 devcontainer에 둡니다.
네트워크·환경변수 충돌도 자주 발생합니다. 아래 체크리스트로 예방하세요.
- compose 서비스명은 접속 호스트명으로 재사용(api-db처럼 짧고 명확하게)
- 포트는 외부 바인딩을 최소화하고 내부 포트 기반으로 연결
- .env는 루트 1곳에서만 관리하고, 서비스별 값은 접두어로 분리(API_, WEB_)
- 볼륨 마운트는 읽기/쓰기 범위를 최소화하여 권한 이슈 방지
비교 관점에서 단일 루트 devcontainer는 초기 진입은 쉽지만, 스케일링 시 변경 영향 범위가 커집니다. 서비스별 분리는 셋업이 조금 늘지만, 변경이 한 서비스로 국한되고 캐시 재사용률이 높아져 빌드 시간이 안정화됩니다.
적용 정리와 바로 실행할 체크리스트
모노레포에서는 서비스별 devcontainer.json으로 런타임을 분리하고, 루트 docker-compose로 공용 의존성을 올리면 됩니다. 목표는 “서비스 컨테이너 최소화, 공용 인프라 공유”입니다.
바로 적용하려면 아래 순서로 진행하세요. 한 단계씩 커밋해 두면 문제 지점 추적이 쉬워집니다.
- 루트에 docker-compose.yml을 만들고 postgres/redis와 공용 네트워크를 정의
- 각 서비스 폴더에 .devcontainer/devcontainer.json 생성, 필요한 이미지·확장·포트만 명시
- 서비스 코드의 DB 호스트를 compose 서비스명으로 변경(ex: postgres)
- VS Code에서 “Dev Containers: Rebuild and Reopen in Container”로 각 서비스 열기
- 컨테이너에서 헬스체크(예: DB 연결, 앱 기동 로그)로 기본 동작 확인
> 팁: 환경변수는 .env로 루트에 두고, devcontainer.json에서는 필요한 키만 주입하세요. 값이 섞이면 원인 파악이 어려워집니다.
마지막으로, 팀 온보딩 문서에 실행 명령과 포트 맵을 짧게 적어 두면 운영 비용이 줄어듭니다. 문제가 생기면 “루트 compose → 서비스 devcontainer → 앱 설정” 순으로 A -> B -> C 흐름을 따라 점검하세요.
'프로그래밍' 카테고리의 다른 글
| pre-commit + lefthook로 커밋 전 자동 품질 게이트 구축 가이드: 초보자도 바로 적용하는 설정 방법 (0) | 2026.09.04 |
|---|---|
| dbt + DuckDB로 팀 내 로컬 레이크하우스 모델링 시작 가이드: 초보 실무자를 위한 첫 설정과 예시 (1) | 2026.09.04 |
| Git sparse-checkout + partial clone으로 모노레포 온보딩 속도 최적화 가이드 (0) | 2026.09.04 |
| Discord 포럼 채널로 개발자 Q&A 지식베이스 구축: 태그·템플릿·모더레이션 가이드 (0) | 2026.08.27 |
| VS Code Copilot ‘BYOK 커스텀 엔드포인트’로 사내 LLM 연결하기 가이드 (0) | 2026.08.06 |