13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] kubeadm

  • [k8s] Kubeadm vs ClusterAPI: Kubernetes 클러스터 프로비저닝 도구 비교

    [k8s] Kubeadm vs ClusterAPI: Kubernetes 클러스터 프로비저닝 도구 비교

    Kubeadm vs ClusterAPI: Kubernetes 클러스터 프로비저닝 도구 비교

    Kubeadm과 ClusterAPI를 비교할 때, 많은 분들이 같은 지점에서 막혀 있더라고요. “클러스터 하나 빨리 올리면 되는 건가?”, 아니면 “여러 환경에서 반복 가능하게 클러스터 구축 체계를 만들어야 하나?” 같은 고민 말이에요. 저도 홈랩에서 처음엔 kubeadm(쿠버네티스 클러스터 초기화 도구)만으로 시작했었는데, 노드 수가 늘고 재현 가능한 배포가 필요해지니까 Cluster API(CAPI, 쿠버네티스 방식으로 클러스터 자체를 관리하는 프로젝트) 쪽이 갑자기 눈에 들어오더라고요. 처음엔 이게 뭔가 싶었습니다. 컨트롤러도 많고, 프로바이더도 많고, YAML도 길고요. 근데 구조를 한 번 이해하고 나니 왜 운영팀들이 이 조합을 진지하게 보는지 감이 왔습니다.

    이 글에서는 단순히 기능 나열만 하지 않고, Kubeadm vs ClusterAPI를 실제 운영 관점에서 풀어보겠습니다. 쉽게 말해, kubeadm은 클러스터를 시작하게 해주는 공구에 가깝고, ClusterAPI는 클러스터 생애주기 자체를 선언형으로 다루는 운영 프레임워크에 가깝습니다. 여기서 중요한 포인트! 둘은 경쟁 관계이면서도, 실전에서는 같이 엮이는 경우가 꽤 많습니다.

    Kubeadm ClusterAPI 비교를 보여주는 쿠버네티스 클러스터 프로비저닝 아키텍처 이미지

    kubeadm은 개별 클러스터 부트스트랩 흐름에, Cluster API는 관리 클러스터에서 워크로드 클러스터를 선언형으로 제어하는 흐름에 초점이 있습니다.

    Kubernetes 클러스터 프로비저닝, 뭐가 다른가요?

    쉽게 말해 kubeadm은 노드에 들어가서 클러스터를 만드는 도구입니다. 컨트롤 플레인(클러스터 제어 영역) 초기화, 조인 토큰 생성, 인증서 배포 같은 부트스트랩 작업을 잘 해주죠. 반면 Cluster API는 클러스터를 쿠버네티스 리소스처럼 다루는 방식입니다. 즉, “이런 모양의 클러스터를 만들어줘”라고 선언하면 컨트롤러가 그 상태를 맞추려고 움직입니다.

    제가 직접 해보니 kubeadm은 구조가 비교적 단순해서 학습 진입 장벽이 낮았습니다. 특히 베어메탈(가상화 없이 물리 서버 직접 운영)이나 홈랩처럼 손으로 만질 수 있는 환경에서는 진짜 빠릅니다. 반대로 Cluster API는 관리 클러스터(다른 클러스터를 제어하는 클러스터)라는 개념부터 잡아야 해서 초반 허들이 있습니다. 대신 익숙해지면 반복 배포, 업그레이드, 스케일링, 클러스터 폐기까지 흐름이 꽤 깔끔해집니다.

    • kubeadm: 단일 클러스터 프로비저닝에 강함
    • Cluster API: 여러 클러스터의 선언형 운영과 생애주기 관리에 강함
    • CAPI + kubeadm: Cluster API가 kubeadm 기반 부트스트랩을 활용하는 조합이 현실

    Kubeadm vs ClusterAPI 핵심 구조 비교

    비교 항목 kubeadm Cluster API
    주요 목적 쿠버네티스 클러스터 초기 구성 클러스터 생성, 변경, 업그레이드, 삭제까지 생애주기 관리
    운영 방식 명령형(명령 실행 중심) 선언형(원하는 상태 기술)
    주요 실행 위치 대상 노드 관리 클러스터의 컨트롤러
    멀티 클러스터 운영 수동 설계 필요 기본 개념 자체가 멀티 클러스터 친화적
    인프라 연동 직접 구성 필요 Infrastructure Provider(인프라 프로바이더)로 연동
    업그레이드 자동화 운영 스크립트나 절차 설계 필요 버전 선언 후 컨트롤러 기반 롤링 변경 가능
    초기 난이도 상대적으로 낮음 상대적으로 높음

    여기서 중요한 포인트! Cluster API가 kubeadm을 대체하는 느낌으로 보일 수 있는데, 실제로는 Cluster API 안에서 kubeadm bootstrap provider를 사용하는 사례가 많습니다. 즉, kubeadm은 여전히 중요한 구성요소고, Cluster API는 그걸 더 큰 자동화 체계 안에 넣는 느낌이라고 보시면 이해가 편합니다.

    언제 kubeadm이 더 잘 맞을까요?

    • 처음 쿠버네티스 구조를 익히는 단계일 때
    • 노드 수가 적고 클러스터 수가 많지 않을 때
    • 베어메탈이나 제한된 홈랩 환경에서 빠르게 검증할 때
    • 구성 과정을 손으로 제어해야 안심되는 팀 문화일 때

    언제 Cluster API가 빛날까요?

    • 동일한 형태의 클러스터를 반복 생성해야 할 때
    • 개발, 스테이징, 운영 환경을 비슷한 클러스터 구축 템플릿으로 관리할 때
    • 클러스터 업그레이드와 노드 교체를 체계화하고 싶을 때
    • GitOps(Git 기반 선언형 운영)와 잘 엮고 싶을 때

    실전 구현 1: kubeadm으로 클러스터 올리기

    먼저 kubeadm 흐름부터 보겠습니다. 실제로 써보니까 kubeadm은 클러스터 내부 동작을 이해하는 데 정말 좋았습니다. 인증서, kubelet(노드 에이전트), CNI(컨테이너 네트워크 플러그인) 같은 개념이 어디서 필요한지 몸으로 익히게 되거든요. 다만 그만큼 수동 단계도 많습니다. 삽질 좀 했습니다 ㅎㅎ

    1. 런타임(container runtime)과 kubelet, kubeadm, kubectl 설치
    2. 컨트롤 플레인 노드에서 초기화
    3. CNI 설치
    4. 워커 노드 조인
    5. 상태 검증
    sudo kubeadm init \
      --pod-network-cidr=192.168.0.0/16
    
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    kubectl get nodes

    초기화가 끝나면 바로 Ready가 안 뜰 수 있습니다. 여기서 당황 많이 하시더라고요. 대부분은 아직 CNI가 없어서 그렇습니다.

    kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml
    kubectl get pods -A

    워커 노드 조인은 `kubeadm token create –print-join-command`로 받은 명령을 그대로 실행하면 됩니다.

    kubeadm token create --print-join-command

    이 방식의 장점은 명확합니다. 어디서 뭐가 실패하는지 눈에 보입니다. 반대로 단점도 명확해요. 같은 클러스터를 세 번, 네 번 반복해서 만들다 보면 사람이 실수할 지점이 계속 생깁니다. 바로 이 지점에서 “클러스터 구축 도구를 더 선언형으로 가져가야 하나?”라는 생각이 들기 시작하더라고요.

    실전 구현 2: Cluster API로 선언형 클러스터 만들기

    이제 Cluster API 쪽입니다. 처음엔 관리 클러스터가 또 필요하다고 해서 부담스러웠는데, 실제 구조를 이해하고 나니 왜 필요한지 납득됐습니다. Cluster API는 몇 가지 핵심 컴포넌트로 나뉩니다.

    • Core Provider: Cluster API 핵심 리소스와 컨트롤러
    • Bootstrap Provider: 노드 초기화 데이터 생성(kubeadm 활용)
    • Control Plane Provider: 컨트롤 플레인 구성 관리
    • Infrastructure Provider: 실제 VM, 인스턴스, 머신, 네트워크 리소스 생성

    기본 흐름은 이렇습니다. 관리 클러스터에 Cluster API 컴포넌트를 설치하고, 그 위에 워크로드 클러스터(실제 애플리케이션이 올라갈 대상 클러스터)의 정의를 YAML로 적용합니다.

    clusterctl init --infrastructure <provider-name>

    프로바이더 이름은 사용하는 환경에 따라 달라집니다. 예를 들어 퍼블릭 클라우드, 프라이빗 클라우드, 베어메탈 쪽에서 선택지가 갈리죠. 여기서는 원리를 이해하는 데 집중하겠습니다.

    Cluster API 관리 클러스터와 워크로드 클러스터 구조를 설명하는 Kubeadm ClusterAPI 비교 이미지

    관리 클러스터에서 컨트롤러가 동작하고, 선언된 리소스를 바탕으로 워크로드 클러스터의 머신과 컨트롤 플레인을 조립하는 구조입니다.

    apiVersion: cluster.x-k8s.io/v1beta1
    kind: Cluster
    metadata:
      name: demo-cluster
    spec:
      controlPlaneRef:
        apiVersion: controlplane.cluster.x-k8s.io/v1beta1
        kind: KubeadmControlPlane
        name: demo-control-plane
      infrastructureRef:
        apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
        kind: GenericInfrastructureCluster
        name: demo-infra
    ---
    apiVersion: controlplane.cluster.x-k8s.io/v1beta1
    kind: KubeadmControlPlane
    metadata:
      name: demo-control-plane
    spec:
      replicas: 1
      version: v1.29.0
      kubeadmConfigSpec:
        clusterConfiguration: {}
        initConfiguration: {}
        joinConfiguration: {}
    ---
    apiVersion: cluster.x-k8s.io/v1beta1
    kind: MachineDeployment
    metadata:
      name: demo-md-0
    spec:
      clusterName: demo-cluster
      replicas: 2
      selector:
        matchLabels: {}
      template:
        spec:
          version: v1.29.0
          clusterName: demo-cluster

    위 YAML은 Cluster API 구조 예시입니다. 실제 배포에서는 인프라 프로바이더 리소스가 더 들어가고, 환경 변수나 자격 증명도 필요합니다. 중요한 건 클러스터를 명령으로 만드는 게 아니라 상태로 선언한다는 점입니다. 이게 Cluster API의 본질이에요.

    kubectl apply -f cluster.yaml
    kubectl get cluster
    kubectl get machinedeployments
    kubectl get machines

    제가 직접 해보니 여기서 재미있는 포인트가 있었습니다. kubeadm은 한 번 만들고 나면 이후 운영 자동화는 별도로 설계해야 하는데, Cluster API는 처음부터 “운영까지 생각한 구조”라는 느낌이 강합니다. 대신 디버깅은 더 추상적입니다. 노드 한 대에서 끝나는 문제가 아니라 컨트롤러, 프로바이더, 템플릿이 다 얽혀 있거든요.

    주의사항과 트러블슈팅: 실제로 많이 막히는 지점

    ⚠️ 여기 진짜 중요합니다. Kubeadm ClusterAPI 비교에서 많은 글이 장점만 말하는데, 실전에서는 막히는 지점이 선택 기준이 되더라고요.

    1. kubeadm은 CNI 전까지 정상처럼 보여도 정상 아닐 수 있습니다

    `kubeadm init`이 끝났다고 클러스터가 다 살아난 건 아닙니다. `kubectl get nodes`에서 `NotReady`가 보이면 CNI부터 의심하세요. 저도 처음엔 인증서 문제인 줄 알고 엉뚱한 로그만 한참 봤었습니다.

    kubectl describe node
    kubectl get pods -A
    journalctl -u kubelet

    2. Cluster API는 실패 지점이 더 분산됩니다

    예를 들어 머신이 안 생기면 인프라 프로바이더 문제인지, bootstrap 데이터 생성 문제인지, control plane reconciliation 문제인지 나눠서 봐야 합니다.

    kubectl get pods -A
    kubectl get clusters,machines,machinedeployments,kubeadmcontrolplanes
    kubectl describe machine <machine-name>
    kubectl logs -n capi-system deployment/capi-controller-manager

    혹시 이런 경험 있으신가요? 리소스는 분명히 생성됐는데 상태가 계속 `Provisioning`에서 안 넘어가는 경우요. 이럴 땐 대부분 인프라 쪽 자격 증명, 이미지 템플릿, 네트워크 전제조건이 빠져 있는 경우가 많았습니다.

    3. kubeadm은 단순한 대신 표준화가 흔들리기 쉽습니다

    운영자가 둘 이상만 돼도 설치 옵션, OS 준비 상태, 네트워크 플러그인 선택이 조금씩 달라집니다. 결국 문서화와 스크립트화가 필수입니다. 즉, kubeadm이 간단하다고 해서 운영 체계까지 단순한 건 아니더라고요.

    4. Cluster API는 관리 클러스터 자체의 안정성이 중요합니다

    관리 클러스터가 흔들리면 워크로드 클러스터 변경 작업도 영향받습니다. 그래서 초기에 “관리 클러스터를 어디에 둘 것인가”를 꽤 신중하게 봐야 합니다. 홈랩에서는 한 대에 몰아넣으면 편하긴 한데, 장애 분리 측면에서는 아쉬움이 남습니다.

    검증과 결과 확인: 뭐가 더 운영 친화적인가

    검증은 단순히 `kubectl get nodes`만 보면 부족합니다. 생성, 변경, 교체, 삭제 흐름까지 봐야 합니다. 이 부분이 Kubernetes 클러스터 프로비저닝 도구를 비교할 때 핵심이거든요.

    1. 클러스터 최초 생성 시간과 절차 복잡도 확인
    2. 워커 노드 확장 방식 확인
    3. 버전 변경 시 운영 개입량 확인
    4. 장애 시 복구 절차 문서화 가능성 확인
    kubectl get nodes -o wide
    kubectl get cluster
    kubectl get machines
    kubectl get events --sort-by=.lastTimestamp
    Kubeadm ClusterAPI 비교 결과를 검증하는 쿠버네티스 상태 확인 이미지

    노드 Ready 상태, Machine 리소스 변화, 이벤트 흐름을 통해 선언한 상태와 실제 상태가 맞아가는지 확인하는 장면을 상상하시면 됩니다.

    실제로 써보니까 결과는 꽤 분명했습니다. 하나의 클러스터를 깊게 이해하고 빠르게 구축하려면 kubeadm이 좋았고, 반복 가능한 다수의 클러스터를 체계적으로 관리하려면 Cluster API가 훨씬 운영 친화적이었습니다. 특히 업그레이드나 머신 교체 시나리오를 생각하면 차이가 더 벌어집니다.

    상황별 선택 가이드: 클러스터 구축 도구 어떤 게 맞을까

    상황 추천 이유
    홈랩에서 쿠버네티스 구조 학습 kubeadm 구성 요소를 직접 체감하기 좋음
    단일 운영 클러스터를 신중하게 수동 관리 kubeadm 절차가 명확하고 제어감이 높음
    여러 환경에 동일한 클러스터 배포 Cluster API 선언형 템플릿 재사용이 쉬움
    업그레이드/교체 자동화를 운영 정책으로 추진 Cluster API 생애주기 관리 철학에 잘 맞음
    베어메탈 자동화까지 포함한 확장 설계 환경에 따라 다름 인프라 프로바이더 성숙도와 운영 역량이 중요
    • 빠른 시작과 학습이 목표면 kubeadm
    • 반복성과 선언형 운영이 목표면 Cluster API
    • 둘 중 하나만 고집할 필요는 없음: kubeadm으로 원리 이해 후 CAPI로 확장하는 경로가 현실적
    Kubeadm ClusterAPI 비교 선택 기준을 정리한 요약 인포그래픽

    팀 규모, 클러스터 수, 자동화 요구사항, 관리 방식에 따라 어떤 도구가 더 어울리는지 한눈에 정리한 비교 이미지입니다.

    자주 묻는 질문

    Q1. Cluster API가 있으면 kubeadm은 이제 안 써도 되나요?

    그렇진 않습니다. 오히려 Cluster API 내부에서 kubeadm 기반 부트스트랩을 활용하는 경우가 흔합니다. kubeadm은 여전히 중요한 기반 기술입니다.

    Q2. 소규모 팀도 Cluster API를 바로 도입해야 할까요?

    반드시 그렇진 않습니다. 클러스터 수가 적고 운영자가 구조를 아직 익히는 단계라면 kubeadm이 더 현실적일 수 있습니다. 자동화 비용보다 복잡도 비용이 더 클 수 있거든요.

    Q3. GitOps와 더 잘 맞는 쪽은 무엇인가요?

    Cluster API가 더 자연스럽습니다. 클러스터 정의 자체를 리소스로 관리하니까 Git 저장소 기반 운영 모델과 궁합이 좋습니다.

    마무리: 현실적인 접근

    정리해보면 이렇습니다. Kubeadm vs ClusterAPI 비교는 단순한 우열 비교가 아니라, 운영 성숙도와 목표가 다른 두 접근입니다. 제가 직접 해보니 kubeadm은 쿠버네티스를 제대로 이해하게 해주는 좋은 선생님이었고, Cluster API는 그 다음 단계에서 운영 자동화를 체계로 바꿔주는 도구였습니다. 둘 중 하나가 무조건 정답은 아니었습니다.

    개인적으로는 이런 순서를 추천드립니다. 처음엔 kubeadm으로 컨트롤 플레인 초기화, CNI 연결, 노드 조인, 인증서 구조를 손으로 한 번 겪어보세요. 그다음 반복 배포가 필요해지는 시점에 Cluster API를 붙이면 훨씬 덜 헷갈립니다. 저도 처음엔 YAML만 보고 멍했었는데, 기반 개념을 알고 나니까 드디어 됐다! 싶은 순간이 오더라고요.

    다음 글에서는 kubeadm으로 만든 클러스터를 운영 표준화하는 방법이나, Cluster API와 GitOps를 연결하는 흐름을 따로 다뤄보겠습니다. 이전 글에서 다룬 네트워크 플러그인 비교나 Ingress(외부 트래픽 진입점) 구성 글과 함께 보시면 더 이해가 잘 되실 겁니다.

    처음엔 수동 구축으로 원리를 익히고, 이후 선언형 운영으로 넘어가는 학습 및 운영 로드맵을 보여주는 마무리 이미지입니다.

  • [Proxmox] Proxmox Nested Virtualization으로 Kubernetes on VM 완벽 가이드

    [Proxmox] Proxmox Nested Virtualization으로 Kubernetes on VM 완벽 가이드

    [가상화] Proxmox Nested Virtualization으로 Kubernetes on VM 분석

    홈랩을 오래 굴리다 보면 결국 한 번은 Proxmox Nested Virtualization에 손이 가게 됩니다. 저도 처음엔 “굳이 VM 안에 또 가상화를 올려야 하나?” 싶었는데요, Kubernetes(쿠버네티스, 컨테이너 오케스트레이션) 실습 환경을 여러 번 갈아엎다 보니 이 구성이 생각보다 꽤 실용적이더라고요. 특히 VM 속 Kubernetes를 빠르게 복제하고, 스냅샷으로 되돌리고, 홈랩 가상화 구성을 유연하게 실험할 때 장점이 분명했습니다. 반대로 성능 손해와 디버깅 복잡도도 있어서, 막연히 “되니까 쓰자”로 접근하면 삽질 좀 하게 됩니다 ㅎㅎ 이 글에서는 제가 직접 해보며 정리한 가상화 성능 관점의 포인트와, Kubernetes on VM을 어떻게 굴렸는지 차근차근 풀어보겠습니다.

    Proxmox 호스트, 중첩 가상화가 활성화된 VM, 그리고 그 안에서 동작하는 Kubernetes 클러스터 흐름을 한눈에 보여주는 구성도입니다.

    1. 왜 굳이 Proxmox Nested Virtualization을 쓰게 됐나

    쉽게 말해 Nested Virtualization(중첩 가상화)는 “가상머신 안에서 또 가상화 기능을 쓰는 것”입니다. 예를 들어 Proxmox VE 위에 Ubuntu VM을 만들고, 그 VM 안에서 KVM(커널 기반 가상화)이나 kind, kubeadm 같은 도구를 써서 Kubernetes 실험 환경을 만드는 식이죠.

    제가 이 구성을 보게 된 이유는 단순했습니다.

    • 클러스터 실험 환경을 빠르게 복제하고 싶었습니다.
    • 실패했을 때 스냅샷으로 바로 되돌아가고 싶었습니다.
    • 물리 서버를 더 늘리지 않고도 여러 토폴로지를 시험해보고 싶었습니다.
    • 홈랩 가상화 환경에서 운영용 워크로드와 실험용 워크로드를 분리하고 싶었습니다.

    특히 kubeadm(쿠브애드엠, 쿠버네티스 수동 부트스트랩)으로 직접 클러스터를 구성해보면 네트워크, CNI(Container Network Interface, 컨테이너 네트워크 계층), cgroup(컨트롤 그룹, 리소스 제어) 같은 요소를 훨씬 잘 이해하게 됩니다. 다만 그만큼 레이어가 깊어져서, 문제 하나가 생기면 호스트인지, 게스트인지, 컨테이너 런타임인지 추적 범위가 넓어집니다. 여기서 중요한 포인트! 학습 효율은 높지만 운영 단순성은 떨어집니다.

    2. Proxmox Nested Virtualization 개념 정리

    저도 처음엔 헷갈렸는데, 구조를 한 줄로 정리하면 이렇습니다.

    물리 CPU의 가상화 확장(VT-x, AMD-V) – Proxmox/KVM – 게스트 VM – 게스트 내부의 컨테이너 또는 추가 가상화 계층

    즉, Proxmox가 게스트 VM에 CPU 가상화 기능을 노출해야 그 안에서 일부 가상화 관련 기능이 제대로 동작합니다. Kubernetes 자체는 반드시 중첩 가상화가 필요한 건 아닙니다. 예를 들어 단순히 containerd(컨테이너디, 컨테이너 런타임)와 kubelet(큐블릿, 노드 에이전트)만 돌리는 거라면 일반 VM으로도 충분합니다. 하지만 다음 같은 경우에는 Proxmox Nested Virtualization이 특히 의미가 있습니다.

    • VM 안에서 다시 KVM 기반 실험을 해야 할 때
    • 클러스터 테스트 도구가 가상화 확장 노출 여부에 민감할 때
    • 쿠버네티스 노드 역할을 하는 VM 내부에서 추가 격리 레이어를 시험할 때
    구성 방식 장점 주의점
    물리 서버에 직접 Kubernetes 설치 성능 손실이 적고 구조가 단순함 되돌리기와 복제가 번거로움
    Proxmox VM 위 Kubernetes 관리 편의성과 스냅샷 활용이 좋음 가상화 성능 오버헤드 고려 필요
    Proxmox Nested Virtualization 활용 실험 유연성이 가장 높음 가상화 성능 추적과 디버깅 난이도 증가

    제 경험상 학습, 검증, 반복 실험에는 정말 편합니다. 반면 장기 운영용 클러스터라면 레이어를 줄이는 쪽이 보통 더 낫더라고요.

    3. 실전 구성: VM 속 Kubernetes 실험 환경 만들기

    제가 홈랩에서 테스트할 때는 Proxmox 호스트 위에 Linux VM을 만들고, 그 안에 containerd와 kubeadm을 올리는 방식을 주로 썼습니다. 여기서는 특정 배포판 버전이나 Kubernetes 버전을 고정해서 적지는 않겠습니다. 버전은 계속 바뀌고, 이 글의 핵심은 원리와 체크포인트거든요.

    3-1. Proxmox VM 생성 시 확인할 것

    1. CPU 타입을 가능한 한 호스트와 가깝게 잡습니다. 일반적으로 호스트 CPU 기능 노출이 중요합니다.
    2. 가상 CPU 수(vCPU)와 메모리를 너무 타이트하게 주지 않습니다. control plane(컨트롤 플레인, 클러스터 제어 노드)은 생각보다 여유가 필요합니다.
    3. 디스크 캐시 정책과 스토리지 유형을 확인합니다. etcd(엣시디, 클러스터 상태 저장소)는 지연시간에 민감해서 가상화 성능에 직결됩니다.
    4. 브리지 네트워크 구성을 먼저 단순하게 잡습니다. 처음부터 VLAN까지 얹으면 문제 범위가 넓어집니다.

    CLI로 VM 설정을 확인할 때는 대략 이런 식으로 봤습니다.

    qm config 101

    CPU 관련 옵션을 조정할 때는 환경에 따라 설정 방식이 조금씩 다를 수 있지만, 핵심은 게스트가 필요한 CPU 가상화 기능을 볼 수 있게 하는 것입니다. 실제 반영 여부는 게스트 안에서 확인하는 편이 안전합니다.

    lscpu
    egrep -wo 'vmx|svm' /proc/cpuinfo | head

    여기서 vmx 또는 svm가 보이면 Intel/AMD 계열 가상화 확장이 게스트에 노출되는지 1차 확인이 됩니다.

    3-2. 게스트 OS에서 Kubernetes 기본 준비

    게스트 VM 안에서는 스왑(swap)을 끄고, 커널 모듈과 sysctl(시스ctl, 커널 런타임 파라미터)을 맞춰주는 작업이 먼저입니다. 이 부분은 예전에도 자주 삽질했던 구간입니다. kubelet이 뜨지 않거나, CNI가 이상하게 동작할 때 의외로 기본 설정이 빠져 있는 경우가 많거든요.

    sudo swapoff -a
    sudo modprobe overlay
    sudo modprobe br_netfilter
    
    cat <<'EOF' | sudo tee /etc/sysctl.d/99-kubernetes.conf
    net.bridge.bridge-nf-call-iptables = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    net.ipv4.ip_forward = 1
    EOF
    
    sudo sysctl --system

    containerd를 기준으로 보면 설정 파일도 한 번은 점검합니다.

    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
      runtime_type = "io.containerd.runc.v2"
    
    [plugins."io.containerd.grpc.v1.cri"]
      sandbox_image = "registry.k8s.io/pause:3.9"

    위 예시는 구조 예시입니다. 실제 배포판 기본값과 패키지 상태를 먼저 확인하세요. 이미 맞게 들어가 있는 경우도 꽤 많습니다.

    Proxmox Nested Virtualization 설정과 VM 속 Kubernetes 준비 과정 이미지

    가상 CPU, 메모리, 브리지 네트워크 설정과 게스트 내부의 containerd, kubeadm 준비 단계가 이어지는 모습을 설명하는 이미지입니다.

    3-3. kubeadm으로 클러스터 초기화

    실제로 써보니까 가장 덜 헷갈리는 건 제어 노드 하나로 먼저 붙이고, 그 다음 worker(워커, 작업 노드)를 늘리는 방식이었습니다.

    sudo kubeadm init --pod-network-cidr=10.244.0.0/16

    초기화 후에는 일반 사용자 기준 kubeconfig(큐브컨피그, 클러스터 접속 설정)를 옮깁니다.

    mkdir -p $HOME/.kube
    sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    그 다음 CNI 플러그인을 적용합니다. 어떤 플러그인을 쓸지는 환경마다 다르지만, 홈랩에서는 단순한 구성이 디버깅에 유리합니다. 제가 예전에 욕심내서 기능 많은 구성을 먼저 넣었다가, 문제 생겼을 때 네트워크 계층을 너무 많이 뒤져야 해서 시간을 꽤 썼습니다.

    4. 가상화 성능: 어디를 봐야 하나

    가상화 성능을 볼 때 단순히 “느리다/빠르다”로 끝내면 남는 게 없더라고요. 저는 보통 네 가지로 나눠서 봅니다.

    1. CPU 스케줄링 지연: vCPU가 실제 물리 코어를 기다리는 시간
    2. 메모리 압박: Ballooning(벌루닝, 동적 메모리 조절)이나 과도한 공유 여부
    3. 스토리지 지연: etcd, 이미지 풀, 로그 쓰기에서 체감이 큼
    4. 네트워크 오버헤드: 브리지, 오버레이 네트워크, MTU 불일치

    이 네 가지 중에서 홈랩에서는 스토리지와 네트워크가 체감 차이를 많이 만듭니다. CPU는 코어 수를 넉넉히 주면 얼추 버티는데, 디스크 레이턴시가 애매하면 control plane 반응성이 갑자기 거칠어지더라고요. 특히 이미지 풀링이나 Pod 재스케줄링 때 가상화 성능의 격차가 잘 보입니다.

    관찰 항목 증상 의심 포인트
    kubectl 응답이 느림 API 응답 지연 etcd 디스크 지연, 메모리 부족
    Pod 생성이 늦음 ContainerCreating 상태 지속 이미지 풀 속도, CNI 초기화
    노드 Ready 지연 초기 부팅 후 상태 불안정 kubelet 설정, cgroup, DNS
    서비스 통신 불안정 간헐적 타임아웃 브리지 설정, MTU, 오버레이 네트워크

    여기서 독자분들이 많이 궁금해하시는 게 “Nested면 못 쓸 정도로 느린가요?”인데요, 제 체감으로는 학습용, 테스트용, CI 비슷한 검증용으로는 충분히 쓸 만했습니다. 다만 I/O가 무겁거나 네트워크 민감한 워크로드를 오래 돌릴 거라면 구조를 더 단순하게 가져가는 게 맞습니다.

    5. ⚠️ 제가 실제로 겪은 문제와 해결 과정

    이 섹션이 제일 중요합니다. 설정 문서는 늘 깔끔한데, 현실은 안 그렇거든요.

    5-1. kubelet은 뜨는데 Pod 네트워크가 불안정했던 경우

    처음엔 Kubernetes 문제라고 생각했는데, 결국은 MTU(Maximum Transmission Unit, 최대 전송 단위)와 브리지 경로 문제였습니다. 오버레이 네트워크가 올라간 상태에서 하위 네트워크 장치 MTU가 엇갈리면, 겉보기엔 붙는 것 같다가 특정 통신에서만 이상해집니다.

    • 증상: 일부 Pod 간 통신은 되는데, 서비스 접근이 간헐적으로 실패
    • 원인 후보: 브리지 네트워크, CNI 기본 MTU, 상위 스위치 경로
    • 해결 방향: 네트워크 경로를 단순화하고 MTU 값을 일관되게 맞춤

    5-2. VM은 멀쩡한데 클러스터 반응이 둔했던 경우

    이건 대부분 저장소 쪽이었습니다. Proxmox 상의 스토리지가 바쁘거나, 게스트 디스크 설정이 애매하면 etcd가 은근히 영향받습니다. 겉으로는 CPU 사용률이 높지 않은데도 kubectl 응답이 굼뜬 경우가 있거든요. 저도 처음엔 “왜 이렇게 느리지?” 했었는데, 디스크 지연 쪽을 보고 나서 감이 오더라고요.

    kubectl get nodes
    kubectl get pods -A
    kubectl top nodes
    journalctl -u kubelet -xe --no-pager

    물론 kubectl top은 metrics-server(메트릭스 서버)가 있어야 합니다. 없는데 명령부터 치면 괜히 또 다른 삽질 시작입니다 ㅎㅎ

    5-3. nested 관련 확인이 애매했던 경우

    게스트 안에서 가상화 기능이 보이는지 먼저 확인하세요. 보이지 않으면 그 다음 단계에서 나오는 이상 증상들은 전부 부차적인 현상일 수 있습니다.

    lscpu | grep Virtualization
    egrep -c '(vmx|svm)' /proc/cpuinfo

    숫자가 0으로 나오면 Proxmox 쪽 CPU 노출 설정부터 다시 보는 게 맞습니다. 저도 예전에 Kubernetes 쪽 설정만 계속 뒤지다가 시간을 날린 적이 있습니다. 문제의 시작점이 더 아래 레이어였던 거죠.

    Proxmox Nested Virtualization 환경의 Kubernetes 트러블슈팅 이미지

    kubelet, CNI, 브리지 네트워크, 스토리지 지연을 순서대로 점검하는 트러블슈팅 흐름을 시각적으로 정리한 이미지입니다.

    6. 검증: 무엇을 확인하면 “이 구성 쓸 만하다”고 볼 수 있나

    저는 아래 체크리스트를 통과하면 일단 실험용으로 합격이라고 봅니다.

    1. 노드가 안정적으로 Ready 상태를 유지하는가
    2. Pod 생성과 삭제가 반복되어도 이상 지연이 없는가
    3. 서비스 간 통신과 DNS 해석이 일관적인가
    4. 재부팅 후에도 클러스터 상태가 다시 정상화되는가
    5. 스냅샷 복구 후 네트워크 식별자 충돌이 없는가

    검증 명령은 복잡할 필요 없습니다. 기본기가 더 중요합니다.

    kubectl get nodes -o wide
    kubectl get pods -A -o wide
    kubectl get svc -A
    kubectl run netcheck --image=busybox:1.36 --restart=Never -it --rm -- nslookup kubernetes.default

    여기서 DNS와 서비스 접근이 안정적이면 절반은 성공입니다. 그다음엔 샘플 워크로드를 배포해봅니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: demo-nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: demo-nginx
      template:
        metadata:
          labels:
            app: demo-nginx
        spec:
          containers:
          - name: nginx
            image: nginx:stable
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-nginx
    spec:
      selector:
        app: demo-nginx
      ports:
      - port: 80
        targetPort: 80

    제 경험상 VM 속 Kubernetes 환경이 제대로 잡히면, 작은 웹 서비스 배포나 GitOps(깃옵스, Git 기반 운영 자동화) 실험 정도는 꽤 쾌적하게 돌아갑니다. 반면 대규모 스토리지 집약 워크로드나 지연시간 민감한 서비스는 가상화 성능 제약이 빨리 보입니다.

    Proxmox Nested Virtualization 기반 Kubernetes on VM 검증 결과 이미지

    노드 Ready 상태, Pod 분포, DNS 테스트 성공, 샘플 워크로드 배포 완료를 보여주는 운영 확인용 대시보드 이미지입니다.

    7. 어떤 경우에 추천하고, 어떤 경우엔 말리고 싶나

    이건 아주 현실적으로 나눠볼 수 있습니다.

    추천하는 경우

    • 쿠버네티스 학습과 반복 실험이 목적일 때
    • 스냅샷과 복제가 중요한 홈랩 가상화 환경일 때
    • 홈랩 가상화 자원이 제한적이라 구조를 유연하게 가져가야 할 때
    • CI 테스트나 배포 검증용 임시 클러스터가 필요할 때

    덜 추천하는 경우

    • 장기 운영용 프로덕션에 가까운 안정성이 필요할 때
    • 고성능 스토리지나 저지연 네트워크가 중요한 워크로드일 때
    • 문제 발생 시 추적 레이어를 최소화해야 할 때

    한마디로 정리하면 이렇습니다. Proxmox Nested Virtualization은 “학습과 실험의 효율을 극대화하는 도구”로는 좋습니다. 하지만 운영 복잡도를 감수해야 하니, 목적이 분명해야 합니다.

    8. 정리 및 다음 단계

    제가 직접 해보니 Proxmox Nested Virtualization은 단순한 장난감 구성이 아니었습니다. 잘만 쓰면 Kubernetes 실습, 네트워크 실험, 스냅샷 기반 복구 테스트에 정말 편하더라고요. 반대로 가상화 성능과 디버깅 난이도를 가볍게 보면 금방 막힙니다. 특히 스토리지 지연, MTU, CPU 기능 노출 이 세 가지는 처음부터 꼭 체크해보세요.

    혹시 지금 홈랩에서 Kubernetes를 굴리고 계신가요? 그렇다면 처음부터 모든 걸 복잡하게 올리지 말고, 단일 control plane + 단순 CNI + 작은 샘플 워크로드로 시작해보시는 걸 권합니다. 그게 결국 가장 빨리 갑니다. 저도 괜히 욕심냈다가 돌아온 적이 많았거든요.

    다음 글에서는 Proxmox VE에서 템플릿 기반으로 Kubernetes 노드 VM을 빠르게 복제하는 방법이나, 이전 글에서 다뤘던 스토리지 설계와 연결해서 etcd와 디스크 지연 이야기를 좀 더 깊게 풀어볼 예정입니다.

    Proxmox Nested Virtualization 활용 장단점 요약 이미지

    언제 쓰면 좋고 언제 피해야 하는지, 가상화 성능과 운영 복잡도 관점에서 한눈에 정리한 요약 인포그래픽입니다.

    9. 자주 묻는 질문

    Q. Kubernetes는 꼭 Nested Virtualization이 있어야 하나요?

    아닙니다. 일반 VM에서도 충분히 돌아갑니다. 다만 VM 내부에서 추가 가상화 기능 실험이 필요하거나, 특정 테스트 시나리오에서 CPU 기능 노출이 중요할 때 의미가 있습니다.

    Q. 홈랩 가상화에서 가장 먼저 점검할 건 뭔가요?

    저는 순서를 이렇게 봅니다. CPU 기능 노출, 디스크 지연, 브리지 네트워크, MTU, 그다음 kubelet과 CNI 로그입니다.

    Q. 가상화 성능 측정은 어떤 방식이 좋나요?

    처음부터 거창한 벤치마크보다, 노드 Ready 시간, Pod 생성 속도, 이미지 풀링, DNS 응답, 서비스 간 통신 안정성 같은 운영 지표부터 보는 게 더 실용적입니다.