빠른 비교
FROM python:3.12-slim
WORKDIR /app
COPY . .
ENTRYPOINT ["python", "-m", "http.server"]
CMD ["8000"]# CMD만 덮어쓰기 — ENTRYPOINT는 그대로 유지됨
docker run my-http 9000
# ENTRYPOINT까지 교체
docker run --entrypoint sh my-http갈리는 기준
어떤 시작 명령 구성을 먼저 떠올리면 되나
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 실행 파일은 고정, 인자만 바꾸기 | ENTRYPOINT + CMD |
| 기본 명령을 쉽게 완전히 교체 | CMD만 사용 |
| 시그널 전달과 graceful shutdown 중요 | exec form |
| 디버깅을 위해 실행 파일 자체 교체 | --entrypoint |
ENTRYPOINT가 컨테이너의 고정 실행 파일을 정의하는 이유
ENTRYPOINT는 이 컨테이너가 "어떤 프로그램으로 동작하는가"를 고정한다. docker run 시 추가 인자를 넘겨도 ENTRYPOINT는 바뀌지 않고, 그 인자가 ENTRYPOINT의 뒤에 붙는다. CLI 도구나 서버처럼 "하나의 역할"이 명확한 이미지에 적합하다.
# 이미지가 항상 gunicorn으로 기동
ENTRYPOINT ["gunicorn", "app:create_app()"]
CMD ["--workers=4", "--bind=0.0.0.0:8000"]CMD가 ENTRYPOINT의 기본 인자로 동작하는 패턴
CMD는 단독으로 쓰면 기본 실행 명령이 되고, ENTRYPOINT와 함께 쓰면 기본 인자 역할을 한다. docker run에 추가 인자를 주면 CMD만 교체되고 ENTRYPOINT는 유지된다.
# CMD ["8000"] 이 기본값 → 9000으로 교체
docker run my-http 9000
# CMD 전체 무시, ENTRYPOINT에 sh 추가 인자 전달
docker run --entrypoint sh my-http -c "ls /app"exec form vs shell form — PID 1과 시그널 전달 문제
exec form(["python", ...])은 프로세스가 PID 1로 직접 실행된다. shell form(python ...)은 /bin/sh -c가 PID 1이 되고 실제 프로세스는 그 자식이 된다. docker stop이 보내는 SIGTERM이 쉘 자식 프로세스까지 전달되지 않아 컨테이너가 10초 대기 후 강제 종료된다.
# exec form: SIGTERM이 python 프로세스에 직접 전달됨 (권장)
ENTRYPOINT ["python", "-m", "http.server"]
# shell form: /bin/sh -c 가 PID 1 → SIGTERM이 python에 도달하지 않을 수 있음
ENTRYPOINT python -m http.serverCMD만 쓸지 ENTRYPOINT + CMD를 쓸지는 "무엇을 고정할지"로 고른다
이미지를 사실상 하나의 서버나 CLI처럼 고정된 역할로 만들고 싶다면 ENTRYPOINT + CMD가 맞습니다. 반대로 실행 명령 자체를 쉽게 바꿔야 하는 범용 이미지라면 CMD만 쓰는 편이 낫습니다. 실행 파일은 고정하고 인자만 바꾸고 싶은지, 명령 전체를 자주 바꾸는지가 핵심 기준입니다.
선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 컨테이너 역할을 고정하고 인자만 바꾸고 싶을 때 | ENTRYPOINT + CMD 조합 |
| 기본 명령만 두고 완전 교체 허용 | CMD만 사용 |
| 시그널 정상 전달이 필요한 프로세스 | exec form (["프로그램", "인자"]) |
| 실행 파일 자체를 덮어써야 할 때 | docker run --entrypoint |
주의할 점
shell form으로 ENTRYPOINT를 작성하면 SIGTERM이 실제 프로세스에 전달되지 않아 컨테이너가 항상 강제 종료된다. 운영 서비스는 반드시 exec form(["실행파일", "인자"])을 사용해야 graceful shutdown이 보장된다.
ENTRYPOINT ["python", "-m", "http.server"]
CMD ["8000"]docker run my-http sh
# "sh"가 ENTRYPOINT 뒤 인자로 붙어서
# 의도한 셸 진입이 아니라 python http.server 인자만 바뀔 수 있음참고 링크
2 sources