본문 바로가기
프로젝트 일지/BoWS

홈서버 구축하기 - Proxmox 설치 및 쿠버네티스 클러스터 구성하기

by 데브겸 2024. 7. 8.

본격적으로 홈서버에 쿠버네티스 클러스터를 구축해보려 한다. 환경은 Proxmox로 선정하였다. 그 이유는 하나의 컴퓨터에 여러 대의 가상머신을 띄워야 하는 상황이고, 사실상 쿠버네티스 클러스터 외에 다른 것을 띄워두진 않을 것이기 때문에 가상머신에 특화된 환경을 구축하고자 했다. 이에 '베어메탈 아키텍처(type1)'와 '호스트형 아키텍처(type2)' 가상화 아키텍처 중 전자를 채택했다. 베어메탈 가상화의 경우 'Proxmox'와 'ESXi' 중 보통 선택하게 되는데, 쿠버네티스와 관련된 레퍼런스가 조금 더 많은 Proxmox를 선택하게 되었다.

 

(하이퍼바이저와 베어메탈 관련한 지식은 아래 글들을 참고하였다)

 

https://lovejaco.github.io/posts/two-types-of-hypervisors/

 

[스터디 정리] 하이퍼바이저의 종류

프론트엔드 팀을 위한 CI/CD 라는 주제의 사내 스터디를 진행하며 발표 내용을 정리/요약한 글이며 참고 링크의 글을 그대로 인용하였습니다. 스터디 중에 동료가 베어메탈에 대한 질문을 하였습

lovejaco.github.io

 

https://velog.io/@kisuk623/Proxmox-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0

 

나만의 홈서버 구축하기 - 1

개발에 입문하고 나만의 홈서버를 만들고 싶다는 생각이 들었다. 기존에 사용하던 컴퓨터를 이용해 하이퍼바이저를 구성하고 여러 서비스를 동작시켜볼 것이다. 기존에 있던 자작 NAS를 이용해

velog.io

 

 

Proxmox 설치하기

이전 글에서 소개했던 것과 비슷한 방식으로 USB를 준비, proxmox의 iso 이미지를 다운받아(링크) 부팅디스크를 만들고 설치해주면 된다

 

https://kyumcoding.tistory.com/108

 

홈서버 구축하기 - 미니 데스크탑 조립 및 우분투 설치

코드스쿼드 멤버들의 사이드 프로젝트를 무료로 호스팅해주는 서비스를 만드려 한다. 홈서버에 온프레미스로 쿠버네티스를 올리고, 이를 활용하여 서비스하려고 한다. 이때 쿠버네티스를 올리

kyumcoding.tistory.com

 

 

 

 

모두 설치하고 나면 까만화면에 웹주소가 화면에 출력되는데, 이때부터는 사실상 proxmox가 설치된 컴퓨터를 직접 사용할 일이 없다. ssh로 접속하거나, https://192.168.0.10:8006/ 로 웹 콘솔 접속이 가능하다. (가상 머신 생성 관리 등은 주로 웹 콘솔에서 GUI를 통해 작업을 하게 된다)

 

 

 

쿠버네티스 클러스터 구축하기

우선 구축은 kubeadm을 사용해서 구축한다. kubeadm이 근본인 느낌이 있기도 하고, 하나하나 설정해가면서 배울게 많다고 생각했기 때문이다. kubespray를 사용하는 방법은 비교적 빠르고 자동화된 프로세스로 만들 수 있지만, ansible에 대한 이해도가 없는 상황이기도 하고 재현성이 크게 중요하지 않은 상황이기 때문에 kubeadm을 사용하기로 결정했다.

 

쿠버네티스 클러스터를 만들기 위해서는 여러 대의 vm 인스턴스가 필요하다(우선 기능적으로 control plane, data plane 두 개의 다른 노드가 있어야 한다. 물론 control plane에 파드를 띄우는게 가능하긴 하지만 굳이..?) 매 vm마다 세팅하고 설정하기 귀찮은데, proxmox에서는 템플릿 기능을 제공하여 동일한 종류의 가상머신을 빠르게 만들 수 있게 지원한다.

 

템플릿을 만드는 과정은 주로 GUI로 진행되기 때문에 영상이 도움이 될 것이다. 나 또한 아래 영상을 참고하여 템플릿을 만들었다

https://www.youtube.com/watch?v=MJgIm03Jxdo

 

중간에 ssh 공개키를 만들어 등록하는 과정이 있는데 로컬 컴퓨터에서(이후 proxmox에 ssh 접속할 주체가 되는) 키를 만들어 넣어두면 된다. t는 암호화 종류 -b는 길이 -C는 코멘트, 엔터를 계속치며 default 설정을 해도 괜찮고, 다른 이름으로 저장하고 싶으면 적당히 변형해서 넣는다.

ssh-keygen -t rsa -b 4096 -C "email@email.com"

 

 

이후 과정은 아래 영상을 참고하되, 쿠버네티스 설치 관련해서는 24년 7월 기준 최신 것들을 참고하여 작성했다.

 

https://www.youtube.com/watch?v=U1VzcjCB_sY

 

가상머신 템플릿 만들어준 이후 controller와 node 인스턴스를 만들어준다.

 

만든 후에 ssh 접속하는데 이전에 만들어서 등록한 ssh key로 접속한다. 처음에는 permission denined가 떠서 식겁했는데 ssh key를 명시적으로 적어주고 접속하려니까 된다… 휴…

ssh -i ~/.ssh/{키이름} {사용자}@{가상머신 ip}

 

 

static ip 설정을 해줘야 한다(영상에서는 dhcp로 하긴 한다). 왜 해줘야 할까 좀 찾아봤는데 1. 클러스터 내에서 노드 간의 통신이 빈번하고 중요하기 때문에 네트워크 일관성을 지켜야 하고 2. 쿠버네티스의 설정 파일, 방화벽 규칙, 네트워크 정책, 모니터링 등이 IP에 의존하는 경우가 많기 때문에 고정 ip를 사용하는 경우가 많은 것 같다.

 

나의 걱정은 static ip를 설정하면 나중에 ip가 계속 바뀌기 때문에 문제가 발생하는 것 아닐까라는 걱정이 있었기 때문(DDNS 같은 느낌). 하지만 조금 더 생각을 해보니 유동적으로 바뀌는 것은 외부로 빠져나갈 때 ip이지(공유기 차원), 지금 설정하는 내부 네트워크에서는 전혀 무리가 없을 것 같다. 외부에 대해서만 DDNS를 쓰고, 내부에서는 그냥 고정 IP를 쓰면 되는 것이다.

 

고정 IP를 할당하는 것은 Iptime등의 공유기에서 DHCP 예약 등을 사용하면 된다. ipTime의 경우 dhcp 서버 주소관리에서 할당해두면 된다.

 

 

혹시 몰라 네트워크 설정 파일 복제본 만들어두자

cd /etc/netplan
sudo cp 50-cloud-init.yaml 50-cloud-init.yaml.bak

 

 

netplan으로 static ip 설정을 해준다.

sudo vi /etc/netplan/50-cloud-init.yaml

network:
  version: 2
  ethernets:
    eth0:
      addresses: [192.168.0.~/24] # 자신의 서버 ip를 확인해서 넣기
      routes:
        - to: default
          via: 192.168.0.1 # 자신의 게이트웨이 ip 확인해서 넣기
      nameservers:
      # DNS 서버 확인해서 넣기, 혹시 몰라 google, cloudfare dns 주소도 넣어두긴 함
        addresses: [~ ,8.8.8.8, 1.1.1.1]

 

sudo netplan apply 
sudo netplan try

# 아래 에러가 날 수도 있는데 경고 정도이니 이상 없으면 넘어가자
# 이상이 있다면 100퍼 알 수 있다고 함...
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.

 

 

container runtime 설치

sudo apt-get update && sudo apt-get install -y containerd

# 잘 설치되었는지 확인
systemctl status containerd

 

아래 명령으로 기존 containerd 설정 저장

sudo mkdir /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

 

 

설정 중 runc.options의 내용 중 일부를 수정한다

sudo vi /etc/containerd/config.toml

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
            BinaryName = ""
            CriuImagePath = ""
            CriuPath = ""
            CriuWorkPath = ""
            IoGid = 0
            IoUid = 0
            NoNewKeyring = false
            NoPivotRoot = false
            Root = ""
            ShimCgroup = ""
            SystemdCgroup = false # 이 부분을 true로 바꿔줘야한다

 

 

swap을 꺼줘야 한다. swap이 켜져있는지는 free -m으로 확인 가능. 나의 경우 swap이 꺼져있다

free -m
               total        used        free      shared  buff/cache   available
Mem:             984          89         148           0         746         879
Swap:              0           0           0

 

 

추가적으로 네트워크 설정을 해줘야 하는데

sudo vi /etc/sysctl.conf
# Uncomment the next line to enable packet forwarding for IPv4
# net.ipv4.ip_forward=1  # 이 부분 주석해제 브릿지 네트워크를 사용하기 위함인듯?

sudo vi /etc/modules-load.d/k8s.conf
br_netfilter # 이 부분 추가 브릿지 넷필터 설정 -> 클러스터에서 브릿징을 가능하게 만들기

 

 

그다음 리부트

sudo reboot

 

 

쿠버네티스 본격적으로 설치하기. 아래 문서(쿠버네티스 공식 문서)를 참고하면서 설치했다

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl

 

Installing kubeadm

This page shows how to install the kubeadm toolbox. For information on how to create a cluster with kubeadm once you have performed this installation process, see the Creating a cluster with kubeadm page. This installation guide is for Kubernetes v1.30. If

kubernetes.io

 

sudo apt-get install -y apt-transport-https ca-certificates curl gpg

# k8s레포를 위한 퍼블릭 사이닝 키 다운받기
# The same signing key is used for all repositories so you can disregard the version in the URL:
# /etc/apt/keyrings 없으면 명령어를 통해 만들고 curl 하기
# sudo mkdir -p -m 755 /etc/apt/keyrings
# curl 명령어 중 k8s 버전 유의해서 설치하기
curl -fsSL <https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key> | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

 

적절한 k8s apt 레포를 추가해준다. 위 curl 명령과 마찬가지로 버전을 유의하면서 설치하자

# This overwrites any existing configuration in /etc/apt/sources.list.d/kubernetes.list
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] <https://pkgs.k8s.io/core:/stable:/v1.30/deb/> /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

 

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

 

(Optional) kubeadm 실행 전 kublet 서비스 구동하기 

sudo systemctl enable --now kubelet

 

 

k8s 노드를 만들어줘야 하는데 위 과정들이 귀찮으니까 템플릿으로 만들어준다. machine-id로 인해 복제된 vm의 ip가 같아지는 문제를 해결하기 위해 아래 명령어를 실행한다.

sudo cloud-init clean

sudo truncate -s 0 /etc/machine-id
sudo rm /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id

sudo poweroff

 

 

노드를 만들어주고, 컨트롤러도 poweroff 한 뒤에 메모리와 cpu 사양을 변경해준다. (ctrlr의 경우 2cpu, 4gb, node의 경우 2cpu, 2gb. 서버 사양이 부족하다면 모두 2cpu에 2gb로 설정). 설정 후 다시 부팅시켜준다.

 

노드 템플릿에서 Full Clone으로 만든 가상머신의 경우 네트워크 설정이 DHCP로 되돌아가 있기 때문에 다시 static ip로 변환해줘야 한다.

 

sudo vi /etc/netplan/50-cloud-init.yaml

network:
  version: 2
  ethernets:
    eth0:
      addresses: [192.168.0.~/24] # 자신의 서버 ip를 확인해서 넣기
      routes:
        - to: default
          via: 192.168.0.1 # 자신의 게이트웨이 ip 확인해서 넣기
      nameservers:
      # DNS 서버 확인해서 넣기, 혹시 몰라 google, cloudfare dns 주소도 넣어두긴 함
        addresses: [~ ,8.8.8.8, 1.1.1.1]
sudo netplan apply 
sudo netplan try

# 아래 에러가 날 수도 있는데 경고 정도이니 이상 없으면 넘어가자
# 이상이 있다면 100퍼 알 수 있다고 함...
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.

 

 

 

컨트롤러에 ssh로 접속해서 pod 네트워크를 만든다. 아래 명령을 내리면 you can now join~이라고 뜨며 control plane, data plane으로 연결시킬 수 있는 명령어가 나온다.

sudo kubeadm init --control-plane-endpoint={vm ip를 넣어준다} \\
--node-name {vm 호스트이름을 적어준다} --pod-network-cidr=10.244.0.0/16
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join ~ --token ~ \\
	--discovery-token-ca-cert-hash ~
	--control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join ~ --token ~ \\
	--discovery-token-ca-cert-hash ~

 

위 join 커맨드가 오래될 경우 만료되는 경우가 있는데, 이럴 경우 아래 명령을 통해 새로 만들 수 있다.

kubeadm token create --print-join-command

 

 

클러스터를 사용하기 위해 아래 명령을 내려야 한다.

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

 

 

pod 네트워크 관리(오버레이 네트워크)를 위해 flannel을 설치해준다. calico도 있긴 한데 동영상 예시에서 사용하기도 하고, 초보자 입장에서는 아직 큰 차이를 느끼지 못했어서 flannel을 설치해주었다.

kubectl apply -f \\
<https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml>

 

 

명령어 입력마다 kubectl을 다 치기 귀찮으니까 자동완성이랑 alias 등록도 해준다. 쉘 다시 로드해서 하면 잘 된다.

sudo apt-get install bash-completion
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -o default -F __start_kubectl k' >>~/.bashrc

source /usr/share/bash-completion/bash_completion

 

 

각각 노드로 ssh 접속하여 static ip 설정을 해주고 위에서 생성된 join 커맨드를 입력해서 node 등록을 해준다.

kubeadm join ~ --token ~ \\
	--discovery-token-ca-cert-hash ~

 

 

컨트롤 플레인이 있는 가상머신으로 들어가 노드가 잘 등록되었는지 확인한다.

k get node

 

이 화면을 보기까지 얼마나 고생했던가...