PAUSE 컨테이너
들어가며
쿠버네티스를 구축하면서 애를 먹었던 적이 있었는데, 그때의 원인이 바로 Pause 컨테이너였습니다.
폐쇄망 환경에서 containerd가 사용하는 Pause 컨테이너 이미지가 존재하지 않아 쿠버네티스 클러스터 bootstrap 과정에서 에러가 발생하였습니다.
보이지 않는 뒷 단에 프로세스로 존재하기 때문에 원인을 쉽게 찾을 수 없었습니다. 그때 만약 CreatePodSandBox 오류가 Pause 컨테이너와 관련된 에러인 줄 알았다면, 금방 에러를 파악할 수 있었을 겁니다. 이후에 파드의 인프라를 관리해주는 컨테이너라고만 어렴풋이 알고 넘겼는데, 이번 스터디를 통해서 Pause Container에 대해 좀 더 자세하게 알아봅니다.
Pause 컨테이너란?
PodSandBox
Pod는 컨테이너 애플리케이션의 기본 단위로, 여러 개의 컨테이너를 가질 수 있습니다.
파드가 생성될 때, 내부의 여러 컨테이너들이 동작할 수 있는 기본 환경을 제공해주는 개념을 PodSandBox라고 합니다.
이러한 PodSandBox를 수행하는 컨테이너가 바로 Pause 컨테이너 입니다.
모든 파드가 생성될 때마다 새로운 Pause 컨테이너가 같이 생성되며, 파드 내의 컨테이너에 대한 부모 컨테이너 역할을 담당합니다.
따라서, Pause 컨테이너는 리눅스 네임스페이스 기술을 활용하여, 파드가 사용하는 네트워크, 볼륨 등이 격리된 환경을 생성하고, 내부 컨테이너들에게 제공합니다.
PodSandBox의 동작 과정
- Pod 생성 시점:
- Kubernetes에서 새로운 Pod가 생성될 때, kubelet은 먼저 해당 Pod를 위한 PodSandBox를 만듭니다.
- Pause 컨테이너 생성:
- PodSandBox가 만들어질 때 pause 컨테이너가 생성됩니다. 이 pause 컨테이너는 Pod 내 모든 컨테이너가 공유하는 네트워크와 네임스페이스를 설정하고 유지합니다.
- 컨테이너 실행:
- pause 컨테이너가 생성되면, 그 위에서 실제 애플리케이션 컨테이너들이 실행됩니다. 이 컨테이너들은 모두 동일한 PodSandBox 환경을 공유하게 됩니다.
- Pod 종료:
- Pod 내 모든 컨테이너가 종료되더라도, pause 컨테이너는 계속 남아서 네임스페이스와 네트워크 설정을 유지합니다. Pod가 완전히 삭제되면 pause 컨테이너와 PodSandBox도 삭제됩니다.
Pause 컨테이너 실습
먼저, 컨테이너가 2개인 파드를 생성합니다.
- container1 : nginx
- container2: netshoot
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
파드의 각 컨테이너 ip 확인
# 컨테이너 1
kubectl exec myweb2 -c myweb2-netshoot -- ip addr
# 컨테이너 2
# ip 명령어가 없으므로 net-tools 설치
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
파드의 각 컨테이너의 IP를 확인하면 두 개의 컨테이너 모두 10.244.1.2로 같은 IP를 사용하는 것을 확인할 수 있습니다.
이번에는 netshoot 파드에 진입하여 포트를 확인해 보면, 프로세스가 존재하지 않는데도, nginx의 컨테이너의 서비스 포트가 보입니다. curl 명령어로 localhost에 요청을 보내면 nginx 서비스 응답이 오는 것을 확인할 수 있습니다. 이는 Network 네임스페이스를 공유하기 때문에 같은 네트워크를 사용하기 때문입니다.
노드에서 컨테이너 프로세스 정보 확인
파드가 동작하는 워커노드에 진입합니다.
pstree 명령어로 파드의 각 컨테이너의 프로세스의 정보를 확인합니다.
: pstree -aclnpsS(전체 명령어 및 인자, PID 순서, 프로세스 ID 표시, 중복된 프로세스 출력 금지, 긴 이름 표시)
각각 프로세스를 변수에 지정합니다.
# 워커 노드에서 컨테이너 프로세스 정보 확인
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
1312
NETSHPID=$(ps -ef | grep 'curl' | grep -v grep | awk '{print $2}')
echo $NETSHPID
1433
PAUSEPID=1255
echo $NETSHPID
1255
파드 내 컨테이너 네임스페이스 정보 확인
lsns 명령어로 파드 내의 각 컨테이너들의 네임스페이스 정보를 확인합니다.
각 컨테이너들의 특정 네임스페이스 PID는 Pause 컨테이너의 PID를 상속받아 사용함을 확인할 수 있습니다.
- mnt, pid, cgroup 네임스페이스는 컨테이너 별로 격리합니다.
- net, uts, ipc 네임스페이스는 파드 내의 컨테이너 간 공유 합니다.
Pause 컨테이너는 IPC, Network, UTS 네임스페이스를 생성하고 유지하고, 나머지 컨테이너들은 해당 네임스페이스를 공유하여 사용합니다. 유저가 실행한 특정 컨테이너가 비정상 종료되어도, 컨테이너 전체에서 공유되는 네임스페이스에 문제가 발생하는 것을 방지합니다.
Flannel CNI
Flnannel CNI이란?
Flannel은 Kubernetes 클러스터에서 사용되는 Container Network Interface(CNI) 중 하나로, 클러스터 내에서 Pod 간의 네트워킹을 설정하는 데 사용됩니다. Flannel은 기본적으로 VXLAN(Virtual Extensible LAN)을 사용하여 간단한 오버레이 네트워크를 제공하여, 서로 다른 노드에 있는 Pod들이 동일한 네트워크에 속한 것처럼 통신할 수 있게 해 줍니다.
Flannel 정보 확인
Flannel 서브넷 정보 확인
- FLANNEL_SUBNET : 해당 노드에 파드가 배포 시 할당할 수 있는 네트워크 대역
- FLANNEL_MTU : MTU(최대 전송 단위) 지정
- FLANNEL_IPMASQ : 마스커레이딩 여부( 외부 통신 시 사용 )
for i in myk8s-control-plane myk8s-worker myk8s-worker2; do echo ">> node $i <<"; docker exec -it $i cat /run/flannel/subnet.env ; echo; done
>> node myk8s-control-plane <<
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
>> node myk8s-worker <<
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.1.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
>> node myk8s-worker2 <<
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.2.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
기본 네트워크 정보 확인
- fnannel.1 : Flannel CNI 플러그인이 생성한 가상 인터페이스, 파드 IP 제공
- cni0 : kubernetes CNI 플러그인이 생성한 브리지 인터페이스, 노드 내의 파드 간 통신 관리
실습 : 통신 흐름 이해하기
파드 생성
실습에 사용할 2개의 파드를 생성합니다.
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-1
labels:
app: pod
spec:
nodeSelector:
kubernetes.io/hostname: myk8s-worker
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
name: pod-2
labels:
app: pod
spec:
nodeSelector:
kubernetes.io/hostname: myk8s-worker2
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 파드 확인 : IP 확인
kubectl get pod -o wide
파드 생성 후 정보 확인
# [터미널1,2] 워커 노드1,2
docker exec -it myk8s-worker bash
docker exec -it myk8s-worker2 bash
-----------------------------
# 브리지 정보 확인
brctl show cni0
# 브리지 연결 링크(veth) 확인
bridge link
# 브리지 VLAN 정보 확인
bridge vlan
# cbr(custom bridge) 정보 : kubenet CNI의 bridge - 링크
tree /var/lib/cni/networks/cbr0
/var/lib/cni/networks/cbr0/
|-- 10.244.1.2
|-- 10.244.1.3
|-- 10.244.1.4
|-- 10.244.1.5
|-- last_reserved_ip.0
`-- lock
# 네트워크 관련 정보들 확인
ip -c addr | grep veth -A3
8: vetha7a44aeb@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default
link/ether c6:58:fc:f8:9f:a7 brd ff:ff:ff:ff:ff:ff link-netns cni-49b07053-d389-08c3-b3c0-47738a869b3d
inet6 fe80::c458:fcff:fef8:9fa7/64 scope link
valid_lft forever preferred_lft forever
...
파드 1에서 다양한 유형의 통신 흐름 분석
1. 동일 노드 간 통신
같은 노드에서 동작하는 파드 간의 통신을 의미합니다.
flannel 인터페이스를 거치지 않고 cni0 인터페이스를 거쳐 통신합니다.
2. 다른 노드 간 파드 통신
다른 노드에서 동작하는 파드 간의 통신을 의미합니다.
flannel 인터페이스를 거쳐 통신합니다. VXAN을 통한 내부적인 네트워크 정보가 캡슐화되어 다른 노드로 전달됩니다.
UDP 프로토콜을 통해 캡슐화하여 통신하기 때문에 tcp의 ICMP 패킷에는 포착이 되지 않는 것을 확인할 수 있습니다.
3. 외부 인터넷 IP 통신
flannel 인터페이스를 거치지 않고 마스크레이딩을 통해 바로 외부 인터넷으로 통신합니다.
정상적으로 외부로 통신되는 것을 확인할 수 있습니다.
와이어 샤크로 패킷 분석하기
tcpdump 명령어로 flannel 패킷을 캡처하여 파일로 떨굽니다. (* flannel 기본 udp port : 8472 )
tcpdump -i eth0 -nn udp port 8472 -w /root/vxlan.pcap
Wireshark를 열어 해당 패킷 파일을 분석합니다.
- Source Address : 출발지 노드 IP
- Destination Addresss : 목적지 노드 IP
- Src : 출발지 파드 IP
- Dst : 목적지 파드 IP
Wireshark에서 VXLAN의 기본 UDP Port를 4789를 사용하는데, Flannel은 8472를 사용하니, flannel 패킷이 보이지 않는다면 참고합니다.
'Kubernetes > Network' 카테고리의 다른 글
kube-proxy IPVS 모드의 동작 원리 이해 - KANS 5주차 2 (1) | 2024.10.06 |
---|---|
MetalLB를 활용한 LoadBalancer 서비스의 동작 원리 이해 - KANS 5주차 1 (2) | 2024.10.06 |
Kubernetes Service(Cluster IP & NodePort) 동작 원리 딥다이브 - KANS 4주차 (1) | 2024.09.28 |
Calico CNI 기본 네트워크 이해 & 네트워크 모드 - KANS 3주차 (4) | 2024.09.22 |
컨테이너 격리 & 네트워크 및 보안 - KANS 1주차 (0) | 2024.08.27 |