Docker 컨테이너는 독자적인 운영체제가 아니라, 호스트 OS 커널 위에서 격리된 '프로세스 트리(Process Tree)'일 뿐이다. 이 트리의 최상단에 위치한 PID 1 프로세스는 컨테이너의 생존을 결정하는 절대적인 기준이 된다.
다음 명령을 예시로 들어보자.
# Case A: Batch Job (일회성 작업) - 즉시 종료
docker run ubuntu:latest echo "Hello world..."
Hello world...
# 결과: 프로세스가 할 일을 마치고 Exit Code 0을 반환하며 종료됨 -> 컨테이너 중지
# Case B: Blocking Process (지속 실행) - 영구 실행
docker run -d nginx:latest tail -f /dev/null
# 결과: 프로세스가 파일의 끝을 기다리며(Blocking) 종료되지 않음 -> 컨테이너 실행 유지 (`Up`)
PID 1의 역할과 컨테이너 수명 결정 로직
일반적인 리눅스 OS와 Docker 컨테이너의 결정적인 차이는 "PID 1(시스템의 첫 번째 프로세스)이 무엇인가?"와 "커널(Kernel)을 누가 가지고 있는가?" 이 두 가지에 있다.
이 차이가 시스템의 목적과 생명주기를 완전히 다르게 만든다.
가장 결정적인 차이는 프로세스 트리의 뿌리인 PID 1번 프로세스가 맡은 역할이다.
A. 일반 리눅스 OS (관리자 모델)
- PID 1 = Systemd (또는 Init)
- 역할: 부팅이 되면 커널은 가장 먼저 Systemd라는관리자 프로그램을 실행시킨다.
- 구조: 사용자가 실행하려는 Nginx, DB, SSH 등은 모두 이 Systemd의 자식이나 손자 프로세스로 실행된다.
- 특징: Nginx가 죽어도 Systemd는 살아있다. 관리자가 살아있으니 OS는 종료되지 않고, Systemd가 Nginx를 다시 살려내거나 로그를 남긴다. 즉, 특정 앱이 죽는다고 시스템이 죽지 않는다.
B. Docker 컨테이너 (작업자 모델)
- PID 1 = 실행할 애플리케이션 그 자체 (예: Nginx, Python, Java)
- 역할: 관리자가 없다. 사용자가 docker run 명령어로 실행시킨 그 프로그램이 곧바로 PID 1이 된다.
- 구조: Systemd 같은 중간 관리자가 없는 상태다.
- 특징: Nginx(PID 1)가 죽으면, 시스템을 지탱할 관리자가 없다. 따라서 컨테이너라는 격리 공간 자체가 즉시 셧다운된다. 즉, 앱이 죽으면 시스템(컨테이너)도 죽는다.

1. PID 1 프로세스 의존성(Process Dependency)
리눅스 커널에서 PID 1은 좀비 프로세스를 수거하고 시스템의 시그널을 처리하는 특수한 책임을 진다. 도커 컨테이너 런타임은 다음과 같은 로직으로 수명 주기를 관리한다.
- Start: 컨테이너 시작 시, Dockerfile의 ENTRYPOINT나 CMD, 또는 docker run 뒤에 붙은 명령어(echo, nginx 등)를 PID 1로 할당하여 실행한다.
- Monitor: 도커 데몬은 이 PID 1 프로세스의 상태를 지속적으로 모니터링한다.
- Terminate:
- Case A (echo): echo는 문자열 출력이라는 작업을 완료하면 exit(0) 시스템 콜을 호출하여 정상 종료된다. Docker는 PID 1이 소멸된 것을 감지하고, 해당 컨테이너의 상태를 Exited로 변경하며 할당된 리소스(네트워크, 네임스페이스)를 회수한다.
- Case B (Daemon/Service): Nginx나 MySQL 같은 데몬은 작업을 마치는 개념이 아니라, 무한 루프(Event Loop)를 돌며 요청을 대기(Listen)한다. 프로세스가 끝나지 않으므로 컨테이너는 Up 상태를 유지한다.
2. Blocking Process Strategy (tail -f /dev/null)
위에 예로 든 tail -f /dev/null 명령어는 컨테이너를 인위적으로 살려두기 위한 대표적인 'Block I/O 패턴'이다.
- 동작 원리:
- /dev/null: 아무 내용도 없는 특수 문자 장치 파일이다.
- tail -f: 파일의 끝(End of File)을 계속 추적(Follow)하며 새로운 데이터가 들어오기를 기다린다.
- 결과: /dev/null에는 영원히 데이터가 추가되지 않으므로, tail 프로세스는 CPU를 거의 쓰지 않는 'Sleep/Wait' 상태로 전환되어 무한 대기한다.
- 이 기법은 실제 서비스를 띄우기 전 컨테이너 내부 쉘에 접속(exec)하여 디버깅을 하거나, 파드(Pod)를 유지시키기 위한 Sidecar Pattern 등에서 기술적 우회책으로 사용된다.

결론: 컨테이너가 살아서 유지되려면 PID 1 프로세스가 포그라운드(Foreground)에서 블로킹(Blocking) 되거나, 이벤트 루프(Event Loop)를 도는 상태여야만 한다. 단순히 백그라운드로 실행 후 종료되는 스크립트는 컨테이너를 유지시킬 수 없다.
'AI Journey > 클라우드' 카테고리의 다른 글
| [Docker] commit을 활용한 커스텀 이미지 생성 (0) | 2025.12.30 |
|---|---|
| [Docker] 다양한 명령, 옵션 살펴보기: 리소스 정리, 이미지 태그 + CLI 출력 포맷팅 (0) | 2025.12.30 |
| [Docker] 런타임 모드와 표준 스트림(stdio) 제어 (0) | 2025.12.29 |
| [Docker] 이미지 레이어링(Image Layering)이란? (0) | 2025.12.29 |
| [Docker] 우분투에 도커 설치하기 (0) | 2025.12.26 |