쿠버네티스 일반

Pause 컨테이너 정리

Jerry_이정훈 2022. 1. 12. 14:27
728x90

KANS 스터디 2주차 Pause 컨테이너 내용 정리. 참고로 면접 때 질문이 pause 컨테이너 역할이었다. 실행 중인거 보았다고 버벅되다 모른다고 하였다.

 

pause 컨테이너란?

  • 파드 내 컨테이너에게 부모처럼 net namespace 제공해준다. 파드 내 복수의 컨테이너는 공통으로 pause 컨테이너가 제공한 network namespace를 공유한다. (리눅스 네임스페이스 설명)
  • 모든 파드에 반드시 실행된다. (세상에서 가장 많이 사용되는 컨테이너, 참조 https://eddie.ee/170 )

pause 컨테이너 왜 필요할까?

  • 파드란 쿠버네티스 환경의 증설하는 기본 단위이다. 파드 내 여러 컨테이너에 같은 net namespace 공유하는게 필요해서 사용한다. (그런데 파드 내 컨테이너들이 서로 다른 네트워크를 가지면 왜 안될까?)

pause 컨테이너를 실습으로 알아보자. 먼저 2개의 컨테이너를 가지는 파드를 실행한다. 

## 2개의 컨테이너를 가지는 파드다.
apiVersion: v1
kind: Pod
metadata:
  name: myweb2
spec:
  containers:
  - name: myweb2-nginx
    image: nginx
    ports:
    - containerPort: 80
      protocol: TCP

  - name: myweb2-netshoot
    image: nicolaka/netshoot
    command: ["/bin/bash"]
    args: ["-c", "while true; do sleep 5; curl localhost; done"] # 포드가 종료되지 않도록 유지합니다

  terminationGracePeriodSeconds: 0

파드를 실행한다. 하나의 파드에 2개의 컨테이너가 실행된다. (READY 상태가 2/2이다.)

kubectl apply -f https://raw.githubusercontent.com/gasida/NDKS/main/3/myweb2.yaml

[spkr@erdia22 ~ (ubun71:default)]$ kgp  ## k get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
myweb2   2/2     Running   0          5s    10.233.67.18   ubun20-74   <none>           <none>

Pause 컨테이너 역할이 파드 내 컨테이너에 net namespace 제공하는 것이다. 2개의 컨테이너가 서로 net namespace를 공유하는지 확인해보자. 

참조 : https://eddie.ee/170 

각 컨테이너의 IP와 net namespace를 확인한다. 먼저 컨테이너 이름을 확인한다.

[spkr@erdia22 ~ (ubun71:default)]$ k describe pod myweb2
(생략)
  myweb2-nginx:
  myweb2-netshoot:

Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  2m52s  default-scheduler  Successfully assigned default/myweb2 to ubun20-74
  Normal  Pulling    2m52s  kubelet            Pulling image "nginx"
  Normal  Pulled     2m50s  kubelet            Successfully pulled image "nginx" in 1.907152063s
  Normal  Created    2m50s  kubelet            Created container myweb2-nginx
  Normal  Started    2m50s  kubelet            Started container myweb2-nginx
  Normal  Pulling    2m50s  kubelet            Pulling image "nicolaka/netshoot"
  Normal  Pulled     2m48s  kubelet            Successfully pulled image "nicolaka/netshoot" in 1.801422476s
  Normal  Created    2m48s  kubelet            Created container myweb2-netshoot
  Normal  Started    2m48s  kubelet            Started container myweb2-netshoot

myweb2-nginx, myweb2-netshoot 2가지 컨테이너가 실행 중이다. 각각 이름으로 컨테이너 접속한다.

## 창을 2개로 나누어서 위, 아래에서 작업한다.
[spkr@erdia22 ~ (ubun71:default)]$ k exec -it myweb2 -c myweb2-nginx -- bash
root@myweb2:/# apt update -y
root@myweb2:/# apt install -y net-tools
root@myweb2:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.233.67.18  netmask 255.255.255.0  broadcast 10.233.67.255

[spkr@erdia22 ~ (ubun71:default)]$ k exec -it myweb2 -c myweb2-netshoot -- bash
bash-5.1# ip a show
(생략)
2: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    link/ether 16:be:51:bc:a2:45 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.233.67.18/24 brd 10.233.67.255 scope global eth0
      valid_lft forever preferred_lft forever

2개의 컨테이너 모두 동일한 IP 10.233.67.18 가진다. 서로 다른 컨테이너가 동일한 IP를 가지는 희한한 상태다. 왜 그럴까?

2개의 컨테이너가 동일한 net namespace 가지기 때문이다. 각각의 컨테이너에서 net namespace를 확인해보자.
호스트 노드에서 각 프로세스 ID를 조회해서 각 프로세스가 사용하는 namespace 정보를 조회한다. NGINX와 NETSHOOT 컨테이너 각각 확인한다.

## 파드가 실행 중인 노드에 접속한다.
[spkr@erdia22 ~ (ubun71:default)]$ ssh ubun20-74

root@ubun20-74:~# NGINXPID=$(ps -ef | grep 'nginx -g' | grep -v grep | awk '{print $2}')
## nginxpid 2개인데 390721를 사용한다. 다른 nginx 파드가 실행 중이라 2개 보인다.
root@ubun20-74:~# echo $NGINXPID
7267 390721
## netshoot 컨테이너에 curl 프로세스를 실행하고 있다.

root@ubun20-74:~# NETSHPID=$(ps -ef | grep 'curl' | grep -v grep | awk '{print $2}')
root@ubun20-74:~# echo $NETSHPID
390785

각 프로세스, 즉 컨테이너의 namespace를 확인해보자. 아래와 같이 net namespace는 동일하게 390680  PID를 가진다. 같은 net namespace 라서 nginx, netshoot 컨테이너 같은 IP를 가진다. 

root@ubun20-74:~# lsns -p 390721
        NS TYPE   NPROCS    PID USER COMMAND
4026531835 cgroup    153      1 root /sbin/init maybe-ubiquity
4026531837 user      153      1 root /sbin/init maybe-ubiquity
4026532250 net        10 390680 root /pause
4026532333 uts        10 390680 root /pause
4026532334 ipc        10 390680 root /pause
4026532336 mnt         6 390721 root nginx: master process nginx -g daemon off;
4026532337 pid         6 390721 root nginx: master process nginx -g daemon off;

root@ubun20-74:~# lsns -p $NETSHPID
        NS TYPE   NPROCS    PID USER COMMAND
4026531835 cgroup    153      1 root /sbin/init maybe-ubiquity
4026531837 user      153      1 root /sbin/init maybe-ubiquity
4026532250 net        10 390680 root /pause
4026532333 uts        10 390680 root /pause
4026532334 ipc        10 390680 root /pause
4026532338 mnt         3 390785 root /bin/bash -c while true; do sleep 5; curl localhost; done
4026532340 pid         3 390785 root /bin/bash -c while true; do sleep 5; curl localhost; done

(참고로 cgroup, user 네임스페이스는 따로 격리하지 않음

## mnt, uts, pid 네임스페이스는 컨테이너별로 격리

## ipc, net 네임스페이스는 파드 내의 컨테이너 간 공유 (IPC : 컨테이너 프로세스간 공유 - signal, socket, pipe 등)

 

명령어를 보면 /pause 이다. nginx, netshoot 컨테이너는 pause 명령어를 실행하지 않는다. pause 컨테이너가 /pause 명령어를 실행하였다. (아쉽게도 containerd 런타임에서는 pause 컨테이너를 확인할 수 없었다.)

 

참고로 docker 런타임을 사용하면 docker ps에서 pause 컨테이너를 확인할 수 있다. 

root@k8s-w2:~# docker ps --format "table {{.Image}}\t{{.Status}}\t{{.Names}}" | grep myweb2
nicolaka/netshoot        Up About a minute   k8s_myweb2-netshoot_myweb2_default_829cf80a-f55d-4ea6-b458-45e2b73620e7_0
nginx                    Up About a minute   k8s_myweb2-nginx_myweb2_default_829cf80a-f55d-4ea6-b458-45e2b73620e7_0
k8s.gcr.io/pause:3.4.1   Up 2 minutes        k8s_POD_myweb2_default_829cf80a-f55d-4ea6-b458-45e2b73620e7_0

그런데 나는 containerd를 사용하고 있어서 아래처럼 pause 컨테이너가 조회되지 않는다.

root@ubun20-74:~# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID
92b1f46dcdc03       f4c8dceca780a       22 minutes ago      Running             myweb2-netshoot     0                   6b8b8f0367a8f
fa290e797b7c8       605c77e624ddb       22 minutes ago      Running             myweb2-nginx        0                   6b8b8f0367a8f

아쉽게도 컨테이너 images 정보로만 pause 컨테이너를 확인할 수 있다.

root@ubun20-74:~# crictl images
IMAGE                                       TAG                 IMAGE ID            SIZE
(생략)
k8s.gcr.io/pause                            3.3                 0184c1613d929       299kB

추가로 netshoot 컨테이너에 접속하면 (황당하게) nginx 프로세스가 실행되지 않는 컨테이너인데 nginx 컨테이너와 동일하게 80 port를 listen하고 있다. nginx 컨테이너와 동일한 네트워크 정보를 가지고 있어서 그렇다.

[spkr@erdia22 ~ (ubun71:default)]$ k exec -it myweb2 -c myweb2-netshoot -- bash

bash-5.1# ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/bash -c while true; do sleep 5; curl localhost; done
  178 root      0:00 bash
 1045 root      0:00 sleep 5
 1046 root      0:00 ps aux

## nginx 프로세스는 실행되지 않지만 80 port를 listen 하고 있는 황당한 상태 bash-5.1# ss -tln
State                       Recv-Q                      Send-Q                                           Local Address:Port                                             Peer Address:Port                      Process
LISTEN                      0                           511                                                    0.0.0.0:80                                                    0.0.0.0:*
LISTEN                      0                           511                                                       [::]:80                                                       [::]:*

정리하면

파드 내 컨테이너는 pause 컨테이너가 마치 부모처럼 제공하는 net namespace을 공유해서 네트워크로 사용한다. 그래서 2개의 컨테이너가 실행되면 동일한 네트워크를 가진다. 하나의 파드에 2개 컨테이너를 실행하려면 포트 충돌나지 않도록 유의해야 한다. (VM에서 프로세스들이 공통 eth0 인터페이스 가지는 것과 동일하다.)

반응형