컨테이너·워크플로우 자동화/DocKer 기본 및 활용

Dockerfile Shell 형식과 Exec 형식의 개념

Data Jun 2026. 2. 18. 09:54

Dockerfile에서 RUN, CMD, ENTRYPOINT는 Shell 형식과 Exec 형식 두 가지로 작성할 수 있다.

Shell 형식은 우리가 터미널에서 명령어를 입력하듯 작성하는 방식이며,  내부적으로 /bin/sh -c를 통해 실행된다.

반면 Exec 형식은 JSON 배열로 작성하며 쉘을 거치지 않고 프로그램을 직접 실행한다.

이 차이로 인해 가장 크게 달라지는 부분이 바로 “셸 프로세싱”, 특히 환경 변수 치환이다.

Shell 형식은 자동으로 환경 변수 치환이 되지만, Exec 형식은 그렇지 않다. 필요하다면 sh -c를 명시적으로 사용해야 한다.

 

1. Shell 형식: 터미널처럼 작성하는 방식

RUN npm ci && npm run build

특징:

  • 터미널 명령어처럼 그대로 작성
  • 내부적으로 /bin/sh -c를 거쳐 실행
  • &&, |, $PORT 같은 셸 문법 사용 가능
  • 환경 변수 치환 자동 동작

실제 내부 동작은 이렇게 됩니다:

/bin/sh(통영사 경로) -c(실행옵션) "npm ci && npm run build"(해석되는 명령어)

비유하면,

통역사(sh)에게 문장을 던져주고 해석해서 실행시키는 구조

 

2. Exec 형식: JSON 배열 방식

ENTRYPOINT ["npm", "run", "start"]
  • 쉘을 거치지 않음
  • 각 요소가 명확히 분리됨
  • 큰따옴표만 사용 (JSON 규칙)
  • 환경 변수 치환 자동으로 안 됨

실행 구조는:

npm run start

즉,

통역사 없이 직접 프로그램에게 말하는 구조

 

3. 가장 중요한 차이: 셸 프로세싱

셸 프로세싱이란:

셸이 명령어를 해석하면서 처리하는 과정

 

대표적인 예가 환경 변수 치환입니다.

export PORT=3000
echo $PORT

→ 3000 출력

Shell 형식은 이 과정이 자동으로 동작합니다.

 

4. Exec 형식에서 환경 변수 치환이 안 되는 이유

예를 들어:

FROM ubuntu
ENV MY_NAME=codeit
ENTRYPOINT ["echo", "My name is ${MY_NAME}"]

출력 결과:

My name is ${MY_NAME}

왜냐하면:

  • 쉘이 없기 때문
  • ${MY_NAME}를 해석할 주체가 없음

Exec 형식은 단순히 문자열을 전달할 뿐입니다.

 

5. Exec 형식에서 셸 프로세싱을 쓰는 방법

ENTRYPOINT ["sh", "-c", "echo \"My name is ${MY_NAME}\""]

이 구조는:

 

즉,

  • Exec 형식 유지
  • 내부에서 명시적으로 쉘 실행
  • 환경 변수 치환 가능

필요하다면 직접 쉘을 호출하면 됩니다.

 

6. 왜 일반적으로 ENTRYPOINT는 Exec 형식을 사용할까?

 

이유는 명확합니다.

  • 신호 전달이 정확함 (PID 1 문제 해결)
  • 예측 가능한 동작
  • 불필요한 쉘 개입 제거

다만, 환경 변수 치환이 필요할 경우 sh -c를 활용합니다.

 

7. 정리 

 

  • Shell 형식 → /bin/sh -c를 통해 실행됨
  • Exec 형식 → 쉘 없이 직접 실행
  • 환경 변수 치환은 Shell 형식에서 자동 동작
  • Exec 형식에서 필요하면 sh -c를 명시적으로 사용

Shell 형식은 셸이 해석해 실행하고, Exec 형식은 셸 없이 직접 실행되며 환경 변수 치환 여부가 가장 큰 차이입니다.