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

빌드노트

Dockerfile의 같은 ENV에서 A를 바꿔도 B는 이전 값을 읽는다

ENV A=new B=$A에서 B가 이전 A를 읽으면 이미지 Config.Env부터 확인한다. 같은 instruction의 치환 시점과 실행 시 덮어쓰기를 구분하고, 새 A에 의존하는 B 선언만 다음 ENV로 분리한다.

Dockerfile에 ENV A=new B=$A를 썼는데 B에는 이전 A 값이 들어갈 수 있다. 같은 ENV instruction 안의 변수 참조는 그 instruction을 처리하기 전의 값을 사용하기 때문이다. 앞에 적힌 A=new를 뒤의 B=$A가 곧바로 읽는 순차 대입이 아니다. B에 새 A가 필요하면 두 ENV로 나눈다.

이미지에 저장된 B부터 확인한다

앱이 값을 잘못 읽는지 조사하기 전에 이미지의 Config.Env를 본다. PowerShell 7과 접근 가능한 Docker 엔진이 필요하다. $image에는 확인할 로컬 이미지의 태그나 ID를 넣는다. A·B·C는 예제용 공개 키이며, 실제 이미지에서는 필터를 조사할 공개 설정 키로 바꿔 필요한 값만 출력한다.

$image = '확인할_이미지:태그'
docker image inspect $image --format '{{range .Config.Env}}{{println .}}{{end}}' | Select-String '^[ABC]='

이미지 설정에서부터 B가 이전 값이면 Dockerfile의 선언 순서를 확인한다. 이 명령은 이미지 기본값을 조회하며 실행 시 덮어쓴 값이나 앱 내부 설정은 보여 주지 않는다. 이미지가 없다는 오류는 태그·ID부터 확인한다. 빈 출력만으로 변수가 없다고 단정하기 전에 명령 직후 $LASTEXITCODE가 0인지도 확인한다. image inspect 사용법 (새 탭에서 열림)

별도 합성 재현에서는 ENV A=old 다음에 ENV A=new B=$A, 그다음에 ENV C=$A를 두었다. 이미지 설정과 일회성 컨테이너 출력은 모두 A=new, B=old, C=new였다. 같은 instruction의 B는 이전 A를 읽었고, 다음 instruction의 C는 바뀐 A를 읽었다. 이미지에 이미 B가 old로 저장돼 있으므로 출력 셸에서 생긴 차이가 아니다.

이 관찰은 Docker의 Environment replacement 문서 (새 탭에서 열림)와 일치한다. 빌더가 치환에 쓰는 값은 한 instruction 안에서 유지되며, 변경한 값은 다음 instruction부터 적용된다.

새 A에 의존하는 값은 다음 ENV에 둔다

현재 Dockerfile의 ENV A=new B=$A를 아래 두 instruction으로 바꾼다. 앞선 ENV A=old와 다음의 ENV C=$A는 그대로 둔 비교다.

ENV A=new
ENV B=$A

수정한 Dockerfile로 다시 빌드한 이미지의 태그·ID를 넣어 같은 조회를 반복한다. 별도 비교에서 이미지 설정과 컨테이너 출력은 모두 A=new, B=new, C=new였다. B를 계산하는 시점이 A를 바꾼 instruction 다음으로 옮겨졌다. 서로 의존하지 않는 변수까지 모두 나눌 필요는 없다.

물리적으로 줄만 나누는 것으로는 부족하다. Dockerfile의 연속행 규칙 (새 탭에서 열림)에 따라 백슬래시로 이어 쓴 ENV는 여전히 하나의 instruction이다.

값이 계속 다르면 재빌드가 성공했는지, 조회한 이미지가 방금 만든 태그·ID인지, 뒤의 ENV에서 다시 덮어쓰는지 확인한다. 이미지 기본값은 맞는데 앱에서만 다르면 실행 시 환경 주입이나 시작 스크립트·앱의 설정 해석을 확인할 차례다.

실행할 때 A를 바꾸는 것은 별도다

ENV의 B에는 $A라는 계산식 대신 치환이 끝난 문자열이 저장된다. ENV 문서 (새 탭에서 열림)에 설명된 대로 이 기본값은 컨테이너에도 남는다. 컨테이너에서 실행한 sh -c가 $A를 읽는 시점은 빌더가 ENV를 처리하는 시점과 다르다.

수정 전 합성 이미지에서 -e A=runtime으로 A만 덮어쓰자 출력 셸은 A를 runtime으로 읽었지만 B는 old, C는 new를 유지했다. run의 환경변수 옵션 (새 탭에서 열림)은 지정한 키를 덮어쓰며 다른 키의 값을 다시 계산하지 않는다. 실행 시에도 A에 따라 B가 달라져야 한다면 시작 스크립트나 앱에서 계산할 관계다. ENV 분리는 빌드 당시 새 A를 읽게 하는 수정이다.

이번 비교는 PowerShell 7.6.6, Docker CLI·Engine 29.8.0, Docker Desktop 4.92.0의 Linux/amd64, BusyBox 1.37.0에서 실행했다. 실제 앱이나 운영 장애 재현이 아닌 합성 값 비교이며, 컨테이너에는 네트워크·포트·볼륨을 연결하지 않았다. Windows 컨테이너, 여러 빌드 단계의 상속, 과거 Docker 버전, 실제 앱의 설정 해석은 확인하지 않았다. 연속행 설명은 문서에 근거하며 별도 변형은 실행하지 않았다.

← 전체 글 보기