Vagrant를 통해 쿠버네티스(K8S) 구축하기

쿠버네티스 사용하기 위한 몇 가지 방법

1. Virtual Machine에 Master node와 Worker node를 직접 구축
2. AWS, Azure, GCP 등 쿠버네티스 서비스를 사용
3. 웹 형태로 제공되는 쿠버네티스 서비스 이용

두 번째와 세 번째 방법이 편하지만 일정 금액을 지불해야 한다는 단점이 존재합니다. 또한, 쿠버네티스 환경을 잘 모르기 때문에 쿠버네티스 환경을 직접 구축해보면서 어떻게 구성되어 있는지 알아볼 겸 직접 구축하기로 했습니다.

VM에 직접 OS를 설치하고 쿠버네티스 클러스터를 구축하는 것은 많은 시간이 소요가 됩니다. 또한, 설치 순서가 틀린 경우 다시 구축하는 것이 빠를 정도로 순서가 복잡합니다. 그래서 설치 방법을 템플릿화하는 것이 좋다고 생각 되었고 vagrant를 사용해서 쿠버네티스 클러스터를 구축한다면 시간 단축도 되고 일관성 가지면서 클러스터를 구축할 수 있다는 사실을 알았습니다. vagrant는 IaC(Infrastructure as Code)의 줄인 말이고 코드를 사용해서 VM에 OS를 설치하고 서버를 배포할 수 있도록 자동화하는 도구입니다.

Vagrant를 사용해 쿠버네티스 클러스터 구축

1. VM Provider 설치 및 Vagrant 설치

VM Provider로 VirtualBox를 사용하기로 했고 버전은 7.0.14입니다
VirtualBox 다운 링크: https://www.virtualbox.org/wiki/Downloads

Vagrant는 Window 환경으로 다운을 받았고 버전은 2.4.1입니다
Vagrant 다운 링크: https://developer.hashicorp.com/vagrant/install

2. Vagrant Script 작성 및 실행

먼저, 생성할 VM 스펙을 정의합니다. 대표적으로 OS, network, provider (hyper-v, virtual box, vmware), resources(cpu, memory)가 있습니다. master node는 2CPU, 4GB MEM, worker node는 2CPU, 2GB MEM로 자원을 할당할 예정입니다. 저의 PC 사양은 CPU는 11th Gen Intel(R) Core(TM) i7-1165G7, Memory는 16GB입니다. 그 후 설치 스크립트를 작성합니다. 저는 master와 worker 의 공통으로 설치되는 부분을 먼저 정의하고 이후 master node에 필요한 스크립트만 따로 정의했습니다. VM에는 ssh로 접속할 예정이라서 gui 옵션은 껐습니다.

아래는 실제로 사용한 스크립트입니다.

$pre_install = <<-SCRIPT
  echo ">>>> pre-install <<<<<<"
  echo 'root:password1234' | sudo chpasswd
  sudo echo "192.168.1.100 master" >> /etc/hosts
  sudo echo "192.168.1.101 worker1" >> /etc/hosts
  sudo echo "192.168.1.102 worker2" >> /etc/hosts
  sudo sysctl net.ipv4.ip_forward=1
  sudo modprobe br_netfilter
  sudo swapoff -a
  
  echo ">>>> Install Containerd <<<<<<"
  sudo apt-get update
  sudo apt-get install ca-certificates curl gnupg -y
  sudo install -m 0755 -d /etc/apt/keyrings
  sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  sudo chmod a+r /etc/apt/keyrings/docker.gpg
  sudo echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
    $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  sudo apt-get update
  sudo apt-get install containerd.io
  sudo echo "" > /etc/containerd/config.toml
  sudo systemctl restart containerd

  echo ">>>> Install K8s Component <<<<<<"
  sudo apt-get install -y apt-transport-https
  sudo curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
  echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | 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
SCRIPT

$mater_config = <<-SCRIPT
  echo ">>>> Master Node Config <<<<<<"
  sudo ssh-keyscan worker1 >> ~/.ssh/known_hosts
  sudo ssh-keyscan worker2 >> ~/.ssh/known_hosts
  sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address 192.168.1.100 2>&1 | tee /root/kubeadm_init_output.txt
  sudo mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config
  export KUBECONFIG=/etc/kubernetes/admin.conf
SCRIPT


Vagrant.configure("2") do |config|
  # Master 노드 설정
  config.vm.define "master" do |master|
    master.vm.box = "bento/ubuntu-22.04"
    master.vm.network "private_network", ip: "192.168.1.100"
    master.vm.provider "virtualbox" do |v|
      v.name = "Master"
      v.gui = false
      v.memory = 4096
      v.cpus = 2
    end
    master.vm.hostname = "master"
    master.vm.provision "shell", inline: $pre_install
    master.vm.provision "shell", inline: $mater_config
  end

  # Worker 노드 설정
  (1..2).each do |i|
    config.vm.define "worker#{i}" do |worker|
      worker.vm.box = "bento/ubuntu-22.04"
      worker.vm.network "private_network", ip: "192.168.1.11#{i}"
      worker.vm.provider "vmware_desktop" do |v|
        v.name = "Worker#{i}"
        v.gui = false
        v.memory = 2048
        v.cpus = 2
      end
      worker.vm.hostname = "worker#{i}"
      worker.vm.provision "shell", inline: $pre_install
    end
  end
end

3. 쿠버네티스 클러스터 구축 마무리

한 대의 master node와 두 대의 worker node가 설치되었다면 worker node를 master node에 join 시켜야 합니다.
master node에서 sudo 권한으로 tail -n 2 kubeadm_init_output.txt 명령을 실행하면 master node에 join할 수 있는 hash 값이 나오게 되는데 해당 값을 그대로 worker node에 적용하면 됩니다.
master node에 join

적용 후 쿠버네티스 노드들을 조회해보면 master node에서 worker node의 상태를 확인할 수 있습니다. 현재는 네트워크 연결이 되어 있지 않기 때문에 NotReady 상태입니다. master node에서 calico를 적용하게 되면 노드 간의 네트워크가 연결됩니다.

마지막으로, master node에서 kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml 명령어를 실행하게 되면 쿠버네티스 클러스가 구축됩니다.


4. 쿠버네티스를 구축할 때 몇 가지 주의할 점

첫번째로 VM을 생성할 때는 최소 사용이 2 CPU, 2 memory를 가져야 한다는 것입니다.
두번째로 swap off를 해줘야 하는데 쿠버네티스는 자신의 자원을 최대한 활용하는 것이 목적이기 때문에 swap에 대한 지원이 따로 없기 때문입니다. 충분한 자원이 없어서 swap를 사용하게 된다면 master 노드에서 아래와 같은 에러를 만날 수 있습니다.

swapoff를 안 했을 경우 오류

충분한 자원을 가지고 쿠버네티스 클러스터를 구축한다면 네트워크를 연결을 제외하면 NotReady인 상태로 클러스터가 구축이 됩니다. 이후 클러스터 간의 네트워크 연결을 하게 된다면 Ready 상태로 Node간의 통신을 할 수 있는 클러스터 환경이 만들어지게 됩니다.

전반적인 쿠버네티스 클러스터 구성하는 방법에 대해서 알아봤으며 다음장부터는 쿠버네티스의 세부적인 내용에 대해서 다룰 예정입니다.

참고 자료

https://alive-wong.tistory.com/67

Leave a Comment