Kubernetes 확장 포인트 세 가지: CNI, CRI, CRD

mizu·2026년 8월 30일

K8S

목록 보기
10/11

Overview

Kubernetes를 공부하다 보면 CNI, CRI, CRD 같은 약어가 자주 나온다. 이름은 비슷하지만 서로 다른 층의 개념이다.

  • CNI는 Pod network를 만드는 쪽에 가깝고,
  • CRI는 kubelet이 container runtime과 대화하는 인터페이스다.
  • CRD는 Kubernetes API 자체를 확장해서 새로운 resource kind를 추가하는 방법이다.

한 문장으로 나누면 이렇게 볼 수 있다.

CNI: Pod network를 연결한다.
CRI: kubelet이 container runtime으로 Pod와 container를 실행한다.
CRD: Kubernetes API에 새로운 resource type을 추가한다.

이 세 가지는 모두 Kubernetes의 확장성과 관련 있지만, 같은 위치에서 동작하지 않는다. CNI와 CRI는 node에서 Pod가 실제로 뜨는 과정에 가깝고, CRD는 API server에서 새로운 Kubernetes resource를 다루게 만드는 쪽에 가깝다.

참고 문서:

CNI

CNI는 Container Network Interface의 약자다. Kubernetes에서는 Pod network를 구현하려면 CNI plugin이 필요하다. Kubernetes 공식 문서는 CNI plugin이 Kubernetes network model을 구현해야 한다고 설명한다.

Pod가 node에 scheduled되면 container runtime은 Pod sandbox를 만들고 network plugin을 통해 Pod network를 구성한다. 이때 CNI plugin은 Pod에 network interface를 붙이고, IP를 할당하고, Pod 간 통신이 가능하도록 network path를 만든다. Calico, Cilium, Flannel 같은 도구가 이 층에 들어간다.

간단히 그리면 이렇다.

Pod 생성
  -> node에 scheduling
    -> container runtime이 Pod sandbox 준비
      -> CNI plugin이 Pod network 구성
        -> Pod IP 할당
        -> Pod 간 통신 가능

CNI 문제가 있으면 Pod가 ContainerCreating에 오래 머물거나, Pod끼리 통신하지 못하거나, NetworkPolicy가 기대대로 적용되지 않을 수 있다. network plugin마다 troubleshooting 방법은 다르지만, 공통적으로는 Pod 상태, Events, node의 CNI 설정, CNI plugin Pod 상태를 본다.

kubectl get pod -A -o wide
kubectl get events -A --sort-by=.lastTimestamp
kubectl get pod -n kube-system

CNI는 Service보다 낮은 층에 있다. Service, Ingress, NetworkPolicy가 Kubernetes networking resource라면, CNI plugin은 그 network model이 실제 cluster에서 동작하도록 밑바닥을 구현한다.

CRI

CRI는 Container Runtime Interface의 약자다. kubelet이 container runtime과 통신할 때 사용하는 표준 인터페이스다. Kubernetes 공식 문서는 CRI를 kubelet과 container runtime 사이의 주요 gRPC protocol로 설명한다.

Kubernetes는 container를 직접 실행하지 않는다. 각 node의 kubelet이 container runtime에 요청해서 Pod와 container를 실행한다. containerd, CRI-O 같은 runtime이 이 역할을 한다.

흐름은 다음과 같다.

API server에 Pod 생성
  -> scheduler가 node 선택
    -> kubelet이 Pod spec 확인
      -> CRI로 container runtime에 요청
        -> image pull
        -> container 생성과 실행

CRI 문제가 있으면 node가 Ready가 아니거나, kubelet이 runtime에 연결하지 못하거나, image pull과 container 생성 단계에서 장애가 날 수 있다. Kubernetes v1.26 이후 kubelet은 container runtime이 CRI v1 API를 지원해야 한다. runtime이 이를 지원하지 않으면 kubelet이 node를 등록하지 못한다.

현장에서 CRI를 확인할 때는 kubelet과 runtime 상태를 함께 본다.

kubectl get node -o wide
kubectl describe node <node-name>
crictl ps
crictl images

docker ps가 아니라 crictl을 쓰는 이유도 여기서 나온다. Kubernetes 관점에서는 kubelet이 CRI를 통해 runtime과 대화하므로, troubleshooting도 CRI 관점의 도구가 더 직접적이다.

CRD

CRD는 CustomResourceDefinition의 약자다. Kubernetes API에 새로운 resource type을 추가하는 방법이다. 공식 문서에 따르면 CRD를 사용하면 별도의 custom API server를 작성하지 않고도 새로운 API group, kind, schema를 선언할 수 있다.

예를 들어 Argo CD의 Application, cert-manager의 Certificate, Gateway API의 GatewayHTTPRoute 같은 resource는 built-in Kubernetes resource가 아니다. 이런 도구들은 CRD를 설치해서 Kubernetes API가 새로운 kind를 이해하게 만든다.

구조는 이렇게 볼 수 있다.

CRD 설치
  -> Kubernetes API server가 새 kind를 인식
    -> 사용자가 custom resource 생성
      -> controller가 custom resource를 watch
        -> 실제 Kubernetes 리소스 생성 또는 외부 작업 수행

CRD 자체는 API type을 추가한다. 실제 동작은 보통 controller가 맡는다. 예를 들어 Application CRD만 있다고 Argo CD 배포가 자동으로 굴러가는 것은 아니다. Argo CD controller가 Application resource를 watch하고 sync 동작을 수행해야 한다.

CRD가 없으면 custom resource manifest를 적용할 때 API server가 해당 kind를 모른다.

error: resource mapping not found for name: "<name>" namespace: "<namespace>" from "<file>": no matches for kind "<Kind>" in version "<group>/<version>"

이 경우에는 custom resource보다 CRD 설치 여부를 먼저 확인해야 한다.

kubectl get crd
kubectl get crd | grep <keyword>
kubectl api-resources | grep <kind-or-group>

세 개를 한 흐름으로 보기

Pod 하나가 뜨고, 그 Pod를 어떤 controller가 관리한다고 생각해보면 CNI, CRI, CRD의 위치가 나뉜다.

CRD
  -> Kubernetes API에 새 resource kind 추가
  -> controller가 custom resource를 보고 desired state 처리

CRI
  -> kubelet이 container runtime에 Pod/container 실행 요청

CNI
  -> Pod sandbox에 network 연결
  -> Pod IP와 Pod 간 통신 구성

예를 들어 Argo CD Application을 만들면 Application은 CRD가 추가한 custom resource다. Argo CD controller는 이 resource를 보고 Deployment나 Service 같은 manifest를 cluster에 적용한다. 그 결과 Pod가 생기면 kubelet은 CRI를 통해 container runtime에 실행을 요청하고, CNI plugin은 Pod network를 구성한다.

Application CRD
  -> Argo CD controller
    -> Deployment 생성
      -> Pod 생성
        -> kubelet + CRI
          -> container runtime
            -> CNI
              -> Pod network

이렇게 보면 세 약어가 서로 경쟁하는 개념이 아니라 서로 다른 층을 맡는다는 점이 보인다.

자주 헷갈리는 경계

CNI와 Service는 다르다. CNI는 Pod network를 구현하는 plugin이고, Service는 Pod 앞에 안정적인 접근 지점을 제공하는 Kubernetes resource다. Service traffic도 결국 Pod network 위에서 움직이므로 CNI가 망가지면 Service도 정상 동작하기 어렵다.

CRI와 container runtime도 구분해야 한다. CRI는 인터페이스이고, containerd나 CRI-O는 그 인터페이스를 구현하는 runtime이다. kubelet은 CRI를 통해 runtime에 요청한다.

CRD와 controller도 분리해서 봐야 한다. CRD는 API server가 새로운 kind를 저장하고 검증할 수 있게 만드는 정의다. controller는 그 custom resource를 보고 실제 행동을 한다.

Troubleshooting 순서

문제 유형에 따라 먼저 볼 곳이 달라진다.

Pod가 ContainerCreating에서 멈추고 network 관련 Events가 보이면 CNI를 의심한다.

kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl get pod -n kube-system

node가 NotReady이거나 kubelet이 container runtime에 연결하지 못한다면 CRI 쪽을 본다.

kubectl describe node <node-name>
crictl ps
crictl info

custom resource apply가 no matches for kind로 실패하면 CRD 설치 여부를 먼저 확인한다.

kubectl get crd
kubectl api-resources | grep <kind>

증상에서 시작해 층을 나누면 조사가 빨라진다. API type이 없는 문제인지, container 실행 문제인지, Pod network 문제인지 분리하는 게 첫 단계다.

정리

CNI, CRI, CRD는 모두 Kubernetes 확장성과 관련 있지만 서로 다른 위치의 개념이다.

  • CNI는 Pod network를 만든다.
  • CRI는 kubelet과 container runtime 사이의 인터페이스다.
  • CRD는 Kubernetes API에 새로운 resource kind를 추가한다.

헷갈릴 때는 “어느 층의 문제인가”를 먼저 묻는 게 좋다.

API server가 kind를 모르면 CRD 문제일 가능성이 크다. kubelet이 container를 못 띄우면 CRI와 runtime을 본다. Pod가 뜨지만 network가 안 되거나 network setup에서 멈추면 CNI를 본다. 약어를 외우는 것보다 이 경계를 잡는 편이 troubleshooting에 훨씬 도움이 된다.

profile
문제를 해결해보자 ✨

0개의 댓글