이재홍의 언제나 최신 Kubernetes - Unit 6.2 Vagrant와 kubeadm으로 가상머신에 클러스터 구축하기

저작권 안내
  • 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
  • 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.

로컬에서 Kubernetes 클러스터 구축하기

이재홍 http://www.pyrasis.com

Vagrant와 kubeadm으로 가상머신에 클러스터 구축하기

VirtualBox와 Vagrant 설치가 끝났으면 본격적으로 쿠버네티스 클러스터를 구축해보겠습니다. 이번에 구축할 클러스터의 형태는 다음과 같습니다.

  1. Vagrant로 VirtualBox 가상머신 생성
  2. Vagrant로 containerd 및 kubeadm 설치
  3. master 노드에 worker 노드를 수동으로 연결

그림 6-1 VirtualBox 가상머신에 클러스터 구축하기

노드

클러스터를 구성하는 서버(머신)를 노드(node)라고 부릅니다. 노드는 물리서버일 수도 있고, 가상머신일 수도 있습니다.

Vagrantfile 작성하기

이제 Vagrant 코드를 작성해보겠습니다. 다음 내용을 Vagrantfile로 저장합니다.

Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.boot_timeout = 3000

  config.vm.define "master" do |master|
    master.vm.box = "ubuntu/jammy64"
    master.vm.network "private_network", ip: "192.168.56.10"
    master.vm.hostname = "master"

    master.vm.provider "virtualbox" do |v|
      v.memory = 4096
      v.cpus = 4
    end

    master.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.10
EOF

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/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

OUTPUT_FILE=/vagrant/join.sh
rm -rf $OUTPUT_FILE
rm -rf /vagrant/.kube
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.56.10 --apiserver-advertise-address=192.168.56.10
sudo kubeadm token create --print-join-command > $OUTPUT_FILE
chmod +x $OUTPUT_FILE

mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
cp -R $HOME/.kube /vagrant/.kube
cp -R $HOME/.kube /home/vagrant/.kube
sudo chown -R vagrant:vagrant /home/vagrant/.kube
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubectl completion bash >/etc/bash_completion.d/kubectl
echo 'alias k=kubectl' >>/home/vagrant/.bashrc
    EOC
  end

  (1..3).each do |i|
    config.vm.define "worker#{i}" do |worker|
      worker.vm.box = "ubuntu/jammy64"
      worker.vm.network "private_network", ip: "192.168.56.1#{i}"
      worker.vm.hostname = "worker#{i}"

      worker.vm.provider "virtualbox" do |v|
        v.memory = 2048
        v.cpus = 2
      end

      worker.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.1#{i}
EOF

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/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
      EOC
    end
  end
end

애플 실리콘 M 시리즈

맥의 CPU가 인텔이 아닌 애플 실리콘 M 시리즈라면 다음 Vagrantfile을 사용합니다.

Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.boot_timeout = 3000

  config.vm.define "master" do |master|
    master.vm.box = "jharoian3/ubuntu-22.04-arm64"
    master.vm.box_version = "0.3"
    master.vm.network "private_network", ip: "192.168.56.10"
    master.vm.hostname = "master"

    master.vm.provider "parallels" do |v|
      v.memory = 4096
      v.cpus = 4
    end

    master.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
swapoff -a
sed -i '/swap/ s/^/#/' /etc/fstab

cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=arm64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.10
EOF

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/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

OUTPUT_FILE=/vagrant/join.sh
rm -rf $OUTPUT_FILE
rm -rf /vagrant/.kube
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.56.10 --apiserver-advertise-address=192.168.56.10
sudo kubeadm token create --print-join-command > $OUTPUT_FILE
chmod +x $OUTPUT_FILE

mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
cp -R $HOME/.kube /vagrant/.kube
cp -R $HOME/.kube /home/vagrant/.kube
sudo chown -R vagrant:vagrant /home/vagrant/.kube
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubectl completion bash >/etc/bash_completion.d/kubectl
echo 'alias k=kubectl' >>/home/vagrant/.bashrc
    EOC
  end

  (1..3).each do |i|
    config.vm.define "worker#{i}" do |worker|
      worker.vm.box = "jharoian3/ubuntu-22.04-arm64"
      worker.vm.box_version = "0.3"
      worker.vm.network "private_network", ip: "192.168.56.1#{i}"
      worker.vm.hostname = "worker#{i}"

      worker.vm.provider "parallels" do |v|
        v.memory = 2048
        v.cpus = 2
      end

      worker.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
swapoff -a
sed -i '/swap/ s/^/#/' /etc/fstab

cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=arm64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.1#{i}
EOF

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/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
      EOC
    end
  end
end

Parallels를 사용하므로 다음 명령으로 가상머신을 생성합니다.

$ vagrant up --provider=parallels

Minikube 클러스터

Minikube 클러스터를 생성했다면 다음 명령으로 먼저 Minikube 클러스터를 삭제합니다.

$ minikube delete

Avast Antivirus 감시 제어 문제

Avast Antivirus 등 안티바이러스 프로그램이 설치되어 있는 경우 vagrant up 명령을 실행했을 때 다음과 같은 메시지가 출력되면서 에러가 발생할 수 있습니다. 따라서 Avast 감시 제어 기능을 반드시 끄도록 합니다.

Bringing machine 'master' up with 'virtualbox' provider...
Bringing machine 'worker1' up with 'virtualbox' provider...
Bringing machine 'worker2' up with 'virtualbox' provider...
Bringing machine 'worker3' up with 'virtualbox' provider...
==> master: Box 'ubuntu/jammy64' could not be found. Attempting to find and install...
    master: Box Provider: virtualbox
    master: Box Version: >= 0
The box 'ubuntu/jammy64' could not be found or
could not be accessed in the remote catalog. If this is a private
box on HashiCorp's Vagrant Cloud, please verify you're logged in via
`vagrant login`. Also, please double-check the name. The expanded
URL and error message are shown below:

URL: ["https://vagrantcloud.com/ubuntu/jammy64"]
Error: schannel: next InitializeSecurityContext failed: Unknown error (0x80092012) - 해당 함수에서 인증서에 대한 파기 여부를 검사하지 못했습니다.

vagrant up 명령으로 가상머신을 생성합니다. 시간이 꽤 오래 걸리므로 느긋하게 기다립니다.

$ vagrant up

SSH auth method: Private Key에서 멈추는 경우

vagrant up 명령으로 가상머신을 생성할 때 SSH auth method: Private Key에서 멈추는 경우가 많습니다. 따라서 VirtualBox GUI 앱인 Oracle VM VirtualBox을 반드시 실행해 놓은 상태로 vagrant up 명령을 실행합니다.

그림 6-2 Oracle VM VirtualBox

vagrant up 명령 실행이 끝났으면 vagrant status 명령을 입력하여 가상머신의 상태를 확인합니다. 다음과 같이 표시되면 정상적으로 생성된 것입니다.

$ vagrant status
Current machine states:

master                    running (virtualbox)
worker1                   running (virtualbox)
worker2                   running (virtualbox)
worker3                   running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.

마스터 노드 확인하기

Vagrantfile안에 내장된 스크립트로 kubeadm 실행에 필요한 설정을 하고 패키지들을 설치했습니다. master 노드에는 제어 플레인(Control Plane)이 구축된 상태고, worker1, 2, 3 노드에는 kubeadm만 설치된 상태입니다.

다음 명령을 실행하여 master 노드 안으로 들어갑니다.

$ vagrant ssh master
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-52-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Nov  6 17:35:51 UTC 2022

  System load:  0.5947265625      Users logged in:         0
  Usage of /:   9.0% of 38.70GB   IPv4 address for cni0:   10.244.0.1
  Memory usage: 37%               IPv4 address for enp0s3: 10.0.2.15
  Swap usage:   0%                IPv4 address for enp0s8: 192.168.56.10
  Processes:    124


11 updates can be applied immediately.
10 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


Last login: Sun Nov  6 11:51:31 2022 from 10.0.2.2
vagrant@master:~$

윈도우에서 vagrant ssh master 실행 시 Permission denied (publickey) 에러 발생 문제

윈도우에서 vagrant ssh master 명령을 실행했을 때 vagrant@127.0.0.1: Permission denied (publickey).와 같은 에러가 발생하는 경우가 있습니다. 이때는 $env:VAGRANT_PREFER_SYSTEM_BIN += 0 명령을 실행한 뒤 vagrant ssh master 명령을 실행하면 됩니다.

윈도우 PowerShell
$env:VAGRANT_PREFER_SYSTEM_BIN += 0
vagrant ssh master

master 노드 안으로 들어왔습니다. kubectl도 설치해놓았으므로 kubectl get node 명령으로 노드 목록을 출력해봅니다.

$ kubectl get node
NAME     STATUS   ROLES           AGE     VERSION
master   Ready    control-plane   7m40s   v1.28.4

master 노드 하나만 생성되어 있고 롤은 제어 플레인(control-plane)인 것을 볼 수 있습니다. 앞으로 vagrant ssh로 들어간 노드에서 빠져나올 때는 Ctrl + D 키를 입력하면 됩니다.

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

이제 worker1, 2, 3 노드를 master 노드에 연결(join) 해보겠습니다. 먼저 worker1부터 들어갑니다.

$ vagrant ssh worker1
vagrant@worker1:~$ cd /vagrant/
vagrant@worker1:/vagrant$ sudo ./join.sh
[preflight] Running pre-flight checks
        [WARNING SystemVerification]: missing optional cgroups: blkio
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

join.sh 파일은 master 노드를 생성한 뒤 kubeadm join 명령을 미리 저장해둔 파일입니다. 이 부분은 뒤에서 자세히 설명하겠습니다.

위 명령들을 worker2, worker3에도 똑같이 실행합니다.

쿠버네티스 클러스터 확인하기

vagrant ssh master 명령을 실행하여 다시 master 노드로 들어갑니다. 그리고 kubectl get node 명령을 실행해봅니다.

$ vagrant ssh master
vagrant@master:~$ kubectl get node
NAME      STATUS   ROLES           AGE     VERSION
master    Ready    control-plane   19m     v1.28.4
worker1   Ready    <none>          5m18s   v1.28.4
worker2   Ready    <none>          68s     v1.28.4
worker3   Ready    <none>          31s     v1.28.4

master, worker1, 2, 3 노드가 모두 Ready 상태인 것을 확인할 수 있습니다. 이렇게 쿠버네티스 클러스터 구축이 끝났습니다.

.kube 디렉터리 설정하기

Vagrantfile이 들어있는 폴더를 보면 join.sh 파일 말고도 .kube 폴더가 들어있는 것을 볼 수 있습니다. 이 폴더를 호스트의 사용자 계정 폴더(디렉터리로) 복사하면 노드 바깥에서도 kubectl로 클러스터를 제어할 수 있습니다.

.kube 디렉터리 백업

아래 명령을 실행하면 기존 .kube/config 파일을 삭제하거나 덮어쓰게 됩니다. 따라서 기존 .kube 디렉터리는 백업해주시기 바랍니다.

윈도우 PowerShell
Copy-Item -Force -Recurse .\.kube C:\Users\${env:UserName}\
리눅스, macOS
cp -R ./.kube ~/

이제 kubectl 명령이 잘 실행되는지 테스트해봅니다.

$ kubectl get node
NAME      STATUS   ROLES           AGE   VERSION
master    Ready    control-plane   23m   v1.28.4
worker1   Ready    <none>          91s   v1.28.4
worker2   Ready    <none>          60s   v1.28.4
worker3   Ready    <none>          31s   v1.28.4

윈도우에서 Unable to connect to the server: net/http: TLS handshake timeout 에러 발생

윈도우에서 kubectl get node 명령을 실행했을 때 Unable to connect to the server: net/http: TLS handshake timeout 에러가 발생한다면, $env:VAGRANT_PREFER_SYSTEM_BIN += 0을 실행한 뒤 kubectl get node 명령을 실행해줍니다.

윈도우 PowerShell
$env:VAGRANT_PREFER_SYSTEM_BIN += 0
kubectl get node

저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

2022-10-22