본문 바로가기

DevOps & Infra/Docker

도커 컨테이너에서 실행 중인 프로세스의 PID 확인 방법

더보기

도커 엔진은 컨테이너를 실행하면서 새로운 프로세스를 만듭니다.

컨테이너는 리눅스 커널의 네임스페이스(Namespaces) 기능으로 인해 부모 프로세스로부터 독립되어 실행됩니다.

그 결과 컨테이너는 두 개의 프로세스 ID(PIDs)를 갖습니다. 첫 번째 PID는 컨테이너 내부에서 두 번째 PID는 호스트에서 사용됩니다.

더보기

이 프로젝트의 개발 환경

  • CentOS Linux release 7.9.2009 (Core)

네임스페이스(Namespaces)와 unshare

네임스페이스는 프로세스 그룹에서 일부 리소스(PID 넘버 공간, 사용자, 네트워크 인터페이스 등)를 분리 할 수 있는 커널의 기능입니다.

각 리소스 유형에 상응하는 네임스페이스 유형은 8개입니다.

  • Cgroup
  • IPD
  • Network
  • Mount
  • PID(Process ID)
  • Time
  • User
  • UTS(Host names, Domain names, etc)

네임스페이스를 생성하려면 unshare 명령어를 사용합니다.

더보기

unshare 명령어는 새로운 네임스페이스를 생성하고 그 안에 주어진 프로그램을 실행합니다.

새로운 PID 네임스페이스에서 ps 명령어를 실행하는 자식 프로세스를 생성합니다.

$ sudo unshare --pid --mount-proc --fork ps ax
    PID TTY      STAT   TIME COMMAND
      1 pts/2    R+     0:00 ps ax
라인 비고
Line 1 --fork 새로운 자식 프로세스를 생성합니다.
--pid 새로운 PID 네임스페이스를 생성합니다.
--mount-proc proc filesystem/proc 디렉토리와 마운트합니다.
ps ax unshare로 생성된 네임스페이스에서 실행되는 프로그램입니다.
모든 프로세스와 백그라운드 작업을 출력합니다.

ps 실행 결과로 unshare 명령어를 사용해서 만든 하나의 프로세스만 출력하고 있습니다.

이 프로세스는 네임스페이스에서 PID 값이 1인 최초의 프로세스입니다.

더보기

--mount-proc 옵션을 추가되지 않으면 새로운 네임스페이스에서의 프로세스 외에도 호스트의 모든 프로세스가 표시됩니다.

네임스페이스 바깥(호스트의 기존 파일 시스템)에 해당하는 /proc 디렉토리를 스캔하기 때문입니다.

unshre 명령의 다른 옵션을 사용하여 예제를 확장하고 네임스페이스 유형을 추가 할 수 있습니다.

lsns 명령어로 새로 생성한 네임스페이스 확인

lsns 명령어는 접근 가능한 네임스페이스에 대한 목록을 표시합니다. 별도의 옵션을 지정하지 않으면 접근 가능한 모든 네임스페이스를 표시합니다.

-t 옵션을 사용하면 특정 네임스페이스 유형을 필터 할 수 있습니다.

$ sudo lsns -t pid
        NS TYPE NPROCS   PID USER   COMMAND
4026531836 pid     100     1 root   /sbin/init

여기서는 루트 PID 네임스페이스를 표시합니다. 표시되는 첫 열은 inode 번호로 네임스페이스 식별자입니다.

예시에서 루트 PID 네임스페이스의 식별자는 NS: 4026531836입니다.

이번에는 unshare 명령어를 사용하여 새로운 PID 네임스페이스를 생성합니다.

$ sudo unshare --pid --mount-proc --fork sleep 1000 &
[1] 1835

자식 프로세스가 ps 명령어 대신 sleep을 실행합니다. 새로운 PID 네임스페이스는 sleep 명령어가 지속되는 동안 유지됩니다.

다시 lsns을 사용하여 네임스페이스 목록을 표시합니다.

$ sudo lsns -t pid
        NS TYPE NPROCS   PID USER COMMAND
4026531836 pid     102     1 root /sbin/init
4026532149 pid       1  1837 root sleep 1000

이제 두 개의 PID 네임스페이스가 표시됩니다.

네임스페이스 식별자 NS: 4026531836은 루트 PID 네임스페이스이고, NS: 4026532149unshare 명령어로 만들어진 PID 네임스페이스입니다.

부모 네임스페이스와 자식 네임스페이스 관계

이전 섹션에서의 예시 NS: 4026532149는 루트 PID 네임스페이스의 자식 네임스페이스입니다.

핵심은 부모-상위 네임스페이스가 자식-하위 네임스페이스 및 프로세스에 엑세스 할 수 있다는 것입니다(이전 섹션에서 lsns 명령어를 사용해 자식 네임스페이스를 스캔하고 있습니다).

마찬가지로 ps 명령어를 사용하면 자식 네임스페이스에서 실행되는 프로세스를 표시 할 수 있습니다.

$ ps aux | grep sleep
 1882 root     sudo unshare --pid --mount-proc --fork sleep 1000
 1883 root     unshare --pid --mount-proc --fork sleep 1000
 1884 root     sleep 1000

자식 네임스페이스에서 실행되고 있는 PID: 1884 프로세스가 표시됩니다. 이 프로세스는 lsns 명령어에서 PID: 1837로 확인되는데 부모 네임스페이스에서 확인되는 PID: 1884와 다른 PID를 갖는 것을 알 수 있습니다.

더보기

결과적으로 네임스페이스에서 실행되는 프로세스는 두 개의 PID(하나는 자신의 네임스페이스에, 다른 하나는 부모 네임스페이스에서)를 갖게 됩니다.

Docker 컨테이너의 PID 확인

이제 도커에서 PID 네임스페이스가 어떻게 동작되는지 살펴봅니다. 실습을 위해서 Alpine Linux 컨테이너를 실행합니다.

$ sudo docker run -d alpine:latest sleep 1000
f0901c0b43329f6f997ec946597c3ab159c58a885cd081a8d0f855ae19c8188f

lsns 명령어를 실행하여 접근 가능한 PID 네임스페이스를 모두 표시합니다.

sudo lsns -t pid
        NS TYPE NPROCS   PID USER COMMAND
4026531836 pid     115     1 root /sbin/init
4026532153 pid       1  2083 root sleep 1000

Docker 컨테이너는 NS: 4026532153의 새로운 PID 네임스페이스를 생성합니다. 그리고 네임스페이스에서 실행되는 PID: 2083입니다.

이는 부모 네임스페이스 상에서 ps 명령어를 사용하는 것으로도 확인 할 수 있습니다.

ps aux | grep sleep
 2083 root     sleep 1000

도커 컨테이너가 생성한 네임스페이스에서의 PID를 확인합니다. 아래는 컨테이너에서 ps 명령어를 실행하기 위한 구문입니다.

sudo docker container exec f0901 ps ax
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 1000
    6 root      0:00 ps ax

자식 네임스페이스에서 sleep 명령어를 실행중인 프로세스는 PID: 1입니다.

더보기

Docker 컨테이너가 실행되면 새로운 PID 네임스페이스를 구성합니다.

컨테이너에서 실행되는 프로세스는 루트의 자식 네임스페이스에서 동작하며 PID: 1번을 할당받습니다.

컨테이너에서 실행되는 프로세스는 현재 위치한 PID 네임스페이스에 따라서 다른 PID를 갖게 됩니다.

부모 네임스페이스에 있는 /proc 파일시스템 status 파일에서 프로세스 ID 매핑 정보를 확인 할 수 있습니다.

$ sudo cat /proc/2083/status | grep NSpid
NSpid:  2083    1
코드 비고
Line 1 /proc/2083/status /proc 파일시스템 status 파일을 열람합니다. /2083은 확인하려는 PID입니다.
grep NSpid NSpid 필드는 이 프로세스의 모든 PID를 포함하는 부모-자식으로 연관된 모든 네임스페이스에 저장한 값입니다.
Line 2 NSpid: 2083 1 PID: 2083은 호스트-부모 네임스페이스에서 확인되며 PID: 1은 Docker 컨테이너-자식 네임스페이스에서 확인됩니다.

정리 및 복습

  • Docker 컨테이너를 실행할 때 새로운 PID 네임스페이스를 생성합니다. 이는 리눅스의 네임스페이스 생성 과정과 동일합니다.
  • 새로 생성된 PID 네임스페이스에서 실행되는 프로세스는 독립된 PID를 갖습니다.
  • 부모 네임스페이스는 자식 네임스페이스 및 프로세스에 엑세스 할 수 있습니다. 부모 네임스페이스에서는 프로세스가 자식 네임스페이스에서 할당된 PID와 다른 PID를 갖습니다.
  • 결론적으로 Docker 컨테이너에서 실행되는 프로세스는 PID: 1부터 시작하며 호스트-부모 네임스페이스에서는 다른 PID로 표시됩니다.