지금부터 아무것도 설치되지 않은 깨끗한 ubuntu vm에 쿠버네티스 설치, 클러스터를 구성하는 방법을 정리해보려고 한다.
그동안 쿠버네티스를 여러번 설치해봤지만.. 방법을 잘 정리해놓지 않아서 나중에 보면 또 새로웠던..ㅠㅠㅋㅋㅋ
오늘은 Kubespray 기본 설치 방법을 깔끔하게 정리해 놓기가 목표다!
혹시라도, 이 글을 보고 바닐라 쿠버네티스로 클러스터를 구성하려고 하시는 분들이 계시다면,
전혀 어렵지 않습니다!
저도 처음에는 매우 헤맸으나 찬찬히 보다보면 어렵지 않고 편리한 도구들이 많이 제공되고 있음을 알 수 있을 거예요.
따라하기 전에 아래 공식 문서 먼저 읽어보시고, 진행 중 어려움이 있다면 댓글로 공유해주세요 (도움이 될 수 있다면 같이 찾아보겠습니다.)
https://kubernetes.io/ko/docs/setup/production-environment/tools/kubespray/
k8s 설치 도구
k8s 공식 문서에서는 쿠버네티스 설치 방법을 세 가지로 안내하고 있다.
https://kubernetes.io/ko/docs/setup/production-environment/tools/
1, 3번 방식으로 클러스터를 구성해 봤다.
1번 방식이 제일 classic한 방법인 것 같다. 클러스터를 구성하기 위해 필요한 요소들(container runtime, kubeadm, kubelet, kubectl 등)을 하나하나 설치해야 하기 때문에 클러스터 구성에 필요한 도구를 명확하게 알 수 있다는 장점이 있지만 node 수가 많아질 경우, 모든 node 마다 위의 도구들을 각각 개별적으로 설치하고 master node에 join 작업을 해줘야 하는 번거로움이 있다.
오늘은 3번 방식 Kubespray 기본 설정으로 간단하게 클러스터를 구성하는 방법을 알아보자!
Kubespray란?
Kubespray는 Ansible 플레이북, 인벤토리, 프로비저닝 도구와 일반적인 운영체제, 쿠버네티스 클러스터의 설정 관리 작업에 대한 도메인 지식의 결합으로 만들어졌다.
즉 ansible 플레이북, 인벤토리, 프로비저닝 도구 등 다양한 도구와 결합하여 쿠버네티스 설치, 클러스터 구축을 쉽고 편리하게 할 수 있도록 해주는 자동화 도구로 이해할 수 있겠다.
Kubeadm으로 설치 시 각 node host 별로 각각 설치해 줬던 작업들을 Kubespray에 미리 정의해 놓은 inventory에 맞게 모든 노드에 한번에 설치 명령을 내릴 수 있다. ssh key 등록을 위해 worker node에서 작업할 때는 제외하고, 한 노드(master node)에서 설치 명령을 내릴 수 있기 때문에 각 노드에서 직접 작업할 필요가 없다. "spray"라는 이름이 모든 노드에 뿌려서 자동으로 설치하는 개념에서 붙은 용어가 아닐까 싶다.
각 노드 별로 필요한 도구들(kubeadm, kubelet, containerd, calico 등)을 자동으로 설치해주고, kubeadm으로 설치 시에 별도로 해줘야 하는 swap 메모리 비활성화 작업도 기본 설정으로 수행해준다.
Kubespray로 설치 시 deployment 속성을 변경하면 아래 내용들을 customize하게 변경할 수 있다. 오늘은 별도의 설정 변경 없이 기본 설정으로 쭉 설치하는 방법으로 진행한다.
기본 container runtime을 변경하거나, kubectl 버전 등을 변경하고 싶다면 속성값을 변경한 후 설치해야 한다.
Kubespray에서는 디플로이먼트의 많은 속성들을 사용자가 정의(customize)할 수 있다:
- 디플로이먼트 모드의 선택: kubeadm 또는 그 외
- CNI(네트워킹) 플러그인
- DNS 설정
- 컨트롤 플레인 선택: 네이티브/바이너리 또는 컨테이너화 된 것
- 컴포넌트 버전
- Calico 라우터 리플렉터
- 컴포넌트 런타임 옵션
- 인증서 생성 방법
설치 환경
- host 환경 : GCP VM 이용
- os : Ubuntu 22.04.4 LTS (GNU/Linux 6.5.0-1025-gcp x86_64)
- node : master node 1, worker node 1, worker node 2
- kubespray version : v2.25.0
- kubernetes version : v1.30.3
Kubespray로 쿠버네티스 설치하기
1. (사전 작업1) vm 생성
작업 환경은 gcloud를 사용하기로 했다. master, worker로 사용할 gcp vm instance 3대를 생성한다.
gcp console에서 직접 생성할 수도 있지만, 나는 gcloud cli를 통해 instance를 생성했다.
vm 생성 스크립트가 필요하신 분은 아래 접은글을 참고해주세요!
# 클러스터 구성용 vm 생성
gcloud compute instances create k8s-master-1 k8s-worker-1 k8s-worker-2 \
--project=pey-playground \
--zone=asia-northeast3-a \
--machine-type=e2-medium \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--boot-disk-size=100GB

# gcp vm 접속
# gcp instance 접속을 위한 ssh key 생성 (매번 하지 않아도 됨. 한번 만들어 놓고 key가 유효한 상태이면 ssh로 바로 접속할 수 있음)
gcloud compute config-ssh --ssh-key-file=~/.ssh/gcp_rsa
# ssh 접속
# ssh vm_instance_name.zone.project_id
ssh k8s-master-1.asia-northeast3-a.pey-playground

2. (사전 작업2) vm 방화벽 오픈
쿠버네티스에서 사용하는 port를 오픈해준다. vm을 생성한 환경에 따라 같은 네트워크 대역인 경우 자동으로 통신에 필요한 port가 오픈되어 있을 수 있으나, 환경에 따라 방화벽 정책이 다르기 때문에 k8s 공식 문서에 기재되어 있는 port는 명시적으로 오픈하는게 좋다.
포트와 프로토콜
물리적 네트워크 방화벽이 있는 온프레미스 데이터 센터 또는 퍼블릭 클라우드의 가상 네트워크와 같이 네트워크 경계가 엄격한 환경에서 쿠버네티스를 실행할 때, 쿠버네티스 구성 요소에서
kubernetes.io
GCP 방화벽 오픈 방법 참고 😬
GCP에서는 아래와 같이 방화벽 규칙을 만들고 vm에 방화벽 규칙 태그를 적용하는 방식으로 port 오픈 규칙을 적용할 수 있다.
아래와 같이 control-plane용 방화벽 규칙, worker-node용 방화벽 규칙을 만든 후 vm에 해당 태그를 적용하였다.


3. (사전 작업3) timezone 설정
k8s 설치와 관련 없지만, 로그 등 작업 내역 확인 시 편의를 위해 시간대를 우리나라로 설정한다.
timedatectl set-timezone Asia/Seoul
# timezone 적용 확인
timedatectl
4. (사전 작업4) 각 node 접속을 위한 ssh key 생성
master node에서 kubespray를 통해 각 worker node에 install을 진행해야 한다. 이렇게 되기 위해서는 각 노드 별 통신이 가능해야 하는데, master node -> worker node로 통신이 가능하도록 ssh key를 생성하고 적용해준다.
즉, master node에서 worker node로 ssh 접속이 모두 가능한 상태로 만든 이후에 설치 작업을 진행해야 한다.
추가로, root 계정으로 설치를 진행하겠다.
아무것도 하지 않은 상태에서 아래와 같이 worker node에 접속하려고하면, 접속이 불가능한 것을 확인할 수 있다.

4-1. key 생성
master node server에서 공개키 생성 후 worker node server에 복사하는 작업을 진행한다.
* ssh-keygen -t rsa 명령어는 SSH(Secure Shell) 프로토콜에서 사용할 RSA 알고리즘 기반의 공개 키와 개인 키 쌍을 생성하는 명령어입니다.
# root로 작업
sudo su -
# ssh key 생성
ssh-keygen -t rsa
# 생성된 key 확인
cd ~/.ssh
ls -al
4-2. 각 worker node vm에 public key 복사
* gcp 환경에서 ssh-copy-id 명령어가 정상 동작하지 않아서 직접 key를 복사하는 방법을 사용했습니다.
(vm 환경에서 key 복사 편하게 할 수 있는 방법 아시는 분들은 알려주세요🧐)
master vm에 생성된 id_rsa.pub 파일의 내용을 worker node /root/.ssh/authorized_keys 파일에 복사한다.
* vi editor 사용했음.
* 모든 worker node에 다 해줘야 함
* 추가로 master node 내의 authorized_keys 파일에도 등록해줘야 한다! (master -> master 에서 접속도 필요하기 때문에..)


4-3. master node -> worker node로 ssh 정상 접속 확인
key 등록을 완료한 후, 아래 방법을 참고하여 master node에서 모든 node(master, worker)로 정상 접속 되는지 확인한다.
# ssh 접속 확인
# ssh <user>@<host>
ssh root@10.178.0.22
5. (사전 작업5) python install
gcp ubuntu 22.04 이미지에 기본으로 Python3 3.10.12 버전이 설치되어 있지만, 확인해 보고 설치되어 있지 않는 경우 아래 명령어로 설치하면 된다.
# python3 설치 버전 확인
python3 -V
# python3 설치
apt update
apt install -y python3-pip
6. kubespray 소스 pull
작업용 workspace 폴더를 만든 후(필수 아님) 해당 경로에 kubespray git clone 으로 소스를 받아온다.
export WORKSPACE=${HOME}/workspace
mkdir -p ${WORKSPACE}
cd ${WORKSPACE}
git clone https://github.com/kubernetes-sigs/kubespray.git
# 참고 - 버전 확인
cd kubespray/
git describe --tags # 2024.07.29 기준 v2.25.0-81-g468c5641b
7. 필수 패키지 install
requirements.txt에 나와 있는 필수 패키지를 설치한다.

pip3 install -r ${WORKSPACE}/kubespray/requirements.txt
8. 설치를 위한 inventory 파일 구성하기
설치를 위한 inventory를 작성한다. 기본 샘플 파일을 복사하여 필요한 값을 변경하는 방식으로 진행하였다.
# inventory 파일 샘플을 복사하여 클러스터 구성할 파일을 생성한다.
cp -rfp ${WORKSPACE}/kubespray/inventory/sample ${WORKSPACE}/kubespray/inventory/mycluster
sample inventory.ini 파일은 아래 형태로 되어 있다.
# ## Configure 'ip' variable to bind kubernetes services on a
# ## different ip than the default iface
# ## We should set etcd_member_name for etcd cluster. The node that is not a etcd member do not need to set the value, or can set the empty string value.
[all]
# node1 ansible_host=95.54.0.12 # ip=10.3.0.1 etcd_member_name=etcd1
# node2 ansible_host=95.54.0.13 # ip=10.3.0.2 etcd_member_name=etcd2
# node3 ansible_host=95.54.0.14 # ip=10.3.0.3 etcd_member_name=etcd3
# node4 ansible_host=95.54.0.15 # ip=10.3.0.4 etcd_member_name=etcd4
# node5 ansible_host=95.54.0.16 # ip=10.3.0.5 etcd_member_name=etcd5
# node6 ansible_host=95.54.0.17 # ip=10.3.0.6 etcd_member_name=etcd6
# ## configure a bastion host if your nodes are not directly reachable
# [bastion]
# bastion ansible_host=x.x.x.x ansible_user=some_user
[kube_control_plane]
# node1
# node2
# node3
[etcd]
# node1
# node2
# node3
[kube_node]
# node2
# node3
# node4
# node5
# node6
[calico_rr]
[k8s_cluster:children]
kube_control_plane
kube_node
calico_rr
아래와 같이 수정한다.
- [all] : 모든 노드를 작성한다.
* ansible_host와 ip 차이 : ansible_host는 ansible이 ssh 연결 시 사용하는 주소. ip는 노드의 실제 네트워크 주소. 일반적으로 두 주소는 동일하게 설정되지만, nat나 dns를 사용하는 경우 다르게 셋팅될 수 있음
* etcd_member_name : etcd 클러스터의 각 멤버를 식별하는 고유한 이름. 별도 설정하지 않으면 자동으로 랜덤 이름이 부여된다고 함. - [kube_control_plane] : master node를 작성한다.
- [etcd] : etcd 노드가 배포될 영역을 지정한다. 일반적으로 master node에 배포된다.
- [kube_node] : worker node를 작성한다.
cd ${WORKSPACE}/kubespray/inventory/mycluster
vi inventory.ini
# 아래와 같이 수정하였음.
# ---------------------------------
# ## Configure 'ip' variable to bind kubernetes services on a
# ## different ip than the default iface
# ## We should set etcd_member_name for etcd cluster. The node that is not a etcd member do not need to set the value, or can set the empty string value.
[all]
master1 ansible_host=10.178.0.23 ip=10.178.0.23 etcd_member_name=etcd1
worker1 ansible_host=10.178.0.24 ip=10.178.0.24 etcd_member_name=etcd2
worker2 ansible_host=10.178.0.22 ip=10.178.0.22 etcd_member_name=etcd3
# ## configure a bastion host if your nodes are not directly reachable
# [bastion]
# bastion ansible_host=x.x.x.x ansible_user=some_user
[kube_control_plane]
master1
[etcd]
master1
[kube_node]
worker1
worker2
[calico_rr]
[k8s_cluster:children]
kube_control_plane
kube_node
calico_rr
# ---------------------------------
9. inventory 파일 host ping test
inventory.ini 파일에 정의한 [all] node와 정상 호출이 되는지 ping 테스트를 진행한다.
위에서 ssh 접속을 확인하였다면 별 문제 없이 성공할 것이다.
ansible all -i inventory.ini -m ping

10. Ansible Playbook을 이용한 cluster deployment
이제 준비가 다 끝났으니, 최종적으로 deployment를 진행한다.
root로 수행하는 --become-user 옵션도 추가해 주었다.
cd ${WORKSPACE}/kubespray
ansible-playbook -i ${WORKSPACE}/kubespray/inventory/mycluster/inventory.ini cluster.yml -b --become-user=root -v
설치되는 것들이 많아서 시간이 꽤 오래 걸린다.
드디어 길고 긴 설치가 끝났다..! (명령어가 정상적으로 끝나는데 20분 정도 걸린 것 같다.)

11. 설치 확인
설치가 다 되었다면 node 상태, pod 상태, 설치된 kubernetes, containerd 버전 등을 확인한다.
# node check
kubectl get nodes -o wide
# pod check
kubectl get pods -A -o wide
# kubernetes version check
kubectl version
kubeadm version
kubelet --version
# containerd version check
containerd --version
# calico version check
calicoctl version
root@k8s-master-1:~/workspace/kubespray# # node check
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master1 Ready control-plane 11m v1.30.3 10.178.0.23 <none> Ubuntu 22.04.4 LTS 6.5.0-1025-gcp containerd://1.7.16
worker1 Ready <none> 10m v1.30.3 10.178.0.24 <none> Ubuntu 22.04.4 LTS 6.5.0-1025-gcp containerd://1.7.16
worker2 Ready <none> 10m v1.30.3 10.178.0.22 <none> Ubuntu 22.04.4 LTS 6.5.0-1025-gcp containerd://1.7.16
root@k8s-master-1:~/workspace/kubespray# # pod check
kubectl get pods -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system calico-kube-controllers-c7cc688f8-cdddq 1/1 Running 0 8m54s 10.233.125.1 worker2 <none> <none>
kube-system calico-node-kh8qk 1/1 Running 0 10m 10.178.0.22 worker2 <none> <none>
kube-system calico-node-pkmxf 1/1 Running 0 10m 10.178.0.23 master1 <none> <none>
kube-system calico-node-pwxgz 1/1 Running 0 10m 10.178.0.24 worker1 <none> <none>
kube-system coredns-776bb9db5d-f4kqj 1/1 Running 0 8m4s 10.233.105.129 worker1 <none> <none>
kube-system coredns-776bb9db5d-hnc52 1/1 Running 0 8m17s 10.233.104.65 master1 <none> <none>
kube-system dns-autoscaler-6ffb84bd6-xd9l2 1/1 Running 0 8m8s 10.233.104.66 master1 <none> <none>
kube-system kube-apiserver-master1 1/1 Running 2 11m 10.178.0.23 master1 <none> <none>
kube-system kube-controller-manager-master1 1/1 Running 2 11m 10.178.0.23 master1 <none> <none>
kube-system kube-proxy-28ptn 1/1 Running 0 11m 10.178.0.23 master1 <none> <none>
kube-system kube-proxy-7b6p7 1/1 Running 0 11m 10.178.0.24 worker1 <none> <none>
kube-system kube-proxy-mnmtg 1/1 Running 0 11m 10.178.0.22 worker2 <none> <none>
kube-system kube-scheduler-master1 1/1 Running 2 (6m3s ago) 11m 10.178.0.23 master1 <none> <none>
kube-system nginx-proxy-worker1 1/1 Running 0 11m 10.178.0.24 worker1 <none> <none>
kube-system nginx-proxy-worker2 1/1 Running 0 11m 10.178.0.22 worker2 <none> <none>
kube-system nodelocaldns-8wx8b 1/1 Running 0 8m3s 10.178.0.23 master1 <none> <none>
kube-system nodelocaldns-dnk4z 1/1 Running 0 8m3s 10.178.0.22 worker2 <none> <none>
kube-system nodelocaldns-x6cl6 1/1 Running 0 8m3s 10.178.0.24 worker1 <none> <none>
root@k8s-master-1:~/workspace/kubespray# # kubernetes version check
kubectl version
Client Version: v1.30.3
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.30.3
root@k8s-master-1:~/workspace/kubespray# kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"30", GitVersion:"v1.30.3", GitCommit:"6fc0a69044f1ac4c13841ec4391224a2df241460", GitTreeState:"clean", BuildDate:"2024-07-16T23:53:15Z", GoVersion:"go1.22.5", Compiler:"gc", Platform:"linux/amd64"}
root@k8s-master-1:~/workspace/kubespray# kubelet --version
Kubernetes v1.30.3
root@k8s-master-1:~/workspace/kubespray# # containerd version check
containerd --version
containerd github.com/containerd/containerd v1.7.16 83031836b2cf55637d7abf847b17134c51b38e53
root@k8s-master-1:~/workspace/kubespray# # calico version check
calicoctl version
Client Version: v3.27.3
Git commit: 638464f94
Cluster Version: v3.27.3
Cluster Type: kubespray,kubeadm,kdd,k8s
root@k8s-master-1:~/workspace/kubespray#

12. (추가작업1 optional) hosts 파일 등록
설치가 완료되면 아래와 같이 hosts 파일에 inventory에 등록한 hosts가 자동으로 추가된다.

필수 작업은 아니나 host명으로 각 node를 사용할 필요가 있기 때문에 등록해둔다.
cat <<EOF>> /etc/hosts
# k8s cluster node
10.178.0.23 master1
10.178.0.24 worker1
10.178.0.22 worker2
EOF
13. (추가작업2 optional) kubectl 자동완성 설정
매번 kubectl 명령어를 작성하기 귀찮기 때문에 k로 사용할 수 있도록 alias를 등록한다.
https://kubernetes.io/ko/docs/reference/kubectl/cheatsheet/
echo "source <(kubectl completion bash)" >> ~/.bashrc # bash-completion 패키지를 먼저 설치한 후, bash의 자동 완성을 현재 셸에 설정한다
echo "source <(kubectl completion bash)" >> ~/.bashrc # 자동 완성을 bash 셸에 영구적으로 추가한다
echo "alias k=kubectl" >> ~/.bashrc
echo "complete -o default -F __start_kubectl k" >> ~/.bashrc
source ~/.bashrc
# 정상 적용 확인
k get nodes
14. (optional) Kubernetes Dashboard 배포 및 접속하기
k8s 대시보드를 NodePort로 오픈해서 접속하는 방법을 안내한다.
대시보드를 NodePort로 오픈하는 방법은 보안 상 이슈가 있으므로 실제 운영 환경에서는 사용하지 않는 것이 좋다. 학습 용도로 사용 시 참고해서 진행할 것!
https://kubernetes.io/ko/docs/tasks/access-application-cluster/web-ui-dashboard/
# 대시보드 UI 배포
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.1/aio/deploy/recommended.yaml
# dashboard 배포 pod 확인
kubectl get pods -n kubernetes-dashboard
# dashboard 배포 service 확인
kubectl get svc -n kubernetes-dashboard
# dashboard NodePort로 오픈
kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}'
# dashboard 배포 service 확인 - NodePort 확인
kubectl get svc -n kubernetes-dashboard
# 위에 기본으로 셋팅된 3만번 대 NodePort를 사용해서 접속해도 되나, 특정 Port로 변경하고 싶을 경우
# 아래 명령어로 직접 port를 변경해준다.
# 수정 : esc + i / 저장 : esc + wq + enter (vi editor 저장 방법과 동일)
kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard
★ 중요! 대시보드 접속을 위해서는 NodePort에 대한 inbound port 방화벽이 꼭 오픈되어 있어야 한다!! (vm 방화벽 오픈 확인 필수)
대시보드 접속 방법 : https://대시보드가 배포된 노드의 ip(public ip):NodePort
(ex, https://13.125.74.103:30000/ chrome인 경우 안전하지 않음으로 이동 클릭)
접속 시 token 입력 창이 뜬다.

아래 샘플 사용자 만들기 링크를 참고해서 접속을 위한 token을 발급받는다.

https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md
(step1) admin user를 생성하고
# Creating a Service Account
vi dashboard-adminuser.yaml
#----------------------------------------------------
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
#----------------------------------------------------
kubectl apply -f dashboard-adminuser.yaml
(step2) token을 생성한다.
# Getting a Bearer Token for ServiceAccount
kubectl -n kubernetes-dashboard create token admin-user
생성된 토큰을 복사하여 위 화면 토큰입력 칸에 붙여넣기 한 후 로그인 버튼을 클릭하여 대시보드에 접속할 수 있다.

그럼 설치 완료~! 👍
참고자료
k8s 공식 문서 참조
https://kubernetes.io/ko/docs/setup/production-environment/tools/kubespray/
Kubespray로 쿠버네티스 설치하기
이 가이드는 Kubespray를 이용하여 GCE, Azure, OpenStack, AWS, vSphere, Equinix Metal(전 Packet), Oracle Cloud infrastructure(실험적) 또는 베어메탈 등에서 운영되는 쿠버네티스 클러스터를 설치하는 과정을 보여준다
kubernetes.io
'Cloud > kubernetes' 카테고리의 다른 글
| kubernetes 명령어 (2) | 2024.06.28 |
|---|---|
| kind란?🧐 1개의 host 안에서 k8s cluster를 쉽게 구성하기 위한 도구 (1) | 2024.06.14 |