Kubernetes 로컬 개발 환경 만들기 - minikube 설치 및 사용

로컬 개발 환경 만들기, 어플리케이션 동작시키기

이번에는 웹 어플리케이션의 컨테이너를 로컬 Kubernetes에 세우는 것을 목표로 한다.

참고로, 여기서는 macOS 중심으로 설치를 진행하였다. 환경이 달라 방법이 다를 수 있으니 참고 바란다.

Minikube 설치 및 사용

이번에는 Minikube라는 로컬 환경에서 Kubernetes를 쉽게 실행할 수 있는 도구를 사용한다. 이 도구를 사용하면 단일 노드 Kubernetes 클러스터를 만들 수 있다.
Minikube의 사용법은 공식 문서를 참고하면 된다.

설치 전 사전 준비

docker 설치

minikube 설치 전에 Docker를 반드시 설치하여 사용하는 것이 좋다.

kubectl 설치

kubectl은 Kubernetes의 Cluster와 통신하여 다양한 Object들의 상태 확인 또는 CRUD 작업 등을 위해 사용되는 CLI 도구이다.
minikube 설치를 하고 Kubernetes Cluster와의 작업을 위해 필요하다.

여기서는 macOS에서 Homebrew를 사용하여 설치할 것이다.

brew install kubectl

다른 시스템에서는 공식 문서를 참고하면서 진행한다.

Minikube macOS에 설치

여기에서는 Homebrew를 사용해서 설치를 진행한다.

brew install minikube
% brew install minikube
Running `brew update --auto-update`...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> New Formulae
agg            echidna        kalign         libplacebo     shaderc
c              gator          kubesess       licenseplist   taplo
distrobox      hof            libff          popeye         vineyard

You have 3 outdated formulae installed.
You can upgrade them with brew upgrade
or list them with brew outdated.

==> Downloading https://ghcr.io/v2/homebrew/core/kubernetes-cli/manifests/1.25.0
######################################################################## 100.0%

... 중간 생략 ...

==> Summary
🍺  /opt/homebrew/Cellar/minikube/1.26.1: 9 files, 70.6MB
==> Running `brew cleanup minikube`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Caveats
==> minikube
zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions

Minikube 사용하기

Minikube cluster 시작

설치가 성공했는지 아래의 Kubernetes 클러스터를 시작하는 명령으로 확인하면 된다.

아래와 같이 쿠버네티스 버전을 입력해서 기동하는 방법이 있다.

minikube start --kubernetes-version [기동하려는 버전]

아래와 같이 지정하지 않으면 신규 버전이 기동된다.

minikube start
% minikube start
😄  Darwin 12.5.1 (arm64) 의 minikube v1.26.1
🆕  이제 1.24.3 버전의 쿠버네티스를 사용할 수 있습니다. 업그레이드를 원하신다면 다음과 같이 지정하세요: --kubernetes-version=v1.24.3
✨  기존 프로필에 기반하여 docker 드라이버를 사용하는 중
👍  minikube 클러스터의 minikube 컨트롤 플레인 노드를 시작하는 중
🚜  베이스 이미지를 다운받는 중 ...
    > gcr.io/k8s-minikube/kicbase:  0 B [______________________] ?% ? p/s 1m11s
🔥  Creating docker container (CPUs=2, Memory=4000MB) ...
    > kubectl.sha1:  41 B / 41 B [---------------------------] 100.00% ? p/s 0s
    > kubeadm.sha1:  41 B / 41 B [---------------------------] 100.00% ? p/s 0s
    > kubelet.sha1:  41 B / 41 B [---------------------------] 100.00% ? p/s 0s
    > kubectl:  42.64 MiB / 42.64 MiB [--------------] 100.00% 4.04 MiB p/s 11s
    > kubeadm:  40.36 MiB / 40.36 MiB [--------------] 100.00% 2.69 MiB p/s 15s
    > kubelet:  111.81 MiB / 111.81 MiB [------------] 100.00% 6.37 MiB p/s 18s

    ▪ 인증서 및 키를 생성하는 중 ...
    ▪ 컨트롤 플레인이 부팅...
💢  initialization failed, will try again: wait: /bin/bash -c "sudo env PATH="/var/lib/minikube/binaries/v1.16.1:$PATH" kubeadm init --config /var/tmp/minikube/kubeadm.yaml  --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests,DirAvailable--var-lib-minikube,DirAvailable--var-lib-minikube-etcd,FileAvailable--etc-kubernetes-manifests-kube-scheduler.yaml,FileAvailable--etc-kubernetes-manifests-kube-apiserver.yaml,FileAvailable--etc-kubernetes-manifests-kube-controller-manager.yaml,FileAvailable--etc-kubernetes-manifests-etcd.yaml,Port-10250,Swap,SystemVerification,FileContent--proc-sys-net-bridge-bridge-nf-call-iptables": Process exited with status 1
stdout:
[init] Using Kubernetes version: v1.16.1
[preflight] Running pre-flight checks

... 중간 생략 ...

stderr:
	[WARNING Swap]: running with swap on is not supported. Please disable swap
	[WARNING SystemVerification]: this Docker version is not on the list of validated versions: 20.10.17. Latest validated version: 18.09
	[WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service'
error execution phase wait-control-plane: couldn't initialize a Kubernetes cluster
To see the stack trace of this error execute with --v=5 or higher

💡  권장: Check output of 'journalctl -xeu kubelet', try passing --extra-config=kubelet.cgroup-driver=systemd to minikube start
🍿  관련 이슈: https://github.com/kubernetes/minikube/issues/4172

Minikube cluster 시작 후에 확인

minikube는 Docker image를 다운받고 실행하여, Kubernetes Cluster를 생성하고, kubectl과의 연결을 위해 ~/.kube/config 파일 설정까지 완료해 준다. 하나씩 살펴보도록 하자.

minikube 시작 시 download 되는 docker image는 아래와 같이 확인 할 수 있다.

% docker images
REPOSITORY                    TAG       IMAGE ID       CREATED        SIZE
gcr.io/k8s-minikube/kicbase   v0.0.33   f7ba2bce4549   5 weeks ago    1.06GB

다운받은 docker image로 minikube container를 실행하여 kubernetes cluster 생성된 것을 확인 할수 잇다.

% docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED             STATUS             PORTS                                                                                                                        NAMES
d9391f64eba5   gcr.io/k8s-minikube/kicbase:v0.0.33   "/usr/local/bin/entr..."   About an hour ago   Up About an hour   0.0.0.0:49463->22/tcp, 0.0.0.0:49464->2376/tcp, 0.0.0.0:49466->5000/tcp, 0.0.0.0:49467->8443/tcp, 0.0.0.0:49465->32443/tcp   minikube

Kubernetes Cluster와 Kubectl의 연결을 위한 정보가 담긴 config 파일 생성되었다.

% cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /Users/user/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Wed, 07 Sep 2022 11:56:39 KST
        provider: minikube.sigs.k8s.io
        version: v1.26.1
      name: cluster_info
    server: https://127.0.0.1:50472
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /Users/user/.minikube/profiles/minikube/client.crt
    client-key: /Users/user/.minikube/profiles/minikube/client.key

Minikube cluster 상태 확인

클러스터에 상태 확인하는 명령어는 아래와 같다.

minikube status
% minikube status
minikube
type: Control Plane
host: Running
kubelet: Stopped
apiserver: Stopped
kubeconfig: Configured

Minikube cluster 일시정지/재가동

kubernetes cluster를 일시정지하는 명령어는 아래와 같다.

minikube pause

일시정지 후에는 kubectl을 통한 Cluster의 접근이나 추가적인 명령어는 timeout이 발생하며 사용이 불가능하다.
단, 이미 배포된 application에는 영향을 미치지 않기 때문에 계속 동작한다.

일시정지 상태에서 다시 Cluster를 재가동 하고자 할때는 아래와 같은 명령어를 사용한다.

minikube unpause

Minikube cluster 종료

minikube stop
% minikube stop
✋  Stopping node "minikube"  ...
🛑  Powering off "minikube" via SSH ...
🛑  1 node stopped.

Minikube cluster 삭제

minikube delete

모든 내용 삭제하는 초기화 명령은 아래와 같다.

% minikube delete --all
🔥  docker 의 "minikube" 를 삭제하는 중 ...
🔥  /Users/user/.minikube/machines/minikube 제거 중 ...
💀  "minikube" 클러스터 관련 정보가 모두 삭제되었습니다
🔥  모든 프로필이 성공적으로 삭제되었습니다

Kubernetes로 웹 서버 설정하여 기동하기

minikube를 설치하였으니, Kubernetes 환경을 만들고 컨테이너를 실행해 보도록 하자.

웹 서버는 Minikube에 해당하는 간단한 응답만 반환하는 echo-server를 사용하도록 하겠다.

minikube 클러스터 생성

그럼 minikube를 기동하여 클러스터를 생성한다. 이미 기동이 되어 있다면 다시 기동하지 않아도 된다.

minikube start

이때 도커 컨테이너의 기동되어 상태를 확인 한다.

% docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED              STATUS              PORTS                                                                                                                        NAMES
39b6898f6256   gcr.io/k8s-minikube/kicbase:v0.0.33   "/usr/local/bin/entr..."   About a minute ago   Up About a minute   0.0.0.0:51435->22/tcp, 0.0.0.0:51436->2376/tcp, 0.0.0.0:51438->5000/tcp, 0.0.0.0:51439->8443/tcp, 0.0.0.0:51437->32443/tcp   minikube

minikube의 컨테이너가 동작하고 있는 것을 확인 할 수 있다.

kubectl 사용하여 생성 배포

다음 kubectl에서 Kubernetes Deployment라는 것을 만든다. 이 Kubernetes Deployment 객체를 작성하는 것으로 어플리케이션을 실행할 수 있게 되었다. 이것은 YAML 파일로 작성할 수 있다. 이것 자체는 서비스라고 하는 것보다, Pod를 만들기 위한 Deployment의 앱인 것이다.

% kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10
deployment.apps/hello-minikube created

혹시, M1 맥북이라면 “echoserver:1.10"가 아닌 “echoserver-arm:1.8"를 사용해야 한다.

kubectl create deploy hello-minikube --image=k8s.gcr.io/echoserver-arm:1.8

생성된 hello-minikube Deployment를 사용하여 서비스로 노출시킨다. 여기가 실제 앱과 거의 동등한 것 같습니다.

% kubectl expose deployment hello-minikube --type=NodePort --port=8080
service/hello-minikube exposed

Pod에 배포된 생성 컨테이너 확인

이 시점에서 docker 컨테이너의 작동 상태를 확인해 보자.

% docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED         STATUS         PORTS                                                                                                                        NAMES
24733d0fd443   gcr.io/k8s-minikube/kicbase:v0.0.33   "/usr/local/bin/entr..."   5 minutes ago   Up 5 minutes   0.0.0.0:54248->22/tcp, 0.0.0.0:54249->2376/tcp, 0.0.0.0:54251->5000/tcp, 0.0.0.0:54247->8443/tcp, 0.0.0.0:54250->32443/tcp   minikube

분명히 hello-minikube라는 컨테이너는 별도로 움직이지 않았으며, minikube의 컨테이너 위에 동작하는거 같다. 아마도 이 minikube 컨테이너 자체에 kubernetes의 단일 노드와 Pod, Deployment가 만들어진 것 같다.

그럼 Pod에 생겼는지 확인한다.

% kubectl get pod
NAME                              READY   STATUS    RESTARTS   AGE
hello-minikube-5d44b6b577-l99jz   1/1     Running   0          4m59s

STATUS가 Running이 되어 있고, 기동하고 있는 것을 확인할 수 있다. 또 “1/1"이라는 것으로 부터 Pod의 수는 1개라는 것도 알 수 있다.

서비스 동작 확인

서비스 URL은 아래와 같이 명령어로 확인 할 수 있다.

% minikube service hello-minikube --url
http://127.0.0.1:54612

브라우저에서 확인해 보면, 어플리케이션이 실행 중인 것을 확인할 수 있다.

echoserver

삭제

다음은 삭제 절차이다.

서비스 삭제는 아래와 같은 명령어로 진행한다.

% kubectl delete services hello-minikube
service "hello-minikube" deleted

hello-minikube Deployment 삭제는 아래와 같은 명령어로 진행한다.

% kubectl delete deployment hello-minikube
deployment.apps "hello-minikube" deleted

부록: 컨테이너 안을 들여다 보기

공식 문서에 있던 로컬 개발 환경을 만드는 튜토리얼은 이 정도로 끝이지만, 컨테이너 안을 들여다 보려고 한다.

아래 명령으로 minikube에 들어가 본다.

% docker exec -itu 0 minikube /bin/bash
root@minikube:/#

컨테이너에 들어가면 루트 디렉터리에 들어가서 뭐가 있는지, 루트 디렉터리에서 ll 명령어를 실행해 보자.

root@minikube:/# ll
total 80
drwxr-xr-x   1 root root 4096 Sep  7 06:33 ./
drwxr-xr-x   1 root root 4096 Sep  7 06:33 ../
-rwxr-xr-x   1 root root    0 Sep  7 06:33 .dockerenv*
-rw-r--r--   1 root root 1093 Jul 29 17:41 Release.key
lrwxrwxrwx   1 root root    7 May 31 15:55 bin -> usr/bin/
drwxr-xr-x   2 root root 4096 Apr 15  2020 boot/
drwxr-xr-x   2 root root 4096 Sep  7 06:33 data/
drwxr-xr-x   9 root root 2820 Sep  7 06:33 dev/
-rw-r--r--   1 root root 3817 Jul 29 17:36 docker.key
drwxr-xr-x   1 root root 4096 Sep  7 06:33 etc/
drwxr-xr-x   1 root root 4096 Jul 29 17:43 home/
-rw-r--r--   1 root root   96 Jul 29 17:43 kic.txt
drwxr-xr-x   1 root root 4096 Sep  7 06:33 kind/
lrwxrwxrwx   1 root root    7 May 31 15:55 lib -> usr/lib/
drwxr-xr-x   2 root root 4096 May 31 15:55 media/
drwxr-xr-x   2 root root 4096 May 31 15:55 mnt/
drwxr-xr-x   1 root root 4096 Sep  7 06:33 opt/
dr-xr-xr-x 231 root root    0 Sep  7 06:33 proc/
drwx------   1 root root 4096 Sep  7 06:33 root/
drwxr-xr-x  13 root root  360 Sep  7 06:33 run/
lrwxrwxrwx   1 root root    8 May 31 15:55 sbin -> usr/sbin/
drwxr-xr-x   2 root root 4096 May 31 15:55 srv/
dr-xr-xr-x  13 root root    0 Sep  7 06:33 sys/
drwxrwxrwt   5 root root  140 Sep  7 06:33 tmp/
drwxr-xr-x   1 root root 4096 Jul 29 17:37 usr/
drwxr-xr-x  14 root root 4096 Sep  7 06:33 var/
root@minikube:/#

top 명령어로 프로세스도 확인해 보자.

root@minikube:/# top
top - 07:23:51 up 18:40,  0 users,  load average: 0.69, 0.44, 0.37
Tasks:  38 total,   1 running,  37 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.5 us,  2.7 sy,  0.0 ni, 94.6 id,  0.1 wa,  0.0 hi,  0.1 si,  0.0 st
MiB Mem :   7851.4 total,   1617.5 free,    972.4 used,   5261.4 buff/cache
MiB Swap:   1024.0 total,   1024.0 free,      0.0 used.   6346.6 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   1855 root      20   0 1998680 100428  64300 S   7.6   1.2   3:17.60 kubelet
   1675 root      20   0 1171496 360280  72324 S   7.3   4.5   5:20.97 kube-apiserver
    588 root      20   0 2028192  91008  44340 S   5.3   1.1   1:24.24 dockerd
    106 root      20   0 1565148  57832  31212 S   3.7   0.7   1:02.06 containerd
    760 root      20   0  740472  40728  24740 S   3.7   0.5   1:13.45 cri-dockerd
   1615 root      20   0  815700  99604  61428 S   3.7   1.2   2:37.76 kube-controller
   1662 root      20   0   10.7g  50516  20972 S   3.3   0.6   2:20.11 etcd
   1669 root      20   0  751044  47684  34416 S   1.0   0.6   0:21.92 kube-scheduler
   1586 root      20   0  712636  10432   7852 S   0.7   0.1   0:02.20 containerd-shim
   1549 root      20   0  712636   9956   7340 S   0.3   0.1   0:02.04 containerd-shim
   1583 root      20   0  712380  10312   7596 S   0.3   0.1   0:02.08 containerd-shim
   1634 root      20   0  712380  10328   7404 S   0.3   0.1   0:02.10 containerd-shim
   2162 root      20   0  712636  10304   7532 S   0.3   0.1   0:03.02 containerd-shim
   2182 root      20   0  750988  44096  32876 S   0.3   0.5   0:15.10 coredns

   ... 이하 생략 ...

콘솔 내용을 보면 상위에 kubeletkube-apiserver의 프로세스가 실행되고 있다.

kube-apiserver는 개발자로부터의 작업을 수락하는 API를 제공하며, kubelet은 에이전트로 각 노드(이번에는 단일 노드)에 있으며, Pod 실행을 보장한다.
containered*로 작성된 많은 프로세스가 있는데, 여러 컨테이너가 올라가 있음을 알 수 있다.

이제 또 docker ps 명령어로 실행되고 있느 도커 컨테이너 목록 조회해 보자.

root@minikube:/# docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS     NAMES
20094df9033f   ba04bb24b957           "/storage-provisioner"   59 minutes ago   Up 59 minutes             k8s_storage-provisioner_storage-provisioner_kube-system_514497a4-deaf-4755-a600-73f796f6be9e_1
a9368295b1f7   7a75aeb869dc           "/usr/local/bin/kube..."   59 minutes ago   Up 59 minutes             k8s_kube-proxy_kube-proxy-52hmm_kube-system_d0ed4ddc-0ccc-4f06-aeb9-cc18d5184e77_0
9b1f9ed7a6c1   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_kube-proxy-52hmm_kube-system_d0ed4ddc-0ccc-4f06-aeb9-cc18d5184e77_0
a7bd350916bd   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_storage-provisioner_kube-system_514497a4-deaf-4755-a600-73f796f6be9e_0
d96748e31b07   edaa71f2aee8           "/coredns -conf /etc..."   59 minutes ago   Up 59 minutes             k8s_coredns_coredns-6d4b75cb6d-8kr7r_kube-system_9c240144-c6cc-4d22-984b-3ea3c0756ea2_0
15ad9748eb82   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_coredns-6d4b75cb6d-8kr7r_kube-system_9c240144-c6cc-4d22-984b-3ea3c0756ea2_0
8ffe4e9bf3b5   531fdfc5fea6           "kube-apiserver --ad..."   59 minutes ago   Up 59 minutes             k8s_kube-apiserver_kube-apiserver-minikube_kube-system_af8a252bb89a737e9c95199d01283487_0
ff7b78b958a0   8f1507b1a173           "kube-scheduler --au..."   59 minutes ago   Up 59 minutes             k8s_kube-scheduler_kube-scheduler-minikube_kube-system_2e95d5efbc70e877d20097c03ba4ff89_0
d7366714e112   a9a710bb96df           "etcd --advertise-cl..."   59 minutes ago   Up 59 minutes             k8s_etcd_etcd-minikube_kube-system_906edd533192a4db2396a938662a5271_0
2beb89ca5127   f98535efcd55           "kube-controller-man..."   59 minutes ago   Up 59 minutes             k8s_kube-controller-manager_kube-controller-manager-minikube_kube-system_76444121a189d8a30add20fb32ab6d4e_0
24a244ecac48   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_etcd-minikube_kube-system_906edd533192a4db2396a938662a5271_0
5ee0a82c5478   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_kube-controller-manager-minikube_kube-system_76444121a189d8a30add20fb32ab6d4e_0
bea7e607e058   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_kube-apiserver-minikube_kube-system_af8a252bb89a737e9c95199d01283487_0
c126a82b0d93   k8s.gcr.io/pause:3.6   "/pause"                 59 minutes ago   Up 59 minutes             k8s_POD_kube-scheduler-minikube_kube-system_2e95d5efbc70e877d20097c03ba4ff89_0
root@minikube:/#

컨테이너 내에서 컨테이너의 가동을 처음해 봤는데, 이것으로 echoserver의 이미지를 사용한 컨테이너가 움직이고 있는 것을 알았다.

가설이지만 NAMES를 보면, POD라는 문자가 쓰여 있는 컨테이너가 있고, Pod를 컨테이너로 표현하고 있는 것으로 생각된다.
kube-proxy의 컨테이너도 있는 것 같고, 이 녀석이 Service의 프록시로서 움직이고 있는 것 같다.

이번은 여기까지 이지만, 다음번은 좀 더 Kubernetes의 아키텍처와 설정을 바꾸어 가면서 어떻게 동작하는지 보도록 하겠다.

참고




최종 수정 : 2022-09-07