Docker Compose 실무 명령어 모음: 서버 운영 필수 가이드
Docker Compose V2 환경에서 매일 사용하는 핵심 명령어를 작업별로 정리했습니다. 컨테이너 라이프사이클 관리부터 로그 확인, 네트워크 설정, 안전한 데이터 정리 방법까지 실무 운영에 필요한 모든 명령어를 한눈에 확인하십시오.
실무에서 자주 사용하는 Compose 명령어
Docker Compose는 40개가 넘는 하위 명령어를 제공합니다. 서버 운영 시 매일 사용하는 명령어는 10여 개 정도입니다. 이 문서에서는 작업 목적에 따라 명령어를 분류하고, 각 명령어의 사용 이유를 간략히 설명하며, 주의가 필요한 경우 심층 분석 문서를 안내합니다.
이 문서의 모든 내용은 Compose V2를 기준으로 합니다. 하이픈 없이 docker compose를 사용하며, 구형 docker-compose 스크립트는 사용하지 않습니다. V2는 Docker Engine과 함께 설치되는 Go 플러그인이며, 현재 패키지에서 V1은 제거되었습니다. 따라서 2026년 7월 기준 최신 Ubuntu 환경에서 docker-compose: command not found을 실행하면 정상적으로 작동합니다. docker compose version로 설치 여부를 확인하십시오. 만약 아무런 결과가 출력되지 않는다면 docker-compose-plugin 패키지를 설치해야 합니다.
아래의 모든 명령어는 compose.yaml 파일이 위치한 디렉터리에서 실행해야 합니다. Compose는 해당 디렉터리 이름으로 프로젝트명을 결정하고, 그 경로를 기준으로 파일을 찾기 때문입니다. 상위 디렉터리에서 동일한 명령어를 실행하면 Compose는 no configuration file provided: not found 오류와 함께 중단됩니다. 파일 형식이 생소하다면 VPS에서 첫 Compose 파일 작성하기를 먼저 읽고 돌아와 명령어를 확인하십시오.
라이프사이클: 네 가지 실행 명령과 컨테이너 삭제 명령
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d은 네트워크를 생성하고 컨테이너를 생성한 뒤 시작하고 종료합니다. 이 명령은 컨테이너가 생성되는 즉시 반환되므로, up -d 직후에 curl 프로브를 실행하는 배포 스크립트는 첫 시도에서 실패하는 경우가 많습니다. up -d --wait은 헬스체크를 선언한 모든 서비스가 정상 상태(healthy)를 보고할 때까지 차단하며, 하나라도 정상 상태에 도달하지 못하면 0이 아닌 값으로 종료합니다. 이 플래그는 기반이 되는 체크만큼만 유효하므로, 자동화에 의존하기 전에 Compose가 신뢰할 수 있는 헬스체크를 먼저 작성하십시오.
stop는 컨테이너를 중지하고 유지하므로, start을 실행하면 동일한 쓰기 가능 레이어를 가진 컨테이너가 다시 시작됩니다. down은 컨테이너를 중지한 후 컨테이너와 프로젝트 네트워크를 모두 삭제합니다. 볼륨 외부의 컨테이너 내부에 기록된 모든 데이터는 함께 삭제됩니다. 이는 Compose에서 가장 비용이 큰 오해이며, down과 stop의 전체적인 차이에서 이로 인해 발생하는 문제를 다룹니다.
restart는 리로드(reload)가 아닙니다. 이 명령은 이미 존재하는 설정으로 동일한 컨테이너를 중지하고 시작할 뿐이므로, 변경된 환경 변수, 새로운 이미지 태그, 수정된 포트 매핑은 전혀 적용되지 않습니다. 파일 변경 사항을 적용하려면 up -d을 다시 실행해야 합니다. Compose는 각 서비스와 실행 중인 컨테이너를 비교하여 설정이 변경된 컨테이너만 다시 생성합니다.
변경 사항 적용: recreate, pull, rebuild
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webup -d는 변경 사항이 없을 때는 아무 작업도 수행하지 않으므로 반복해서 실행해도 안전합니다. --force-recreate는 이러한 비교 과정을 무시하고 설정이 동일하더라도 모든 컨테이너를 교체하므로, 컨테이너 내부의 비정상적인 상태를 초기화하는 가장 빠른 방법입니다.
이미지 업데이트는 두 가지 작업을 수행하기 위해 두 개의 명령어가 필요합니다. pull은 파일에 명시된 각 태그의 최신 이미지를 다운로드합니다. 그 후 up -d은 서비스의 이미지 ID가 실행 중인 컨테이너와 일치하지 않음을 감지하고 컨테이너를 다시 생성합니다. pull을 건너뛰면 up -d은 오류 없이 지난달의 latest를 계속 실행합니다.
build은 image: 대신 build: 섹션을 선언한 서비스에 적용됩니다. up -d --build은 빌드와 시작을 한 번에 처리하며, 코드를 수정하는 동안 사용하는 일반적인 반복 작업입니다. --no-cache는 캐시된 레이어가 명확히 오래된 경우에만 사용하십시오. 모든 레이어를 처음부터 다시 빌드하기 때문입니다.
실행 중인 서비스 확인하기
docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose lsps는 실행 중인 컨테이너만 나열합니다. 시작 도중 충돌한 서비스는 -a 옵션을 추가하기 전까지는 보이지 않습니다. 따라서 ps에는 보이지 않지만 ps -a에서는 Exited (1) 상태로 표시되는 컨테이너는 일반적인 시작 실패 사례입니다. 종료 코드를 확인한 뒤 로그를 읽으십시오.
logs -f은 모든 서비스를 동시에 추적하며 각 줄 앞에 서비스 이름을 붙여 출력합니다. 서비스 간 통신이 이루어지고 이벤트 순서가 중요할 때 유용한 보기 방식입니다. 특정 서비스 이름을 지정하여 범위를 좁힐 수 있습니다. --tail=100은 한 달 이상 실행된 컨테이너에서 중요합니다. 기본 설정은 전체 기록을 출력하여 터미널을 가득 채우기 때문입니다. --since 15m는 방금 수행한 재시작 중에 무슨 일이 일어났는지 확인하려는 일반적인 상황에 적합합니다.
top은 각 컨테이너 내부의 프로세스를 나열합니다. 이를 통해 "컨테이너가 실행 중인 상태"와 "내부 프로세스가 실행 중인 상태"를 구분할 수 있습니다. ls는 현재 디렉터리에서 벗어나 호스트에 있는 모든 Compose 프로젝트와 그 상태를 나열합니다. 이를 통해 3개월 전에 시작했던 스택을 찾을 수 있습니다.
서비스 내부에서 셸 실행하기
docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web shexec는 이미 실행 중인 컨테이너 내부에서 명령을 수행합니다. 서비스가 너무 빨리 종료되어 exec 명령을 사용할 수 없을 때는 run을 사용하여 동일한 서비스 정의로 새 컨테이너를 시작해야 합니다. run을 사용할 때는 항상 --rm을 함께 사용하십시오. 이를 생략하면 실행할 때마다 중지된 컨테이너가 남게 되며, 이것이 쌓이면 docker compose ps -a를 읽기 어렵게 됩니다.
bash을 실행하기 전에 sh을 먼저 시도하십시오. Alpine 기반 이미지는 bash를 포함하지 않으며, 이 경우 exec: "bash": executable file not found in $PATH 오류가 발생합니다. run에 --no-deps를 추가하면 서비스의 의존성 항목을 건너뛰므로, 간단한 설정 확인을 위해 전체 데이터베이스를 부팅하는 일을 방지할 수 있습니다.
run --rm web env은 모든 .env 파일, environment: 블록, 셸 변수가 병합된 후 서비스가 실제로 적용받는 환경을 확인하는 가장 빠른 방법입니다. 값이 올바르지 않다면 병합 순서가 원인인 경우가 많으며, Compose가 환경 파일과 비밀 값을 해석하는 방식에서 어떤 설정이 우선하는지 확인할 수 있습니다.
네트워크, 포트 및 이름 확인
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksCompose는 모든 서비스를 하나의 프로젝트 네트워크에 배치하며, 각 서비스 이름은 해당 네트워크 내의 DNS 이름이 됩니다. web 내부에서 getent hosts db를 실행하면 이름 확인이 정상적일 때 컨테이너 IP가 출력되고, 그렇지 않으면 아무것도 출력되지 않습니다. 따라서 이 명령은 "컨테이너들이 서로 통신할 수 있는가"라는 질문에 2초 안에 답을 줍니다. 이름은 확인되지만 연결이 거부된다면, db 내부의 프로세스가 0.0.0.0이 아닌 127.0.0.1에 바인딩된 상태이므로 다른 컨테이너로부터 오는 패킷을 수신할 수 없는 것입니다. 이 모델에 대한 자세한 내용은 Compose 네트워크와 서비스 DNS 작동 방식에서 확인할 수 있습니다.
port web 80는 컨테이너 포트가 게시된 호스트 주소와 포트를 출력하므로, 매핑이 변수에서 비롯된 경우 추측할 필요가 없습니다. 포트를 게시하면 Docker가 직접 관리하는 방화벽 규칙이 생성되는데, 이 규칙은 사용자가 설정한 규칙보다 우선합니다. 따라서 비공개라고 생각했던 서비스가 인터넷에 노출될 수 있습니다. 이 사례는 게시된 Docker 포트가 ufw를 우회하는 이유에서 다룹니다.
볼륨 및 데이터
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes는 프로젝트에 선언된 명명된 볼륨을 한 줄에 하나씩 출력합니다. 이 목록이 백업 대상입니다. cp은 셸을 열지 않고도 컨테이너 내부로 파일을 복사하거나 외부로 가져올 수 있으며, 컨테이너 쪽 경로에는 service:path 형식을 사용합니다.
down -v은 컨테이너와 함께 해당 명명된 볼륨을 삭제합니다. 테스트 스택을 제거할 때는 적절한 명령어이지만, 데이터가 보존되어야 하는 환경에서는 사용해서는 안 됩니다. 별도의 확인 절차가 없으며 되돌릴 수도 없기 때문입니다. 바인드 마운트는 호스트 파일 시스템에 위치하므로 이 명령의 영향을 받지 않습니다. 이러한 영향 범위의 차이는 바인드 마운트와 명명된 볼륨 중 하나를 신중하게 선택해야 하는 이유 중 하나입니다.
데이터 손실 없이 디스크 공간을 확보하는 정리 작업
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans는 프로젝트에는 속해 있지만 파일에는 더 이상 나타나지 않는 컨테이너를 삭제합니다. 이는 서비스를 이름을 변경한 후에 발생하는 상황과 정확히 일치합니다. 이 명령을 사용하지 않으면 해당 컨테이너는 계속 실행되지만 docker compose ps에서는 보이지 않게 됩니다.
docker system df은 삭제를 수행하기 전에 디스크 공간이 어디에 사용되고 있는지 보여줍니다. 이미지, 컨테이너, 로컬 볼륨, 빌드 캐시를 구분하여 각각 회수 가능한 용량을 표시합니다. image prune -a는 태그가 지정되지 않은 모든 이미지를 제거합니다. 여러 버전의 대용량 이미지를 내려받은 서버에서는 보통 이 작업으로 가장 많은 공간을 확보할 수 있습니다. builder prune은 빌드 캐시를 삭제합니다. 빌드 캐시는 자체 이미지를 빌드하는 모든 서버에서 조용히 증가합니다.
위의 명령들은 명명된 볼륨(named volume)에는 영향을 주지 않습니다. 오직 docker volume prune와 docker compose down -v만이 볼륨을 삭제합니다.
파일이 문제를 일으키기 전에 확인하기
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dconfig --quiet은(는) 성공 시 아무것도 출력하지 않으므로 배포 전 단계나 git hook에 적합합니다. 단순히 config을(를) 실행하면 병합 및 보간이 완료된 전체 파일이 출력되며, 이를 통해 변수가 올바르게 해석되었는지, override 파일이 의도한 대로 적용되었는지 확인할 수 있습니다. 설정되지 않은 변수는 The "X" variable is not set. Defaulting to a blank string. 경고와 함께 빈 값으로 나타납니다.
--dry-run은(는) 하위 명령 플래그가 아닌 전역 플래그이므로 up 앞에 위치해야 합니다. 이 플래그는 Compose가 수행할 모든 작업을 출력하되 실제 변경은 가하지 않습니다. 중요한 스택에 down을(를) 실행하기 전에 30초 정도 시간을 투자하여 확인하는 것이 좋습니다.
파일, 프로필, 프로젝트 간 작업
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d여러 개의 -f 플래그는 순서대로 병합되며, 나중에 지정된 파일이 앞선 파일의 설정을 키 단위로 덮어씁니다. 이는 기본 파일 하나와 운영 환경용 소규모 오버라이드 파일을 유지하는 표준적인 방법입니다. 단, 리스트와 맵에 대한 병합 규칙은 다르므로 예상치 못한 동작을 디버깅하기 전에 Compose가 여러 파일을 병합하는 방식을 읽어보시기 바랍니다.
--profile은 해당 프로필로 태그된 서비스를 태그가 없는 서비스와 함께 시작하며, 이를 통해 일반적인 up 실행 시 디버깅 도구가 포함되지 않도록 할 수 있습니다. -p는 프로젝트 이름을 설정하므로, 동일한 스택의 복사본 두 개를 서로 다른 네트워크와 볼륨 이름을 사용하여 동시에 실행할 수 있습니다. 재부팅 후 스택을 복구하는 것은 별도의 명령어를 입력하는 것이 아니라, Compose 스택을 부팅 시 시작하는 방법에 설명된 대로 시스템이 자동으로 실행하는 유닛을 통해 이루어집니다.
FAQ
docker-compose을 하이픈으로 대체한 이유는 무엇입니까?
Compose V2는 docker compose과 같이 공백을 사용하여 호출합니다. 이는 Docker Engine에 포함된 플러그인이며, 현재 패키지에서는 더 이상 V1 Python 도구를 설치하지 않습니다. 공백을 사용한 명령이 아무것도 출력하지 않는다면 배포판에 맞는 docker-compose-plugin 패키지를 설치하십시오. V2에는 V1에 없던 플래그가 존재하므로, 별칭(alias)을 추가하기보다 기존 스크립트를 공백을 사용하는 형식으로 업데이트하십시오.
docker compose restart가 설정 변경 사항을 반영하지 않는 이유는 무엇입니까?
restart은 기존 컨테이너를 생성 당시의 설정으로 중지하고 시작할 뿐이며, compose.yaml을 다시 읽지 않습니다. 환경 변수, 포트, 볼륨 또는 이미지 태그를 변경하려면 docker compose up -d를 사용해야 합니다. 이 명령은 각 서비스를 실행 중인 컨테이너와 비교하여 차이가 있는 컨테이너를 다시 생성합니다. 파일 내용이 변경되지 않았더라도 교체를 강제하려면 --force-recreate을 추가하십시오.
서비스를 더 최신 이미지로 업데이트하려면 어떻게 해야 합니까?
docker compose pull를 실행한 다음 docker compose up -d를 실행하십시오. pull 명령은 파일에 정의된 각 태그의 최신 이미지를 가져오며, up -d은 이미지 ID가 컨테이너와 일치하지 않는 모든 서비스를 다시 생성합니다. up -d만 단독으로 실행하면 디스크에 이미 존재하는 이미지를 재사용합니다. 이것이 바로 latest로 고정된 스택이 오류 메시지 없이 수개월 된 빌드 상태로 유지되는 이유입니다.
운영 중인 서버에서 안전하게 실행할 수 있는 정리 명령은 무엇입니까?
docker system df, docker image prune -a 및 docker builder prune은 이미지와 캐시만 제거하므로 실행 중인 서비스는 계속 작동하며 명명된 볼륨(named volumes)은 영향을 받지 않습니다. 위험한 명령은 docker compose down -v와 docker volume prune이며, 이들은 별도의 확인 절차 없이 명명된 볼륨을 삭제합니다. 무엇이 삭제될지 미리 확인하려면 먼저 docker compose config --volumes를 실행하십시오.
전체 스택을 시작하지 않고 하나의 명령만 실행할 수 있습니까?
예, 가능합니다. docker compose run --rm --no-deps web sh는 web 서비스 정의에서 단일 컨테이너를 시작하고 의존성을 건너뛰며, 종료 시 컨테이너를 제거합니다. 컨테이너가 이미 실행 중인 경우에는 exec을 대신 사용하십시오. exec은 실행 중인 프로세스에 연결하여 서비스의 실제 상태를 보여줍니다.