Skip to content
Published on

containerd 네트워킹과 스토리지

Authors

containerd 네트워킹과 스토리지

containerd는 네트워킹과 스토리지를 직접 구현하지 않고 표준 인터페이스를 통해 외부 플러그인과 통합합니다. 이 글에서는 CNI를 통한 네트워크 구성, 네임스페이스 관리, 볼륨 마운트, 디바이스 접근, 보안 모듈 통합을 분석합니다.


1. CNI 통합

1.1 CNI 개요

Container Network Interface(CNI)는 컨테이너 네트워킹의 표준 인터페이스입니다. containerd는 CNI 플러그인을 호출하여 네트워크를 구성합니다.

CNI 호출 흐름:

kubelet -> containerd (CRI RunPodSandbox)
                |
                v
        네트워크 네임스페이스 생성
                |
                v
        CNI 플러그인 호출
        (ADD 명령)
                |
                v
        IP 할당, 라우팅 설정, 인터페이스 생성
                |
                v
        결과를 containerd에 반환

1.2 CNI 설정

CNI 설정 파일 위치:
  설정 디렉토리: /etc/cni/net.d/
  바이너리 디렉토리: /opt/cni/bin/

containerd CNI 설정 (config.toml):
  [plugins."io.containerd.grpc.v1.cri".cni]
    bin_dir = "/opt/cni/bin"
    conf_dir = "/etc/cni/net.d"
    max_conf_num = 1

1.3 CNI 플러그인 체인

CNI 설정 예시 (10-calico.conflist):

네트워크 구성은 플러그인 체인으로 정의:

1. 메인 플러그인 (calico, cilium, flannel 등):
   - 네트워크 인터페이스 생성
   - IP 할당 (IPAM)
   - 라우팅 규칙 설정

2. 메타 플러그인 (bandwidth, portmap 등):
   - 대역폭 제한
   - 포트 매핑
   - 방화벽 규칙

실행 순서:
  ADD: 메인 -> 메타 플러그인 (순방향)
  DEL: 메타 -> 메인 플러그인 (역방향)

1.4 CNI 호출 과정

CNI ADD 실행 상세:

1. containerd가 네트워크 네임스페이스 경로 결정
   /var/run/netns/cni-abc123

2. CNI 환경 변수 설정:
   CNI_COMMAND=ADD
   CNI_CONTAINERID=abc123
   CNI_NETNS=/var/run/netns/cni-abc123
   CNI_IFNAME=eth0
   CNI_PATH=/opt/cni/bin

3. CNI 플러그인 바이너리 실행
   stdin으로 설정 JSON 전달

4. 플러그인이 stdout으로 결과 반환:
   - 할당된 IP 주소
   - 게이트웨이 주소
   - DNS 설정
   - 라우팅 정보

5. containerd가 결과를 저장

2. 네트워크 네임스페이스

2.1 네임스페이스 생성

Pod 네트워크 네임스페이스:

Pod Sandbox 생성 시:
1. unshare(CLONE_NEWNET)으로 새 네트워크 네임스페이스 생성
2. /var/run/netns/ 에 바인드 마운트로 영구화
3. 해당 네임스페이스에서 CNI 플러그인 실행
4. Pod의 모든 컨테이너가 이 네임스페이스를 공유

네임스페이스 공유:
  Pause 컨테이너가 네트워크 네임스페이스를 보유
  App 컨테이너가 같은 네임스페이스에 참여
  -> Pod 내 컨테이너가 localhost로 통신 가능

2.2 네임스페이스 정리

네임스페이스 정리:

Pod 삭제 시:
1. CNI DEL 명령으로 네트워크 리소스 해제
   - IP 주소 반환
   - 인터페이스 삭제
   - 라우팅 규칙 제거
2. /var/run/netns/ 에서 바인드 마운트 해제
3. 네트워크 네임스페이스 자동 삭제

3. 볼륨 마운트

3.1 마운트 타입

containerd는 OCI 스펙의 마운트 구성을 통해 볼륨을 관리합니다:

마운트 타입:

1. bind 마운트:
   - 호스트 파일/디렉토리를 컨테이너에 마운트
   - 호스트와 컨테이너가 동일 데이터 공유
   - ConfigMap, Secret, emptyDir 등에 사용

2. tmpfs 마운트:
   - 메모리 기반 파일시스템
   - 컨테이너 종료 시 데이터 소멸
   - /dev/shm, /run 등에 사용

3. 특수 파일시스템:
   - proc: /proc
   - sysfs: /sys
   - cgroup: /sys/fs/cgroup
   - devpts: /dev/pts

3.2 마운트 전파

마운트 전파(Propagation) 옵션:

1. private:
   - 마운트 이벤트 전파 없음
   - 기본값

2. rprivate:
   - 재귀적 private

3. shared:
   - 마운트 이벤트를 양방향 전파
   - 호스트에서 마운트 -> 컨테이너에서도 보임
   - 컨테이너에서 마운트 -> 호스트에서도 보임

4. rshared:
   - 재귀적 shared

5. slave:
   - 호스트 -> 컨테이너 단방향 전파
   - 볼륨 플러그인에 유용

6. rslave:
   - 재귀적 slave

Kubernetes에서의 사용:
  - MountPropagation 필드로 제어
  - CSI 드라이버는 주로 Bidirectional (shared) 사용

3.3 CRI 볼륨 처리

CRI를 통한 볼륨 처리:

kubelet이 OCI 스펙에 마운트를 추가:

1. emptyDir:
   - kubelet이 호스트에 디렉토리 생성
   - bind 마운트로 컨테이너에 전달

2. hostPath:
   - 호스트 경로를 직접 bind 마운트

3. ConfigMap/Secret:
   - kubelet이 tmpfs에 데이터 생성
   - bind 마운트로 컨테이너에 전달

4. PersistentVolumeClaim:
   - kubelet이 CSI 드라이버를 통해 볼륨 마운트
   - 마운트된 경로를 bind 마운트로 전달

containerd의 역할:
  - kubelet이 준비한 마운트 정보를 OCI 스펙에 반영
  - runc가 실제 마운트 수행

4. 디바이스 접근

4.1 디바이스 매핑

디바이스 접근 메커니즘:

OCI 스펙의 devices 섹션:
  linux:
    devices:
      - path: "/dev/nvidia0"
        type: "c"
        major: 195
        minor: 0
        fileMode: 438
        uid: 0
        gid: 0

cgroup 디바이스 접근 제어:
  linux:
    resources:
      devices:
        - allow: true
          type: "c"
          major: 195
          access: "rwm"

4.2 GPU 지원

GPU 접근 (NVIDIA):

NVIDIA Container Toolkit 통합:

1. nvidia-container-runtime-hook:
   - OCI 런타임 훅으로 동작
   - 컨테이너 시작 전에 실행
   - NVIDIA 드라이버 라이브러리를 컨테이너에 마운트
   - GPU 디바이스 노드를 컨테이너에 추가

2. CDI (Container Device Interface):
   - 디바이스 벤더 중립적 표준
   - /etc/cdi/ 에 디바이스 스펙 정의
   - containerd가 CDI 스펙을 읽어 OCI 스펙에 반영

CDI 스펙 예시:
  cdiVersion: "0.5.0"
  kind: "nvidia.com/gpu"
  devices:
    - name: "0"
      containerEdits:
        deviceNodes:
          - path: "/dev/nvidia0"
        mounts:
          - hostPath: "/usr/lib/x86_64-linux-gnu/libnvidia-ml.so"
            containerPath: "/usr/lib/x86_64-linux-gnu/libnvidia-ml.so"

4.3 기타 디바이스

기타 디바이스 접근:

1. FPGA:
   - CDI 스펙으로 FPGA 디바이스 노출
   - 벤더별 디바이스 플러그인

2. InfiniBand/RDMA:
   - /dev/infiniband/* 디바이스 매핑
   - 네트워크 디바이스 네임스페이스 공유

3. 시리얼/USB:
   - 호스트 디바이스 직접 매핑
   - privileged 모드 또는 명시적 디바이스 허용

5. SELinux 통합

5.1 SELinux 컨텍스트

SELinux 컨테이너 보안:

OCI 스펙의 SELinux 설정:
  linux:
    mountLabel: "system_u:object_r:container_file_t:s0:c1,c2"
    processLabel: "system_u:system_r:container_t:s0:c1,c2"

구성 요소:
  - user: system_u
  - role: system_r (프로세스) / object_r (파일)
  - type: container_t (프로세스) / container_file_t (파일)
  - level: s0:c1,c2 (MCS 카테고리)

MCS (Multi-Category Security):
  - 각 컨테이너에 고유 카테고리 할당
  - 다른 컨테이너의 파일에 접근 불가
  - 호스트와 컨테이너 간 격리

5.2 SELinux 처리 흐름

SELinux 적용:

1. kubelet이 Pod의 SELinux 옵션 결정
   - securityContext.seLinuxOptions
   - 자동 MCS 라벨 할당

2. CRI를 통해 containerd에 전달
   - processLabel: 프로세스 보안 컨텍스트
   - mountLabel: 파일 보안 컨텍스트

3. containerd가 OCI 스펙에 반영

4. runc가 실행 시:
   - 프로세스에 SELinux 라벨 적용
   - rootfs에 SELinux 라벨 적용
   - 마운트에 SELinux 라벨 적용

6. AppArmor 통합

6.1 AppArmor 프로파일

AppArmor 컨테이너 보안:

기본 프로파일: cri-containerd.apparmor.d

주요 규칙:
  - 파일시스템 접근 제한
    deny /proc/kcore r,
    deny /sys/firmware/** r,
  - 네트워크 접근 제어
  - 능력(capability) 제한
  - 마운트 연산 제한

프로파일 적용:
  OCI 스펙:
    process:
      apparmorProfile: "cri-containerd.apparmor.d"

6.2 커스텀 프로파일

커스텀 AppArmor 프로파일:

1. 호스트에 프로파일 설치:
   /etc/apparmor.d/ 에 프로파일 파일 배치
   apparmor_parser -r /etc/apparmor.d/my-profile

2. Pod에서 지정:
   annotations:
     container.apparmor.security.beta.kubernetes.io/app: localhost/my-profile

3. containerd가 OCI 스펙에 반영:
   process:
     apparmorProfile: "my-profile"

7. Seccomp 통합

7.1 Seccomp 프로파일

Seccomp (Secure Computing):

허용/차단할 시스템 콜을 정의:

기본 동작: SCMP_ACT_ERRNO (거부)

허용 시스템 콜 예시:
  - read, write, open, close
  - mmap, mprotect, munmap
  - socket, connect, accept
  - ...

차단 시스템 콜 예시:
  - mount, umount (컨테이너 탈출 방지)
  - reboot
  - kexec_load
  - ptrace (일부 환경)

7.2 Seccomp 적용

Seccomp 프로파일 적용:

1. Kubernetes SecurityContext:
   securityContext:
     seccompProfile:
       type: RuntimeDefault

2. RuntimeDefault 프로파일:
   - containerd/runc 기본 Seccomp 프로파일
   - 위험한 시스템 콜 차단
   - 대부분의 워크로드에 적합

3. 커스텀 프로파일:
   securityContext:
     seccompProfile:
       type: Localhost
       localhostProfile: "profiles/my-seccomp.json"

8. 정리

containerd의 네트워킹과 스토리지는 표준 인터페이스를 통한 위임 모델을 따릅니다. CNI를 통한 네트워크 구성, OCI 스펙을 통한 마운트 관리, CDI를 통한 디바이스 접근, SELinux/AppArmor/Seccomp를 통한 보안 격리가 핵심입니다. 이러한 표준 기반 설계로 containerd는 다양한 네트워킹 솔루션과 보안 모듈을 유연하게 통합합니다. 다음 글에서는 containerd의 CRI 구현과 Kubernetes 런타임 통합을 분석합니다.