minikube, kind, multipass, lima 비교
minikube
- 로컬에서 쿠버네티스(Kubernetes) 클러스터를 쉽게 실행할 수 있게 해주는 도구
- 다양한 드라이버 지원(Docker, VirtualBox, Hyperkit, KVM 등)
- 쿠버네티스 학습, 개발, 테스트에 적합
- 다양한 애드온, 대시보드, 멀티노드 등 실습에 편리한 기능 제공
kind (Kubernetes IN Docker)
- Docker 컨테이너 위에 쿠버네티스 클러스터를 실행하는 도구
- 모든 노드(컨트롤 플레인, 워커)가 Docker 컨테이너로 동작
- CI/CD 환경, 빠른 테스트, GitHub Actions 등에서 많이 사용
- VM이 아닌 컨테이너 기반이므로 리소스 소모가 적고, 클러스터 생성/삭제가 매우 빠름
- 네트워크, 스토리지 등 실제 환경과 차이가 있을 수 있음
multipass
- Canonical(우분투 개발사)에서 만든 경량 VM 관리 도구
- minikube, kind와 달리 쿠버네티스 전용이 아니라, 다양한 용도의 Ubuntu VM을 빠르게 생성/관리
- minikube, k3s, microk8s 등 쿠버네티스 환경을 multipass 위에 올려서 사용할 수 있음
- macOS, Windows, Linux에서 동일한 방식으로 VM 관리 가능
lima (Linux Machines)
- macOS에서 리눅스 VM을 쉽게 실행할 수 있게 해주는 도구
- Docker Desktop 없이도 컨테이너, 쿠버네티스 환경을 구축할 수 있음
- nerdctl, k3s, rancher 등과 연동해 개발 환경 구성에 활용
- Lima 위에 kind, minikube, k3s 등 다양한 쿠버네티스 환경을 올릴 수 있음
요약 비교
| 도구 | 목적/특징 | 쿠버네티스 전용 | 실행 방식 |
|---|---|---|---|
| minikube | 로컬 쿠버네티스, 다양한 드라이버 지원 | O | VM/컨테이너 |
| kind | Docker 기반 쿠버네티스, 빠른 테스트 | O | Docker 컨테이너 |
| multipass | 경량 Ubuntu VM 관리 | X | VM |
| lima | macOS 리눅스 VM, 컨테이너 개발환경 | X | VM |
minikube 실습 환경 구성
minikube 설치
brew install minikubeminikube 실행
meatsby ~ minikube start
😄 Darwin 15.6.1 (arm64) 의 minikube v1.37.0
✨ 자동적으로 docker 드라이버가 선택되었습니다. 다른 드라이버 목록: virtualbox, ssh
📌 Docker Desktop 드라이버를 루트 권한으로 사용 중
👍 "minikube" 클러스터의 "minikube" primary control-plane 노드를 시작하는 중
🚜 기본 이미지 v0.0.48를 가져오는 중 ...
💾 쿠버네티스 v1.34.0 을 다운로드 중 ...
> preloaded-images-k8s-v18-v1...: 332.38 MiB / 332.38 MiB 100.00% 22.68 M
🔥 docker container (CPUs=2, 메모리=4000MB) 를 생성하는 중 ...
🐳 쿠버네티스 v1.34.0 을 Docker 28.4.0 런타임으로 설치하는 중
🔗 bridge CNI (Container Networking Interface) 를 구성하는 중 ...
🔎 Kubernetes 구성 요소를 확인...
▪ 이미지 gcr.io/k8s-minikube/storage-provisioner:v5 사용 중
🌟 애드온 활성화 : storage-provisioner, default-storageclass
🏄 끝났습니다! kubectl이 "minikube" 클러스터와 "default" 네임스페이스를 기본적으로 사용하도록 구성되었습니다
meatsby ~ k get componentstatuses
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy okdashboard 실행
meatsby ~ minikube dashboard
🔌 대시보드를 활성화하는 중 ...
▪ 이미지 docker.io/kubernetesui/metrics-scraper:v1.0.8 사용 중
▪ 이미지 docker.io/kubernetesui/dashboard:v2.7.0 사용 중
💡 Some dashboard features require the metrics-server addon. To enable all features please run:
minikube addons enable metrics-server
🤔 Dashboard 의 상태를 확인 중입니다 ...
🚀 프록시를 시작하는 중 ...
🤔 Proxy 의 상태를 확인 중입니다 ...
🎉 Opening http://127.0.0.1:57530/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...Ingress 실습
# ingress addon 설치
meatsby ~ minikube addons enable ingress
💡 ingress is an addon maintained by Kubernetes. For any concerns contact minikube on GitHub.
You can view the list of minikube maintainers at: https://github.com/kubernetes/minikube/blob/master/OWNERS
💡 애드온이 활성화된 후 "minikube tunnel"을 실행하면 인그레스 리소스를 "127.0.0.1"에서 사용할 수 있습니다
▪ 이미지 registry.k8s.io/ingress-nginx/controller:v1.13.2 사용 중
▪ 이미지 registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.2 사용 중
▪ 이미지 registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.2 사용 중
🔎 ingress 애드온을 확인 중입니다 ...
🌟 'ingress' 애드온이 활성화되었습니다
# nginx IngressClass 생성된다.
meatsby ~ k get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 9s
# ingress-controller 로 nginx 파드가 구동중이다.
meatsby ~ k get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-77dsb 0/1 Completed 0 14s
ingress-nginx-admission-patch-wgw4h 0/1 Completed 1 14s
ingress-nginx-controller-9cc49f96f-gf9mt 1/1 Running 0 14s
# 예제 ingress 를 배포해보자.
meatsby ~ kubectl apply -f https://storage.googleapis.com/minikube-site-examples/ingress-example.yaml
pod/foo-app created
service/foo-service created
pod/bar-app created
service/bar-service created
ingress.networking.k8s.io/example-ingress created
# ingress 생성 확인.
meatsby ~ k get ingress -w
NAME CLASS HOSTS ADDRESS PORTS AGE
example-ingress nginx * 80 6s
example-ingress nginx * 192.168.49.2 80 59s
# mac 은 minikube tunnel 을 실행해줘야한다.
meatsby ~ minikube tunnel
✅ Tunnel successfully started
📌 NOTE: Please do not close this terminal as this process must stay alive for the tunnel to be accessible ...
❗ The service/ingress example-ingress requires privileged ports to be exposed: [80 443]
🔑 sudo permission will be asked for it.
🏃 example-ingress 서비스의 터널을 시작하는 중/# minikube tunnel 실행 후 새로운 터미널에서 curl 요청을 보내보자.
# bar-app 으로 트래픽이 전달된다.
meatsby ~ curl 127.0.0.1/bar
Request served by bar-app
HTTP/1.1 GET /bar
Host: 127.0.0.1
Accept: */*
User-Agent: curl/8.7.1
X-Forwarded-For: 10.244.0.1
X-Forwarded-Host: 127.0.0.1
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Real-Ip: 10.244.0.1
X-Request-Id: 8fcbd14bfef458a7f88a9cef50b6698d
X-Scheme: http
# foo-app 으로 트래픽이 전달된다.
meatsby ~ curl 127.0.0.1/foo
Request served by foo-app
HTTP/1.1 GET /foo
Host: 127.0.0.1
Accept: */*
User-Agent: curl/8.7.1
X-Forwarded-For: 10.244.0.1
X-Forwarded-Host: 127.0.0.1
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Real-Ip: 10.244.0.1
X-Request-Id: d1903d0f75a0cb744c3b5d01f08bd419
X-Scheme: http
# X-Forwarded-For: 10.244.0.1 가 뭔지 살펴보자.
meatsby ~ minikube node list
minikube 192.168.49.2
# bridge 10.244.0.1 에서 Pod 로 전달된다.
meatsby ~ minikube ssh
docker@minikube:~$ ip addr show | grep bridge: -A5
13: bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 66:bc:1e:16:98:64 brd ff:ff:ff:ff:ff:ff
inet 10.244.0.1/16 brd 10.244.255.255 scope global bridge
valid_lft forever preferred_lft forever
inet6 fe80::64bc:1eff:fe16:9864/64 scope link
valid_lft forever preferred_lft forevermetrics-server 설치
# top 명령을 사용하려면 metrics-server 가 구동중이어야한다.
meatsby ~ k top no
error: Metrics API not available
meatsby ~ k top po
error: Metrics API not available
# metrics-server addon 설치
meatsby ~ minikube addons enable metrics-server
💡 metrics-server is an addon maintained by Kubernetes. For any concerns contact minikube on GitHub.
You can view the list of minikube maintainers at: https://github.com/kubernetes/minikube/blob/master/OWNERS
▪ 이미지 registry.k8s.io/metrics-server/metrics-server:v0.8.0 사용 중
🌟 'metrics-server' 애드온이 활성화되었습니다
# addon list 확인
meatsby ~ minikube addons list
┌────────────── ┬─────┬──────┬────────────────────┐
│ ADDON NAME │ PROFILE │ STATUS │ MAINTAINER │
├────────────── ┼─────┼──────┼────────────────────┤
│ ambassador │ minikube │ disabled │ 3rd party (Ambassador) │
│ amd-gpu-device-plugin │ minikube │ disabled │ 3rd party (AMD) │
│ auto-pause │ minikube │ disabled │ minikube │
│ cloud-spanner │ minikube │ disabled │ Google │
│ csi-hostpath-driver │ minikube │ disabled │ Kubernetes │
│ dashboard │ minikube │ enabled ✅ │ Kubernetes │
│ default-storageclass │ minikube │ enabled ✅ │ Kubernetes │
│ efk │ minikube │ disabled │ 3rd party (Elastic) │
│ freshpod │ minikube │ disabled │ Google │
│ gcp-auth │ minikube │ disabled │ Google │
│ gvisor │ minikube │ disabled │ minikube │
│ headlamp │ minikube │ disabled │ 3rd party (kinvolk.io) │
│ inaccel │ minikube │ disabled │ 3rd party (InAccel [info@inaccel.com]) │
│ ingress │ minikube │ enabled ✅ │ Kubernetes │
│ ingress-dns │ minikube │ disabled │ minikube │
│ inspektor-gadget │ minikube │ disabled │ 3rd party (inspektor-gadget.io) │
│ istio │ minikube │ disabled │ 3rd party (Istio) │
│ istio-provisioner │ minikube │ disabled │ 3rd party (Istio) │
│ kong │ minikube │ disabled │ 3rd party (Kong HQ) │
│ kubeflow │ minikube │ disabled │ 3rd party │
│ kubetail │ minikube │ disabled │ 3rd party (kubetail.com) │
│ kubevirt │ minikube │ disabled │ 3rd party (KubeVirt) │
│ logviewer │ minikube │ disabled │ 3rd party (unknown) │
│ metallb │ minikube │ disabled │ 3rd party (MetalLB) │
│ metrics-server │ minikube │ enabled ✅ │ Kubernetes │
│ nvidia-device-plugin │ minikube │ disabled │ 3rd party (NVIDIA) │
│ nvidia-driver-installer │ minikube │ disabled │ 3rd party (NVIDIA) │
│ nvidia-gpu-device-plugin │ minikube │ disabled │ 3rd party (NVIDIA) │
│ olm │ minikube │ disabled │ 3rd party (Operator Framework) │
│ pod-security-policy │ minikube │ disabled │ 3rd party (unknown) │
│ portainer │ minikube │ disabled │ 3rd party (Portainer.io) │
│ registry │ minikube │ disabled │ minikube │
│ registry-aliases │ minikube │ disabled │ 3rd party (unknown) │
│ registry-creds │ minikube │ disabled │ 3rd party (UPMC Enterprises) │
│ storage-provisioner │ minikube │ enabled ✅ │ minikube │
│ storage-provisioner-gluster │ minikube │ disabled │ 3rd party (Gluster) │
│ storage-provisioner-rancher │ minikube │ disabled │ 3rd party (Rancher) │
│ volcano │ minikube │ disabled │ third-party (volcano) │
│ volumesnapshots │ minikube │ disabled │ Kubernetes │
│ yakd │ minikube │ disabled │ 3rd party (marcnuri.com) │
└────────────── ┴─────┴──────┴────────────────────┘
# 이제 metric 을 확인할 수 있다.
meatsby ~ k top no
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
minikube 309m 3% 1110Mi 14%
meatsby ~ k top po
NAME CPU(cores) MEMORY(bytes)
bar-app 1m 8Mi
foo-app 1m 6Mimulti-node cluster 구성
meatsby ~ minikube node list
minikube 192.168.49.2
# worker node 3대 추가
meatsby ~ minikube node add --worker
😄 노드 m02 를 클러스터 minikube 에 [worker] 로 추가합니다
❗ CNI 없이 클러스터가 생성되었으므로, 클러스터에 노드를 추가하면 네트워킹이 중단될 수 있습니다.
👍 "minikube" 클러스터의 "minikube-m02" worker 노드를 시작하는 중
🚜 기본 이미지 v0.0.48를 가져오는 중 ...
🔥 docker container (CPUs=2, 메모리=2200MB) 를 생성하는 중 ...
🐳 쿠버네티스 v1.34.0 을 Docker 28.4.0 런타임으로 설치하는 중
🔎 Kubernetes 구성 요소를 확인...
🏄 m02 를 minikube 에 성공적으로 추가하였습니다!
meatsby ~ minikube node add --worker
😄 노드 m03 를 클러스터 minikube 에 [worker] 로 추가합니다
👍 "minikube" 클러스터의 "minikube-m03" worker 노드를 시작하는 중
🚜 기본 이미지 v0.0.48를 가져오는 중 ...
🔥 docker container (CPUs=2, 메모리=2200MB) 를 생성하는 중 ...
🐳 쿠버네티스 v1.34.0 을 Docker 28.4.0 런타임으로 설치하는 중
🔎 Kubernetes 구성 요소를 확인...
🏄 m03 를 minikube 에 성공적으로 추가하였습니다!
meatsby ~ minikube node add --worker
😄 노드 m04 를 클러스터 minikube 에 [worker] 로 추가합니다
👍 "minikube" 클러스터의 "minikube-m04" worker 노드를 시작하는 중
🚜 기본 이미지 v0.0.48를 가져오는 중 ...
🔥 docker container (CPUs=2, 메모리=2200MB) 를 생성하는 중 ...
🐳 쿠버네티스 v1.34.0 을 Docker 28.4.0 런타임으로 설치하는 중
🔎 Kubernetes 구성 요소를 확인...
🏄 m04 를 minikube 에 성공적으로 추가하였습니다!
meatsby ~ minikube node list
minikube 192.168.49.2
minikube-m02 192.168.49.3
minikube-m03 192.168.49.4
minikube-m04 192.168.49.5
meatsby ~ k get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 3h39m v1.34.0
minikube-m02 Ready <none> 2m8s v1.34.0
minikube-m03 Ready <none> 114s v1.34.0
minikube-m04 Ready <none> 99s v1.34.0
# worker node labeling
meatsby ~ k label node minikube-m02 node-role.kubernetes.io/worker=worker
node/minikube-m02 labeled
meatsby ~ k label node minikube-m03 node-role.kubernetes.io/worker=worker
node/minikube-m03 labeled
meatsby ~ k label node minikube-m04 node-role.kubernetes.io/worker=worker
node/minikube-m04 labeled
meatsby ~ k get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 3h40m v1.34.0
minikube-m02 Ready worker 2m52s v1.34.0
minikube-m03 Ready worker 2m38s v1.34.0
minikube-m04 Ready worker 2m23s v1.34.0multipass
multipass 란
Mac 하드웨어 (Apple Silicon, EL0/EL1/EL2/EL3)
│
├─ EL2: Apple 하이퍼바이저 ←── Hypervisor.framework가 여기 접근권을 유저에 열어줌
│ (게스트 CPU를 물리코어에서 네이티브 실행 + 메모리 가상화)
│
└─ macOS 커널 XNU (EL1)
├─ vmnet.framework ─── 가상 스위치 / NAT / DHCP(bootpd)
│ └─ bridge100 (기본망, 192.168.64.0/24, 항상 NAT, VM 관리용)
│ └─ member: vmenet0 (VM ↔ 스위치 연결)
│
├─ en0 (실제 Wi-Fi, 192.168.0.122) ──→ 공유기(192.168.0.1) ──→ 인터넷
│ ▲
│ └─ [BRIDGE 모드일 때만] vmnet이 여기에 브리지로 얹어 VM NIC2 생성
│
└─ 유저스페이스
├─ multipassd (root 데몬) ── VM 생성/삭제/상태
│
├─ qemu-system-aarch64 [controlplane] ← 프로세스 1개 = VM 1대
│ ├─ (CPU/메모리 → Hypervisor.framework 호출)
│ ├─ (디스크 → virtio-blk → Mac 이미지파일)
│ └─ 게스트 Ubuntu
│ ├─ enp0s1 → bridge100(192.168.64.x) = 관리용 NIC1
│ ├─ enp0s2 → 공유기(192.168.0.x) = PRIMARY_IP, default gw ★ (BRIDGE 모드)
│ └─ kubelet / kube-apiserver / containerd ...
│
├─ qemu-system-aarch64 [node01]
└─ qemu-system-aarch64 [node02]
- Canonical 이 만든 경량 VM 관리 도구
multipass설치 시 상시 데몬multipassd가 VM 수명주기를 관리multipass launch/shell/exec/delete명령어로multipassd에 요청하여 VM 생성- Apple Silicon 에서
multipass는 QEMU 를 사용 - macOS 에선 네트워크를 인터넷 공유/vmnet 으로 자동 구성(
192.168.64.x)해 별도 설정 없이 VM이 바로 인터넷 통신 가능
multipass launchmultipassd가 qemu 프로세스 실행 (qemu 가 기본 드라이버, AppleVZ 드라이버도 있음)- VM 하나 = mac 위의 QEMU 프로세스 하나(
qemu-system-aarch64) - 즉,
controlplane,node01,node02는 각각 별개의 QEMU 프로세스로 구성된다ps aux | grep qemu로 실제로 볼 수 있다.
- VM 하나 = mac 위의 QEMU 프로세스 하나(
- qemu 가 vCPU, 메모리, 가상 디스크, 가상 인터페이스 생성
- vCPU, 메모리는
Hypervisor.framework(커널 수준 API) 호출해서 할당- AppleVZ 드라이버 일 경우
Virtualization.framework호출
- AppleVZ 드라이버 일 경우
- 가상 디스크는 mac 디스크 위 이미지 파일을
virtio-blk디바이스로 에뮬레이트 - 가상 인터페이스는 vmnet.framework 호출해서
bridge100,vmenet0등virtio-net디바이스 생성--bridged로 실행 시bridge101,vmenet1등 인터페이스를 생성하여, mac 이 사용하는 공유기에 붙을 스위치bridge101에 mac 의 nicen0와 vm 의 nicvmenet1을 구성한다.
- vCPU, 메모리는
QEMU 란
- 오픈소스 머신 에뮬레이터 겸 가상화기(VMM, Virtual Machine Monitor)
- VM 의 가상 하드웨어(CPU, 메모리, 디스크=
virtio-blk, NIC=virtio-net)를 만들어 게스트 OS(Ubuntu ARM64)를 실행 - Apple Silicon 에서는 CPU/메모리 가상화를 Hypervisor.framework(hvf 가속기)에 위임해 게스트를 네이티브 속도로 돌림
- multipass 에서 QEMU 는 VM 당 프로세스 1개(
qemu-system-aarch64)로 뜨며,multipassd가 이 프로세스를 관리
❯ multipass launch --name test jammy위 명령어를 실행하면 multipassd 가 QEMU 프로세스를 실행해서 vCPU, 메모리, 가상 디스크, 가상 NIC 등을 생성하여 VM 을 구성한다.
❯ ps -ef | grep multipass
0 24431 1 0 8:04PM ?? 0:01.65 /Library/Application Support/com.canonical.multipass/bin/multipassd --verbosity debug
0 29125 24431 0 8:30PM ?? 0:36.87 /Library/Application Support/com.canonical.multipass/bin/qemu-system-aarch64 -machine virt,gic-version=3 -accel hvf -drive file=/Library/Application Support/com.canonical.multipass/bin/../Resources/qemu/edk2-aarch64-code.fd,if=pflash,format=raw,readonly=on -cpu host -nic vmnet-shared,start-address=192.168.252.1,end-address=192.168.252.254,subnet-mask=255.255.255.0,model=virtio-net-pci,mac=52:54:00:f3:88:54 -device virtio-scsi-pci,id=scsi0 -drive file=/var/root/Library/Application Support/multipassd/qemu/vault/instances/testn/ubuntu-22.04-server-cloudimg-arm64.img,if=none,format=qcow2,discard=unmap,id=hda -device scsi-hd,drive=hda,bus=scsi0.0 -smp 2 -m 3072M -qmp stdio -chardev null,id=char0 -serial chardev:char0 -nographic -cdrom /var/root/Library/Application Support/multipassd/qemu/vault/instances/testn/cloud-init-config.iso -uuid f5988137-9236-3bdf-ae37-fc70257638a9
501 29555 23812 0 8:32PM ttys003 0:00.00 rg --color=auto multipass
❯ ps -ef | grep bootpd
0 29169 1 0 8:30PM ?? 0:00.03 /usr/libexec/bootpd
501 29580 23812 0 8:32PM ttys003 0:00.00 rg --color=auto bootpdps -ef 로 multipassd 가 QEMU 프로세스를 실행한 것과 DHCP 역할을 수행하는 bootpd 를 직접 확인할 수 있다.
multipass 네트워킹
qemu 는 macOS kernel 의 vmnet.framework 를 호출해서 virtio-net 디바이스를 만들어 가상 스위치, 가상 인터페이스를 구현한다.
NAT 네트워킹
❯ multipass launch --disk 10G --memory 3G --cpus 2 --name testn jammy
Launched: testn
❯ multipass list
Name State IPv4 Image
testn Running 192.168.252.11 Ubuntu 22.04 LTS
❯ ifconfig
...
vmenet0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether d2:55:69:80:5b:1b
media: autoselect
status: active
bridge100: flags=8a63<UP,BROADCAST,SMART,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether be:d0:74:14:cc:64
inet 192.168.252.1 netmask 0xffffff00 broadcast 192.168.252.255
inet6 fe80::bcd0:74ff:fe14:cc64%bridge100 prefixlen 64 scopeid 0x1a
inet6 fd65:8bbd:f4af:d0b3:8e0:63a:ad73:f9a2 prefixlen 64 autoconf secured
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x0
member: vmenet0 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 25 priority 0 path cost 0
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
❯ multipass shell testn
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-185-generic aarch64)
...
ubuntu@testn:~$ ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 52:54:00:f3:88:54 brd ff:ff:ff:ff:ff:ff
inet 192.168.252.11/24 metric 100 brd 192.168.252.255 scope global dynamic enp0s1
valid_lft 3380sec preferred_lft 3380sec
inet6 fd65:8bbd:f4af:d0b3:5054:ff:fef3:8854/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 2591935sec preferred_lft 604735sec
inet6 fe80::5054:ff:fef3:8854/64 scope link
valid_lft forever preferred_lft forevermultipass 는 기본적으로 NAT 모드로 실행된다. NAT 모드는 macOS 에 가상 스위치 bridge100 과 VM 이 사용할 가상 인터페이스 vmenet0 을 만든다.
192.168.252.0/24 범위의 서브넷에서 macOS 의 bootpd 가 192.168.252.1 에서 게이트웨이/DHCP/DNS 역할을 수행해 새로 생성되는 VM 들을 bridge100 에 연결한다. NAT 모드는 bridge100 을 통해 인터넷 egress 는 되지만 ingress 는 안되고 일반적으로 multipass shell/exec 을 통해 multipass cli 와 소통하는 역할을 한다? NAT 구성에서는 VM이 도는 네트워크가 하이퍼바이저가 관리하는 NAT 게이트웨이를 통해 공유기 네트워크와 격리된다. VM은 밖으로 나갈 수 있지만(인터넷 접속 가능), 밖에서 안은 볼 수 없다(브라우저로 NodePort 접속 불가). 현재 Multipass에서 포트포워딩 룰 설정은 불가능하다. VM이 쓰는 네트워크는 Multipass가 고른다?
Bridge 네트워킹
❯ multipass launch --bridged --disk 10G --memory 3G --cpus 2 --name testb jammy
Launched: testb
❯ multipass list
Name State IPv4 Image
testb Running 192.168.252.9 Ubuntu 22.04 LTS
192.168.0.131
❯ ifconfig
...
vmenet0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether d2:55:69:80:5b:1b
media: autoselect
status: active
bridge100: flags=8a63<UP,BROADCAST,SMART,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether be:d0:74:14:cc:64
inet 192.168.252.1 netmask 0xffffff00 broadcast 192.168.252.255
inet6 fe80::bcd0:74ff:fe14:cc64%bridge100 prefixlen 64 scopeid 0x1a
inet6 fd65:8bbd:f4af:d0b3:8e0:63a:ad73:f9a2 prefixlen 64 autoconf secured
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x0
member: vmenet0 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 25 priority 0 path cost 0
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
vmenet1: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether fa:52:a3:b8:ea:9d
media: autoselect
status: active
bridge101: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether be:d0:74:14:cc:65
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
ipfilter disabled flags 0x0
member: vmenet1 flags=3<LEARNING,DISCOVER>
ifmaxaddr 0 port 27 priority 0 path cost 0
member: en0 flags=8003<LEARNING,DISCOVER,MACNAT>
ifmaxaddr 0 port 14 priority 0 path cost 0
media: autoselect
status: active
❯ multipass shell testb
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-185-generic aarch64)
...
ubuntu@testb:~$ ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 52:54:00:e8:e5:9c brd ff:ff:ff:ff:ff:ff
inet 192.168.252.9/24 metric 100 brd 192.168.252.255 scope global dynamic enp0s1
valid_lft 2587sec preferred_lft 2587sec
inet6 fd65:8bbd:f4af:d0b3:5054:ff:fee8:e59c/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 2591998sec preferred_lft 604798sec
inet6 fe80::5054:ff:fee8:e59c/64 scope link
valid_lft forever preferred_lft forever
3: enp0s2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 52:54:00:d3:0d:2a brd ff:ff:ff:ff:ff:ff
inet 192.168.0.131/24 metric 200 brd 192.168.0.255 scope global dynamic enp0s2
valid_lft 6190sec preferred_lft 6190sec
inet6 fe80::5054:ff:fed3:d2a/64 scope link
valid_lft forever preferred_lft forevermultipass 를 Bridge 모드로 실행하면 kubernetes 노드가 로컬 네트워크(집 공유기)에 추가 머신처럼 나타나고, IP 는 공유기가 동적으로 준다. 위 예시에선 enp0s2 주소가 공유기가 할당한 내 브로드밴드(홈) 네트워크상의 주소이다. 덕분에 브라우저로 배포한 NodePort 서비스에 접속할 수 있다. 같은 와이파이 공유기에 연결된 스마트폰 등에서 192.168.0.131 로 접속할 수 있다.
Bridge 모드 동작 방식 때문에 각 VM 은 2개의 nic 를 생성한다. enp0s1 은 multipass 가 사용하는 nic 이고 enp0s2 는 노드에서 default gateway 가 있는 네트워크에 연결된 인터페이스의 IP 로 노드가 다른 노드 및 인터넷과 통신할 때 쓰는 nic 이다. kubernetes 컴포넌트가 enp0s1 에 바인딩될 수 있기 때문에 모든 VM /etc/default/kubelet 에 KUBELET_EXTRA_ARGS='--node-ip 192.168.0.131' 를 집어넣어 kubelet 이 사용할 nic 를 명시적으로 지정해준다.
DHCP leases 정리
❯ multipass delete testn testb && multipass purge
❯ sudo nvim /var/db/dhcpd_leasesmultipass 는 자동으로 DHCP leases 정리하지 않기 때문에 직접 정리하지 않으면 결국 multipass VM 네트워크에서 IP 주소가 부족해질 수 있다.
kubernetes-the-multipass-kubeadm-way
apt 패키지 인덱스 업데이트 및 쿠버네티스 apt 레포 사용을 위한 패키지 설치
sudo apt-get update
# apt-transport-https는 더미 패키지일 수 있다. 그렇다면 해당 패키지를 건너뛸 수 있다
sudo apt-get install -y apt-transport-https ca-certificates curl gpg쿠버네티스 패키지 리포지터리용 public signing key 다운로드
# 데비안 12와 우분투 22.04보다 오래된 릴리스에서는 `/etc/apt/keyrings` 디렉터리가 기본적으로 존재하지 않으며, curl 명령 전에 생성되어야 한다.
# `/etc/apt/keyrings` 디렉터리가 존재하지 않으면, curl 명령 전에 생성해야 한다.
# sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg쿠버네티스 apt 리포지터리 추가
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.listapt package index 업데이트, kubelet, kubeadm, kubectl 설치
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
kubeadm version # kubeadm 버전 확인containerd 설치
sudo apt update
sudo apt install -y containerdkubeadm 은 기본적으로 쿠버네티스 컴포넌트를 파드로 실행하기 때문에 master, worker 모두 containerd 컨테이너 런타임을 설치해야 한다.
kubelet cgroup driver 설정
Linux 에선 cgroup 을 사용해 프로세스(컨테이너)마다 할당할 리소스를 제한한다. kubelet 과 container runtime 은 cgroup driver 를 통해 cgroup 을 사용하여 파드와 컨테이너의 리소스를 제한한다. 때문에 kubelet 과 container runtime 은 동일한 cgroup driver 를 가져야한다.
cgroup driver 의 종류는 아래와 같다.
cgroupfssystemd
ps -p 1 # PID 1 이 systemd 인지 확인kubelet 의 기본 cgroup 드라이버는 cgroupfs 드라이버이다. 리눅스 배포판의 init 시스템이 systemd 인 경우, init 프로세스는 root control group(cgroup)을 생성 및 사용하는 cgroup 관리자로 작동하기 때문에 cgroup 드라이버 역시 systemd 로 사용해야 한다. systemd 를 cgroup 드라이버로 사용하려면, KubeletConfiguration 의 cgroupDriver 옵션을 systemd 로 설정해야 한다. v1.22 이후 버전부터 kubeadm 으로 클러스터를 생성할 경우 사용자가 KubeletConfiguration 하위의 cgroupDriver 필드를 설정하지 않아도 kubeadm 이 기본값으로 systemd 를 사용한다.
containerd cgroup driver 설정
systemd 를 kubelet 의 cgroup 드라이버로 구성했다면, 반드시 컨테이너 런타임의 cgroup 드라이버 또한 systemd 로 설정해야 한다. runc 와 함께 /etc/containerd/config.toml 에서 systemd cgroup 드라이버를 사용하려면, 사용 중인 containerd 버전에 따라 다음과 같이 설정한다.
Containerd 1.x 버전:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = trueContainerd 2.x 버전:
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc]
...
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
SystemdCgroup = truecgroup v2 를 사용할 경우 systemd cgroup 드라이버가 권장된다.
sudo mkdir -p /etc/containerd
containerd config default \
| sed 's/SystemdCgroup = false/SystemdCgroup = true/' \
| sudo tee /etc/containerd/config.toml
sudo systemctl restart containerdcontainderd config default 명령어는 containerd 의 기본 config.toml 을 추력한다. 기본 출력을 | sed 's/SystemdCgroup = false/SystemdCgroup = true/' 에 넘겨 systemd cgroup 드라이버를 사용하도록 수정하고 | sudo tee /etc/containerd/config.toml 로 설정파일 경로에 저장한다.
컨트롤 플레인 노드 초기화
ip add # 마스터 노드 enp0s8 로 --apiserver-advertise-address 설정
sudo kubeadm init \
--apiserver-advertise-address "192.168.56.11" \
--pod-network-cidr "10.244.0.0/16" \ # 기본 pod 네트워크 cidr
--upload-certs여기서 etcd, kube-apiserver, kube-controller-manager, kube-scheduler 이 설치되고 ca certificate 이 생성된다.
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 # 아직 네트워크 애드온이 설치되지 않아서 마스터 노드가 NotReady 상태kubeadm init 으로 생성된 /etc/kubernetes/admin.conf 을 사용하여 kubectl 을 통해 kube-apiserver 와 통신할 수 있다.
CNI 설치
kubectl apply -f ${add-on}.yamlCNI 네트워크 애드온 중 하나를 설치한다.
Worker node join
kubeadm join 192.168.56.11:6443 \
--token xxxxxx.xxxxxxxxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkubeadm init 이후 나온 출력에서 join 명령어를 사용해 워커 노드를 클러스터에 조인한다.