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

빌드노트

앱이 cd해도 docker exec의 기본 경로는 그대로다

앱의 현재 디렉터리와 컨테이너의 Config.WorkingDir는 다른 값일 수 있다. 이미지 설정, 실제 /proc/1/cwd, 기본 exec와 exec -w의 출력을 비교해 점검 명령의 시작 경로를 정한다.

컨테이너의 앱은 /srv/app으로 이동해 실행 중인데 docker exec로 확인한 위치는 /opt/start일 수 있다. 새 exec 명령은 컨테이너를 만들 때 설정한 작업 디렉터리에서 시작한다. 실행 중인 앱의 현재 디렉터리(cwd)가 바뀌어도 이 기본값은 그대로다. 앱과 같은 경로에서 점검 명령을 실행하려면 docker exec -w /srv/app ...처럼 이번 명령의 위치를 지정한다. Docker exec의 작업 디렉터리 규칙 (새 탭에서 열림)

이미지 설정, 컨테이너 설정, 실제 프로세스 위치를 비교한다

아래는 PowerShell에서 실행할 조회다. Docker CLI가 연결된 엔진에 실행 중인 Linux 컨테이너가 있고, 그 안에 pwd와 readlink가 있어야 한다. myapp을 확인할 컨테이너 이름이나 ID로 바꾼다. /proc/1/cwd는 컨테이너 안에서 본 PID 1의 현재 위치를 가리킨다. Linux의 프로세스별 /proc 항목 (새 탭에서 열림)

이 명령은 해당 컨테이너가 사용한 이미지의 기본값, 생성 시 설정값, 새 명령의 위치, 기존 PID 1의 위치를 차례로 읽는다.

$container = 'myapp'
$image = docker inspect --format '{{.Image}}' $container
docker image inspect --format '{{.Config.WorkingDir}}' $image
docker inspect --format '{{.Config.WorkingDir}}' $container
docker exec $container pwd
docker exec $container readlink /proc/1/cwd

이미지는 컨테이너의 .Image로 찾았다. 나중에 다른 이미지를 가리킬 수 있는 태그 대신, 이 컨테이너를 생성한 이미지의 설정을 읽기 위해서다. 로컬에 그 이미지가 없어 이미지 조회가 실패하더라도 컨테이너의 설정과 프로세스 조회는 각각 확인할 수 있다.

별도로 만든 BusyBox 실습 이미지에서 같은 조회를 실행한 출력은 다음과 같았다.

/opt/start
/opt/start
/opt/start
/srv/app

이 이미지에는 WORKDIR /opt/start를 선언했다. 시작 셸은 미리 준비한 /srv/app으로 cd한 뒤 exec sleep 180을 실행하도록 했다. 실제 앱 대신 위치를 유지하며 기다리는 프로세스를 쓴 재현이다. /proc/1/comm은 sleep, /proc/1/cwd는 /srv/app이었으므로, 시작 명령에 cd가 적혀 있다는 것만 보고 이동했다고 판단한 결과가 아니다.

첫 두 줄은 이미지와 컨테이너의 Config.WorkingDir가 /opt/start라는 뜻이다. 세 번째 줄은 새로 실행한 pwd도 그 위치에서 시작했음을 보여 준다. 마지막 줄은 이미 실행 중인 PID 1이 /srv/app에 있음을 보여 준다. 설정된 시작 위치와 실행 중 프로세스의 현재 위치가 동시에 다른 값일 수 있다.

Docker 문서는 exec를 실행 중인 컨테이너에 새 명령을 시작하는 기능으로 설명한다. 따라서 docker exec ... pwd가 알려 주는 것은 방금 시작한 명령 자신의 cwd다. 기존 PID 1의 위치를 알고 싶다면 마지막 조회처럼 그 프로세스를 직접 관찰해야 한다.

PID 1이 init이나 래퍼라면 /proc/1/cwd도 그 프로세스의 위치다. 앱의 위치를 확인하려면 컨테이너 안의 실제 앱 PID로 /proc/번호/cwd를 조회한다. readlink가 없거나 권한 때문에 읽지 못했다면 앱이 자체 출력한 cwd 등의 별도 근거가 필요하다. 조회 실패를 두 경로가 같다는 증거로 해석해서는 안 된다. 반대로 두 조회가 같은 경로라면, 그 시점에는 이 경로 차이를 관찰하지 못한 것이다.

점검 명령의 위치는 exec에 지정한다

/srv/app에서 실행할 필요가 있다면 -w를 컨테이너 이름 앞에 넣는다. 이 경로는 컨테이너 내부에 존재하고 실행 사용자가 접근할 수 있어야 한다. 앞서 설정한 $container를 그대로 사용해, 위치를 지정한 명령과 그다음 기본 명령을 비교한다.

docker exec -w /srv/app $container pwd
docker exec $container pwd

같은 실습 컨테이너에서 순서대로 다음 값이 나왔다.

/srv/app
/opt/start

첫 줄의 pwd를 필요한 점검 명령으로 바꾸면 그 명령을 /srv/app에서 시작할 수 있다. 두 번째 호출처럼 -w를 생략하면 다시 컨테이너의 기본값을 쓴다. 실행 후에도 Config.WorkingDir는 /opt/start, PID 1의 cwd는 /srv/app인 것을 다시 확인했다. exec -w는 이번에 추가하는 프로세스의 시작 위치를 정한다. Docker 문서상 이 옵션은 API 1.35 이상에서 지원한다. exec 옵션 (새 탭에서 열림)

경로를 지정했는데도 시작하지 못한다면 오류에서 디렉터리와 실행 파일 중 무엇을 찾지 못했는지 읽는다. 이 환경에서 존재하지 않는 /does-not-exist를 -w로 지정하자 chdir to cwd와 no such file or directory가 포함된 오류로 실패했다. -w를 주기만 하면 없는 디렉터리도 준비된다고 가정하면 안 된다.

매번 시작할 기본 경로를 바꾸려면

여러 점검 명령이 항상 같은 위치에서 시작해야 한다면, 다음 컨테이너를 만들 때의 기본값을 검토한다. 이미지에서는 Dockerfile의 WORKDIR로 선언하고, 생성할 때는 docker run의 -w로 덮어쓸 수 있다. 이 설정과 앱이 실행 도중 수행하는 cd를 구분해야 한다. WORKDIR (새 탭에서 열림), 컨테이너 생성 시 작업 디렉터리 (새 탭에서 열림)

같은 실습 이미지로 컨테이너를 새로 만들면서 -w /opt/created를 준 변형도 확인했다. 이미지의 기본값은 여전히 /opt/start였지만, 컨테이너의 Config.WorkingDir와 기본 exec pwd는 모두 /opt/created였다. 시작 명령이 이동한 PID 1은 계속 /srv/app에 있었다. 이 변형은 기본 exec 경로를 판단할 때 이미지의 WORKDIR만 읽지 말고 실제 컨테이너의 설정까지 봐야 하는 이유를 보여 준다.

이 비교는 2026년 10월 24일 Windows 11의 Docker Desktop 4.92.0, Linux Engine·CLI 29.8.0(API 1.56), busybox:1.37.0으로 실행했다. 조회와 수정 명령은 Windows PowerShell 5.1에서도 실행했다. 확인한 범위는 새로 만든 Linux 컨테이너에서의 기본 경로, 생성 시 경로 지정, exec -w의 적용 범위다. Windows 컨테이너와 비루트 사용자 간 /proc 접근 제한은 실험하지 않았다.

← 전체 글 보기