티스토리 뷰

DEV

Docker Compose Watch 사용법 완벽 가이드

Code Brewer 2026. 5. 23. 18:52
반응형

Docker Compose Watch는 개발 중 파일을 저장할 때 컨테이너에 변경 사항을 자동 반영하는 기능입니다. 핵심은 compose.yaml의 서비스 아래에 develop.watch 규칙을 추가하고, docker compose up --watch 또는 docker compose watch로 실행하는 것입니다. 소스 코드는 sync, 의존성 파일은 rebuild, 설정 파일은 sync+restart로 나누면 불필요한 재빌드를 줄이고 개발 피드백 속도를 높일 수 있습니다. 이 글은 로컬 개발 환경에서 Docker를 쓰지만 매번 build, up, restart를 반복하는 분에게 유용합니다.

검색 의도: 이 주제는 정보형 의도가 가장 강합니다. 따라서 개념 설명보다 바로 적용 가능한 설정 예시, 액션별 차이, 문제 해결 체크리스트를 중심으로 구성했습니다.

Docker Compose Watch란 무엇인가

Docker Compose Watch는 호스트의 파일 변경을 감지해 실행 중인 Compose 서비스에 자동으로 반영하는 개발용 기능입니다. 기존에는 코드를 수정한 뒤 컨테이너 내부에 반영하려면 bind mount를 쓰거나, docker compose build && docker compose up을 반복해야 했습니다. Watch를 사용하면 어떤 파일은 컨테이너로 동기화하고, 어떤 파일은 이미지를 다시 빌드하며, 어떤 파일은 동기화 후 컨테이너를 재시작하도록 세밀하게 제어할 수 있습니다.

공식 문서 기준으로 Watch는 develop.watch 아래에 여러 규칙을 선언하는 방식입니다. 각 규칙은 주로 path, action, 필요 시 target, ignore, include, initial_sync 같은 속성을 사용합니다. 예를 들어 프론트엔드의 src/ 변경은 sync로 빠르게 반영하고, package.json 변경은 의존성 설치가 필요하므로 rebuild로 처리하는 식입니다.

간단히 말하면 Watch는 개발 환경 자동 반영 레이어입니다. 운영 배포를 위한 기능이라기보다, 로컬에서 컨테이너 기반 개발을 할 때 저장과 반영 사이의 반복 작업을 줄이는 도구에 가깝습니다.

방식 특징 적합한 상황
bind mount 호스트 디렉터리를 컨테이너에 직접 연결 단순 개발, 즉시 파일 공유
Compose Watch 변경 감지 후 규칙에 따라 sync/rebuild/restart 복잡한 프로젝트, OS 차이, 의존성 제외 필요
수동 rebuild 명령어를 직접 반복 변경 빈도가 낮은 프로젝트

Docker Compose Watch 사용법: 기본 설정

가장 기본적인 Docker Compose Watch 사용법은 compose.yamldevelop.watch를 추가하는 것입니다. 다음 예시는 Node.js 또는 Vite 기반 프론트엔드 프로젝트에서 자주 쓰는 패턴입니다.

services:
  web:
    build: .
    command: npm run dev
    ports:
      - "5173:5173"
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
          initial_sync: true
          ignore:
            - node_modules/
        - action: rebuild
          path: package.json

실행은 다음 중 하나를 사용합니다.

docker compose up --watch

또는 애플리케이션 로그와 Watch 이벤트를 분리하고 싶다면 다음 명령을 사용할 수 있습니다.

docker compose watch

docker compose up --watch는 서비스를 올리면서 Watch 모드를 함께 시작합니다. 반면 docker compose watch는 Watch에 집중한 명령이며, 옵션으로 --no-up, --quiet, --prune 등을 사용할 수 있습니다. 이미 서비스를 띄워둔 상태에서 파일 감시만 별도로 보고 싶다면 후자가 더 깔끔합니다.

주의할 점은 Compose Watch가 주로 build 속성으로 로컬 소스에서 이미지를 만드는 서비스에 맞춰 설계되어 있다는 점입니다. 단순히 image: nginx:latest처럼 미리 빌드된 이미지만 사용하는 서비스라면 Watch가 기대한 대로 동작하지 않을 수 있습니다.

Docker Compose Watch action 차이: sync, rebuild, restart

Docker Compose Watch의 핵심은 action 선택입니다. 같은 파일 변경이라도 어떤 액션을 쓰느냐에 따라 개발 속도와 정확성이 크게 달라집니다.

action 동작 추천 대상
sync 호스트 파일을 컨테이너의 target 경로로 동기화 React, Vue, Next.js, Flask 코드
rebuild 이미지를 다시 빌드하고 컨테이너 재생성 package.json, requirements.txt, Dockerfile 영향 파일
sync+restart 파일 동기화 후 컨테이너 재시작 nginx.conf, 앱 설정 파일
restart 컨테이너만 재시작 재시작만 필요한 경우, Compose 2.32.0 이상
sync+exec 동기화 후 컨테이너 안에서 명령 실행 reload 명령이 있는 서버, Compose 2.32.2 이상

가장 많이 쓰는 조합은 syncrebuild입니다. 예를 들어 src/App.tsx를 수정할 때마다 이미지를 다시 빌드하면 개발 흐름이 느려집니다. 이 경우 sync로 파일만 컨테이너에 복사하고, 컨테이너 내부의 Vite나 Webpack 같은 개발 서버가 Hot Reload를 처리하게 하는 편이 효율적입니다.

반대로 package.json, pnpm-lock.yaml, requirements.txt, go.mod 같은 파일은 단순 파일 복사만으로 충분하지 않을 수 있습니다. 의존성 설치, 빌드 캐시, 실행 환경 자체가 바뀌기 때문입니다. 이런 파일은 rebuild로 처리해야 컨테이너 상태가 실제 개발 환경과 어긋나지 않습니다.

설정 파일은 중간 지점에 있습니다. 예를 들어 nginx.conf는 이미지를 다시 빌드하지 않아도 되지만, 프로세스가 설정을 다시 읽어야 합니다. 이때 sync+restart가 적합합니다.

Docker Compose Watch 예제: 프론트엔드와 백엔드 구성

실제 프로젝트에서는 프론트엔드, 백엔드, 프록시가 함께 움직이는 경우가 많습니다. 다음은 Vite 프론트엔드와 Express 백엔드를 단순화한 예시입니다.

services:
  frontend:
    build:
      context: ./frontend
    command: npm run dev -- --host 0.0.0.0
    ports:
      - "5173:5173"
    develop:
      watch:
        - action: sync
          path: ./frontend/src
          target: /app/src
          initial_sync: true
          ignore:
            - node_modules/
            - dist/
        - action: rebuild
          path: ./frontend/package.json

  backend:
    build:
      context: ./backend
    command: npm run dev
    ports:
      - "3000:3000"
    develop:
      watch:
        - action: sync
          path: ./backend/src
          target: /app/src
          initial_sync: true
        - action: rebuild
          path: ./backend/package.json

이 구성에서 frontend/srcbackend/src는 저장 즉시 컨테이너에 반영됩니다. 프론트엔드는 Vite의 HMR이 화면 갱신을 맡고, 백엔드는 nodemon, tsx watch, spring-boot-devtools, uvicorn --reload 같은 프레임워크별 개발 서버가 재시작을 처리하는 구조가 일반적입니다.

중요한 포인트는 node_modules를 동기화하지 않는 것입니다. 호스트가 macOS 또는 Windows이고 컨테이너가 Linux인 경우, 네이티브 모듈이 OS나 CPU 아키텍처에 따라 달라질 수 있습니다. 또한 node_modules는 파일 수가 많아 감시와 동기화 비용이 커집니다. 따라서 의존성은 이미지 빌드 단계에서 설치하고, 소스만 Watch로 동기화하는 방식이 안정적입니다.

Python 프로젝트라면 app/ 또는 src/sync, requirements.txtrebuild로 두면 됩니다. Java나 Go처럼 컴파일 과정이 중요한 언어는 단순 동기화보다 rebuild 또는 컨테이너 내부 개발 도구의 watch 명령과 조합하는 편이 낫습니다.

Docker Compose Watch와 bind mount 비교

많은 개발자가 먼저 떠올리는 방식은 bind mount입니다. 예를 들어 ./src:/app/src처럼 호스트 폴더를 컨테이너에 직접 연결하면 파일 변경이 즉시 보입니다. 단순한 프로젝트에서는 여전히 좋은 선택입니다. 하지만 Docker Compose Watch는 더 세밀한 제어가 필요할 때 장점이 있습니다.

bind mount는 연결된 디렉터리를 그대로 노출합니다. 그래서 제외하고 싶은 파일이나 OS별로 달라지는 산출물이 섞이면 문제가 생길 수 있습니다. 반면 Watch는 ignoreinclude로 감시 대상을 좁힐 수 있습니다. 예를 들어 src/는 동기화하되 dist/, .next/, node_modules/, coverage/는 제외하는 식입니다.

develop:
  watch:
    - action: sync
      path: ./app
      target: /app
      ignore:
        - node_modules/
        - .next/
        - dist/
        - coverage/

다만 Watch가 bind mount를 완전히 대체한다고 보기는 어렵습니다. 로그 파일, 업로드 파일, 데이터베이스 초기화 스크립트처럼 호스트와 컨테이너가 같은 파일 시스템을 공유해야 편한 경우도 있습니다. 실무에서는 다음 기준으로 선택하면 됩니다.

  • 소스 코드 자동 반영이 목적이면 Watch가 적합합니다.
  • 양방향 파일 공유가 중요하면 bind mount가 단순합니다.
  • 의존성 디렉터리 충돌이 걱정되면 Watch가 더 안전합니다.
  • 빌드가 필요한 변경이 많으면 rebuild 규칙을 명확히 분리해야 합니다.

Docker Compose Watch 문제 해결 체크리스트

Watch가 동작하지 않을 때는 대부분 경로, 권한, 액션 선택, 컨테이너 내부 개발 서버 설정 중 하나가 원인입니다. 먼저 path가 Compose 파일 기준 상대 경로인지 확인하세요. target은 컨테이너 내부 경로이며, sync 계열 액션에서 파일이 복사될 위치입니다. pathtarget을 혼동하면 변경은 감지되지만 앱이 읽는 위치에는 반영되지 않을 수 있습니다.

권한도 자주 만나는 문제입니다. Docker 공식 문서에서는 Watch가 정상 동작하려면 이미지 안에 stat, mkdir, rmdir 같은 일반 명령이 있어야 하고, 컨테이너의 실행 사용자가 target 경로에 쓸 수 있어야 한다고 설명합니다. Dockerfile에서 비루트 사용자를 쓴다면 COPY --chown으로 소유권을 맞추는 것이 좋습니다.

FROM node:20
WORKDIR /app
RUN useradd -ms /bin/sh -u 1001 app
COPY package*.json ./
RUN npm install
COPY --chown=app:app . /app
USER app
CMD ["npm", "run", "dev"]

또 하나의 흔한 착각은 Watch만 켜면 애플리케이션이 자동 재시작한다고 생각하는 것입니다. sync는 파일을 컨테이너에 반영할 뿐, 프로세스를 반드시 재시작하지는 않습니다. 따라서 Node.js 백엔드는 nodemon이나 tsx watch, Python은 --reload, Spring은 DevTools처럼 컨테이너 내부에서 변경을 감지하는 개발 도구가 함께 필요할 수 있습니다. 재시작이 꼭 필요하다면 sync+restart를 선택하세요.

점검 순서는 다음과 같습니다.

  • docker compose version이 Watch 지원 버전인지 확인합니다.
  • 서비스에 build가 선언되어 있는지 확인합니다.
  • path는 호스트 경로, target은 컨테이너 경로로 구분합니다.
  • ignore 패턴은 해당 path 기준 상대 경로로 작성합니다.
  • 컨테이너 사용자가 target에 쓸 수 있는지 확인합니다.
  • sync만으로 부족하면 sync+restart 또는 개발 서버 watch 옵션을 사용합니다.

Docker Compose Watch 추천 설정 패턴

실무에서 가장 안정적인 패턴은 파일 종류별로 액션을 분리하는 것입니다. 모든 변경을 rebuild로 처리하면 정확하긴 하지만 느립니다. 모든 변경을 sync로 처리하면 빠르지만 의존성이나 런타임 상태가 꼬일 수 있습니다. 따라서 다음 기준을 추천합니다.

파일 유형 추천 action 이유
src/, app/, pages/ sync 코드만 빠르게 반영
package.json, lock 파일 rebuild 의존성 설치 필요
Dockerfile rebuild 이미지 레이어 변경
.env, 설정 파일 sync+restart 프로세스 재시작 필요 가능성
빌드 산출물 ignore 불필요한 감시 비용 방지

최소 구성은 다음처럼 시작하면 됩니다.

develop:
  watch:
    - action: sync
      path: ./src
      target: /app/src
      initial_sync: true
    - action: rebuild
      path: package.json
    - action: rebuild
      path: Dockerfile

이후 프로젝트가 커지면 ignoreinclude를 추가합니다. include는 특정 패턴만 감시하고 싶을 때 유용합니다. 예를 들어 Go 프로젝트에서 .go 파일 변경만 rebuild 대상으로 삼고 싶다면 include: "*.go"처럼 작성할 수 있습니다. YAML에서 *는 특별한 의미가 있으므로 와일드카드 패턴은 따옴표로 감싸는 것이 안전합니다.

마지막으로 initial_sync: true는 기존 컨테이너가 있을 때 Watch 세션 시작 전에 파일 상태를 맞추는 데 도움이 됩니다. 컨테이너를 계속 재사용하는 개발 환경이라면 켜두는 편이 예측 가능성이 높습니다.

자주 묻는 질문

Docker Compose Watch는 운영 환경에서도 써도 되나요?

일반적으로 권장하지 않습니다. Docker Compose Watch는 개발 중 파일 변경을 빠르게 반영하기 위한 기능입니다. 운영 환경에서는 이미지 빌드, 태깅, 배포 파이프라인, 롤백 전략을 명확히 관리하는 편이 안전합니다.

docker compose up --watchdocker compose watch의 차이는 무엇인가요?

docker compose up --watch는 서비스를 시작하면서 Watch 모드까지 함께 실행합니다. docker compose watch는 Watch 명령을 별도로 실행하는 방식이며, 필요에 따라 --no-up으로 서비스 시작 없이 감시만 수행할 수 있습니다. 로그를 분리해서 보고 싶다면 별도 명령이 더 편합니다.

Watch를 쓰면 bind mount를 제거해야 하나요?

항상 제거할 필요는 없습니다. 다만 같은 경로에 bind mount와 Watch를 동시에 적용하면 동작을 추적하기 어려워질 수 있습니다. 소스 코드 반영은 Watch, 데이터 공유는 volume 또는 bind mount처럼 목적을 나누는 것이 좋습니다.

파일을 저장했는데 화면이 갱신되지 않는 이유는 무엇인가요?

먼저 target 경로가 앱이 실제로 읽는 경로와 같은지 확인하세요. 그다음 컨테이너 내부 개발 서버가 Hot Reload 또는 자동 재시작을 지원하는지 확인해야 합니다. sync는 파일 복사만 수행하므로, 프로세스 재시작이 필요하면 sync+restart를 사용해야 합니다.

Docker Compose Watch에서 node_modules를 제외해야 하나요?

대부분의 Node.js 프로젝트에서는 제외하는 편이 좋습니다. 파일 수가 많아 성능 부담이 크고, 호스트 OS와 컨테이너 OS가 다를 때 네이티브 패키지 문제가 생길 수 있습니다. 의존성은 이미지 빌드 단계에서 설치하고 소스 코드만 동기화하는 구성이 안정적입니다.

핵심 요약

  • Docker Compose Watch 사용법의 핵심은 develop.watch에 파일별 액션 규칙을 선언하는 것입니다.
  • sync는 소스 코드처럼 빠른 반영이 필요한 파일에 적합합니다.
  • rebuildpackage.json, requirements.txt, Dockerfile처럼 이미지나 의존성이 바뀌는 파일에 적합합니다.
  • sync+restart는 설정 파일처럼 복사 후 프로세스 재시작이 필요한 경우에 유용합니다.
  • ignorenode_modules, dist, .next, coverage 같은 디렉터리를 제외하면 성능과 안정성이 좋아집니다.
  • Watch가 동작하려면 컨테이너 사용자에게 target 경로 쓰기 권한이 있어야 합니다.
  • docker compose up --watch는 서비스 시작과 감시를 함께 처리하고, docker compose watch는 감시를 별도로 실행할 때 유용합니다.

결론적으로 Docker Compose Watch는 컨테이너 기반 개발 환경에서 저장 즉시 변경 사항을 반영하기 위한 실용적인 방법입니다. 처음에는 srcsync, 의존성 파일은 rebuild, 설정 파일은 sync+restart라는 세 가지 규칙으로 시작해 보세요. 이후 프로젝트 구조에 맞춰 ignore, include, initial_sync를 조정하면 개발 속도와 환경 일관성을 함께 확보할 수 있습니다.

참고 자료: Docker 공식 문서의 Compose Watch 가이드(https://docs.docker.com/compose/how-tos/file-watch/), Compose Develop Specification(https://docs.docker.com/reference/compose-file/develop/), docker compose watch CLI Reference(https://docs.docker.com/reference/cli/docker/compose/watch/)를 기준으로 정리했습니다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함
반응형