영어로 배우는 Cluster API: KubeVirt 위에 클러스터 찍어 내기
Management cluster: 클러스터를 만드는 클러스터
한 줄 요약
Cluster API 는 클러스터를 쿠버네티스 오브젝트로 선언하게 해 주고, 그 선언을 실제 VM 과 노드로 바꾸는 컨트롤러들은 관리 클러스터 안에서 돕니다.
왜 이게 필요했나
kubeadm 은 노드 한 대에서 "이 머신을 컨트롤 플레인으로 만들어라" 를 잘합니다. 그런데 머신을 준비하는 일(VM 만들기, 네트워크 붙이기, 디스크 고르기)과 여러 대를 묶어 관리하는 일(늘리기, 교체, 판 올리기)은 kubeadm 의 범위 밖입니다. 회사마다 그 빈자리를 Terraform 과 셸 스크립트로 채웠고, 클라우드가 바뀔 때마다 그 스크립트를 처음부터 다시 썼습니다. Cluster API 는 이 일을 쿠버네티스 방식으로 바꿉니다. "컨트롤 플레인 1대, 워커 2대, 판 1.34" 를 오브젝트로 적어 두면 컨트롤러가 현재 상태를 그 선언에 맞춰 갑니다. 이 맞춰 가는 동작을 영어로 reconcile 이라고 부르고, 이 코스 내내 듣게 될 단어입니다.
어떻게 동작하나
클러스터가 두 층입니다. 오브젝트를 저장하고 컨트롤러가 도는 쪽이 management cluster, 그 컨트롤러가 만들어 낸 쪽이 workload cluster 입니다. 이 코스에서는 VM 안의 k3s 가 관리 클러스터이고, 같은 VM 안의 KubeVirt 가 워크로드 클러스터의 노드가 될 VM 을 띄웁니다.
관리 클러스터에는 컨트롤러가 넷 들어갑니다. clusterctl init 이 이 넷을 각자의 네임스페이스에 깝니다.
core (cluster-api) Cluster, Machine, MachineSet, MachineDeployment, MachineHealthCheck
bootstrap (kubeadm) KubeadmConfig: 노드가 첫 부팅 때 실행할 cloud-init 을 만든다
control plane (kubeadm) KubeadmControlPlane: 컨트롤 플레인 Machine 들을 묶어 관리한다
infrastructure (kubevirt) KubevirtCluster, KubevirtMachine: 실제 VM 과 서비스를 만든다
넷이 서로의 코드를 모르는데도 함께 돌 수 있는 이유가 contract 입니다. core 는 "인프라 프로바이더의 Machine 오브젝트에는 이런 필드가 있어야 한다" 는 약속만 알고, 어떤 클라우드인지는 모릅니다. contract 에는 판이 있고(v1beta1, v1beta2), 프로바이더는 자기 CRD 에 cluster.x-k8s.io/<contract 판>: <자기 API 판> 라벨을 달아 "그 약속에는 내 이 API 판이 맞는다" 고 알립니다. 실습 3단계에서 그 라벨을 직접 읽습니다.
컨트롤러는 controller-runtime 이라는 라이브러리로 만들어져 있어서, 뜰 때 남기는 로그 모양이 같습니다. 오브젝트 변화를 받는 통로(EventSource)를 열고, 컨트롤러를 시작하고, 마지막으로 정해진 수의 worker 를 띄웁니다. worker 하나가 오브젝트 하나를 reconcile 하므로 worker count 가 곧 동시 처리 수입니다.
현장에서 만나는 모습
이 코스를 만들며 4 vCPU · 8 GiB VM 에서 잰 값입니다. k3s 27초, cert-manager 15초, KubeVirt 가 Available 이 되기까지 150초, clusterctl init(CAPI v1.14.3, CAPK v0.11.2) 32초였고, init 직후 VM 의 메모리 사용은 2.46GiB 였습니다. 컨트롤러 넷은 각각 25MiB 남짓만 썼고, 메모리를 가장 많이 쓴 것은 KubeVirt 의 operator 와 virt-api(각 160MiB 이상)였습니다.
현장에서 자주 만나는 함정이 둘 있습니다. 첫째, clusterctl 은 기본으로 GitHub API 를 부르는데 인증 없는 API 는 IP 하나당 시간당 60번입니다. 사무실 하나가 같은 공인 IP 로 여러 번 init 하면 rate limit exceeded 로 막힙니다. 토큰을 주거나(GITHUB_TOKEN), 파일을 미리 받아 로컬 저장소로 가리키면 됩니다. 이 실습 VM 은 뒤의 방법을 씁니다. 둘째, 판을 적지 않으면 그날의 최신 판이 깔립니다. 실측 중에도 CAPK 0.11 의 기본 템플릿이 CAPI 1.14 와 맞지 않는 곳을 하나 찾았는데(2모듈에서 직접 만납니다), 판을 고정해 두지 않았다면 어제 되던 것이 오늘 안 되는 이유를 찾기 어려웠을 것입니다.
English corner
🏓 티티: 공식 문서와 로그에 매일 나오는 단어 셋만 오늘 확실히 가져가요!
reconcile (동사). 원래 뜻은 "두 장부를 맞춰 보다, 화해시키다" 입니다. 컨트롤러 세계에서는 "원하는 상태(spec)와 실제 상태(status)를 비교해 차이를 없애는 일" 입니다. 명사는 reconciliation, 그 일을 하는 것은 reconciler 입니다.
- The controller reconciles the Machine every time its spec changes. (spec 이 바뀔 때마다 컨트롤러가 그 Machine 을 맞춘다)
- I'm seeing a reconcile loop that never settles. (끝없이 다시 맞추는 고리가 보인다. 이슈에서 자주 쓰는 표현)
provider (명사). 특정 클라우드나 역할을 맡는 플러그인 묶음입니다. infrastructure provider, bootstrap provider 처럼 앞에 역할을 붙입니다. 이슈에서는 "this is a provider issue, not a core issue" 처럼 책임 위치를 가리킬 때 씁니다.
initialize / initialized successfully. clusterctl init 이 마지막에 찍는 문장이 "Your management cluster has been initialized successfully!" 입니다. has been + 과거분사(현재완료 수동태)는 "막 끝나서 지금 그 상태다" 를 말합니다. 진행 보고에서는 "The management cluster is up." 처럼 더 짧게 말해도 됩니다.
pin a version (판을 고정하다). "Please pin the provider version in the reproduction steps." 처럼 재현 단계에서 판을 고정해 달라고 할 때 씁니다. 반대말은 float(떠 있게 두다)입니다.
다음 실습에서 할 것
KubeVirt 가 VM 을 받을 준비가 되었는지 확인하고, 판을 고정해 clusterctl init 을 돌립니다. Provider 오브젝트와 CRD 라벨에서 판과 contract 를 읽고, core 컨트롤러의 Starting workers 로그에서 worker 수를 모읍니다. 기본 템플릿의 필수 변수를 확인해 워크로드 클러스터 매니페스트를 만들어 두고, 마지막에 Done·Next·Blockers 세 줄의 영어 진행 보고를 씁니다.