Skip to content

필사 모드: containerd CRI 구현: Kubernetes 런타임 통합

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

containerd CRI 구현: Kubernetes 런타임 통합

containerd는 Kubernetes CRI(Container Runtime Interface)를 내장 플러그인으로 구현합니다. 이 글에서는 CRI gRPC 서비스의 구현 상세, Pod Sandbox 관리, 컨테이너 스펙 변환, 스트리밍 API, RuntimeClass, NRI를 분석합니다.

1. CRI gRPC 서비스

1.1 서비스 구조

CRI는 두 개의 gRPC 서비스로 구성됩니다:

CRI gRPC 서비스:

RuntimeService:

+-- PodSandbox 관리

| RunPodSandbox

| StopPodSandbox

| RemovePodSandbox

| PodSandboxStatus

| ListPodSandbox

|

+-- Container 관리

| CreateContainer

| StartContainer

| StopContainer

| RemoveContainer

| ListContainers

| ContainerStatus

| UpdateContainerResources

|

+-- 스트리밍

| ExecSync

| Exec

| Attach

| PortForward

|

+-- 런타임 정보

Status

Version

ImageService:

+-- PullImage

+-- ListImages

+-- ImageStatus

+-- RemoveImage

+-- ImageFsInfo

1.2 소켓 구성

CRI 소켓:

containerd는 동일한 gRPC 소켓에서 CRI를 제공:

/run/containerd/containerd.sock

kubelet 설정:

--container-runtime-endpoint=unix:///run/containerd/containerd.sock

CRI 플러그인이 containerd 서버에 CRI 서비스를 등록:

플러그인 ID: io.containerd.grpc.v1.cri

2. Pod Sandbox

2.1 Pod Sandbox 개념

Pod Sandbox는 Pod의 격리 환경을 나타냅니다:

Pod Sandbox 구성:

Pod Sandbox = Pause 컨테이너 + 공유 네임스페이스

공유 리소스:

- 네트워크 네임스페이스 (같은 IP, 포트 공간)

- IPC 네임스페이스 (프로세스 간 통신)

- UTS 네임스페이스 (호스트명)

- PID 네임스페이스 (선택적)

격리 리소스:

- 마운트 네임스페이스 (컨테이너별)

- cgroup (컨테이너별 리소스 제한)

2.2 RunPodSandbox 흐름

RunPodSandbox 처리:

1. Sandbox 메타데이터 생성

- ID 생성

- 로그 디렉토리 생성

|

v

2. Pause 이미지 풀

- sandbox_image 설정에서 이미지 결정

- 기본값: registry.k8s.io/pause:3.9

|

v

3. Pause 컨테이너 스냅샷 준비

|

v

4. OCI 스펙 생성

- Pause 컨테이너용 최소 스펙

- 호스트명, DNS 설정 포함

|

v

5. 네트워크 네임스페이스 생성

- /var/run/netns/ 에 네임스페이스 파일 생성

|

v

6. CNI 플러그인 호출

- 네트워크 인터페이스 생성

- IP 할당

|

v

7. Pause 컨테이너 Task 생성 및 시작

|

v

8. Sandbox 상태를 SANDBOX_READY로 설정

2.3 Pause 컨테이너

Pause 컨테이너의 역할:

1. 네임스페이스 보유자:

- 네트워크 네임스페이스의 첫 번째 프로세스

- App 컨테이너가 종료되어도 네임스페이스 유지

- 네임스페이스의 생명주기를 Pod에 바인딩

2. PID 1 역할:

- Pod PID 네임스페이스의 init 프로세스

- 좀비 프로세스 수거 (reap)

- 최소 리소스 사용 (약 1MB)

3. 동작:

- pause() 시스템 콜로 무한 대기

- SIGTERM 수신 시 종료

3. 컨테이너 스펙 변환

3.1 CRI 요청에서 OCI 스펙으로

스펙 변환 과정:

CRI ContainerConfig:

- Image

- Command, Args

- Envs

- Mounts

- Devices

- SecurityContext

- Resources

|

v

containerd CRI 플러그인이 변환

|

v

OCI Runtime Spec:

- root (이미지 스냅샷 경로)

- process (커맨드, env, capabilities)

- mounts (볼륨, 특수 파일시스템)

- linux.resources (cgroup 설정)

- linux.namespaces (Sandbox와 공유)

- hooks (OCI 훅)

3.2 리소스 변환

Kubernetes 리소스 -> OCI 리소스 변환:

CPU:

requests.cpu: 250m

-> linux.resources.cpu.shares = 256

(1000m = 1024 shares 기준)

limits.cpu: 500m

-> linux.resources.cpu.quota = 50000

linux.resources.cpu.period = 100000

(500m/1000m * 100000us)

Memory:

limits.memory: 512Mi

-> linux.resources.memory.limit = 536870912

(바이트 단위)

requests.memory:

-> 스케줄링에만 사용, OCI 스펙에 반영하지 않음

Hugepages:

limits.hugepages-2Mi: 100Mi

-> linux.resources.hugepageLimits:

pageSize: "2MB"

limit: 104857600

3.3 보안 컨텍스트 변환

SecurityContext -> OCI 스펙 변환:

runAsUser: 1000

-> process.user.uid = 1000

runAsGroup: 1000

-> process.user.gid = 1000

readOnlyRootFilesystem: true

-> root.readonly = true

privileged: true

-> 모든 capabilities 부여

-> 모든 디바이스 접근 허용

-> AppArmor/SELinux/Seccomp 비활성화

capabilities:

add: ["NET_ADMIN"]

drop: ["ALL"]

-> process.capabilities 설정

seccompProfile:

type: RuntimeDefault

-> linux.seccomp 프로파일 적용

4. 스트리밍 API

4.1 ExecSync

ExecSync 동작:

동기적으로 컨테이너에서 명령 실행:

1. kubelet이 ExecSync(containerID, cmd, timeout) 호출

|

v

2. containerd가 shim에 Exec 요청

|

v

3. shim이 runc exec 실행

- 컨테이너 네임스페이스에 새 프로세스 생성

|

v

4. stdout/stderr 캡처

|

v

5. 프로세스 종료 대기

|

v

6. exit code + stdout + stderr 반환

사용 사례: liveness/readiness probe, kubectl exec (동기)

4.2 Exec (비동기 스트리밍)

Exec 스트리밍 동작:

1. kubelet이 Exec(containerID, cmd, stdin, stdout, stderr) 호출

|

v

2. containerd가 스트리밍 URL 반환

- 스트리밍 서버 주소: https://node:10250/exec/...

|

v

3. kubelet이 클라이언트에 URL 전달

|

v

4. 클라이언트가 WebSocket/SPDY로 스트리밍 서버 연결

|

v

5. 스트리밍 서버가 containerd에 실제 Exec 수행

|

v

6. stdin/stdout/stderr 양방향 스트리밍

스트리밍 프로토콜:

- SPDY (레거시)

- WebSocket (최신)

4.3 Attach

Attach 동작:

실행 중인 컨테이너의 메인 프로세스에 연결:

1. 스트리밍 URL 생성 (Exec와 유사)

|

v

2. 컨테이너의 stdin/stdout/stderr에 연결

- 새 프로세스를 생성하지 않음

- 기존 프로세스의 I/O에 직접 연결

|

v

3. 양방향 스트리밍

사용 사례: kubectl attach

4.4 PortForward

PortForward 동작:

Pod의 포트에 로컬 트래픽 전달:

1. 스트리밍 URL 생성

|

v

2. Pod의 네트워크 네임스페이스에서 socat/nsenter 실행

- 지정 포트에 TCP 연결

|

v

3. 로컬 포트와 Pod 포트 간 양방향 데이터 전달

구현:

containerd는 Pod의 네트워크 네임스페이스에 진입하여

대상 포트에 TCP 연결을 생성합니다.

사용 사례: kubectl port-forward

5. RuntimeClass

5.1 RuntimeClass 매핑

RuntimeClass 처리:

1. Kubernetes RuntimeClass 리소스:

apiVersion: node.k8s.io/v1

kind: RuntimeClass

metadata:

name: kata

handler: kata

2. kubelet이 CRI RunPodSandbox 호출 시

runtime_handler = "kata" 전달

3. containerd가 handler를 런타임 설정에 매핑:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata]

runtime_type = "io.containerd.kata.v2"

4. 해당 shim 바이너리로 Task 생성:

containerd-shim-kata-v2

5.2 기본 런타임

기본 런타임 설정:

[plugins."io.containerd.grpc.v1.cri".containerd]

default_runtime_name = "runc"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]

runtime_type = "io.containerd.runc.v2"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]

SystemdCgroup = true

Pod에 runtimeClassName이 없으면 기본 런타임(runc) 사용

5.3 RuntimeClass별 오버헤드

RuntimeClass 리소스 오버헤드:

apiVersion: node.k8s.io/v1

kind: RuntimeClass

metadata:

name: kata

handler: kata

overhead:

podFixed:

memory: "160Mi"

cpu: "250m"

오버헤드 처리:

- kubelet이 Pod 리소스에 오버헤드를 추가

- 스케줄러가 오버헤드를 포함하여 노드 선택

- VM 기반 런타임의 고정 비용 반영

6. NRI (Node Resource Interface)

6.1 NRI 개요

NRI는 containerd의 플러그인 확장 메커니즘으로, 컨테이너 생명주기 이벤트에 훅을 등록할 수 있습니다:

NRI 아키텍처:

kubelet -> containerd

|

+-- NRI Plugin 1 (리소스 할당)

+-- NRI Plugin 2 (토폴로지 인식)

+-- NRI Plugin 3 (모니터링)

NRI 플러그인은 컨테이너 생명주기 이벤트를 수신하고

OCI 스펙을 수정할 수 있습니다.

6.2 NRI 훅 포인트

NRI 훅 포인트:

1. RunPodSandbox:

- Pod 생성 시 호출

- Pod 레벨 리소스 할당

2. CreateContainer:

- 컨테이너 생성 시 호출

- OCI 스펙 수정 가능

- CPU 핀닝, 메모리 NUMA 할당 등

3. StartContainer:

- 컨테이너 시작 시 호출

4. UpdateContainer:

- 리소스 업데이트 시 호출

5. StopContainer:

- 컨테이너 중지 시 호출

- 리소스 해제

6. RemoveContainer:

- 컨테이너 삭제 시 호출

6.3 NRI 사용 사례

NRI 활용 사례:

1. CPU/메모리 토폴로지 인식 할당:

- NUMA 노드 인식 CPU 핀닝

- 메모리를 특정 NUMA 노드에 할당

- 토폴로지 매니저와 연동

2. 디바이스 리소스 관리:

- GPU 할당 최적화

- RDMA 리소스 관리

- 디바이스 플러그인 보완

3. 보안 정책 적용:

- 동적 Seccomp 프로파일

- 런타임 보안 규칙 주입

4. 모니터링/감사:

- 컨테이너 시작/종료 이벤트 로깅

- 리소스 사용 추적

7. 이미지 서비스

7.1 이미지 Pull

CRI PullImage 처리:

1. kubelet이 PullImage(imageSpec, authConfig) 호출

|

v

2. containerd가 이미지 참조 해석

- 태그 또는 다이제스트

- 레지스트리 인증 정보 적용

|

v

3. 이미지 다운로드

- Manifest, Config, Layers

- k8s.io 네임스페이스에 저장

|

v

4. 레이어 언패킹

- Snapshotter로 스냅샷 체인 생성

|

v

5. 이미지 참조(imageRef) 반환

7.2 이미지 캐싱

이미지 캐싱:

containerd의 이미지 캐싱:

- Content Store에 레이어가 이미 존재하면 다운로드 건너뜀

- Snapshotter에 스냅샷이 이미 존재하면 언패킹 건너뜀

- 다이제스트 기반 정확한 중복 제거

kubelet의 이미지 정책:

imagePullPolicy: Always

-> 항상 레지스트리 매니페스트 확인 (레이어는 캐시 활용)

imagePullPolicy: IfNotPresent

-> 로컬에 없을 때만 Pull

imagePullPolicy: Never

-> 로컬 이미지만 사용

8. 모니터링과 디버깅

8.1 CRI 메트릭

containerd CRI 관련 메트릭:

container_runtime_cri_operations_total: CRI 연산 수

container_runtime_cri_operations_errors_total: CRI 연산 오류 수

container_runtime_cri_operations_latency_seconds: CRI 연산 지연

containerd 내부 메트릭:

containerd_task_count: 실행 중인 Task 수

containerd_container_count: 컨테이너 수

containerd_image_pull_duration_seconds: 이미지 Pull 소요 시간

8.2 디버깅 도구

디버깅 도구:

1. crictl (CRI CLI):

crictl ps # 컨테이너 목록

crictl pods # Pod 목록

crictl images # 이미지 목록

crictl inspect CONTAINER_ID # 컨테이너 상세

crictl logs CONTAINER_ID # 컨테이너 로그

crictl exec -it CONTAINER_ID /bin/sh # exec

2. ctr (containerd CLI):

ctr -n k8s.io containers list

ctr -n k8s.io tasks list

ctr -n k8s.io images list

3. containerd 로그:

journalctl -u containerd -f

9. 정리

containerd의 CRI 구현은 Kubernetes와 컨테이너 런타임 사이의 핵심 인터페이스입니다. Pod Sandbox를 통한 Pod 수준의 격리, CRI 요청에서 OCI 스펙으로의 정확한 변환, WebSocket/SPDY 기반 스트리밍, RuntimeClass를 통한 다중 런타임 지원, NRI를 통한 유연한 확장이 주요 특징입니다. 이러한 계층화된 설계로 containerd는 Kubernetes의 안정적인 컨테이너 런타임으로 자리매김하고 있습니다.

현재 단락 (1/354)

containerd는 Kubernetes CRI(Container Runtime Interface)를 내장 플러그인으로 구현합니다. 이 글에서는 CRI gRPC 서비스의 구현 상세...

작성 글자: 0원문 글자: 6,624작성 단락: 0/354