← 전체 글로 돌아가기

Docker

멀티스테이지 Docker 빌드가 로컬과 서버에서 다르게 동작할 때

멀티스테이지 Dockerfile이 로컬 개발 환경과 CI/CD 서버에서 다른 결과를 낼 때 원인을 찾고 안전하게 수정하는 방법을 정리했다.

멀티스테이지 Docker 빌드는 최종 이미지 크기를 줄이는 좋은 방법이지만, 로컬에서는 잘 동작하는데 서버에서만 실패하거나 예상과 다른 결과가 나올 때가 있다. 특히 빌드 단계와 런타임 단계에서 다른 환경을 구성할 때 이런 문제가 많이 생긴다.

각 스테이지의 역할을 명확히 하기

멀티스테이지 빌드에서 첫 번째 스테이지(보통 builder)에서는 빌드 도구와 소스 코드가 필요하지만, 최종 스테이지(보통 runtime)에서는 빌드된 결과물만 필요하다. Dockerfile을 작성할 때 각 스테이지가 정말 필요한 파일만 가져가는지 확인하자. 불필요한 파일이 포함되면 이미지 크기가 커질 뿐 아니라 예상치 못한 동작을 할 수 있다.

빌드 시간대에 결정되는 값들 관리하기

런타임 환경 변수와 빌드 타임 환경 변수를 혼동하면 안 된다. ARG는 빌드할 때만 사용되고, ENV는 컨테이너가 실행될 때도 사용된다. 만약 API 엔드포인트 같은 설정이 빌드할 때 고정되어야 한다면 ARG를 쓰면 되지만, 서버마다 다르게 설정해야 한다면 ENV로 둬야 한다.

sudo ss -lntp
df -h
sudo journalctl -n 80

FROM 이미지 태그 확인하기

FROM node:18-alpine 같은 베이스 이미지를 쓸 때, 태그를 명시하지 않거나 latest 태그를 쓰면 빌드할 때마다 다른 이미지가 다운로드될 수 있다. 로컬에서는 며칠 전 버전으로 빌드했는데 CI 서버에서는 최신 버전으로 빌드되면서 호환성 문제가 생길 수 있다. 항상 구체적인 버전 태그를 명시하자.

빌드 캐시와 Docker BuildKit 활용하기

Docker는 각 단계의 레이어를 캐싱한다. 로컬에서는 캐시가 쌓여있지만, CI 서버나 클린한 환경에서는 캐시가 없을 수 있다. --no-cache 플래그로 테스트해보거나, Docker BuildKit을 사용해서 더 효율적으로 캐싱을 관리하자.

권한 문제 확인하기

첫 번째 스테이지에서 빌드한 파일을 두 번째 스테이지로 복사할 때, 파일의 소유권이나 권한이 문제가 될 수 있다. COPY --chown 옵션을 사용해서 명시적으로 소유권을 설정하거나, 런타임 스테이지에서 애플리케이션을 실행하는 사용자(보통 root가 아닌 일반 사용자)가 파일에 접근할 수 있는지 확인하자.

한 가지씩 변경하고 확인하기

Dockerfile을 여러 줄 동시에 수정하면 어느 부분이 문제를 일으켰는지 알기 어렵다. 한 번에 한 줄씩만 변경하고, 매번 docker build 후 컨테이너를 실행해서 동작하는지 확인하자. 운영 환경에 배포하기 전에 스테이징에서 충분히 테스트해야 한다.