Pause 컨테이너란?
KANS 스터디 2주차 PAUSE 컨테이너 알아보기
💡 KANS 스터디
CloudNet에서 주관하는 KANS(Kubernetes Advanced Networking Study)으로 쿠버네티스 네트워킹 스터디입니다. 아래의 글은 스터디의 내용을 기반으로 작성했습니다.스터디에 관심이 있으신 분은 CloudNet Blog를 참고해주세요.
파드 & PAUSE 컨테이너
여기서는 파드 생성시 Init으로 생성되는 PAUSE 컨테이너에 대해 알아봅니다.
PAUSE 컨테이너 역할
먼저 컨테이너의 역할을 먼저 확인하고 가면 아래와 같습니다. 추후 실습에서 한번 더 확인합니다.
- 파드에서 Linux 네임스페이스 공유의 유지 역할을 합니다.
- 생성은 Containerd 기준으로 CRI에서 진행합니다. 참고 악분님 블로그
- 각 파드에 대한 PID 1 역할을 하며 좀비 프로세스를 제거한다.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
... Apache 라이선스 내용
*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define STRINGIFY(x) #x
#define VERSION_STRING(x) STRINGIFY(x)
#ifndef VERSION
#define VERSION HEAD
#endif
static void sigdown(int signo) {
psignal(signo, "Shutting down, got signal");
exit(0);
}
static void sigreap(int signo) {
while (waitpid(-1, NULL, WNOHANG) > 0)
;
}
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; ++i) {
if (!strcasecmp(argv[i], "-v")) {
printf("pause.c %s\n", VERSION_STRING(VERSION));
return 0;
}
}
if (getpid() != 1)
/* Not an error because pause sees use outside of infra containers. */
fprintf(stderr, "Warning: pause should be the first process\n");
if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
return 1;
if (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)
return 2;
if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap,
.sa_flags = SA_NOCLDSTOP},
NULL) < 0)
return 3;
for (;;)
pause();
fprintf(stderr, "Error: infinite loop terminated\n");
return 42;
}
💡 코드 설명(요약본)
이 프로그램은 주로 컨테이너 환경에서 실행되며, 신호(SIGINT, SIGTERM, SIGCHLD)를 처리하는 데 사용됩니다.
컨테이너에서 첫 번째 프로세스로 동작하며, 적절한 신호 처리(프로세스 종료, 자식 프로세스 종료 처리)를 수행합니다.
pause()
함수를 사용하여 신호가 발생할 때까지 무한 대기합니다.
[실습] 네트워크 네임스페이스 공유 확인
여기에서는 파드를 배포하여, 실제 pause container의 존재를 확인하고, 같은 파드내에서는 네트워크 스택을 공유함을 확인합니다.
파드 배포
간단하게 nginx 파드를 배포합니다.
1
kubectl run web-app1 --image=nginx
worker노드에 접속하여 정보를 확인합니다.
- 현재 3개의 파드가 동작 중(kindnet, kube-proxy, web-app1)
- 모든 파드에 pause 프로세스가 확인됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
root@myk8s-worker:/# crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
425023d6bf498 a9dfdba8b7190 13 seconds ago Running web-app1 0 62300a8320ec7 web-app1
6c78d35736270 4740c1948d3fc 2 minutes ago Running kindnet-cni 0 8cbc0152756f1 kindnet-ndvkp
07c51c7ffe9aa d2d4e1917462f 2 minutes ago Running kube-proxy 0 0c554532b5e25 kube-proxy-vtrnp
root@myk8s-worker:/# pstree -aln
systemd
|-systemd-journal
|-containerd
| `-14*[{containerd}]
|-kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime-endpoint=unix:///run/containerd/containerd.sock --node-ip=172.18.0.3 --node-labels= --pod-infra-container-image=registry.k8s.io/pause:3.9 --provider-id=kind://docker/myk8s/myk8s-worker --runtime-cgroups=/system.slice/containerd.service
| `-12*[{kubelet}]
|-containerd-shim -namespace k8s.io -id 8cbc0152756f1be78361e598b20fa2ed9e0d0d70d7e3167061c72ffb44ba26b7 -address /run/containerd/containerd.sock
| |-11*[{containerd-shim}]
| |-pause
| `-kindnetd
| `-8*[{kindnetd}]
|-containerd-shim -namespace k8s.io -id 0c554532b5e2582948170afc3646c9e77291bf13fb86efe5b49d019b1053a518 -address /run/containerd/containerd.sock
| |-11*[{containerd-shim}]
| |-pause
| `-kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=myk8s-worker
| `-7*[{kube-proxy}]
`-containerd-shim -namespace k8s.io -id 62300a8320ec795961fedb61238854616bed234a28405a7079f6ed4ecfb2f9da -address /run/containerd/containerd.sock
|-11*[{containerd-shim}]
|-pause
`-nginx
|-nginx
|-nginx
|-nginx
|-nginx
`-nginx
pause 프로세스의 PID를 확인합니다. (가장 나중에 띄운 파드이므로, PID가 가장 큰 pause 프로세스를 찾으면 됩니다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.2 0.1 21736 12360 ? Ss 12:16 0:00 /sbin/init
...
65535 306 0.0 0.0 792 4 ? Ss 12:16 0:00 /pause
65535 314 0.0 0.0 792 4 ? Ss 12:16 0:00 /pause
root 364 0.0 0.6 1283236 50024 ? Ssl 12:16 0:00 /usr/local/bin/kube-proxy --config=/var/lib/kub
root 447 0.0 0.3 740344 24628 ? Ssl 12:16 0:00 /bin/kindnetd
root 1046 0.0 0.1 1238296 12476 ? Sl 12:18 0:00 /usr/local/bin/containerd-shim-runc-v2 -namespa
65535 1065 0.0 0.0 792 4 ? Ss 12:18 0:00 /pause
root 1078 0.0 0.0 4052 3280 pts/1 Ss 12:18 0:00 bash
root 1129 0.0 0.0 11136 6900 ? Ss 12:18 0:00 nginx: master process nginx -g daemon off;
statd 1166 0.0 0.0 11596 2952 ? S 12:18 0:00 nginx: worker process
statd 1167 0.0 0.0 11596 2952 ? S 12:18 0:00 nginx: worker process
...
nginx와 위에서 찾은 pause 프로세스의 네임스페이스 정보를 확인합니다.
- net, uts, ipc가 같은 것을 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@myk8s-worker:/# lsns -p 1129
NS TYPE NPROCS PID USER COMMAND
4026531834 time 20 1 root /sbin/init
4026531837 user 20 1 root /sbin/init
4026533140 net 7 1065 65535 /pause
4026533255 uts 7 1065 65535 /pause
4026533256 ipc 7 1065 65535 /pause
4026533258 mnt 6 1129 root nginx: master process nginx -g daemon off;
4026533259 pid 6 1129 root nginx: master process nginx -g daemon off;
4026533260 cgroup 6 1129 root nginx: master process nginx -g daemon off;
root@myk8s-worker:/# lsns -p 1065
NS TYPE NPROCS PID USER COMMAND
4026531834 time 20 1 root /sbin/init
4026531837 user 20 1 root /sbin/init
4026532731 cgroup 13 1 root /sbin/init
4026533140 net 7 1065 65535 /pause
4026533254 mnt 1 1065 65535 /pause
4026533255 uts 7 1065 65535 /pause
4026533256 ipc 7 1065 65535 /pause
4026533257 pid 1 1065 65535 /pause
같은 파드내의 다른 컨테이너끼리 네임스페이스 공유 확인
이제 두 개의 컨테이너를 가진 파드를 배포하여, 네임스페이스 공유를 확인합니다.
netshoot 컨테이너는 네트워크 관련 디버깅 전용 컨테이너입니다. 자세한 내용은 GitHub에서 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cat <<EOF | kubectl apply -f -
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
EOF
배포가 완료되면, netshoot 컨테이너에 접속합니다.
1
kubectl exec myweb2 -c myweb2-netshoot -it -- zsh
현재 점유하고 있는 포트를 찾아보고, localhost로 curl를 날립니다.
결과를 확인하면, 마치 여기가 nginx 컨테이너 내부인 것처럼 설정되어있습니다.
위에서 봤듯이 네트워크 네임스페이스(스택)를 공유한다는 것을 다시 한번 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 12:16 ? 00:00:00 /sbin/init
...
65535 306 268 0 12:16 ? 00:00:00 /pause
65535 314 267 0 12:16 ? 00:00:00 /pause
root 364 268 0 12:16 ? 00:00:00 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.
root 447 267 0 12:16 ? 00:00:00 /bin/kindnetd
root 1460 1 0 12:25 ? 00:00:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 0
65535 1479 1460 0 12:25 ? 00:00:00 /pause
root 1509 1460 0 12:26 ? 00:00:00 nginx: master process nginx -g daemon off;
statd 1547 1509 0 12:26 ? 00:00:00 nginx: worker process
statd 1548 1509 0 12:26 ? 00:00:00 nginx: worker process
statd 1549 1509 0 12:26 ? 00:00:00 nginx: worker process
statd 1550 1509 0 12:26 ? 00:00:00 nginx: worker process
statd 1551 1509 0 12:26 ? 00:00:00 nginx: worker process
root 1631 1460 0 12:26 ? 00:00:00 /bin/bash -c while true; do sleep 5; curl localhost; done
root 2088 0 0 12:30 pts/1 00:00:00 bash
root 4097 1631 0 12:31 ? 00:00:00 sleep 5
root 4110 2088 0 12:31 pts/1 00:00:00 ps -ef
다시 한번 Pause 컨테이너의 정보를 확인합니다. 위에 결과에서는 nginx 프로세스 바로 위에 있는 1479번인 것을 확인했습니다.
crictl을 이용해서 네임스페이스 정보를 확인하면 Pause가 생성한 네트워크 네임스페이스를 갖는다는 것을 알 수 있습니다.
정리
- Pause 컨테이너가 net/ipc/uts 네임스페이스를
생성하고공유한다.- init 프로세스의 역할도 수행하여, 좀비 프로세스를 제거한다.
- network 네임스페이스는 CRI에서 생성한다고 한다. 악분님 블로그 참고.
- 같은 파드 내의 컨테이너는 네트워크 스택이 동일하다.
- 그렇기에 container port를 조심해서 세팅해야 한다. (중복되면 안된다.)
- 사이드카로 붙이면, 쉽게 네트워크 테스트가 가능하다.