SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor

Docker Compose stop vs down 차이점 완벽 정리

docker compose stop은 컨테이너를 정지하고 상태를 유지하지만, down은 컨테이너와 네트워크를 완전히 삭제합니다. 볼륨 삭제 여부와 데이터 손실을 방지하기 위한 --volumes 옵션 사용법을 상세히 설명합니다.

간단한 답변

docker compose stop은 컨테이너를 중지하지만 디스크에는 그대로 남겨둡니다. docker compose down은 컨테이너를 중지한 뒤 해당 프로젝트를 위해 생성된 컨테이너와 네트워크를 모두 삭제합니다. 두 명령어 모두 명명된 볼륨(named volume)에는 영향을 주지 않습니다. docker compose down -v과 같이 -v 옵션을 추가하면, Compose 파일의 volumes 섹션에 선언된 프로젝트 소속의 비외부(non-external) 명명된 볼륨이 삭제됩니다. down가 삭제하는 대상은 볼륨 외부의 컨테이너 자체 쓰기 가능 레이어(writable layer)에 기록된 모든 데이터입니다.

이것이 한 문단으로 요약한 전체 차이점입니다. 이 가이드의 나머지 부분에서는 down 이후에도 유지되고 down -v을 실행하면 사라지는 Postgres 볼륨을 통해 이를 증명하며, --force-recreate이 필요한 두 가지 경우를 설명합니다.

docker compose stop: 컨테이너는 유지됩니다

stop은(는) 각 컨테이너의 메인 프로세스에 컨테이너에 설정된 정지 신호(기본값은 SIGTERM)를 보낸 뒤 대기하며, 프로세스가 여전히 살아있으면 SIGKILL을 보냅니다. 기본 대기 시간은 10초이며 -t을(를) 통해 변경할 수 있습니다. 아무것도 삭제되지 않습니다. 컨테이너는 자신의 ID, 쓰기 가능한 레이어, 로그를 그대로 유지합니다.

docker compose stop
docker compose ps -a

docker compose ps은(는) 기본적으로 실행 중인 컨테이너만 보여주므로, stop 이후에는 빈 표가 출력되어 컨테이너가 사라졌다고 오해하기 쉽습니다. ps -a은(는) 정지된 컨테이너까지 포함하며, 각 서비스 옆에 프로세스가 반환한 종료 코드와 함께 Exited 상태가 표시되는 것을 확인할 수 있습니다. 정상적인 종료 시에는 보통 Exited (0)가 표시되지만, 항상 그런 것은 아닙니다. 일부 서버는 정상적인 종료 절차를 마친 뒤 정지 신호를 다시 발생시켜 프로세스가 해당 신호로 종료되도록 만드는데, Uvicorn이 정확히 이 방식으로 동작하므로 정상적인 정지 과정에서도 0이 아닌 코드가 남을 수 있습니다. 0이 아닌 코드는 프로세스가 실패했거나 타임아웃 이후 강제 종료되었음을 의미할 수도 있습니다. docker compose start을(를) 사용하면 동일한 컨테이너를 재사용하여 다시 시작할 수 있습니다.

컨테이너가 여전히 존재하기 때문에 볼륨 외부의 컨테이너 내부에 기록된 모든 내용은 그대로 유지됩니다. 여기에는 docker compose exec을(를) 사용하여 수동으로 설치한 패키지나 컨테이너 내부에서 수정한 설정 파일이 포함됩니다. 이것이 디버깅 중에 stop을(를) 선호하는 실질적인 이유입니다. 동일한 상태로 다시 시작할 수 있기 때문입니다.

docker compose down: 컨테이너와 네트워크 제거

down는 컨테이너를 중지한 다음, Compose가 해당 프로젝트를 위해 생성한 기본 네트워크와 함께 컨테이너를 제거합니다. Docker 문서에서는 이를 컨테이너 중지 및 up으로 생성된 컨테이너, 네트워크, 볼륨, 이미지 제거라고 설명하지만, 볼륨과 이미지 제거는 -v 및 --rmi 옵션을 명시적으로 사용할 때만 수행됩니다.

docker compose down
docker compose ps -a
docker network ls

down을 실행한 후 ps -a를 입력하면 해당 프로젝트에 대해 아무것도 출력되지 않으며 <project>_default 네트워크도 사라집니다. 프로젝트 이름은 Compose 파일 내에 name:을 설정하거나, COMPOSE_PROJECT_NAME 환경 변수를 지정하거나, -p 옵션을 전달하지 않는 한 프로젝트 디렉터리 이름을 따릅니다. 컨테이너의 쓰기 가능 레이어(writable layer) 내에서 수행한 모든 변경 사항은 이제 복구할 수 없으므로, down는 컨테이너를 폐기하고 볼륨에 저장된 데이터만 유지하는 명령어로 간주해야 합니다.

현재 디렉터리나 상위 디렉터리에서 설정 파일을 찾을 수 없고 -f 또는 COMPOSE_FILE을 통해 파일을 제공하지 않은 경우 no configuration file provided: not found 오류가 발생합니다. Compose는 어떤 프로젝트를 의도했는지 알 수 없으므로 작업을 거부합니다. 프로젝트 폴더 외부에서 작업할 때는 docker compose -f /srv/myapp/compose.yaml down을 사용하십시오.

docker compose down 명령을 실행하면 볼륨이 삭제됩니까?

아니요. 최상위 volumes 키 아래에 선언된 명명된 볼륨(named volume)은 down 이후에도 유지되며, 해당 볼륨이 연결되었던 컨테이너가 삭제된 후에도 남아 있습니다. 이는 해당 명령에 대해 가장 흔히 갖는 우려 사항입니다. Compose v5.7.0에서 down -v 동작이 변경되었습니다. 이제 다른 프로젝트에 속하거나 Compose 외부에서 생성된 명명된 볼륨은 경고와 함께 건너뜁니다.

테스트할 스택을 구성합니다. voltest이라는 빈 디렉터리를 만들고 아래 내용을 compose.yaml에 저장합니다.

services:
  db:
    image: postgres:16.4
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

스택을 시작하고 나중에 확인할 수 있는 행을 기록합니다.

docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "create table marker (note text);"
docker compose exec -T db psql -U postgres -c "insert into marker values ('survived');"

이제 컨테이너를 삭제하고 볼륨을 확인합니다.

docker compose down
docker volume ls

출력 결과에 여전히 voltest_pgdata가 표시됩니다. 컨테이너는 사라졌지만 데이터는 남아 있습니다. 스택을 다시 시작하고 해당 행을 읽어옵니다.

docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "select * from marker;"

survived이 포함된 행 하나가 출력됩니다. 새로 생성된 컨테이너는 이전과 다른 ID를 가진 별개의 컨테이너이지만, 동일한 볼륨에 연결되어 있습니다. 더 자세한 내용을 알고 싶다면 Compose 기초 가이드에서 명명된 볼륨과 바인드 마운트의 차이점, 그리고 각 데이터가 호스트의 어디에 실제로 저장되는지 확인할 수 있습니다.

down -v 명령이 정확히 삭제하는 대상

-v (전체 명령어 --volumes)는 Compose 파일의 volumes 섹션에 선언된, 해당 프로젝트에 속한 비외부(non-external) 명명된 볼륨과 컨테이너에 연결된 익명 볼륨을 제거합니다. Compose v5.7.0 버전부터는 다른 프로젝트의 소유권 레이블이 있거나 프로젝트 레이블이 없는 명명된 볼륨은 경고와 함께 건너뜁니다. 볼륨의 소유권을 확인할 수 없는 경우, 해당 명령은 실패하며 볼륨을 유지합니다. 동일한 스택을 대상으로 이 명령을 실행하십시오.

docker compose down -v
docker volume ls

voltest_pgdata가 더 이상 목록에 나타나지 않습니다. 스택을 다시 시작하면 Postgres 엔트리포인트가 비어 있는 데이터 디렉터리를 발견하고 새로운 클러스터를 초기화합니다. 컨테이너 로그에 이 내용이 명확하게 기록됩니다.

The files belonging to this database system will be owned by user "postgres".
PostgreSQL init process complete; ready for start up.

수개월 동안 실행 중이던 스택에서 해당 블록이 나타난다면, Postgres가 비어 있는 데이터 디렉터리를 초기화하고 있다는 의미입니다. 귀하의 marker 테이블은 사라졌으며, 이를 복구하는 유일한 방법은 백업본을 사용하는 것뿐입니다.

일부 저장소는 -v 명령으로도 제거되지 않습니다. 바인드 마운트는 호스트 경로를 사용하므로 Docker는 마운트만 해제하며 파일은 원래 위치에 그대로 남습니다. external: true로 표시된 볼륨은 이 프로젝트 외부의 것으로 선언되어 있으므로 Compose는 이를 절대 제거하지 않습니다. Compose 파일에서 볼륨을 삭제한 후 down -v를 실행하면 해당 볼륨은 더 이상 선언되지 않은 상태가 됩니다. 따라서 Compose는 이를 제거해야 할 대상으로 인식하지 못하며, 컨테이너가 참조하지 않게 된 볼륨은 docker volume prune -a을 위한 고아(orphan) 상태로 남게 됩니다.

마지막 사례는 리팩터링 과정에서 자주 발생합니다. 파일에서 서비스와 볼륨을 제거한 뒤 down -v을 실행하면, 파일에 해당 볼륨에 대한 언급이 없기 때문에 볼륨은 삭제되지 않고 남습니다. 파일을 수정하기 전, 즉 수정하기 전에 down -v를 실행하십시오.

--force-recreate가 실제로 필요한 경우

docker compose up -d는 매번 모든 것을 다시 빌드하지 않습니다. Compose는 각 서비스의 해석된 설정에 대한 해시를 컨테이너에 레이블로 저장합니다. Compose v5.7.0에서는 설정 해시, 이미지 ID, 이미지 볼륨 다이제스트가 일치하고, 예상되는 네트워크 연결과 명명된 볼륨 마운트가 존재하며, 네임스페이스나 볼륨을 공유하는 상위 항목이 다시 생성되지 않는 경우 실행 중인 컨테이너를 그대로 둡니다. 이때 Recreated 대신 Container voltest-db-1 Running이 수행됩니다. 이는 up -d를 반복적으로 실행해도 안전하게 만들기 때문에 거의 모든 상황에서 의도한 동작입니다.

일부 편집 내용이 아무런 변화를 일으키지 않는 것처럼 보이는 이유도 여기에 있습니다. Compose는 정의가 가리키는 파일의 내용이 아니라 해석된 서비스 정의 자체를 해싱합니다. 컨테이너에 마운트되어 시작 시 한 번 읽히는 설정 파일은 편집하더라도 마운트 경로가 바뀌지 않으므로 재생성을 유발하지 않습니다. 서비스는 부팅 시 읽은 값을 유지하며 계속 실행됩니다.

docker compose up -d --force-recreate

이 명령은 각 컨테이너를 중지하고 제거한 뒤 동일한 정의로 새 컨테이너를 생성합니다. 마운트된 설정 파일을 편집한 후나 컨테이너가 설명할 수 없는 상태로 변했을 때 사용하십시오. 볼륨은 건드리지 않으므로 데이터베이스는 강제 재생성 후에도 유지됩니다. 동일한 태그에서 더 최신 이미지를 가져오려면 pull도 함께 수행해야 합니다.

docker compose pull
docker compose up -d

pull은 새로운 이미지 ID를 가져오며, up -d은 실행 중인 컨테이너와 다른 이미지 ID를 감지하여 스스로 컨테이너를 다시 생성합니다. pull 없이 --force-recreate만 추가하면 동일한 이전 이미지로 새 컨테이너가 생성됩니다. "강제 재생성을 했는데도 여전히 이전 버전이다"라는 불만이 흔한 이유가 바로 이것입니다.

docker compose restart은 이러한 작업을 전혀 수행하지 않습니다. 기존 컨테이너를 설정 변경 없이 재시작하기 때문에, 변경된 환경 변수나 포트 매핑은 적용되지 않습니다. 파일을 편집했다면 up -d을 사용하십시오.

유지해야 할 사고방식

컨테이너는 교체 가능한 대상입니다. 컨테이너는 프로세스와 얇은 쓰기 가능 계층으로 구성되며, Compose는 파일과 이미지를 사용하여 이를 대체할 수 있습니다. 볼륨은 리포지토리의 어떤 파일로도 재생성할 수 없는 유일한 상태 사본을 담고 있으므로 교체할 수 없습니다.

모든 Compose 명령어는 이러한 구분과 일치합니다. stop와 start은 컨테이너를 유지합니다. down와 up는 컨테이너를 교체하되 볼륨은 유지합니다. down -v은 상태를 제거하는 유일한 일상적 명령어이므로 명시적인 플래그가 필요합니다. 실제 운영 환경에서 이 명령어를 입력하기 전에, 최소 한 번 이상 복원해 본 백업이 있는지 확인하십시오.

동일한 논리가 비밀값(secrets)에도 적용됩니다. POSTGRES_PASSWORD을 통해 설정된 비밀번호는 데이터베이스가 처음 초기화될 때 데이터베이스 비밀번호를 설정하는 용도로만 사용됩니다. 따라서 환경 파일에서 이를 변경하고 up -d을 실행해도 저장된 비밀번호는 변경되지 않습니다. 컨테이너는 새로 생성되지만 볼륨은 이전 상태 그대로이며, 이전 볼륨에는 여전히 기존 비밀번호가 저장되어 있기 때문입니다. Compose가 환경 파일과 비밀값을 해석하는 방식에서는 동일한 변수가 두 번 설정될 때 어떤 계층이 우선하는지 설명합니다.

실패 유형과 표시되는 메시지

no configuration file provided: not found는 Compose가 현재 디렉터리와 상위 디렉터리 검색, -f, 또는 COMPOSE_FILE을 통해 설정 파일을 찾지 못했음을 의미합니다. -f에 전체 경로를 지정하여 전달하십시오.

Compose v5.7.0의 down에서 발생하는 Network voltest_default Resource is still in use은 컨테이너가 여전히 프로젝트 네트워크에 연결되어 있음을 의미하며, 보통 docker run --network를 사용하여 수동으로 시작한 외부 프로젝트의 컨테이너가 원인입니다. 해당 컨테이너를 제거한 후 down을 다시 실행하십시오.

Found orphan containers (voltest-old-1) for this project은 서비스를 이름을 변경하거나 삭제한 후에 나타납니다. 현재 Compose는 이름들을 쉼표로 구분하여 나열합니다. 이전 버전인 Compose v2 릴리스는 ([voltest-old-1])과 같이 대괄호 안에 이름을 넣어 동일한 경고를 출력합니다. 이전 컨테이너는 여전히 프로젝트 레이블을 유지하고 있습니다. docker compose down --remove-orphans를 실행하면 이를 정리할 수 있습니다.

수동 docker volume rm 실행 시 발생하는 Error response from daemon: remove voltest_pgdata: volume is in use은 중지된 컨테이너를 포함하여 여전히 해당 볼륨을 참조하는 컨테이너가 있음을 의미합니다. 먼저 docker compose down를 실행한 후 볼륨을 제거하거나, 단순히 down -v을 사용하십시오. 규모가 큰 프로젝트의 경우, 다중 서비스 Compose 스택에서 하나의 프로젝트에 얼마나 많은 볼륨이 쌓일 수 있는지 확인할 수 있습니다.

FAQ

docker compose down 명령을 실행하면 데이터베이스가 삭제됩니까?

데이터베이스가 named volume이나 bind mount에 저장되어 있다면 삭제되지 않습니다. down는 컨테이너와 프로젝트 네트워크를 제거하지만, 볼륨은 데이터가 보존된 채로 디스크에 남습니다. 이후 docker compose up -d를 실행하면 새 컨테이너가 동일한 볼륨에 연결되어 데이터를 그대로 사용할 수 있습니다. docker compose down -v은 Compose 파일의 volumes 섹션에 선언된, 외부 볼륨이 아닌 named volume을 제거합니다.

다시 사용할 컨테이너를 다룰 때 stop과 down의 차이는 무엇입니까?

stop은 컨테이너를 유지하므로, docker compose start를 실행하면 동일한 쓰기 가능 레이어를 가진 원래의 컨테이너로 돌아갑니다. 컨테이너 내부에서 수동으로 설치하거나 수정한 내용은 그대로 유지됩니다. down은 컨테이너를 삭제하므로, 다음 up -d 실행 시 이미지로부터 새로운 컨테이너가 생성되어 수동으로 변경한 내용은 모두 사라집니다. 디버깅 중에는 stop를 사용하십시오.

Compose 프로젝트가 생성한 모든 것을 제거하려면 어떻게 해야 합니까?

docker compose down -v --rmi all --remove-orphans은 컨테이너, 프로젝트 네트워크, 파일에 선언된 외부 볼륨이 아닌 named volume, 서비스가 사용한 이미지, 그리고 프로젝트의 고아 컨테이너를 모두 제거합니다. bind mount나 external: true로 표시된 볼륨은 건드리지 않습니다. 실행하기 전에 docker volume ls를 사용하여 삭제될 항목을 확인하십시오.

마운트된 설정 파일을 변경했는데 왜 컨테이너에 반영되지 않습니까?

Compose는 해석된 서비스 정의의 해시값을 비교하여 컨테이너를 다시 생성할지 결정하는데, 이 해시값에는 마운트된 파일의 내용은 포함되지 않습니다. 파일 경로는 변경되지 않았으므로, Compose는 컨테이너를 시작 시점에 읽은 설정값 그대로 유지합니다. docker compose up -d --force-recreate을 실행하여 파일을 다시 읽는 새로운 컨테이너를 생성하십시오.

변경한 POSTGRES_PASSWORD가 적용되지 않는 이유는 무엇입니까?

Postgres 이미지는 데이터 디렉터리가 비어 있을 때 초기화하는 용도로만 POSTGRES_PASSWORD을 사용합니다. 이미 볼륨에 초기화된 클러스터가 존재하므로 해당 변수는 무시되며 기존 비밀번호가 계속 적용됩니다. 새 비밀번호로 접속하면 password authentication failed for user "postgres" 오류가 발생합니다. 실행 중인 데이터베이스 내부에서 ALTER USER를 사용하여 비밀번호를 변경하거나, 데이터를 삭제해도 괜찮다면 docker compose down -v을 사용하여 처음부터 다시 시작하십시오.

이 글이 도움이 되었나요?