티스토리 뷰
CloudNet@ 가시다님이 진행하는 KANS Study 3기 스터디 내용 참고.
3. 파드 & PAUSE 컨테이너
요약 : 파드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합이며, PAUSE 컨테이너가 Network/IPC/UTS 네임스페이스를 생성하고 유지/공유합니다.
k8s CRI - Old_Docs
- Container Runtime : kubelet → CRI → High Level Runtime (containerd) ← OCI → Low Level Runtime (Runc)
- CRI 배경 - Old_Docs
- 쿠버네티스 노드의 가장 낮은 계층(Low Level)에는 컨테이너를 시작하고 중지하는 것 외에도 소프트웨어가 있습니다. 이를 "컨테이너 런타임(Runc 등)"이라고 합니다. 가장 널리 알려진 컨테이너 런타임은 Docker이지만 이 분야에서 유일한 것은 아닙니다. 사실, 컨테이너 런타임 공간은 빠르게 진화해 왔습니다. 쿠버네티스를 더 확장 가능하게 만들기 위한 노력의 일환으로, "CRI"라고 하는 쿠버네티스의 컨테이너 런타임을 위한 새로운 플러그인 API를 개발해 왔습니다.
- CRI란 무엇이고 쿠버네티스에 왜 필요한가요? 표준 인터페이스를 통해서 kubelet 재컴파일 없이 다양한 컨테이너 런타임 사용
- 각 컨테이너 런타임에는 고유한 강점이 있으며, 많은 사용자가 Kubernetes가 더 많은 런타임을 지원하도록 요청했습니다. Kubernetes 1.5 릴리스에서, 우리는 컨테이너 런타임 인터페이스 (CRI)를 소개하게 되어 자랑스럽습니다. 이 플러그인 인터페이스는 kubelet이 재컴파일할 필요 없이 다양한 컨테이너 런타임을 사용할 수 있도록 해줍니다. CRI는 프로토콜 버퍼 와 gRPC API , 라이브러리 로 구성되어 있으며, 추가 사양과 도구가 활발하게 개발 중입니다. CRI는 Kubernetes 1.5 에서 알파로 릴리스됩니다 .
- 쿠버네티스에서 상호 교환 가능한 컨테이너 런타임을 지원하는 것은 새로운 개념이 아닙니다. 1.3 릴리스에서 Docker 컨테이너 런타임의 대안으로 rkt 컨테이너 엔진을 활성화하는 rktnetes 프로젝트를 발표했습니다 . 그러나 Docker와 rkt는 모두 내부적이고 휘발성 있는 인터페이스를 통해 kubelet 소스 코드에 직접적이고 깊이 통합되었습니다. 이러한 통합 프로세스에는 Kubelet 내부 구조에 대한 심층적인 이해가 필요하며 쿠버네티스 커뮤니티에 상당한 유지 관리 오버헤드가 발생합니다. 이러한 요소는 신생 컨테이너 런타임에 대한 진입 장벽을 높입니다. 명확하게 정의된 추상화 계층을 제공함으로써 장벽을 제거하고 개발자가 컨테이너 런타임을 빌드하는 데 집중할 수 있도록 합니다. 이는 플러그형 컨테이너 런타임을 진정으로 활성화하고 보다 건강한 생태계를 구축하기 위한 작지만 중요한 단계입니다.
- CRI 아키텍처 개선 과정 - Blog
- containerd 1.0의 경우 Kubelet과 containerd 사이에서 작동하려면 cri-containerd라는 데몬이 필요했습니다. Cri-containerd는 Kubelet의 컨테이너 런타임 인터페이스(CRI) 서비스 요청을 처리하고 containerd를 사용하여 컨테이너와 컨테이너 이미지를 적절히 관리했습니다. Docker CRI 구현( dockershim )과 비교했을 때, 스택에서 하나의 추가 홉을 제거했습니다.
- 그러나 cri-containerd와 containerd 1.0은 여전히 grpc를 통해 상호 작용하는 2개의 다른 데몬이었습니다. 루프에 데몬이 추가되어 사용자가 이해하고 배포하기가 더 복잡해졌고 불필요한 통신 오버헤드가 발생했습니다.
- containerd 1.1에서 cri-containerd 데몬은 이제 containerd CRI 플러그인으로 리팩토링되었습니다. CRI 플러그인은 containerd 1.1에 내장되어 있으며 기본적으로 활성화되어 있습니다. cri-containerd와 달리 CRI 플러그인은 직접 함수 호출을 통해 containerd와 상호 작용합니다. 이 새로운 아키텍처는 통합을 보다 안정적이고 효율적으로 만들고 스택에서 또 다른 grpc 홉을 제거합니다. 이제 사용자는 Kubernetes를 containerd 1.1과 함께 직접 사용할 수 있습니다. cri-containerd 데몬은 더 이상 필요하지 않습니다.
https://kubernetes.io/blog/2022/05/03/dockershim-historical-context/
- CRI
- Kubelet은 gRPC 프레임워크를 사용하여 Unix 소켓을 통해 컨테이너 런타임(또는 런타임용 CRI shim)과 통신합니다.
- 여기서 kubelet은 클라이언트 역할을 하고 CRI shim은 서버 역할을 합니다.
- 프로토콜 버퍼 API에는 두 가지 gRPC 서비스인 ImageService와 RuntimeService가 포함되어 있습니다. ImageService는 리포지토리에서 이미지를 가져오고, 이미지를 검사하고, 제거하는 RPC를 제공합니다. RuntimeService에는 포드와 컨테이너의 수명 주기를 관리하는 RPC와 컨테이너와 상호 작용하기 위한 호출(exec/attach/port-forward)이 포함되어 있습니다. 이미지와 컨테이너(예: Docker 및 rkt)를 모두 관리하는 모놀리식 컨테이너 런타임은 단일 소켓으로 두 서비스를 동시에 제공할 수 있습니다. 소켓은 Kubelet에서 --container-runtime-endpoint 및 --image-service-endpoint 플래그로 설정할 수 있습니다.
- Pod는 리소스 제약이 있는 격리된 환경의 애플리케이션 컨테이너 그룹으로 구성됩니다. CRI에서 이 환경을 PodSandbox라고 합니다.
- 우리는 의도적으로 컨테이너 런타임이 내부적으로 작동하는 방식에 따라 PodSandbox를 다르게 해석할 수 있는 여지를 남겨둡니다. 하이퍼바이저 기반 런타임의 경우 PodSandbox는 가상 머신을 나타낼 수 있습니다. Docker와 같은 다른 경우 Linux 네임스페이스일 수 있습니다. PodSandbox는 Pod 리소스 사양을 준수해야 합니다. v1alpha1 API에서 이는 kubelet이 생성하여 런타임에 전달하는 Pod 수준 cgroup 내의 모든 프로세스를 시작하여 달성됩니다.
- 포드를 시작하기 전에 kubelet은 RuntimeService.RunPodSandbox를 호출하여 환경을 만듭니다. 여기에는 포드에 대한 네트워킹 설정(예: IP 할당)이 포함됩니다. PodSandbox가 활성화되면 개별 컨테이너를 독립적으로 생성/시작/중지/제거할 수 있습니다. 포드를 삭제하기 위해 kubelet은 PodSandbox를 중지하고 제거하기 전에 컨테이너를 중지하고 제거합니다.
- Kubelet은 RPC를 통해 컨테이너의 수명 주기를 관리하고, 컨테이너 수명 주기 후크와 활성/준비 확인을 실행하며, Pod의 재시작 정책을 준수합니다.
Containerd Brings More Container Runtime Options for Kubernetes - Blog
- cri-containerd
- Architecture : 그림에 sandbox container = pause contianer
Kubelet이 단일 컨테이너 파드를 생성하는 경우에 cri-containerd가 어떻게 동작하는지 예시로 설명하겠습니다:
- Kubelet은 CRI 런타임 서비스 API를 통해 cri-containerd를 호출하여 파드를 생성합니다.
- cri-containerd는 containerd를 사용하여 특수한 pause 컨테이너 (즉, sandbox 컨테이너)를 생성하고 시작하며, 해당 컨테이너를 파드의 cgroups 및 namespace에 배치합니다(세부 단계는 생략).
- cri-containerd는 CNI를 사용하여 파드의 네트워크 네임스페이스를 구성합니다.
- Kubelet은 그 후 CRI 이미지 서비스 API를 통해 cri-containerd에 애플리케이션 컨테이너 이미지를 풀링(pull)하도록 호출합니다.
- cri-containerd는 해당 이미지가 노드에 없는 경우 containerd를 사용하여 이미지를 풀링합니다.
- 그 후 Kubelet은 CRI 런타임 서비스 API를 통해 cri-containerd에 호출하여 풀링된 컨테이너 이미지를 사용해 파드 내부에서 애플리케이션 컨테이너를 생성하고 시작합니다.
- cri-containerd는 마지막으로 containerd를 호출하여 애플리케이션 컨테이너를 생성하고 이를 파드의 cgroups 및 namespace에 배치한 후, 파드의 새로운 애플리케이션 컨테이너를 시작합니다. 이러한 단계가 완료되면 파드와 해당 애플리케이션 컨테이너가 생성되고 실행됩니다.
파드(Pod) : 컨테이너 애플리케이션의 기본 단위를 파드(Pod)라고 부르며, 파드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합 - 링크 , code
- Pod 는 1개 이상의 컨테이너를 가질 수 있습니다 ⇒ sidecar 패턴 등
- Pod 내에 실행되는 컨테이너들은 반드시 동일한 노드에 할당되며 동일한 생명 주기를 갖습니다 → Pod 삭제 시, Pod 내 모든 컨테이너가 삭제
- Pod IP - Pod 는 노드 IP 와 별개로 클러스터 내에서 접근 가능한 IP를 할당 받으며, 다른 노드에 위치한 Pod 도 NAT 없이 Pod IP로 접근 가능 ⇒ 요걸 CNI 해줌!
- IP 공유 - Pod 내에 있는 컨테이너들은 서로 IP를 공유, 컨테이너끼리는 localhost 통해 서로 접근하며 포트를 이용해 구분
- pause 컨테이너가 'parent' 처럼 network ns 를 만들어 주고, 내부의 컨테이너들은 해당 net ns 를 공유 ← 세상에서 제일 많이 사용되는 컨테이너!
- 쿠버네티스에서 pause 컨테이너는 포드의 모든 컨테이너에 대한 "부모 컨테이너" 역할을 합니다 - Link
- pause 컨테이너에는 두 가지 핵심 책임이 있습니다.
- 첫째, 포드에서 Linux 네임스페이스 공유의 기반 역할을 합니다.
- 둘째, PID(프로세스 ID) 네임스페이스 공유가 활성화되면 각 포드에 대한 PID 1 역할을 하며 좀비 프로세스를 거둡니다.
- volume 공유 - Pod 안의 컨테이너들은 동일한 볼륨과 연결이 가능하여 파일 시스템을 기반으로 서로 파일을 주고받을 수 있음
- Pod는 리소스 제약이 있는 격리된 환경의 애플리케이션 컨테이너 그룹으로 구성됩니다. CRI에서 이 환경을 PodSandbox라고 합니다.
- 포드를 시작하기 전에 kubelet은 RuntimeService.RunPodSandbox를 호출하여 환경을 만듭니다. (파드 네트워킹 설정 ’IP 할당’ 포함)
- Kubelet은 RPC를 통해 컨테이너의 수명 주기를 관리하고, 컨테이너 수명 주기 후크와 활성/준비 확인을 실행하며, Pod의 재시작 정책을 준수합니다
pause.c - Code
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#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;
}
- 실습 환경 구성 : Multi-Node Cluster (Control-plane, Nodes) with kube-ops-view
# '컨트롤플레인, 워커 노드 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"
- Pod 배포 및 격리 확인
# [터미널1] myk8s-worker bash 진입 후 실행 및 확인
docker exec -it myk8s-worker bash
----------------------------------
systemctl list-unit-files | grep 'enabled enabled'
containerd.service enabled enabled
kubelet.service enabled enabled
...
#
crictl ps
# 확인 : kubelet에 --container-runtime-endpoint=unix:///run/containerd/containerd.sock
pstree -aln
systemd
|-systemd-journal
|-containerd
| \-12*[{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.4 --node-labels=mynode=worker2 --pod-infra-container-image=registry.k8s.io/pause:3.9 --provider-id=kind://docker/myk8s/myk8s-worker2 --runtime-cgroups=/system.slice/containerd.service
| \-14*[{kubelet}]
|-containerd-shim -namespace k8s.io -id e41d2d62c1bb44a955fe13ddef0dbb006c44352fda493e8d76c489138756d2fa -address /run/containerd/containerd.sock
| |-12*[{containerd-shim}]
| |-pause
| \-kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=myk8s-worker2
| \-9*[{kube-proxy}]
|-containerd-shim -namespace k8s.io -id 9768cd57beeee9b0d1dc38e46dce44697113c3e3924d098e7b8c776909852f63 -address /run/containerd/containerd.sock
| |-11*[{containerd-shim}]
| |-pause
| \-flanneld --ip-masq --kube-subnet-mgr
| \-10*[{flanneld}]
\-containerd-shim -namespace k8s.io -id 6bd147995b3a6c17384459eb4d3ceab4369329e6b57c009bdc6257b72254e1fb -address /run/containerd/containerd.sock
|-11*[{containerd-shim}]
|-pause
\-metrics-server --cert-dir=/tmp --secure-port=10250 --kubelet-insecure-tls --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --kubelet-use-node-status-port --metric-resolution=15s
\-12*[{metrics-server}]
# 확인 : 파드내에 pause 컨테이너와 metrics-server 컨테이너, 네임스페이스 정보
pstree -aclnpsS
...
\-containerd-shim,1776 -namespace k8s.io -id 6bd147995b3a6c17384459eb4d3ceab4369329e6b57c009bdc6257b72254e1fb -address /run/containerd/containerd.sock
|-{containerd-shim},1777
...
|-pause,1797,ipc,mnt,net,pid,uts
|-metrics-server,1896,cgroup,ipc,mnt,net,pid,uts --cert-dir=/tmp --secure-port=10250 --kubelet-insecure-tls --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --kubelet-use-node-status-port --metric-resolution=15s
| |-{metrics-server},1912
...
# 네임스페이스 확인 : lsns - List system namespaces
lsns -p 1
lsns -p $$
NS TYPE NPROCS PID USER COMMAND
4026531834 time 15 1 root /sbin/init
4026531837 user 15 1 root /sbin/init
4026532525 mnt 9 1 root /sbin/init
4026532550 uts 13 1 root /sbin/init
4026532551 ipc 9 1 root /sbin/init
4026532577 pid 9 1 root /sbin/init
4026532579 net 13 1 root /sbin/init
4026532891 cgroup 13 1 root /sbin/init
# 해당 파드에 pause 컨테이너는 호스트NS와 다른 5개의 NS를 가짐 : mnt/pid 는 pasue 자신만 사용, net/uts/ipc는 app 컨테이너를 위해서 먼저 생성해둠
lsns -p 1797
NS TYPE NPROCS PID USER COMMAND
4026531834 time 15 1 root /sbin/init
4026531837 user 15 1 root /sbin/init
4026532891 cgroup 13 1 root /sbin/init
4026533496 net 2 1797 65535 /pause
4026533625 uts 2 1797 65535 /pause
4026533626 ipc 2 1797 65535 /pause
4026533624 mnt 1 1797 65535 /pause
4026533627 pid 1 1797 65535 /pause
# app 컨테이너(metrics-server)는 호스트NS와 다른 6개의 NS를 가짐 : mnt/pid/cgroup 는 자신만 사용, net/uts/ipc는 pause 컨테이너가 생성한 것을 공유 사용함
pgrep python3
lsns -p $(pgrep python3)
pgrep metrics-server
1896
lsns -p $(pgrep metrics-server)
NS TYPE NPROCS PID USER COMMAND
4026531834 time 15 1 root /sbin/init
4026531837 user 15 1 root /sbin/init
4026533496 net 2 1797 65535 /pause
4026533625 uts 2 1797 65535 /pause
4026533626 ipc 2 1797 65535 /pause
4026533628 mnt 1 1896 1000 /metrics-server --cert-dir=/tmp --secure-port=10250 --kubelet-insecure-tls --kubelet-preferred-address-types=Inte
4026533629 pid 1 1896 1000 /metrics-server --cert-dir=/tmp --secure-port=10250 --kubelet-insecure-tls --kubelet-preferred-address-types=Inte
4026533630 cgroup 1 1896 1000 /metrics-server --cert-dir=/tmp --secure-port=10250 --kubelet-insecure-tls --kubelet-preferred-address-types=Inte
#
ls -l /run/containerd/containerd.sock
# 특정 소켓 파일을 사용하는 프로세스 확인
lsof /run/containerd/containerd.sock
#
ss -xl | egrep 'Netid|containerd'
#
findmnt -A
TARGET SOURCE FSTYPE OPTIONS
/ overlay overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/HW4BGGJ4LV6M5
...
|-/sys sysfs sysfs ro,nosuid,nodev,noexec,relatime
| |-/sys/kernel/debug debugfs debugfs rw,nosuid,nodev,noexec,relatime
| |-/sys/kernel/tracing tracefs tracefs rw,nosuid,nodev,noexec,relatime
| |-/sys/fs/fuse/connections fusectl fusectl rw,nosuid,nodev,noexec,relatime
| |-/sys/kernel/config configfs configfs rw,nosuid,nodev,noexec,relatime
| \-/sys/fs/cgroup cgroup cgroup2 rw,nosuid,nodev,noexec,relatime
findmnt -t cgroup2
grep cgroup /proc/filesystems
stat -fc %T /sys/fs/cgroup/
----------------------------------
- 신규 파드를 배포하고 확인
# [터미널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
- myweb2 파드 정보 : myweb2 파드에 2개의 컨테이너가 동작
- myweb2.yaml : containers 가 복수형을 주목!
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
- 배포 후 확인 ⇒ NET IPC UTS 공유 확인
# [터미널1] 파드 생성
kubectl apply -f https://raw.githubusercontent.com/gasida/NDKS/main/3/myweb2.yaml
# kind POD 정보 확인 : 컨테이너의 집합
kubectl explain pod
KIND: Pod
VERSION: v1
DESCRIPTION:
Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts.
...
# 확인
# 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"
}
],
...
- 파드 삭제: kubectl delete pod myweb2
- 실습 완료 후 kind 삭제 : kind delete cluster --name myk8s
'KANS study' 카테고리의 다른 글
[3주차] Calico CNI & Mode - #1 (0) | 2024.09.22 |
---|---|
[2주차] K8S Flannel CNI & PAUSE - #3 (0) | 2024.09.08 |
[2주차] K8S Flannel CNI & PAUSE - #1 (0) | 2024.09.07 |
[1주차] 컨테이너 격리 & 네트워크 및 보안 - #2 (0) | 2024.09.01 |
[1주차] 컨테이너 격리 & 네트워크 및 보안 - #3 (0) | 2024.09.01 |