빌드노트
docker run 이미지 뒤의 /bin/sh가 셸을 띄우지 않는 이유
docker run 이미지 뒤에 /bin/sh를 붙였는데 기존 프로그램의 인자 오류가 난다면 컨테이너의 Path/Args와 실제 이미지의 Entrypoint/Cmd를 비교한다. 보존된 격리 관찰로 CMD 전체 대체와 --entrypoint 교체·기본 CMD 제거를 구분하고, 실행 파일을 바꿀 최소 명령을 설명한다.
docker run 이미지 /bin/sh를 실행했는데 셸 대신 기존 프로그램의 unrecognized arguments: /bin/sh 오류가 나온다면, 이미지의 ENTRYPOINT부터 확인한다. exec-form ENTRYPOINT가 있는 이미지에서는 이미지 뒤의 내용이 그 프로그램의 인자로 붙는다. 셸을 실행하려면 이미지 뒤의 명령만 바꾸는 대신, 이미지 앞에 --entrypoint /bin/sh를 지정해야 한다. Dockerfile의 ENTRYPOINT 설명 (새 탭에서 열림)
오류를 낸 컨테이너가 남아 있다면 다시 실행하기 전에 다음 PowerShell 명령으로 조회한다. Docker CLI가 해당 Linux 엔진에 연결되어 있어야 하며, my-container를 자신의 컨테이너 이름으로 바꾼다. 이미지 태그가 나중에 바뀌었을 수 있으므로 컨테이너에 기록된 이미지 ID를 사용한다.
$container = 'my-container'
$imageId = docker container inspect --format '{{.Image}}' $container
if ($LASTEXITCODE -ne 0) { throw 'Container lookup failed' }
docker image inspect --format 'Entrypoint={{json .Config.Entrypoint}} Cmd={{json .Config.Cmd}}' $imageId
if ($LASTEXITCODE -ne 0) { throw 'Image lookup failed' }
docker container inspect --format 'Path={{json .Path}} Args={{json .Args}} Exit={{.State.ExitCode}}' $container
if ($LASTEXITCODE -ne 0) { throw 'Container lookup failed' }
아래 출력과 뒤의 argv 비교는 2026년 10월 21일 Windows의 Docker Desktop 4.92.0, Docker CLI·Linux 엔진 29.8.0, 컨테이너 안의 Python 3.12.14로 수행한 별도 격리 실험에서 보존한 결과다. 실제 서비스 장애 로그가 아니다. 첫 줄은 이미지의 기본값이고, 둘째 줄은 이미지 뒤에 /bin/sh를 붙여 실행한 컨테이너의 시작 설정과 종료 코드다.
Entrypoint=["python3","/lab/argv.py","--origin","entrypoint"] Cmd=["--mode","default"]
Path="python3" Args=["/lab/argv.py","--origin","entrypoint","/bin/sh"] Exit=2
실행 파일인 Path는 여전히 python3다. /bin/sh는 Args의 마지막에 들어갔고, 기본 옵션인 --mode default는 사라졌다. 셸이 실패한 것이 아니라 기존 프로그램의 인자 파서가 /bin/sh를 거부해 종료 코드 2를 반환했다. 다른 프로그램의 인자 오류도 같은 종료 코드를 쓴다는 뜻은 아니다.
json 형식은 배열의 요소와 문자열 경계를 구별하기 위한 것이다. inspect 공식 문서 (새 탭에서 열림)에서 출력 템플릿을 확인할 수 있다. 조회가 실패했다면 우선 엔진 연결과 대상 이름을 확인한다. --rm으로 이미 삭제된 컨테이너는 조회할 수 없다. Entrypoint가 비어 있거나 Path가 예상과 다르면, 이 사례와 같은 시작 설정인지부터 다시 확인한다.
셸을 실행하려면 --entrypoint를 이미지 앞에 둔다
앞의 조회가 성공했고 그 이미지에 /bin/sh가 있다면, 다음 두 줄이 수정 전후의 차이다. 새 단기 컨테이너를 만들어 비교하므로 실행해도 되는 이미지에서 사용한다. 첫 줄은 이 실험의 인자 오류를 다시 내고, 둘째 줄은 shell-ok를 출력한 뒤 종료한다. 두 컨테이너는 종료 시 자동 삭제된다.
$image = $imageId
docker run --rm --network none $image /bin/sh
docker run --rm --network none --entrypoint /bin/sh $image -c 'echo shell-ok'
--entrypoint는 Docker 옵션이라 이미지 앞에 둔다. 값에는 실행 파일 이름이나 경로만 넣고, 셸의 -c와 명령 문자열은 이미지 뒤에 둔다. '/bin/sh -c echo shell-ok' 전체를 실행 파일 경로로 넣는 방식이 아니다. 조회용으로 남긴 같은 입력의 컨테이너에서는 Path="/bin/sh" Args=["-c","echo shell-ok"] Exit=0을 확인했다. 원래 ENTRYPOINT의 /lab/argv.py --origin entrypoint도 함께 빠졌다. 기본 entrypoint 교체 설명 (새 탭에서 열림)
셸이 없는 최소 이미지에서는 두 번째 명령도 실행 파일을 찾지 못해 실패할 수 있다. 그 경우에는 이미지에 실제로 들어 있는 진단 프로그램을 선택해야 한다. 기존 프로그램이 /bin/sh를 인자로 거부한 오류와 실행 파일 자체가 없는 오류를 구별한다.
옵션만 바꿀 때도 CMD 전체가 교체된다
프로그램은 그대로 두고 옵션을 바꾸려면 이미지 뒤에 필요한 옵션 전체를 적는다. exec-form ENTRYPOINT 뒤에는 이미지의 기본 CMD 또는 실행 시 지정한 후행 인자가 이어진다. 후행 인자는 CMD에 덧붙는 것이 아니라 CMD 전체를 대체한다. 기본 명령과 옵션의 교체 규칙 (새 탭에서 열림)
격리 실험의 프로그램은 Linux의 /proc/self/cmdline에서 실제 인자 배열인 argv를 읽었다. 세 경우 모두 앞부분은 ["python3","/lab/argv.py","--origin","entrypoint"]였고, 뒤에 이어진 값이 달랐다.
- 후행 인자 없음:
["--mode","default"]가 이어졌고 종료 코드는 0이었다. - 후행 인자
--mode override:["--mode","override"]로 교체됐고 종료 코드는 0이었다.default는 남지 않았다. - 후행 인자
/bin/sh:["/bin/sh"]로 교체됐고 인자 파서 오류로 종료 코드 2를 반환했다.
각 경우의 실제 argv는 컨테이너의 Path와 Args를 순서대로 합친 값과 같았다. 또한 같은 이미지에서 후행 인자 없이 --entrypoint /bin/echo만 지정했을 때는 빈 줄만 출력했고, Path="/bin/echo" Args=[] Exit=0, 컨테이너의 Cmd=null을 확인했다. --entrypoint를 지정하면 이미지의 CMD 기본값도 비워진다. 새 실행 파일에 필요한 인자는 직접 다시 줘야 한다.
이 비교는 ENTRYPOINT와 CMD가 모두 JSON 배열인 exec-form이며, 프로그램을 직접 실행하는 Linux 이미지에 한정한다. Path와 Args는 컨테이너의 시작 설정이다. 진입점이 스크립트라면 내부에서 인자를 다시 가공할 수 있으므로 그 실행 코드도 읽어야 한다. shell-form ENTRYPOINT, Compose·Kubernetes의 명령 설정, Windows 컨테이너와 PID 1의 신호 전달은 이 실험의 검증 범위가 아니다.