Kubernetes

Kind와 OrbStack를 사용해서 쉽게 Local에서 Kubernetes 사용하기

mokpolar 2024. 9. 5. 00:10
반응형

들어가며

안녕하세요?
Kind 라는 도구와 Orbstack를 함께 사용해본 후기를 써보겠습니다.

이 글은 CloudNeta팀 가시다님의 KANS (Kubernetes Advanced Network Study) 2주차 스터디의 과제로 작성하였습니다.

Kind가 뭔가요?

Kind를 이용하면 로컬에서 Kubernetes를 쉽고 간단하게 올릴 수 있습니다.
Macbook M1 Pro를 사용하는 제 환경에서도 아주 편리하게 할 수 있습니다.

Kind 공식문서에서는 이렇게 소개하고 있습니다.

kind is a tool for running local Kubernetes clusters using Docker container “nodes”.
kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI.
kind는 도커 컨테이너 "노드"를 사용하여 로컬 쿠버네티스 클러스터를 실행하는 도구로, 주로 쿠버네티스 자체를 테스트하기 위해 설계되었지만 로컬 개발이나 CI에 사용할 수도 있다.

 

Kind를 로컬에서 쓰려면 어쨌거나 로컬에서 Container를 구동할 수 있어야 합니다.
하지만 편리한 도구였던 Docker Desktop은 이제 사용하지 않습니다.
그래서 OrbStack 이란 도구를 소개합니다.

OrbStack이 뭔가요?

OrbStack은 이 글을 작성한 2024.9.3 기준 최근에 GeekNews에 소개되었습니다.
OrbStack - macOS에서 빠르고 쉽게 Docker 컨테이너 및 Linux 실행하기 | GeekNews

OrbStack은 Docker Desktop의 대체재를 찾다가 사용하게 된 도구입니다.


틈틈이 유료화된 Docker Desktop의 대체제를 찾는 과정이 있었습니다.
EC2에서 container build하기, Rancher Desktop쓰기.... 하지만 아무래도 Docker Desktop을 사용하던 경험으로는 불편했습니다.

 

GeekNew에서는 Orbstack의 도구를 아래와 같이 소개하고 있습니다.
굉장히 성능이 좋다고 합니다.


M1 Mac에서 Docker를 사용하는 사람들에게 강력 추천! 이라고 하네요.

Geeknews의 요약

  • 맥에서 Docker 컨테이너, 쿠버네티스, 각종 Linux 배포본을 빠르고 간편하게 실행하는 Docker Desktop 대체제
  • 몇초만에 부팅 가능 : 부드러운 Rosetta x86 에뮬레이션, VirtioFS 파일 공유, 최적화된 네트워크
  • 더 적은 CPU 및 디스크 사용량. 배터리를 절약하고 더 적은 메모리에서 동작하는 네이티브 Swift 앱
    • Apple Silicon에서 백그라운드 CPU 사용량 0.1% 미만. 디스크 사용량 10MB 미만
  • 각 컨테이너에 대해 자동으로 도메인 네임 설정 (*.orb.local)
  • 기존 Docker Desktop 마이그레이션 지원
  • 네이티브 앱 외에도 모든 작업을 CLI 명령어로 수행 가능. Mac과 Linux 간 파일 복사 및 명령어 실행 용이
  • 성능 벤치 마크
    • Open edX 빌드 : OrbStack 17분, Docker Desktop 45분
    • PostHog 빌드 : OrbStack 7분, Docker Desktop 19분
    • CPU & 배터리 사용량 (쿠버네티스 wth Traefik/Grafana) : OrbStack 27mW, Docker Desktop 123mW
    • CPU & 배터리 사용량 (Supabase) : OrbStack 82mW, Docker Desktop 137mW
  • 개인 사용자는 무료, 비즈니스 & 상용은 사용자당 월 $8, 교육용 무료 라이센스 제공

사용자 리뷰

  • Mark_Shust: Docker Desktop을 삭제하고 OrbStack을 사용. 성능이 100배 더 좋음.
  • Michael Roberts: Docker Desktop에서 OrbStack으로 전환 후 성능이 획기적으로 향상됨.
  • Hynek Schlawack: Docker, Colima 등을 완전히 대체. 빠르고 업데이트도 잘 됨.
  • Francesco Di Lorenzo: M1 Mac에서 Docker를 사용하는 사람들에게 강력 추천.
  • Koen Bok: Docker를 사용하는 사람들에게 OrbStack을 추천.
  • Sibelius Seraphini: OrbStack 덕분에 Docker 사용이 다시 좋아짐.
  • Mikael Henriksson: M1/M2 Mac 사용자에게 강력 추천.
  • Mohamed Akram: OrbStack을 사용하여 컴퓨터 팬 소음 줄임.
  • Luis Dalmolin: Intel Mac에서 Docker를 OrbStack으로 대체 후 성능 향상.

OrbStack · Fast, light, simple Docker & Linux on macOS
위 공식홈페이지에서 다운 받아 설치할 수 있습니다.

brew install orbstack

 

OrbStack의 UI

사실 OrbStack 은 Container를 로컬에서 구동하기 위해 Docker Desktop의 대체재로 사용한 것뿐이라 사용 경험에 대해 많이 쓸 건 없습니다.
편하고 빠릅니다.

UI는 아래와 같이 생겼습니다.

 

이렇게 구동하면 바로 docker를 사용할 수 있습니다.
심지어 좌측 간이 Kubernetes Cluster도 쉽게 띄울 수 있습니다.
아마 곧 자세히 소개하게 될 Kind와 같이 D in D 원리를 이용한 것이 아닌가 하는 생각이 듭니다.

Kind의 사용

Kind 설치

설치해서 사용하는 방법은 굉장히 간단합니다.
설치하는 김에 유용한 도구들도 같이 설치해줍니다.
가시다님의 스터디는 유용한 도구들을 많이 알려줍니다.

  • 터미널에서 쿠버네티스 사용시 유용한 도구들
    kube-ps1 : 현재 쿠버네티스 컨텍스트와 네임스페이스를 Bash/Zsh 프롬프트 문자열에 추가해줍니다.
    kubecolor: kubectl output에 예쁘게 색을 넣어줍니다.
    kubectx: kube context 전환이 굉장히 쉬워집니다.
brew install kind
brew install kubernetes-cli
berw install helm
brew install krew
brew install kube-ps1
brew install kubecolor
brew install kubectx

 

Kind 클러스터는 아래와 같이 실행하면 순식간에 생성됩니다.
Kind의 장점 중 하나는 제가 사용 중인 Mac M1은 ARM 인데,
알아서 크로스플랫폼 이미지를 제공해서 상관없이 구동할 수 있게 해줍니다.

kind create cluster
kind get nodes
kind-control-plane

 

클러스터가 잘 생성되었는지 확인해봅니다.
순식간에 생성되었지만 진짜 제대로 쿠버네티스 클러스터처럼 정보들을 볼 수 있습니다.

kind get clusters

kind

kind get nodes

kind-control-plane

kubectl get pod -A

NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE
kube-system          coredns-6f6b679f8f-h59c7                     1/1     Running   0          42s
kube-system          coredns-6f6b679f8f-l5zg9                     1/1     Running   0          42s
kube-system          etcd-kind-control-plane                      1/1     Running   0          49s
kube-system          kindnet-r4xb4                                1/1     Running   0          42s
kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          49s
kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          48s
kube-system          kube-proxy-swgbn                             1/1     Running   0          42s
kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          48s
local-path-storage   local-path-provisioner-57c5987fd4-68qlw      1/1     Running   0          42s

 

그럼 컨테이너로서 동작하고 있는걸까요?
네 이건 실제로 컨테이너입니다!

docker ps
CONTAINER ID   IMAGE                  COMMAND                   CREATED              STATUS              PORTS                       NAMES
4c9eb7705bcf   kindest/node:v1.31.0   "/usr/local/bin/entr…"   About a minute ago   Up About a minute   127.0.0.1:60363->6443/tcp   kind-control-plane

 

도커 이미지로 보면 아래와 같습니다.

docker images
REPOSITORY        TAG             IMAGE ID       CREATED        SIZE
kindest/node      <none>          9d05f134f12f   2 weeks ago    1.04GB
traefik           latest          dfdbdfae3fb3   3 weeks ago    172MB
timberio/vector   0.39.0-debian   87e3c55810d3   2 months ago   245MB
traefik/whoami    latest          9dd7aa3decf4   3 months ago   6.66MB

 

이제 이 컨테이너로 이루어진 클러스터에 테스트용 nginx pod를 배포해보겠습니다.
딱히 제약을 두지는 않아서 컨트롤플레인 노드에 배포가 된다.

kubectl run nginx --image=nginx:alpine

pod/nginx created

k get pod -o wide
NAME    READY   STATUS              RESTARTS   AGE   IP       NODE                 NOMINATED NODE   READINESS GATES
nginx   0/1     ContainerCreating   0          5s    <none>   kind-control-plane   <none>           <none>

 

이번엔 컨테이너로 배포된 "노드" 에 대해 describe를 실행해보겠습니다.
노드.. 네요?

k describe node
Name:               kind-control-plane
Roles:              control-plane
Labels:             beta.kubernetes.io/arch=arm64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=arm64
                    kubernetes.io/hostname=kind-control-plane
                    kubernetes.io/os=linux
                    node-role.kubernetes.io/control-plane=
Annotations:        kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock
                    node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Sun, 01 Sep 2024 20:16:44 +0900
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  kind-control-plane
  AcquireTime:     <unset>
  RenewTime:       Sun, 01 Sep 2024 20:19:50 +0900
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  MemoryPressure   False   Sun, 01 Sep 2024 20:19:49 +0900   Sun, 01 Sep 2024 20:16:42 +0900   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure     False   Sun, 01 Sep 2024 20:19:49 +0900   Sun, 01 Sep 2024 20:16:42 +0900   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure      False   Sun, 01 Sep 2024 20:19:49 +0900   Sun, 01 Sep 2024 20:16:42 +0900   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready            True    Sun, 01 Sep 2024 20:19:49 +0900   Sun, 01 Sep 2024 20:17:05 +0900   KubeletReady                 kubelet is posting ready status
Addresses:
  InternalIP:  192.168.247.2
  Hostname:    kind-control-plane
Capacity:
  cpu:                10
  ephemeral-storage:  615233208Ki
  memory:             5440520Ki
  pods:               110
Allocatable:
  cpu:                10
  ephemeral-storage:  615233208Ki
  memory:             5440520Ki
  pods:               110
System Info:
  Machine ID:                 d3b62ae81dc448168ffd6b457507e591
  System UUID:                d3b62ae81dc448168ffd6b457507e591
  Boot ID:                    ae1c832f-c1d0-4672-a00c-652a29151768
  Kernel Version:             6.10.6-orbstack-00249-g92ad2848917c
  OS Image:                   Debian GNU/Linux 12 (bookworm)
  Operating System:           linux
  Architecture:               arm64
  Container Runtime Version:  containerd://1.7.18
  Kubelet Version:            v1.31.0
  Kube-Proxy Version:
PodCIDR:                      10.244.0.0/24
PodCIDRs:                     10.244.0.0/24
ProviderID:                   kind://docker/kind/kind-control-plane
Non-terminated Pods:          (10 in total)
  Namespace                   Name                                          CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                          ------------  ----------  ---------------  -------------  ---
  default                     nginx                                         0 (0%)        0 (0%)      0 (0%)           0 (0%)         32s
  kube-system                 coredns-6f6b679f8f-h59c7                      100m (1%)     0 (0%)      70Mi (1%)        170Mi (3%)     3m1s
  kube-system                 coredns-6f6b679f8f-l5zg9                      100m (1%)     0 (0%)      70Mi (1%)        170Mi (3%)     3m1s
  kube-system                 etcd-kind-control-plane                       100m (1%)     0 (0%)      100Mi (1%)       0 (0%)         3m8s
  kube-system                 kindnet-r4xb4                                 100m (1%)     100m (1%)   50Mi (0%)        50Mi (0%)      3m1s
  kube-system                 kube-apiserver-kind-control-plane             250m (2%)     0 (0%)      0 (0%)           0 (0%)         3m8s
  kube-system                 kube-controller-manager-kind-control-plane    200m (2%)     0 (0%)      0 (0%)           0 (0%)         3m7s
  kube-system                 kube-proxy-swgbn                              0 (0%)        0 (0%)      0 (0%)           0 (0%)         3m1s
  kube-system                 kube-scheduler-kind-control-plane             100m (1%)     0 (0%)      0 (0%)           0 (0%)         3m7s
  local-path-storage          local-path-provisioner-57c5987fd4-68qlw       0 (0%)        0 (0%)      0 (0%)           0 (0%)         3m1s
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests    Limits
  --------           --------    ------
  cpu                950m (9%)   100m (1%)
  memory             290Mi (5%)  390Mi (7%)
  ephemeral-storage  0 (0%)      0 (0%)
Events:
  Type    Reason                   Age    From             Message
  ----    ------                   ----   ----             -------
  Normal  Starting                 3m     kube-proxy
  Normal  Starting                 3m7s   kubelet          Starting kubelet.
  Normal  NodeAllocatableEnforced  3m7s   kubelet          Updated Node Allocatable limit across pods
  Normal  NodeHasSufficientMemory  3m7s   kubelet          Node kind-control-plane status is now: NodeHasSufficientMemory
  Normal  NodeHasNoDiskPressure    3m7s   kubelet          Node kind-control-plane status is now: NodeHasNoDiskPressure
  Normal  NodeHasSufficientPID     3m7s   kubelet          Node kind-control-plane status is now: NodeHasSufficientPID
  Normal  RegisteredNode           3m2s   node-controller  Node kind-control-plane event: Registered Node kind-control-plane in Controller
  Normal  NodeReady                2m48s  kubelet          Node kind-control-plane status is now: NodeReady

 

kind로 배포한 뒤에 지우는것도 쉽게 할 수 있습니다.

kind delete cluster
Deleting cluster "kind" ...
Deleted nodes: ["kind-control-plane"]

Kind의 구조

설치를 먼저 해봤으니 Kind 구조에 대한 내용을 확인해보겠습니다.
공식 문서는 이곳입니다. kind – Initial design

 

Kind는 Docker in Docker 구조로 구성되어 있다고 합니다.

무슨 의미인지는 아래 그림을 보면 알 수 있습니다.

 

docker가 떠서 "컨테이너"로 된 컨트롤 플레인 노드, 워커 노드를 띄우고 그 안에서 docker가 다시 pod를 띄우는 모습을 볼 수 있습니다.

 

위 구조대로 띄워서 Kind 내부 확인해보기

 

아래와 같이 node를 role을 지정하여 2개를 띄울 수 있습니다.
control-plane, worker 각각 1개씩입니다.

cat << EOT > kind-2node.yaml 
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOT

kind create cluster --config kind-2node.yaml --name myk8s

Creating cluster "myk8s" ...
 ✓ Ensuring node image (kindest/node:v1.31.0) 🖼
 ✓ Preparing nodes 📦 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-myk8s"
You can now use your cluster with:

kubectl cluster-info --context kind-myk8s

Have a nice day! 👋

도커가 각 노드 컨테이너들을 이미지로 띄웁니다.
이렇게 컨테이너를 조회해보면
myk8s-control-plane
myk8s-worker
의 이름을 가진 컨테이너 2개가 떠있습니다.

 

컨테이너지만 각각 control-plane node, worker node의 역할을 하는 것입니다.

docker container ls
CONTAINER ID   IMAGE                  COMMAND                   CREATED          STATUS          PORTS                       NAMES
788fb26a49c1   kindest/node:v1.31.0   "/usr/local/bin/entr…"   40 seconds ago   Up 38 seconds   127.0.0.1:51046->6443/tcp   myk8s-control-plane
5430e59496dd   kindest/node:v1.31.0   "/usr/local/bin/entr…"   40 seconds ago   Up 38 seconds                               myk8s-worker

 

이제 OrbStack을 통해 control-plane에 접근해보겠습니다.

 

Terminal을 클릭하면

 

이런 식으로 접근이 가능합니다.
여기서 docker command가 아니라 crictl command를 사용하겠습니다.

 

노드 내부에는 container runtime이 CRI 기반의 런타임인 containerd로 되어있기 때문입니다.
이미지를 조회해보면 pod로 뜰 image들을 볼 수 있습니다.

crictl image ls
IMAGE                                           TAG                  IMAGE ID            SIZE
docker.io/kindest/kindnetd                      v20240813-c6f155d6   6a23fa8fd2b78       33.3MB
docker.io/kindest/local-path-helper             v20230510-486859a6   d022557af8b63       2.92MB
docker.io/kindest/local-path-provisioner        v20240813-c6f155d6   282f619d10d4d       17.4MB
registry.k8s.io/coredns/coredns                 v1.11.1              2437cf7621777       16.5MB
registry.k8s.io/etcd                            3.5.15-0             27e3830e14027       66.5MB
registry.k8s.io/kube-apiserver-arm64            v1.31.0              add78c37da6e2       92.6MB
registry.k8s.io/kube-apiserver                  v1.31.0              add78c37da6e2       92.6MB
registry.k8s.io/kube-controller-manager-arm64   v1.31.0              c50d473e11f63       86.9MB
registry.k8s.io/kube-controller-manager         v1.31.0              c50d473e11f63       86.9MB
registry.k8s.io/kube-proxy-arm64                v1.31.0              c573e1357a14e       95.9MB
registry.k8s.io/kube-proxy                      v1.31.0              c573e1357a14e       95.9MB
registry.k8s.io/kube-scheduler-arm64            v1.31.0              8377f1e14db4c       67MB
registry.k8s.io/kube-scheduler                  v1.31.0              8377f1e14db4c       67MB
registry.k8s.io/pause                           3.10                 afb61768ce381       268kB

 

또한 실제로 동작하고 있는 컨테이너들로서 존재하고 있는 것을 볼 수 있습니다.

crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                      ATTEMPT             POD ID              POD
540f586b174e6       282f619d10d4d       7 minutes ago       Running             local-path-provisioner    0                   af1a6218fcb80       local-path-provisioner-57c5987fd4-fkh2c
f830ab7f6a99c       2437cf7621777       7 minutes ago       Running             coredns                   0                   860c9795268ee       coredns-6f6b679f8f-t2dzn
01b40847359e4       2437cf7621777       7 minutes ago       Running             coredns                   0                   235c208e5ddac       coredns-6f6b679f8f-f6drq
27a35c43a02fb       6a23fa8fd2b78       7 minutes ago       Running             kindnet-cni               0                   b405b0f3f2fa9       kindnet-qtpsz
57c41de1d4995       c573e1357a14e       7 minutes ago       Running             kube-proxy                0                   7f936e130c2f9       kube-proxy-rnlqz
d4bb82e61d08c       27e3830e14027       7 minutes ago       Running             etcd                      0                   b3a4fdfe5caf6       etcd-myk8s-control-plane
1abadf943e468       add78c37da6e2       7 minutes ago       Running             kube-apiserver            0                   8bafab3726336       kube-apiserver-myk8s-control-plane
94c33059b4b3b       c50d473e11f63       7 minutes ago       Running             kube-controller-manager   0                   7976afb4c1494       kube-controller-manager-myk8s-control-plane
1189bb3c7a923       8377f1e14db4c       7 minutes ago       Running             kube-scheduler            0                   9961e0f2fd8db       kube-scheduler-myk8s-control-plane

 

이제 다시 일반 터미널로 돌아와서 pod들을 조회해보겠습니다.
위에서 본 컨테이너들과 같은 pod들이 떠 있는 것을 알 수 있습니다.

k get pod -A
NAMESPACE            NAME                                          READY   STATUS    RESTARTS   AGE
kube-system          coredns-6f6b679f8f-f6drq                      1/1     Running   0          9m12s
kube-system          coredns-6f6b679f8f-t2dzn                      1/1     Running   0          9m12s
kube-system          etcd-myk8s-control-plane                      1/1     Running   0          9m19s
kube-system          kindnet-qtpsz                                 1/1     Running   0          9m12s
kube-system          kindnet-tz28w                                 1/1     Running   0          9m10s
kube-system          kube-apiserver-myk8s-control-plane            1/1     Running   0          9m19s
kube-system          kube-controller-manager-myk8s-control-plane   1/1     Running   0          9m18s
kube-system          kube-proxy-rnlqz                              1/1     Running   0          9m12s
kube-system          kube-proxy-txwbd                              1/1     Running   0          9m10s
kube-system          kube-scheduler-myk8s-control-plane            1/1     Running   0          9m19s
local-path-storage   local-path-provisioner-57c5987fd4-fkh2c       1/1     Running   0          9m12s

 

이제 컨트롤 플레인 노드의 내부 파일들을 한번 볼까요?

 

다시 OrbStack으로 돌아와서 Files를 클릭해보겠습니다.

 

이렇게 쉽게 컨트롤 플레인의 파일 목록을 볼 수 있습니다.

/etc/kubernetes/manifests 경로로 가보면 아래와 같이 저희가 생각하는 파일들이 있는 모습을 볼 수 있습니다.

 

 

Reference

https://kind.sigs.k8s.io/
https://news.hada.io/topic?id=16581&utm_source=slack&utm_medium=bot&utm_campaign=T01DC7G8W4X
https://kind.sigs.k8s.io/docs/design/initial/

반응형