
Mac에서 만든 Docker 이미지를 Linux 서버에 올렸더니 exec format error로 시작하지 않는다면 실행 파일의 CPU 아키텍처부터 확인하세요. Apple Silicon의 arm64와 일반적인 x86 서버의 amd64가 다를 수 있습니다. 다만 같은 오류가 시작 스크립트의 실행 형식에서도 생길 수 있으므로 “무조건 amd64로 설정”하는 해결법으로 끝내면 재발합니다. 이미지 플랫폼 → 실제 실행 파일 → ENTRYPOINT 순서로 점검하는 방법을 정리합니다.
1. 오류가 난 실행 파일과 Docker 서버 위치를 확인하기
먼저 오류에 나온 경로가 /bin/sh인지, 애플리케이션 바이너리인지, entrypoint.sh인지 기록합니다. Docker 명령을 실행하는 노트북과 실제 Docker 데몬의 서버가 다를 수도 있습니다. 로컬 uname -m 결과만으로 원격 context의 아키텍처를 판단하지 마세요.
docker context show
docker version --format '{{.Server.Os}}/{{.Server.Arch}}'
docker image inspect myapp:2026-10-01 --format '{{.Os}}/{{.Architecture}}'
docker image inspect myapp:2026-10-01 --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}'
위 명령은 설치 환경과 로컬 이미지 구성을 읽는 예시입니다. myapp:2026-10-01은 실제 문제가 난 이미지로 바꾸세요. 이미지가 로컬에 없으면 inspect가 실패하므로 그 결과를 플랫폼 오류로 혼동하지 않습니다. Docker image inspect 문서에서 출력 형식 옵션을 확인할 수 있습니다. 서버가 amd64이고 이미지가 arm64라면 우선 플랫폼 불일치를 조사할 근거가 됩니다.
2. 같은 태그에 필요한 플랫폼이 들어 있는지 보기
멀티플랫폼 이미지는 한 태그 아래 여러 플랫폼의 변형을 제공합니다. Docker의 멀티플랫폼 안내는 매니페스트 목록과 호스트에 맞는 이미지 선택을 설명합니다. 태그 이름이 같다는 사실만으로 amd64와 arm64가 모두 포함된 것은 아닙니다. 실제 레지스트리 참조를 확인하세요.
docker buildx imagetools inspect registry.example.com/team/myapp:2026-10-01
이 참조는 자리표시자입니다. 본인의 레지스트리와 태그를 넣으면 플랫폼 목록을 확인할 수 있습니다. imagetools inspect 공식 문서의 Platform 항목과 실행 서버의 OS·아키텍처를 대조하세요. 특정 플랫폼의 digest를 직접 지정했다면 다른 변형이 선택되지 않을 수 있으므로 배포 설정의 태그와 digest도 함께 봅니다.
| 관찰 결과 | 다음 점검 | 해결 방향 |
| 서버 amd64, 이미지 arm64 | 레지스트리의 amd64 변형 존재 여부 | 맞는 변형을 배포하거나 해당 플랫폼으로 다시 빌드 |
| 이미지 플랫폼은 일치 | COPY한 바이너리의 실제 아키텍처 | 목표 플랫폼용 바이너리를 생성해 포함 |
| entrypoint.sh 경로에서 실패 | 첫 줄의 인터프리터·줄바꿈·실행 권한 | 스크립트 형식과 이미지 안의 인터프리터 확인 |
| no such file 또는 permission denied | 파일·인터프리터 경로·권한 | 같은 장애로 묶지 말고 해당 오류의 원인 조사 |
| 플랫폼 지정 후 에뮬레이션에서도 실패 | 호스트·빌더의 에뮬레이션 지원 | 네이티브 이미지 또는 지원되는 빌드 경로 검증 |
3. 단일 서버와 멀티플랫폼 배포의 빌드 예시
배포 서버가 linux/amd64 한 종류라면 목표 플랫폼을 명시해 별도 태그로 빌드하는 방법을 검토할 수 있습니다. 여러 플랫폼에 배포하려면 두 변형을 빌드해 같은 태그로 푸시할 수 있습니다. 아래는 구성을 설명하는 예시이며 본인의 Dockerfile·레지스트리 권한·빌더 지원이 준비돼 있어야 합니다.
# 단일 플랫폼을 로컬에 적재하는 예시
docker buildx build --platform linux/amd64 --load -t myapp:amd64-test .
# 두 플랫폼을 레지스트리에 올리는 예시
docker buildx build --platform linux/amd64,linux/arm64 --push \
-t registry.example.com/team/myapp:2026-10-01 .
플랫폼을 지정하는 것은 이미 존재하는 잘못된 바이너리를 자동 변환하는 기능이 아닙니다. 호스트에서 빌드한 arm64 실행 파일을 amd64 이미지에 그대로 COPY하면 이미지 메타데이터가 맞아도 실행은 실패할 수 있습니다. 컴파일 대상과 베이스 이미지, 네이티브 라이브러리를 같은 목표에 맞추세요. 에뮬레이션은 지원 환경이 필요하고 컴파일 작업이 느려질 수 있으므로 배포용 이미지를 시험한 뒤 사용합니다.
4. 스크립트 형식과 ENTRYPOINT를 구분해서 점검하기
직접 실행하는 쉘 스크립트라면 첫 줄에 #!/bin/sh처럼 실제로 존재하는 인터프리터가 있어야 합니다. Windows 줄바꿈, 파일 맨 앞의 불필요한 바이트, 실행 권한, 인터프리터 경로를 각각 확인하세요. Linux execve 매뉴얼은 인식할 수 없는 실행 형식이나 잘못된 아키텍처를 ENOEXEC 원인으로 설명합니다. 줄바꿈·경로 문제는 다른 오류로 나타날 수도 있으므로 정확한 메시지를 남깁니다.
# 소스 파일을 확인하는 예시
file entrypoint.sh
head -n 1 entrypoint.sh
# 같은 플랫폼의 컨테이너 셸이 실행되고 sh가 있을 때만
docker run --rm --entrypoint /bin/sh myapp:2026-10-01 \
-c 'ls -l /app/entrypoint.sh; head -n 1 /app/entrypoint.sh'
이미지에 셸이 없는 distroless 구성에서는 위 셸 점검 명령을 사용할 수 없습니다. 빌드 단계나 별도 디버깅 방법으로 파일을 확인하세요. ENTRYPOINT ["/app/entrypoint.sh"]와 ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"]는 실행 방식이 다릅니다. Dockerfile ENTRYPOINT 문서를 참고해 의도한 방식으로 구성하고, 셸 호출을 추가해 문제를 감추기보다 스크립트 형식과 종료 신호 처리도 검증합니다.
5. 재발을 막는 배포 전 체크리스트
① 실제 Docker 서버의 OS·아키텍처를 기록합니다. ② 레지스트리 태그의 플랫폼 목록과 배포 digest를 확인합니다. ③ COPY되는 실행 파일·라이브러리의 대상 플랫폼을 확인합니다. ④ 시작 스크립트의 줄바꿈·권한·인터프리터를 확인합니다. ⑤ 각 배포 플랫폼에서 시작·기본 요청·정상 종료를 시험합니다. ⑥ CI에 플랫폼별 성공 결과를 남기고 검증한 태그를 배포합니다.
같은 태그를 계속 덮어쓰는 방식보다 빌드 버전과 digest를 기록하면 어느 변형이 배포됐는지 추적하기 쉽습니다. 시작 오류를 수정한 뒤에도 재시작이 반복된다면 기존 Docker Restarting 반복 점검 글의 종료 코드와 로그 절차로 다음 원인을 확인하세요. 플랫폼 불일치를 해결했다는 사실과 서비스가 정상 동작한다는 사실은 별도로 검증해야 합니다.
6. 자주 묻는 질문
--platform linux/amd64만 추가하면 항상 해결되나요?
맞는 이미지 변형과 실행 환경이 있어야 합니다. arm64 호스트에서 amd64 실행을 요구하면 지원되는 에뮬레이션이 필요하며, 이미지 안의 바이너리도 확인해야 합니다.
arm64 이미지에 amd64라고 라벨만 붙이면 되나요?
아닙니다. 바이너리의 실제 기계어 형식이 달라지지 않습니다. 목표 플랫폼에 맞게 빌드하고 해당 환경에서 실행을 시험하세요.
chmod +x로 모든 시작 오류를 해결할 수 있나요?
실행 권한 문제일 때만 관련이 있습니다. 아키텍처·인터프리터·파일 형식 문제는 별도로 해결해야 합니다.
자료 확인: 2026년 10월 1일. 명령은 진단과 구성 방법을 설명하는 예시이며 이 글에서 실제 독자의 서버에 실행한 결과는 아닙니다. Docker 버전·이미지 저장 방식·빌더와 에뮬레이션 지원에 맞춰 공식 문서를 확인하세요.
'소프트웨어개발' 카테고리의 다른 글
| Nginx 499 Client Closed Request 해결: 요청 취소·시간 제한·백엔드 지연 점검 (0) | 2026.10.01 |
|---|---|
| Amazon MQ와 자체 RabbitMQ 비교: 메시지 브로커 비용·가용성·운영 책임 (0) | 2026.10.01 |
| S3와 Cloudflare R2 비교: 파일 다운로드 비용·S3 호환성·이전 체크리스트 (0) | 2026.10.01 |