"Everything about infra" 2026. 3. 20. 02:30
포스팅은 CloudNet@팀 서종호(Gasida)님이 진행하시는
AWS EKS Workshop Study 내용을 참고하여 작성합니다.

 

안녕하세요!

 

오늘은 도전과제인 eks와 vanilla k8s 간

control plane, data plane을 비교해보는 시간을 갖도록 하겠습니다.

 

 

01. vanilla k8s 란?

처음 도전과제를 읽어보았을 때 왜 바닐라일까? 라는 생각이 가장 먼저 들었습니다.

 

찾아보다가.. 제가 생각한게 맞았듯이 아이스크림에서 온 비유라고 하네요.

"아이스크림 가게에서 가장 기본이 되는 맛, 바닐라"가 맞다고 합니다.

 

즉, Vanilla는 제조사가 배포한 원본 그대로, 아무 커스터마이징도 없는 상태를 뜻한다고 합니다.

그렇다면 확실히 EKS는 AWS사가 자사 인프라에 맞게 패치하고 통합한 k8s 배포판이니 반대 개념이네요.

 

📌 vanilla = on-prem ?

그렇다면 온프렘 아닌가 라고 생각이 드셨겠지만 조금 더 생각해 보았을 때

클라우드 환경에서 EC2 서버를 올리고, 거기에 self-managed로 구축하면 컨트롤 플레인까지

저희가 관리를 해야하니 이게 vanilla k8s를 뜻하는게 아닌가? 라고 생각해보았습니다.

 

그래서 아래와 같은 결론이 내려졌습니다.

  • vanilla k8s : 물리 서버든 클라우드 환경이든 kubeadm 으로 설치하여 직접 컨트롤플레인 까지 관리.
  • EKS : 클라우드 환경에서 컨트롤 플레인은 AWS에서 관리.

클라우드 환경 위에 올렸다고 해서 자동으로 관리형이 되는게 아니라, 어떤 배포판을 썼느냐

AWS가 얼마나 관여하느냐가 관리형 여부를 결정한다고 마무리 짓도록 하겠습니다.

 


02. vanilla k8s vs EKS

vanilla k8s에서 control plane은 직접 구성하고 관리해야 하는 컴포넌트들의 묶음입니다.

 

컨트롤 플레인 비교

control plane의 구성은 아래와 같습니다.

  • kube-apiserver : 클러스터의 유일한 진입점. 모든 컴포넌트는 서로 직접 통신하지 않고 전부 apiserver를 거침
    • 모든 컴포넌트라 함은 scheduler, cm, kubelet, kubectl 등..
    • REST API를 제공하고, 요청마다 인증 → 인가 → Admission Control 세 단계를 순서대로 통과시킵니다.

 

  • etcd : 클러스터의 유일한 데이터 저장소. 모든 오브젝트의 상태가 여기에 저장된다고 보시면 됩니다.
    • 모든 오브젝트라고 함은 Pod, Service, ConfigMap, Secret 등..
    • apiserver만 etcd에 직접 접근하고, 나머지 컴포넌트들은 apiserver를 통해서만 데이터를 읽고 씁니다.
    • Raft 합의 알고리즘을 사용하는 분산 KV 스토어라고도 합니다.

 

  • kube-scheduler : 새로 생성된 Pods를 어느 노드에 배치할지 결정하는 컴포넌트 입니다.
    • etcd에 nodeName이 비어있는 Pod가 생기면 스케줄러가 감지하고, Filtering(배치 불가 노드 제거) → Scoring(최적 노드 점수화) → Binding(nodeName 기록) 순서로 처리합니다.

 

  • kube-controller-manager : 다양한 컨트롤러들을 하나의 프로세스로 묶어 실행하는 컴포넌트 입니다.
    • Node Controller (노드 장애 감지), Replicaset Controller(Pod 수 유지) 등 수십 개의 컨트롤러가 동작

 

위 내용들을 가지고 도식화를 해보자면 그림과 같습니다 (apiserver 중심)

 

vanilla k8s는 이런 컨트롤 플레인의 구성들을 직접 관리해야 합니다.

추가적으로 위 구성들을 어떤 노드에 올릴지, HA구성을 어떻게 할지, 인증서 갱신은 어떻게 처리할지,

버전 업그레이드는 어떻게 할지 전부 사용자 책임입니다.

 

EKS는 스터디 하면서 잘 아시다 싶이 컨트롤 플레인 전체가 AWS Managed VPC 관리 영역으로 빠집니다.

사용자는 Control Plane 노드 자체를 볼 수도 없고, etcd backup이나 apiserver HA 구성에

신경 쓸 필요도 없습니다. (AWS가 알아서 Multi-AZ에 Control Plane을 배치하고, 장애 시 자동 복구)

위의 내용을 도식화 해보았을 때 확실히 사용자가 까다롭게 관리해야 할 것 같습니다만,

커스터마이징이 자유로워 사내 보안 규정에 맞게 잘 관리가 될 것 같기도 합니다.

 

데이터플레인 비교

vanilla k8s는 data plane 까지도 직접 구성한 EC2(또는 베어메탈, VM) 위에 올리고

kubelet, kube-proxy, CNI 플러그인도 직접 설치 및 관리를 해야 합니다.

 

반면에 EKS는 add-on 기능을 사용하여 쉽게 구성이 가능하며, 관리도 용이합니다 !

 

EKS에 대해서 학습할 때 데이터플레인은 많이 뜯어봤기 때문에 자세한 설명은 생략하고,

 

EKS에서 add-on으로 vpc-cni를 사용했었는데 여기에선 Calico, Cilium, Flannel에 대해서

간단하게 나마 알아보는 시간을 갖도록 하겠습니다.

 

📌 CNI (Container Network Interface) Plugin

k8s는 네트워킹 구현을 직접 제공하지 않습니다.

"Pod끼리 통신할 수 있어야 한다", "Pod에 IP가 할당되어야 한다"는 스펙만 정의하고, 구현은 CNI에 위임.

 

vanilla k8s를 설치하면 CNI가 없는 상태로 시작하기 때문에 클러스터 관리자가 직접 골라서 설치해야함.

 

1) Flaneel : 가장 단순한 오버레이 네트워크 방식

  • 노드 간 트래픽을 VXLAN으로 캡슐화해서 전달합니다.
  • 설정이 거의 없어서 학습용이나 간단한 스테이징, 개발 환경에 적합하지만 Network Policy를 미지원.

 

2) Calico : BGP 라우팅 기반으로 동작합니다.

  • 오버레이 없이 실제 라우팅 테이블을 조작하기 때문에 성능이 좋고, Network Policy를 지원함.
  • 대규모 프로덕션 환경에서 가장 많이 선택되는 CNI 중 하나입니다.

 

3) Cilium : eBPF를 기반으로 동작합니다.

  • 커널 레벨에서 패킷을 처리하기 때문에 성능이 뛰어나고, L7 수준의 네트워크 정책, Service Mesh 기능 제공
  • 복잡하지만 현재 가장 활발하게 발전중인 CNI라고 합니다.

 

각 CNI마다 특징이 다르지만, 핵심은 명확합니다. "다른 노드에 있는 Pod끼리 어떻게 통신하게 만들 것인가?" 

이걸 해결하는 방식이 크게 오버레이(VXLAN) vs 언더레이(BGP / Calico)로 나뉩니다.

이 내용은 2주차의 EKS 네트워킹 중, CNI 동작 과정에서 딥하게 다뤄볼 예정입니다.

간단하게 말씀드리자면, 인캡슐레이션 디캡슐레이션 시 사용되는 리소스에 대한 오버헤드 차이 입니다.

 


03. sample application 배포

📌 kube-ops-view install

클러스터의 노드와 파드 상태를 실시간으로 시각화 해주는 대쉬보드를 설치해 볼 예정입니다.

# 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 \
  --set 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 접속
open "http://$NODE1:30000/#scale=1.5"
open "http://$NODE1:30000/#scale=1.3"

위 helm 차트에서 kube-ops-view를 가져올 때 명령어를 잠깐 살펴보도록 하겠습니다.

service.main.type=NodePort : 외부에서 노드IP로 직접 접근할 수 있게 NodePort 방식으로 서비스를 연다.
service.main.ports.http.nodeport=30000 : NodePort 번호를 30000으로 고정한다.
(지정을 안하게 되면 30000~32767 사이에서 랜덤으로 배정됨)
--namespace kube-system : kube-ops-view가 클러스터 전체 상태를 읽어야 하기 때문에 kube-system에 설치.

 

위 명령으로 서비스를 띄운 후 pod, service, endpoint 까지 확인할 수 있습니다.

 

실제로 데쉬보드 형태로 보았을 때 아래와 같이 테스트 환경에서 파드 상태를 확인하기 좋습니다.

 

📌 게임 파드 배포 by nodePort 30001

# 샘플 애플리케이션 배포
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mario
  labels:
    app: mario
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mario
  template:
    metadata:
      labels:
        app: mario
    spec:
      containers:
      - name: mario
        image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
   name: mario
spec:
  selector:
    app: mario
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
    nodePort: 30001
  type: NodePort
EOF

# 확인
kubectl get deploy,pod,svc,ep

# 접속
curl http://$NODE1:30001 -I
open http://$NODE1:30001

위 yaml 파일을 배포하였을 때 아래와 같이 서비스들을 확인할 수 있습니다.

서비스에 대해서 아래와 같이 간단하게 설명하도록 하겠습니다.

service/mario -> 80:30001/TCP
 - 80은 서비스 내부 포트, 30001은 외부에서 접근하는 NodePort 이므로 http://$NODE1:30001로 접근
 - 서비스가 192.168.1.230:8080 (mario Pod)으로 트래픽을 전달합니다.

게임 파드를 띄워서 마리오 게임을 오랜만에 해보았는데 재밌었습니다!

 


 

긴 글 읽어주셔서 감사합니다.