배경
기존에는 Dockerfile에서 Java 애플리케이션을 실행할 때 ENTRYPOINT에 모든 JVM 옵션과 실행 명령어를 길게 나열해서 작성했었다. 하지만 JVM 옵션이 많아지고 환경별로 다른 설정이 필요해지면서 관리가 어려워졌다. 그래서 별도의 쉘 스크립트 파일에서 이런 복잡한 실행 로직을 관리할 수 있도록 entrypoint.sh를 만들게 되었다.
entrypoint.sh를 추가하여 Docker 컨테이너를 실행하자 entrypoint.sh에서 예상치 못한 format 에러가 발생했다.
standard_init_linux.go:xxx: exec user process caused "exec format error“
개발 환경
- Docker
- Portainer
- Linux
- Java 17
- Spring Boot 3.4.x
- Bash/Shell Script
문제
기존 Dockerfile
처음에는 Dockerfile에서 다음과 같이 ENTRYPOINT를 직접 작성했었다. 하지만 JVM 옵션이 길어질수록 가독성이 저하되는 문제가 있었다.
FROM openjdk:17-jre-slim
COPY app.jar /app.jar
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-XX:+UseG1GC", "-XX:+UseStringDeduplication", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]
개선된 Dockerfile (문제 발생)
별도의 쉘 스크립트로 분리해서 더 유연하게 관리할 수 있도록 개선했다.
하지만 추가된 entrypoint.sh 파일에서 format 에러가 발생했다.
FROM openjdk:17-jre-slim
COPY app.jar /app.jar
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
# entrypoint.sh
# JVM 기본 옵션 설정
JAVA_OPTS="-Xms512m -Xmx2g"
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
JAVA_OPTS="$JAVA_OPTS -XX:+UseStringDeduplication"
JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=prod"
# 애플리케이션 실행
exec java $JAVA_OPTS -jar /app.jar "$@"
원인
exec format error는 주로 다음과 같은 상황에서 발생한다.
- 실행 파일의 아키텍처가 맞지 않는 경우 (예: ARM 바이너를 x86에서 실행)
- 실행 파일이 손상된 경우
- 스크립트 파일에 shebang 라인이 없는 경우
내 경우에는 세 번째 케이스였다. Shebang 라인은 스크립트의 실행 환경을 결정하기 때문에 반드시 있어야 한다. Shebang 라인이 없으면 Docker는 entrypoint.sh 파일을 실행할 때 어떤 인터프리터로 실행해야 하는지 알 수 없어서 바이너리 파일로 인식하려고 실행하려다가 실패한다.
Shebang이란?
#!/bin/sh
Shebang 라인은 스크립트 파일의 맨 첫 번째 줄에 위치하는 #!(주석 아님) 로 시작하는 라인이다.
Shebang 라인은 스크립트 파일이 어떤 인터프리터의 명령어 집합인지를 시스템에 알려주는 역할을 한다.
#! 뒤에는 명령어들을 해석할 프로그램의 위치를 나타낸다.
# 예시
#!/bin/sh # POSIX 호환 shell
#!/bin/bash # Bash shell
#!/usr/bin/python # Python 2
#!/usr/bin/env python # 환경에서 python 찾기
해결 방법
entrypoint.sh 파일 맨 첫 줄에 shebang 라인을 추가해주면 된다.
# entrypoint.sh
# shebang 라인 추가
#!/bin/sh
# JVM 기본 옵션 설정
JAVA_OPTS="-Xms512m -Xmx2g"
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
JAVA_OPTS="$JAVA_OPTS -XX:+UseStringDeduplication"
JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=prod"
# 애플리케이션 실행
exec java $JAVA_OPTS -jar /app.jar "$@"
참조
https://iksciting.com/what-is-shebang/
Linux: What is Shebang? - IKSciting
Linux에서 script를 열었을 때 첫 줄이 #!로 시작하는 경우를 종종 보게 된다. 이를 shebang이라고 부르는데 어원에 대해서는 sharp + bang, hash + bang, shell + bang 등 여러가지 설이 있지만 이름이나 어원은
iksciting.com
https://github.com/opencontainers/runc/issues/1773
"exec format error" for ENTRYPOINT pointing to shell script lacking shebang line · Issue #1773 · opencontainers/runc
I'm posting this here because error message is raised by a file in this project: standard_init_linux.go:195: exec user process caused "exec format error" As an end user I'd like it if somehow it wa...
github.com