빌드노트
컨테이너는 실패했는데 docker wait는 성공했다
docker wait의 stdout에는 컨테이너 종료 코드가 나오지만 CLI 종료 상태는 0일 수 있다. exit 7·0과 없는 컨테이너를 실제 비교하고, PowerShell 자동화에서 CLI 오류를 먼저 확인한 뒤 stdout으로 작업 성공을 판정하는 코드를 설명한다.
Docker 작업 컨테이너가 종료 코드 7로 끝났는데, PowerShell에서 docker wait를 실행한 뒤 읽은 $LASTEXITCODE는 0일 수 있다. docker wait의 실행 성공과 컨테이너 안 작업의 성공은 따로 확인해야 한다. 컨테이너의 종료 코드는 표준 출력(stdout)으로 나오고, $LASTEXITCODE에는 Docker CLI 프로세스의 종료 상태가 남는다.
Docker의 wait 문서 (새 탭에서 열림)는 컨테이너가 멈출 때까지 기다린 다음 그 종료 코드를 출력한다고 설명한다. docker wait는 docker container wait의 별칭이다. 화면에 7이 보인다고 해서 Docker CLI 자체도 종료 상태 7을 반환하는 것은 아니다.
내 컨테이너에서 두 값을 나눠 읽는다
다음 명령으로 stdout과 CLI 종료 상태를 따로 보관하고, 종료된 컨테이너의 기록과 대조할 수 있다. PowerShell에서 Docker CLI가 대상 Linux 엔진에 연결돼 있어야 한다. my-job을 자신의 작업 컨테이너 이름이나 ID로 바꾼다. 아직 실행 중이면 wait는 종료될 때까지 기다리므로, 종료를 기다려도 되는 작업에 실행한다. 조회할 컨테이너는 삭제되지 않고 남아 있어야 한다.
$container = 'my-job'
$exitCodeText = @(docker wait $container)
$waitCliCode = $LASTEXITCODE
"stdout=$($exitCodeText -join ','); CLI=$waitCliCode"
docker container inspect --format 'status={{.State.Status}} exit={{.State.ExitCode}}' $container
$LASTEXITCODE는 docker wait 직후에 저장한다. 뒤의 docker container inspect도 외부 명령이므로 그 실행이 끝나면 값이 바뀔 수 있다. PowerShell 자동 변수 문서 (새 탭에서 열림)는 이 변수를 마지막으로 실행한 외부 프로그램이나 PowerShell 스크립트의 종료 코드로 설명한다. @(...)는 여기서 stdout을 줄 단위 배열로 받기 위해 썼다.
차이를 확인하기 위해 별도 컨테이너 두 개에서 /bin/sh가 잠깐 기다린 뒤 각각 exit 7, exit 0으로 끝나게 했다. 외부 네트워크를 끊은 합성 실험이며 실제 업무 장애 기록은 아니다. Windows의 PowerShell 7.6.6, Docker Desktop 4.92.0, CLI와 Linux Engine 29.8.0, Alpine 3.22.7에서 실행했다.
exit 7 컨테이너에 위 조회를 실행한 결과는 다음과 같았다.
stdout=7; CLI=0
status=exited exit=7
첫 줄의 7이 컨테이너에서 실행한 작업의 종료 코드다. CLI는 그 값을 정상적으로 받아 출력했으므로 0이었다. 둘째 줄의 State.ExitCode도 7로 일치했다. inspect가 성공했다는 사실과 그 안의 종료 코드 역시 구별해서 읽는다. 컨테이너 inspect 문서 (새 탭에서 열림)의 --format으로 필요한 상태 필드만 골라 출력한 것이다.
exit 0 컨테이너에서는 첫 줄이 stdout=0; CLI=0, 둘째 줄이 status=exited exit=0이었다. 컨테이너의 성공·실패가 바뀌어도 wait의 CLI 상태는 두 경우 모두 0이었다. 따라서 그 상태 하나만 성공 조건으로 삼으면 실패한 작업도 통과한다.
존재하지 않는 새 이름으로 실행하자 결과가 달랐다. stdout은 비어 있었고 CLI 종료 상태는 1이었다. 오류 출력(stderr)에는 No such container가 나왔다. 이것은 작업이 종료 코드 1로 끝났다는 뜻이 아니라, 지정한 컨테이너의 결과를 얻지 못했다는 뜻이다. CLI 29.8.0의 wait 구현 (새 탭에서 열림)에서도 컨테이너 종료 값을 stdout에 쓰는 처리와 API 오류를 반환하는 처리가 나뉜다.
자동화에서는 CLI 검사 뒤에 stdout을 해석한다
종료 코드 0만 작업 성공으로 인정한다면, 성공 조건은 “CLI 상태가 0이고, stdout에서 읽은 컨테이너 종료 코드도 0”이다. 아래 코드를 자신의 PowerShell 스크립트의 작업 판정 부분에 넣는다. 대상은 앞과 같이 삭제되지 않은 단일 작업 컨테이너이며, my-job을 실제 이름으로 바꾼다.
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $false
$container = 'my-job'
$exitCodeText = @(docker wait $container)
$waitCliCode = $LASTEXITCODE
if ($waitCliCode -ne 0) { throw "docker wait failed: CLI=$waitCliCode" }
if ($exitCodeText.Count -ne 1 -or $exitCodeText[0] -notmatch '^[0-9]+$') {
throw 'Expected one container exit code.'
}
$containerCode = [int]$exitCodeText[0]
if ($containerCode -ne 0) { throw "Container job failed: exit=$containerCode" }
'job succeeded'
먼저 CLI 오류를 확인하므로, 없는 컨테이너의 빈 stdout을 작업 성공으로 바꾸지 않는다. 그다음 한 줄의 숫자인지 검사하고 정수로 변환한다. 2>&1로 stderr를 합치지 않은 이유도 종료 코드가 실리는 stdout만 해석하기 위해서다. 이 코드는 컨테이너 하나를 대상으로 하며, 여러 컨테이너의 결과를 한꺼번에 합산하는 코드는 아니다.
$PSNativeCommandUseErrorActionPreference는 PowerShell 7.4 이상에서 사용하는 설정이다. 여기서는 외부 명령의 실패를 직접 분기하기 위해 스크립트 안에서 $false로 정했다. 설정이 $true이면 외부 명령의 0이 아닌 종료 코드가 $ErrorActionPreference에 따라 오류를 발생시킨다. 어느 설정도 컨테이너의 stdout 7을 CLI 실패로 바꿔 주지는 않는다. 외부 명령 오류 처리 설정 (새 탭에서 열림)
같은 판정 코드를 별도 .ps1 파일로 만들어 pwsh -NoProfile -File로 실행했다. 컨테이너 종료 코드가 7이면 Container job failed: exit=7에서 중단돼 PowerShell 프로세스가 1로 끝났고, 0이면 job succeeded를 출력하며 0으로 끝났다. 없는 이름은 숫자를 해석하기 전에 docker wait failed: CLI=1에서 중단됐다. 컨테이너의 7을 그대로 호출자에게 돌려주는 대신 이 예제는 모든 실패를 스크립트 종료 상태 1로 알린다. 상위 코드에서 예외를 잡는다면 그 실패를 다시 성공으로 처리하지 않도록 해야 한다.
직접 비교한 범위는 자동 삭제와 재시작 정책을 사용하지 않는 단발 Linux 컨테이너다. 실행 중 시작한 wait와 이미 종료된 컨테이너를 대상으로 한 조회를 모두 확인했다. 자동 삭제·재시작이 겹치는 경우, 여러 컨테이너를 한 번에 기다리는 경우, Docker 연결이 중간에 끊기는 경우는 검증하지 않았다. 이 실험은 종료 코드 전달 방식을 확인한 것이며, 코드 7을 낸 실제 앱의 원인까지 알려 주지는 않는다.