Application Lifecycle Management - Docker CMD/Entrypoint와 쿠버네티스

2025. 12. 30. 12:44·CKA

이 섹션은 인증 커리큘럼의 “필수”로 자주 나오지는 않지만, 운영/디버깅에서 매우 자주 쓰이면서도 간과하기 쉬운 주제입니다. 결론부터 말하면 Kubernetes의 command와 args는 Docker 이미지의 ENTRYPOINT와 CMD 개념을 그대로 이어받아 “컨테이너가 시작할 때 무엇을 실행할지”를 결정합니다.

이 글은 강의 흐름대로 먼저 Docker에서 CMD/ENTRYPOINT를 복습하고, 이어서 Ubuntu Sleeper 이미지를 실제로 Pod로 옮기는 과정까지 포함해 정리합니다.


1) 컨테이너는 “OS”가 아니라 “프로세스”를 실행한다

가상 머신처럼 “OS를 호스팅”하려고 컨테이너를 띄우는 게 아닙니다. 컨테이너는 특정 작업/프로세스(웹서버, 앱서버, DB, 배치 작업 등)를 실행하기 위한 격리된 런타임입니다.

  • 컨테이너는 PID 1 프로세스가 살아있는 동안만 살아 있습니다.
  • 컨테이너 내부의 프로세스가 종료되면 컨테이너도 종료됩니다.
  • 웹서버가 죽거나 크래시 나면 컨테이너도 같이 죽습니다.

이 관점을 잡아야 “왜 우분투 컨테이너가 바로 죽지?” 같은 현상을 정확히 이해할 수 있습니다.


2) docker run ubuntu는 왜 바로 종료될까?

예를 들어, 우분투 이미지로 컨테이너를 실행합니다.

docker run ubuntu

컨테이너가 바로 종료되고, 실행 중인 컨테이너 목록에는 안 보일 겁니다.

docker ps

대신 종료된 컨테이너까지 포함해서 보면 흔적이 있습니다.

docker ps -a

이유: Ubuntu 이미지의 기본 CMD가 bash이기 때문

우분투 이미지 Dockerfile을 보면 기본 명령(CMD)이 bash로 설정되어 있는 경우가 많습니다. 그런데 bash는 웹서버처럼 계속 떠 있는 데몬이 아니라 터미널 입력을 받아야 의미가 있는 셸입니다.

  • Docker는 기본적으로 컨테이너 실행 시 터미널을 붙여주지 않습니다.
  • 그래서 bash가 입력을 받을 터미널이 없고 바로 종료합니다.
  • 프로세스가 끝났으니 컨테이너도 종료됩니다.

3) 기본 CMD를 “일시적으로” 바꾸는 방법: docker run <image> <command>

이미지에 정의된 기본 CMD를 실행 시점에 바꿀 수 있습니다.

docker run ubuntu sleep 5

이 경우 컨테이너 시작 시 bash 대신 sleep 5가 실행되고, 5초 후 종료됩니다.


4) 기본 CMD를 “영구적으로” 바꾸는 방법: Dockerfile의 CMD

예를 들어 “항상 sleep을 실행하는 이미지”를 만들고 싶다면, 우분투 기반으로 새 이미지를 빌드합니다.

FROM ubuntu
CMD ["sleep", "5"]

여기서 중요한 포인트:

  • JSON 배열(exec form)일 때 첫 요소는 실행 파일이어야 합니다.
  • ["sleep 5"]처럼 한 덩어리로 쓰면 안 됩니다.
  • ["sleep", "5"]처럼 명령과 인자를 분리해야 합니다.

빌드 및 실행:

docker build -t ubuntu-sleeper .
docker run ubuntu-sleeper

5) “sleep 시간”을 바꾸고 싶다: CMD만으로는 불편함

지금 상태에서는 기본이 sleep 5로 하드코딩입니다. 10초로 바꾸려면 이렇게 해야 합니다.

docker run ubuntu-sleeper sleep 10

하지만 이건 어색합니다. 이미지 이름이 이미 “sleeper”인데 굳이 sleep을 다시 쓰고 싶지 않습니다. 이상적인 UX는 이런 형태입니다.

docker run ubuntu-sleeper 10

즉 “명령은 고정(sleep)이고, 인자만 바꾸고 싶다”가 요구사항입니다.


6) 여기서 등장하는 게 ENTRYPOINT: 고정 실행 + 인자만 받기

Dockerfile을 다음처럼 바꿉니다.

FROM ubuntu
ENTRYPOINT ["sleep"]

이제 실행 시 전달하는 값은 sleep의 인자로 붙습니다.

docker run ubuntu-sleeper 10
# => 실제 실행: sleep 10

CMD vs ENTRYPOINT 핵심 차이

  • CMD: 실행 시 전달한 값이 기본 명령 자체를 대체(override)할 수 있음
  • ENTRYPOINT: 실행 시 전달한 값이 인자로 추가(append)됨

7) “기본 인자”도 필요하다면: ENTRYPOINT + CMD 조합

ENTRYPOINT ["sleep"]만 두고 인자를 안 주면 sleep은 피연산자가 없어서 에러가 납니다. 기본값(예: 5초)을 주고 싶다면 CMD를 함께 씁니다.

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]

동작:

  • docker run ubuntu-sleeper → sleep 5
  • docker run ubuntu-sleeper 10 → sleep 10 (CMD의 "5"가 "10"으로 대체)

중요: 이 패턴은 exec form(JSON 배열)로 쓰는 것이 안전합니다.


8) 런타임에 ENTRYPOINT를 바꾸고 싶다면: --entrypoint

실행 시점에 ENTRYPOINT 자체를 바꾸는 것도 가능합니다.

docker run --entrypoint sleep ubuntu-sleeper 2
# => sleep 2

9) Kubernetes로 번역: Pod의 command와 args는 무엇을 의미하나?

이제 이 강의의 핵심인 Kubernetes Pod의 명령/인수로 넘어갑니다. 강의에서 했던 흐름 그대로 Ubuntu Sleeper 이미지를 Pod로 실행해보면 규칙이 더 선명해집니다.

9-1) Ubuntu Sleeper 이미지로 Pod 만들기 (기본 5초 sleep)

이전 강의에서 “주어진 시간 동안 sleep하는 간단한 이미지”를 만들었습니다.

  • 이름: ubuntu-sleeper
  • 기본 동작: 5초 sleep 후 종료
  • 인자를 주면 sleep 시간이 바뀜(override)

이 이미지를 사용하는 Pod 정의 파일은 최소한 이렇게 시작합니다.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-pod
spec:
  containers:
    - name: ubuntu-sleeper
      image: ubuntu-sleeper

이 Pod가 생성되면:

  • 지정된 이미지로 컨테이너가 생성되고
  • 컨테이너는 5초 동안 sleep
  • 이후 프로세스가 종료되며 컨테이너도 종료됩니다.

10) Pod에서 sleep 시간을 10초로 바꾸려면? → args

Docker에서 아래처럼 실행했던 것을 기억해보면:

docker run ubuntu-sleeper 10

여기서 10은 “docker run 뒤에 추가로 붙는 값”이었고, ENTRYPOINT sleep에 인자로 추가되어 sleep 10이 됐습니다.

Kubernetes에서는 docker run 뒤에 추가되는 모든 것이 Pod 스펙의 args 배열로 들어갑니다.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-10
spec:
  containers:
    - name: ubuntu-sleeper
      image: ubuntu-sleeper
      args: ["10"]
  • 결과 실행: sleep 10

11) Dockerfile의 ENTRYPOINT/CMD와 Pod의 command/args 관계 정리

강의에서 강조한 핵심을 정확히 매핑하면 다음과 같습니다.

Dockerfile

  • ENTRYPOINT: 시작 시 실행될 “고정 명령”
  • CMD: 기본 인자(혹은 기본 명령/인자)

Pod 스펙

  • command: Dockerfile의 ENTRYPOINT를 재정의
  • args: Dockerfile의 CMD를 재정의

즉, Dockerfile에 다음이 있다고 가정하면:

ENTRYPOINT ["sleep"]
CMD ["5"]
  • Pod에서 args: ["10"]을 주면 CMD(기본 인자 5)가 10으로 대체됩니다.
  • Pod에서 command: ["sleep2.0"] 같은 걸 주면 ENTRYPOINT 자체가 바뀝니다.

12) ENTRYPOINT를 재정의해야 한다면? → command

강의의 예시처럼, 런타임에 진입점을 sleep이 아니라 가상의 sleep2.0(혹은 다른 실행 파일)로 바꿔야 한다면 Docker에서는 --entrypoint로 재정의했습니다.

Kubernetes에서는 그 역할이 command입니다.

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-custom
spec:
  containers:
    - name: ubuntu-sleeper
      image: ubuntu-sleeper
      command: ["sleep2.0"]
      args: ["10"]
  • 의미: 이미지의 ENTRYPOINT를 sleep2.0로 덮고, 인자로 10을 전달

포인트: Dockerfile의 CMD를 재정의하는 건 command가 아니라 args입니다. 이게 가장 많이 헷갈리는 부분입니다.


13) 요약

  • 컨테이너는 OS가 아니라 프로세스를 실행하며, PID 1이 끝나면 컨테이너도 끝난다.
  • Dockerfile:
    • ENTRYPOINT: 시작 시 실행할 “고정 명령”
    • CMD: 기본 인자(또는 기본 명령/인자)
  • Kubernetes Pod:
    • command: Dockerfile의 ENTRYPOINT를 재정의
    • args: Dockerfile의 CMD를 재정의
  • “docker run 이미지 뒤에 붙는 값”은 Pod에서는 args로 옮겨온다.

 

Practice Test: https://uklabs.kodekloud.com/topic/practice-test-commands-and-arguments-2/

'CKA' 카테고리의 다른 글

Application Lifecycle Management - Secret  (0) 2025.12.30
Application Lifecycle Management - ConfigMap  (0) 2025.12.30
Application Lifecycle Management - 배포전략  (0) 2025.12.30
Logging - 쿠버네티스 로깅 기초  (0) 2025.12.30
Monitoring - Metric Server  (0) 2025.12.30
'CKA' 카테고리의 다른 글
  • Application Lifecycle Management - Secret
  • Application Lifecycle Management - ConfigMap
  • Application Lifecycle Management - 배포전략
  • Logging - 쿠버네티스 로깅 기초
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      log trace
      스레드
      JPQL
      고급
      @args
      @within
      락
      프록시
      빈 후처리기
      Target
      @discriminatorcolumn
      cglib
      jpq
      조회 성능 최적화
      reentarantlock
      자바
      gesingleresult
      페치 조인
      typequery
      단방향 맵핑
      버퍼
      WAS
      jdk 동적 프록시
      김영한
      requset scope
      Thread
      프록시 팩토리
      @discriminatorvalue
      양방향 맵핑
      hibernate5module
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Application Lifecycle Management - Docker CMD/Entrypoint와 쿠버네티스
    상단으로

    티스토리툴바