- PAUSE 컨테이너 vs init container
- https://blog.hyojun.me/4
요약 : 파드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합이며, PAUSE 컨테이너가 Network/IPC/UTS 네임스페이스를 생성하고 유지/공유합니다.
Init Container와 Pause Container는 Kubernetes에서 각각 다른 목적으로 사용됩니다. 주요 차이점을 설명해드릴게요.
1. Init Container
- 목적: 메인 애플리케이션 컨테이너가 시작되기 전에 반드시 수행해야 할 작업을 위해 사용됩니다.
- 사용 예시: 데이터베이스 연결 확인, 파일 다운로드, 초기화 작업 등.
- 작동 방식: Init 컨테이너는 순차적으로 실행되며, 모든 Init 컨테이너가 정상적으로 종료되어야 메인 애플리케이션 컨테이너가 시작됩니다.
- 특징: 메인 컨테이너와는 별도의 이미지로 실행할 수 있어서, 메인 컨테이너의 이미지에는 포함시키기 힘든 별도의 툴이나 설정을 사용할 수 있습니다.
2. Pause Container
- 목적: 네트워크 네임스페이스를 유지하기 위해 사용됩니다.
- 사용 예시: 여러 컨테이너가 하나의 Pod 안에서 네트워크를 공유해야 할 때, 그 네트워크 네임스페이스를 'Pause' 컨테이너가 제공하게 됩니다.
- 작동 방식: Pause 컨테이너는 Pod 생성 시 가장 먼저 실행되며, 해당 Pod 내의 다른 모든 컨테이너가 이를 통해 네트워크를 공유합니다.
- 특징: 거의 아무 작업도 수행하지 않고, 네트워크 네임스페이스만 관리하는 용도로 사용됩니다. 보통 "Paused" 상태로 대기하면서, Pod 내 다른 컨테이너들이 공유할 네트워크 공간을 제공하게 됩니다.
주요 차이점 요약
- 기능 목적: Init 컨테이너는 초기 작업을 수행하기 위한 것이고, Pause 컨테이너는 네트워크 네임스페이스를 제공하고 관리하기 위한 것입니다.
- 실행 방식: Init 컨테이너는 순차적으로 실행되고 종료되지만, Pause 컨테이너는 항상 Pod의 네트워크를 유지합니다.
이렇게 Init Container와 Pause Container는 Pod 내에서 다른 역할과 용도로 활용됩니다.
실습 환경
1. 클러스터배포
# '컨트롤플레인, 워커 노드 1대' 클러스터 배포 : 파드에 접속하기 위한 포트 맵핑 설정
cat <<EOT> kind-2node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
EOT
kind create cluster --config kind-2node.yaml --name myk8s
# 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
docker exec -it myk8s-worker sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop -y'
# 확인
kubectl get nodes -o wide
docker ps
docker port myk8s-worker
docker exec -it myk8s-control-plane ip -br -c -4 addr
docker exec -it myk8s-worker ip -br -c -4 addr
# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30000 --set env.TZ="Asia/Seoul" --namespace kube-system
# 설치 확인
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view
# kube-ops-view 접속 URL 확인 (1.5 , 2 배율) : macOS 사용자
echo -e "KUBE-OPS-VIEW URL = http://localhost:30000/#scale=1.5"
echo -e "KUBE-OPS-VIEW URL = http://localhost:30000/#scale=2"
# kube-ops-view 접속 URL 확인 (1.5 , 2 배율) : Windows 사용자
echo -e "KUBE-OPS-VIEW URL = http://192.168.50.10:30000/#scale=1.5"
echo -e "KUBE-OPS-VIEW URL = http://192.168.50.10:30000/#scale=2"
2. 팟 배포
# [터미널2] kubectl 명령 실행 및 확인
# Pod 생성 : YAML 파일에 컨테이너가 사용할 포트(TCP 80)을 설정
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: myweb
spec:
containers:
- image: nginx:alpine
name: myweb-container
ports:
- containerPort: 80
protocol: TCP
terminationGracePeriodSeconds: 0
EOF
# Pod 정보 확인 : pause 컨테이너 정보가 보이는가?
kubectl get pod -o wide
kubectl describe pod myweb
kubectl get pod myweb -o json # status.conditions 에 Type 정보 확인 : 시간 정렬은 안되어 있음..
---
# [터미널1] myk8s-worker bash 진입 후 실행 및 확인
docker exec -it myk8s-worker bash
----------------------------------
crictl ps
pstree -aln
pstree -aclnpsS # 파드내에 pause 컨테이너와 app 컨테이너, 네임스페이스 정보
# 네임스페이스 확인 : lsns - List system namespaces
lsns -p 1
lsns -p $$
lsns -p <pstree -aclnpsS에서 출력된 pause 컨테이너 PID>
lsns -p $(pgrep nginx) # app 컨테이너(metrics-server)
----------------------------------
# [터미널2] kubectl 명령 실행 및 확인
kubectl delete pod myweb
3. 팟 내부에 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
3. NET IPC UTS 공유 확인
# [터미널1] 파드 생성
kubectl apply -f https://raw.githubusercontent.com/gasida/NDKS/main/3/myweb2.yaml
# 확인
# pod 정보 READY 에 2/2 를 확인 : pod 내 모든 컨테이너가 정상이여야지 status 가 Running 가 됨
kubectl get pod -owide
# Pod 상세 정보에 컨테이너 2개 정보가 보인다
kubectl describe pod myweb2
root@k8s-m:~# kubectl describe pod myweb2
Name: myweb2
...
Containers:
myweb2-nginx:
Container ID: docker://2717dd093ee5c69a918c6c52461f47cf5f0c0330378730ce717d1fcabb0fc748
Image: nginx
...
myweb2-netshoot:
Container ID: docker://e3e3aef9ee53ef805336d4b6e0986f63e23c767b1648d18ff09948815c5f06a9
Image: nicolaka/netshoot
...
# 파드의 각각 컨테이너 IP 확인 >> IP가 같다!
kubectl exec myweb2 -c myweb2-netshoot -- ip addr
kubectl exec myweb2 -c myweb2-nginx -- apt update
kubectl exec myweb2 -c myweb2-nginx -- apt install -y net-tools
kubectl exec myweb2 -c myweb2-nginx -- ifconfig
# myweb2-netshoot 컨테이너 zsh 진입
kubectl exec myweb2 -c myweb2-netshoot -it -- zsh
----------------------------------
ifconfig
ss -tnlp
curl localhost # nginx 컨테이너가 아닌데, 로컬 접속 되고 tcp 80 listen 이다. 왜그럴까?
ps -ef # nginx 프로세스 정보가 안보이는데...
exit
----------------------------------
# 터미널3 : nginx 컨테이너 웹 접속 로그 출력 : 접속자(myweb2-netshoot)의 IP 가 ::1(ipv6) 혹은 127.0.0.1(ipv4) 이닷!
kubectl logs -f myweb2 -c myweb2-nginx
::1 - - [01/Sep/2024:06:33:26 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.7.1" "-"
혹은
127.0.0.1 - - [16/Jun/2021:06:22:24 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.77.0" "-"
# [터미널2]
docker exec -it myk8s-worker bash
----------------------------------
# 컨테이너 정보 확인 : POD 와 POD ID가 같음을 확인
crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
f0401ef30af36 e286c635d1232 About a minute ago Running myweb2-netshoot 0 40f9a3021011a myweb2
1f83b080de52d a9dfdba8b7190 About a minute ago Running myweb2-nginx 0 40f9a3021011a myweb2
...
# 워커 노드에서 컨테이너 프로세스 정보 확인
ps -ef | grep 'nginx -g' | grep -v grep
root 14508 14483 0 09:23 ? 00:00:00 nginx: master process nginx -g daemon off;
ps -ef | grep 'curl' | grep -v grep
root 14596 14574 0 09:23 ? 00:00:00 /bin/bash -c while true; do sleep 5; curl localhost; done
# 각각 프로세스를 변수에 지정
NGINXPID=$(ps -ef | grep 'nginx -g' | grep -v grep | awk '{print $2}')
echo $NGINXPID
NETSHPID=$(ps -ef | grep 'curl' | grep -v grep | awk '{print $2}')
echo $NETSHPID
# 한 파드 내의 각 컨테이너의 네임스페이스 정보 확인
## time, user 네임스페이스는 호스트와 같음, 격리하지 않음
## mnt, uts, pid 네임스페이스는 컨테이너별로 격리
## ipc, uts, net 네임스페이스는 파드 내의 컨테이너 간 공유 (IPC : 컨테이너 프로세스간 공유 - signal, socket, pipe 등)
## Pause 컨테이너는 IPC, Network, UTS 네임스페이스를 생성하고 유지 -> 나머지 컨테이너들은 해당 네임스페이스를 공유하여 사용
## 유저가 실행한 특정 컨테이너가 비정상 종료되어 컨터이너 전체에서 공유되는 네임스페이스에 문제가 발생하는 것을 방지
lsns -p $NGINXPID
NS TYPE NPROCS PID USER COMMAND
4026531834 time 28 1 root /sbin/init
4026531837 user 28 1 root /sbin/init
4026533482 net 12 2112 65535 /pause
4026533611 uts 12 2112 65535 /pause
4026533612 ipc 12 2112 65535 /pause
4026533614 mnt 9 2172 root nginx: master process nginx -g daemon off;
4026533615 pid 9 2172 root nginx: master process nginx -g daemon off;
4026533616 cgroup 9 2172 root nginx: master process nginx -g daemon off;
lsns -p $NETSHPID
NS TYPE NPROCS PID USER COMMAND
4026531834 time 28 1 root /sbin/init
4026531837 user 28 1 root /sbin/init
4026533482 net 12 2112 65535 /pause
4026533611 uts 12 2112 65535 /pause
4026533612 ipc 12 2112 65535 /pause
4026533617 mnt 2 2296 root /bin/bash -c while true; do sleep 5; curl localhost; done
4026533618 pid 2 2296 root /bin/bash -c while true; do sleep 5; curl localhost; done
4026533619 cgroup 2 2296 root /bin/bash -c while true; do sleep 5; curl localhost; done
# pause 정보 확인 :
PAUSEPID=<각자 자신의 pause PID>
PAUSEPID=2112
lsns -p $PAUSEPID
NS TYPE NPROCS PID USER COMMAND
4026531834 time 28 1 root /sbin/init
4026531837 user 28 1 root /sbin/init
4026532760 cgroup 15 1 root /sbin/init # cgroup 호스트와 같은 이유는?
4026533482 net 12 2112 65535 /pause
4026533610 mnt 1 2112 65535 /pause # app 컨테이너와 다른 이유는?
4026533611 uts 12 2112 65535 /pause
4026533612 ipc 12 2112 65535 /pause
4026533613 pid 1 2112 65535 /pause # app 컨테이너와 다른 이유는?
# 개별 컨테이너에 명령 실행 : IP 동일 확인
crictl ps
crictl ps -q
crictl exec -its 904e43d8fca65 ifconfig
crictl exec -its 63f82edc9caa6 ifconfig
# PAUSE 의 NET 네임스페이스 PID 확인 및 IP 정보 확인
lsns -t net
nsenter -t $PAUSEPID -n ip -c addr
nsenter -t $NGINXPID -n ip -c addr
nsenter -t $NETSHPID -n ip -c addr
# 2개의 네임스페이스 비교 , 아래 2112 프로세스의 정제는?
crictl inspect <myweb2-nginx 컨테이너ID> | jq
crictl inspect <myweb2-netshoot 컨테이너ID> | jq
crictl inspect 904e43d8fca65 | jq
crictl inspect 63f82edc9caa6 | jq
...
"namespaces": [
{
"type": "pid"
},
{
"type": "ipc",
"path": "/proc/2112/ns/ipc"
},
{
"type": "uts",
"path": "/proc/2112/ns/uts"
},
{
"type": "mount"
},
{
"type": "network",
"path": "/proc/2112/ns/net"
},
{
"type": "cgroup"
}
],
...
같은 네트워크 네임스페이스이기 때문에 IP가 같음
같은 네트워크 네임스페이스이기 때문에 IP가 같다..
2014년부터 쿠버네티스 개발자들은 pause 컨테이너를 통한 네트워크 네임스페이스 공유에 대해 지속적으로
논의 했었습니다.
기존 레거시 시스템에서 IP를 기준으로 모니터링 및 운영하던 방식에서 벗어나는 관점이기 때문이었죠.
하지만, 파드 내에서 유연한 통신을위해서 pause 컨테이너는 네트워크 컨테이너 라는 이름으로 사용되기 시작했습니다.
중간에 이름을 인프라 컨테이너로 한번 변경..
현재는 pause 컨테이너라고 부르고 있습니다.
쿠버네티스가 출시되고 16년도 cri-o 이슈에 pause 컨테이너가 정말 필요한가에 대한 논의가 다시 수면위로 올라왔습니다.
- Github cri-o Issue 에 PAUSE 컨테이너가 꼭 필요한지 질문 올림
- podman cri-o 등 당시 시장을 장악하던 컨테이너 런타임 쪽에서 pause 컨테이너를 옵션으로 on,off 할수 있도록 다시 방향성이 조정되기도 했었습니다.
2018년도 해당 이슈에 대한 지속적인 논의를 공식적으로 종료하며 지금과 같은 내용으로 발표됩니다.
Pause Container는 Kubernetes에서 Pod 안의 컨테이너들이 네트워크와 리소스를 공유할 수 있도록 만들어진 "인프라" 컨테이너입니다.
❤ 역할:
Pod 내의 여러 컨테이너가 같은 네트워크와 리소스를 쓸 수 있게 해줍니다.
만약 Pod 내 다른 컨테이너가 실패해도 네트워크 공간을 유지할 수 있도록 합니다.
❤ 작동 방식:
이 컨테이너는 실제로 아무 일도 하지 않으며, pause 시스템 호출로 대기만 합니다. 이 때문에 이름도 Pause Container입니다.
❤ PID 1로 실행:
Pause Container는 Pod에서 가장 먼저 실행되며 PID 1을 차지합니다. 이를 통해 좀비 프로세스를 방지하는 역할도 합니다.
❤ 설정 가능:
원한다면 다른 이미지로 교체할 수 있지만, 특별한 이유가 없는 한 기본 설정을 사용하는 것이 좋습니다.
이 Pause Container 덕분에 Pod의 네트워크 네임스페이스가 유지되며, 다른 컨테이너들이 같은 네트워크 환경에서 작업할 수 있게 됩니다.
'컨테이너 > 쿠버네티스 네트워크' 카테고리의 다른 글
[KANS] 쿠버네티스 네트워크 (7) Calico CNI (0) | 2024.09.14 |
---|---|
[KANS] 쿠버네티스 네트워크 (6) Flannel CNI (0) | 2024.09.03 |
[KANS] 쿠버네티스 네트워크 (4) 쿠버네티스 인증 deep div (0) | 2024.09.02 |
[KANS] 쿠버네티스 네트워크 (3) 컨테이너 네트워크 & IPTABLES (0) | 2024.08.29 |
[KANS] 쿠버네티스 네트워크 (2) 컨테이너 격리 (0) | 2024.08.27 |