본문 바로가기
빌드노트 검색

빌드노트

같은 Compose 파일인데 컨테이너가 하나 더 생겼다

같은 Compose 파일로 실행해도 프로젝트 이름이 다르면 기존 서비스 대신 별도 컨테이너가 생긴다. 프로젝트·서비스 라벨과 현재 명령의 name을 비교하고, 기존 프로젝트에 맞는 -p로 관리 대상을 고정하는 방법을 실제 격리 실행 결과로 설명한다.

같은 compose.yaml로 docker compose up -d app을 실행했는데 기존 컨테이너는 그대로 남고 새 컨테이너가 생겼다면, 실행 명령이 선택한 프로젝트 이름을 확인한다. Compose에서는 서비스 이름이 app으로 같아도 프로젝트 이름이 다르면 별도 서비스로 관리한다. 같은 파일을 지정했다는 사실만으로 기존 컨테이너를 갱신하는 것은 아니다. Docker의 프로젝트 이름 설명 (새 탭에서 열림)

확인할 것은 두 가지다. 기존 컨테이너가 어느 프로젝트에 속하는지 라벨로 읽고, 지금 실행하는 명령도 그 프로젝트를 선택하는지 비교한다. 기존 서비스를 계속 관리하려는 경우에는 확인한 프로젝트 이름으로 -p를 맞춘다.

컨테이너 이름보다 프로젝트·서비스 라벨을 읽는다

Compose 파일의 services: 아래에 있는 app은 서비스 이름이다. Compose는 서비스 컨테이너에 com.docker.compose.service 라벨을 붙이고, 프로젝트 이름은 별도 라벨인 com.docker.compose.project에 남긴다. 이 두 값을 읽으면 서로 다른 프로젝트의 app인지 구별할 수 있다. Compose의 기본 라벨 (새 탭에서 열림)

다음은 PowerShell 7에서 기존 컨테이너 두 개의 ID와 라벨만 조회하는 명령이다. Docker CLI를 사용할 수 있고, 두 컨테이너가 있는 엔진에 연결되어 있어야 한다. $containers의 두 문자열을 조사할 실제 컨테이너 이름이나 ID로 바꾼다. 이름을 모르면 docker ps -a에서 대상을 찾는다.

$containers = @('my-service-app-1', 'other-service-app-1')
docker inspect --type container $containers | ConvertFrom-Json |
    Select-Object @{n='ID';e={$_.Id.Substring(0,12)}},
        @{n='Project';e={$_.Config.Labels.'com.docker.compose.project'}},
        @{n='Service';e={$_.Config.Labels.'com.docker.compose.service'}}

ID는 실제 컨테이너 ID의 앞 12자리다. 아래는 뒤에서 설명할 별도 실험에서, 두 프로젝트의 설정을 각각 갱신한 뒤 이 조회를 실행한 출력이다.

ID           Project             Service
--           -------             -------
97b7c347cee3 cplab_f9f935874679a app
1e449df30c0c cplab_f9f935874679b app

두 줄 모두 Service는 app이지만 Project는 다르다. 이 경우 하나의 프로젝트 안에 같은 서비스가 두 개 생긴 것으로 해석하면 관리 대상을 잘못 고른다. 컨테이너 이름에 붙은 접두사를 추측하는 대신 라벨 값을 기준으로 판단한다. inspect는 이름이나 ID로 실제 Docker 객체를 조회한다. inspect의 조회 방식 (새 탭에서 열림)

No such container가 나오면 조회에 실패한 것이므로 이름·ID와 연결한 엔진부터 확인한다. 라벨이 비어 있다면 이 결과만으로 Compose 프로젝트를 판정할 수 없다. 두 라벨이 모두 같은 경우에도 ID가 다르다는 사실만으로 프로젝트 이름 문제라고 단정하지 않는다. 스케일 설정과 컨테이너를 만든 명령을 더 확인해야 한다.

같은 파일을 읽어도 선택되는 프로젝트는 다를 수 있다

이번에는 문제가 난 명령이 해석하는 프로젝트 이름을 읽는다. 같은 터미널 환경에서 실행하며, 아래 $composeArgs에는 문제가 난 명령의 Compose 옵션을 그대로 옮긴다. 예시의 파일 경로는 자신의 파일로 바꾼다. 원래 있던 -p, 여러 -f, --env-file, --project-directory, 프로필 옵션도 유지한다. 진단 단계에서 원래 없던 -p를 넣으면 이름이 달라진 원인을 가릴 수 있다.

$composeArgs = @('-f', 'D:\my-service\compose.yaml')
docker compose @composeArgs config --format json | ConvertFrom-Json |
    Select-Object -ExpandProperty name

이 명령은 현재 옵션과 변수로 해석한 모델에서 name만 출력한다. 앞에서 확인한 기존 컨테이너의 Project와 다르면 지금의 명령은 기존 프로젝트를 선택하고 있지 않다. config는 적용할 설정을 보여 주는 조회이므로, 성공해도 실행 중인 컨테이너가 바뀌지는 않는다. 오류가 나면 프로젝트 이름을 확인한 것이 아니다. config가 해석하는 대상 (새 탭에서 열림)

일반적인 로컬 Compose 파일에서 프로젝트 이름을 정하는 우선순위는 -p, COMPOSE_PROJECT_NAME, 파일 최상위의 name:, 프로젝트 디렉터리 이름 순이다. 여러 파일을 병합하면 최상위 name:은 마지막 값을 따른다. 따라서 파일에 name:을 추가해도 명령의 -p나 환경의 COMPOSE_PROJECT_NAME이 있으면 그 값이 우선한다. 프로젝트 이름의 우선순위 (새 탭에서 열림)

파일을 보관하는 폴더 이름이 달라진 경우에도 기본 프로젝트 이름을 확인할 필요가 있다. 여기서 조사하는 것은 상대 경로가 어느 폴더를 가리키는지가 아니라, Compose가 어느 프로젝트의 리소스를 관리할지다.

프로젝트 이름만 바꿔 실행해 보니

이 동작은 Windows 11의 로컬 Docker Desktop Linux 엔진에서 별도로 실행했다. Compose는 v5.5.1, Engine은 29.8.0, 이미지는 BusyBox 1.37.0이었다. 서비스는 app 하나이며 호스트 포트와 볼륨은 없었다. 외부 통신을 막은 기본 네트워크를 프로젝트마다 만들었다.

앞의 출력에 나온 cplab_f9f935874679a를 A, 끝이 b인 프로젝트를 B로 부르겠다. 동일한 파일을 계속 사용하면서 -p와 합성 환경값만 바꿨다. 다음 ID는 모두 실제 관찰값의 앞 12자리다.

  • A를 처음 실행했을 때 ID는 f8682ee30150이었다. 같은 설정으로 A를 다시 올려도 이 ID가 유지됐다.
  • 같은 파일을 B로 실행하자 2fd112fb481a가 생겼다. A의 ID는 그대로였고 두 컨테이너의 서비스 라벨은 모두 app이었다. 프로젝트 라벨과 기본 네트워크는 각각 달랐다.
  • 합성 환경값 LAB_REVISION을 one에서 two로 바꾸고 B를 올렸다. B는 1e449df30c0c로 재생성돼 two를 받았다. A는 처음 ID와 one을 유지했다.
  • 같은 변경을 A에도 적용하자 A가 97b7c347cee3으로 재생성돼 two를 받았다. B의 ID는 바뀌지 않았다.

어느 프로젝트를 선택했는지가 갱신 대상을 갈랐다. 같은 이름으로 재실행해도 설정이 바뀌면 ID는 달라질 수 있다. Compose의 up은 서비스 설정이나 이미지가 바뀐 경우 기존 컨테이너를 재생성할 수 있으므로, ID 유지 자체를 갱신 성공의 기준으로 삼지는 않는다. up의 재생성 동작 (새 탭에서 열림)

정리 범위도 확인했다. 이 실험에서 만든 A만 down한 뒤 B를 조회하니, B는 같은 컨테이너·네트워크 ID로 실행 중이었다. 이후 B도 따로 정리했고 두 실험 프로젝트의 컨테이너와 네트워크가 남지 않았음을 확인했다. 기존 프로젝트에는 down을 실행하지 않았다. down은 선택한 프로젝트의 서비스 컨테이너와 기본 네트워크 등을 제거하는 명령이다. down의 기본 제거 대상 (새 탭에서 열림)

기존 프로젝트의 라벨 값으로 -p를 맞춘다

기존 서비스를 갱신하려면 새 이름을 짓지 말고, 앞에서 읽은 Project 값을 사용한다. 다음 예시의 my-service를 그 값으로 바꾸고 파일 경로도 실제 경로로 바꾼다. 앞에서 사용한 배열을 수정할 때는 다른 프로젝트를 가리키던 -p 값을 교체한다. 여러 파일이나 환경 파일을 쓰고 있었다면 그 옵션을 유지한다.

아래 첫 명령으로 관리 대상을 조회한 뒤 Project, Service, ID를 기존 컨테이너와 대조한다. 확인이 끝나면 두 번째 명령으로 해당 프로젝트의 app에 현재 설정을 적용한다. 서비스 이름이 다르면 app도 바꾼다.

$composeArgs = @('-p', 'my-service', '-f', 'D:\my-service\compose.yaml')
docker compose @composeArgs ps --all --format json
docker compose @composeArgs up -d app

ps는 선택한 프로젝트의 컨테이너를 보여 주고 --all은 중지된 컨테이너도 포함한다. 출력이 비어 있으면 곧바로 up을 실행하지 말고 프로젝트 이름·파일·엔진이 맞는지 다시 확인한다. ID가 축약돼 나오면 앞부분을 대조한다. 프로젝트 단위 ps 조회 (새 탭에서 열림)

-p를 맞추는 것은 기존 프로젝트의 이름을 변경하거나 B의 컨테이너를 A로 옮기는 작업이 아니다. 이후 명령이 선택할 대상을 고정하는 것이다. 배포 명령뿐 아니라 ps, logs, exec 같은 확인 명령에서도 같은 프로젝트 이름을 사용해야 엉뚱한 복사본을 보고 판단하지 않는다.

이번에는 본문의 PowerShell 조회와 적용 명령도 실험 컨테이너에 실제로 실행했다. 이름의 우선순위 중 -p·프로세스 환경변수·최상위 name:의 관계는 합성 설정의 config 결과로 추가 확인했고, 디렉터리 기본값은 공식 문서의 규칙으로 설명했다. 영속 볼륨·공유 외부 리소스·고정 호스트 포트가 있는 구성, 원격 엔진, 다른 호스트 운영체제는 실행하지 않았다. 이미 생긴 별도 프로젝트를 삭제할지 판단하려면 그 프로젝트의 데이터와 사용 여부를 따로 확인해야 한다.

← 전체 글 보기