MacOS 에서 쿠버네티스 클러스터를 위한 Vagrant 설치.
- DevTools / Vagrant
- 2023. 8. 23.
- Vagrant와 Vagrant Manager에 대해
- Master Node : Mac Mini에 Vagrant로 가상머신을 설치해보자.
- Worker Node : Mac Book에 Vagrant로 가상머신을 설치해보자.

주로 인프라를 다루는 업무를 하다보니 일적으로나 취미적으로나 리눅스환경에서 쿠버네티스를 만지는일이 많다.
특히 멀티노드 클러스터로 구성된 쿠버네티스(K8s)를 필요로 하는 경우가 많은데, Minikube나 Docker Desktop의 Kubernetes로는 동일한 환경으로 가정해 테스트나 실제 작업을 염두에 두고 작업후 적용하는데 어려울 수가 있다.
회사의 클라우드 테스트환경을 아무렇게나 사용하기엔 동료들에게도 살짝 눈치가 보일때도 많아서 집에 있는 맥북과 맥미니 윈도우 데스크탑에 Vagrant로 VirtualBox 호스트를 만들어 쿠버네티스 클러스터를 구성해보려고 한다.

Vagrant와 Vagrant Manager에 대해
우선 Vagrant와 Vagrant Manager를 설치 하는 이유를 알고 넘어가자.
- Vagrant : VirtualBox나 VMware, Hyper-V등의 가상 머신을 프로비저닝를 한꺼번에 Vagrant를 통해서 관리 할 수 있다.
- Vagrant Manager : Vagrant Manager는 Vagrant로 가상 머신을 관리하는 UI 도구다. UI를 통해 Vagrant 가상머신을 끄고 켜고 관리를 할 수 있다. 결정적으로 Mac을 껏다 켰을때(Reboot) 자동실행된 Vagrant Manager가 가상머신을 자동시작해 줄수 있다. (운영이 편하다!)
![Vagrant Manger : [ Launch at Login ] Option](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
Master Node : Mac Mini에 Vagrant로 가상머신을 설치해보자.
거실 티비 뒤에서 늘 켜져 있는 맥미니를 마스터 노드로 구성하려고 한다.
1. 설치 환경.
- macOS Monterey 12.6.8 (Intel i7 CPU )
- iTerm2
- zsh / ohmyzsh
- Homebrew
2. Vagrant 와 Vagrant Manager 설치.
맥에서는 brew를 이용해서 쉽게 설치 할수 있다.
> brew install vagrant vagrant-manager > vagrant plugin install vagrant-disksize vagrant-hostmanager vagrant-qemu vagrant-vbguest > vagrant plugin list vagrant-disksize (0.1.3, global) - Version Constraint: > 0 vagrant-hostmanager (1.8.10, global) - Version Constraint: > 0 vagrant-qemu (0.3.5, global) - Version Constraint: > 0 vagrant-vbguest (0.31.0, global) - Version Constraint: > 0
3. Virtualbox 설치.
> brew install virtualbox
4. 가상 머신 Master Node 생성에 필요한 VagrantFile 생성.
브릿지로 사용할 네트워크 인터페이스의 정보를 먼저 확인한다.
## 인터넷 연결에 사용하는 인터페이스 이름을 확인한다. ## 나같은 경우는 'en0' 로 확인 된다. > networksetup -listallhardwareports Hardware Port: Ethernet Device: en0 Ethernet Address: ac:87:b3:2f:92:7c Hardware Port: Wi-Fi Device: en1 Ethernet Address: 60:f8:1d:b1:f2:28 Hardware Port: Thunderbolt 1 Device: en2 Ethernet Address: 82:15:05:6f:2a:00 Hardware Port: Thunderbolt 2 Device: en3 Ethernet Address: 82:15:05:6f:2a:01 Hardware Port: Thunderbolt Bridge Device: bridge0 Ethernet Address: 82:15:05:6f:2a:00 VLAN Configurations ===================
$ vim ~/vagrant/VagrantFile 으로 Vagrant 프로비저닝에 필요한 파일을 생성합니다.
- 마스터 노드를 생성하고 업데이트나 쿠버네티스 설치등의 기본적인 설정을 함께 하도록 스크립트를 포함하고 있다.
- 2cpu에 4G 메모리
- 가상머신이 맥미니와 같은 네트워크에 독립적인 호스트로 기능을 할수 있도록 IP를 "192.168.1.200" 으로하고
- config.vm.network을 "public_network"으로 설정했다.
- 쿠버네티스 워커노드 Join에 필요한 커맨드는 마스터노드의 ~/vagrant/join.sh 로 저장됩니다.
# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure("2") do |config| # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. # config.vm.box = "base" config.vm.box = "ubuntu/jammy64" config.vbguest.auto_update = false config.hostmanager.enable = false config.hostmanager.manage_host = true config.hostmanager.include_offline = true config.hostmanager.ignore_private_ip = false # master config.vm.define :master do |config| config.vm.provider :virtualbox do |vb| vb.name = "master" vb.gui = false vb.cpus = 2 vb.memory = 4096 # vb.customize ["modifyvm", :id, "--cpus", "2"] # vb.customize ["modifyvm", :id, "--memory", "4096"] end config.vm.hostname = "master" # config.vm.synced_folder ".", "/vargrant", disabled: true config.vm.network "public_network", bridge: 'en0: eth0', ip: "192.168.1.200" config.disksize.size = "150GB" config.vm.provision "set_net_foward", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf overlay br_netfilter EOF sudo modprobe overlay 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 SHELL config.vm.provision "set_containerd", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL sudo DEBIAN_FRONTEND=noninteractive apt-get update -yq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y curl gnupg2 gnupg-agent software-properties-common apt-transport-https ca-certificates sudo rm -f /etc/apt/trusted.gpg.d/docker.gpg sudo rm -f /usr/share/keyrings/kubernetes-archive-keyring.gpg sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg sudo curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg| sudo gpg --dearmor -o /usr/share/keyrings/kubernetes-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo DEBIAN_FRONTEND=noninteractive add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo DEBIAN_FRONTEND=noninteractive apt-get 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 sed -i 's#registry.k8s.io/pause:3.6#registry.k8s.io/pause:3.9#g' /etc/containerd/config.toml sudo systemctl daemon-reload sudo systemctl restart containerd sudo systemctl enable containerd SHELL config.vm.provision "set_kubelet", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL cat <<-'EOF' >/etc/default/kubelet KUBELET_EXTRA_ARGS=--node-ip=192.168.1.200 EOF sudo DEBIAN_FRONTEND=noninteractive apt-get update -yq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y kubelet kubeadm kubectl sudo DEBIAN_FRONTEND=noninteractive apt-mark hold kubelet kubeadm kubectl SHELL config.vm.provision "set_kube_join_sh", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL OUTPUT_FILE=/vagrant/join.sh rm -rf $OUTPUT_FILE rm -rf /vagrant/.kube sudo kubeadm config images pull --cri-socket=unix:///run/containerd/containerd.sock sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.1.200 --apiserver-advertise-address=192.168.1.200 --cri-socket=unix:///run/containerd/containerd.sock sudo kubeadm token create --print-join-command > $OUTPUT_FILE chmod +x $OUTPUT_FILE SHELL config.vm.provision "set_kubadmin", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL 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 create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml # curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml -O # kubectl create -f custom-resources.yaml kubectl completion bash >/etc/bash_completion.d/kubectl echo 'alias k=kubectl' >>/home/vagrant/.bashrc SHELL config.vm.provision "set_harbor", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL git clone https://github.com/litmudoc/vbox_harbor_installer.git $HOME/vbox_harbor_installer chmod +x $HOME/vbox_harbor_installer/harbor.sh IPorFQDN=192.168.1.200 $HOME/vbox_harbor_installer/harbor.sh sudo chmod 666 /home/vagrant/harbor/common/config/*/env SHELL config.vm.provision "restart_harbor", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL cd /home/vagrant/harbor docker compose stop docker compose start SHELL config.vm.provision "set_upgrade_reboot", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL sudo DEBIAN_FRONTEND=noninteractive apt-get -y full-upgrade [ -f /var/run/reboot-required ] && sudo reboot -f SHELL end end
5. VagrantFile 구성 파일로 Master Node를 생성 하자.
Vagrant Manager에서 'Provisioning' 을 클릭해 생성 하거나, 쉘에서 커맨드를 통해서 로그를 확인 하면서 생성 할 수 있습니다.
* 쉘에서 Log를 보면서 생성하는것이 좋습니다. (마스터노드 프로비저닝에는 10분 정도가 소요 됩니다.)
## 설정파일이 있는 위치로 이동후 진행 하면 됩니다. > cd ~/vagrant > vagrant up master Bringing machine 'master' up with 'virtualbox' provider... ==> master: Importing base box 'ubuntu/jammy64'... ==> master: Matching MAC address for NAT networking... ==> master: Checking if box 'ubuntu/jammy64' version '20230302.0.0' is up to date... ==> master: Setting the name of the VM: master ==> master: Clearing any previously set network interfaces... ==> master: Preparing network interfaces based on configuration... master: Adapter 1: nat master: Adapter 2: bridged ==> master: Forwarding ports... master: 22 (guest) => 2222 (host) (adapter 1) ==> master: Running 'pre-boot' VM customizations... ==> master: Resized disk: old 40960 MB, req 153600 MB, new 153600 MB ==> master: You may need to resize the filesystem from within the guest. ==> master: Booting VM... ==> master: Waiting for machine to boot. This may take a few minutes... master: SSH address: 127.0.0.1:2222 master: SSH username: vagrant master: SSH auth method: private key ... master: done master: NEEDRESTART-VER: 3.5 master: NEEDRESTART-KCUR: 5.15.0-67-generic master: NEEDRESTART-KEXP: 5.15.0-88-generic master: NEEDRESTART-KSTA: 3 master: NEEDRESTART-SVC: containerd.service master: NEEDRESTART-SVC: cron.service master: NEEDRESTART-SVC: dbus.service master: NEEDRESTART-SVC: docker.service master: NEEDRESTART-SVC: getty@tty1.service master: NEEDRESTART-SVC: kubelet.service master: NEEDRESTART-SVC: multipathd.service master: NEEDRESTART-SVC: networkd-dispatcher.service master: NEEDRESTART-SVC: packagekit.service master: NEEDRESTART-SVC: polkit.service master: NEEDRESTART-SVC: serial-getty@ttyS0.service master: NEEDRESTART-SVC: systemd-logind.service master: NEEDRESTART-SVC: systemd-manager master: NEEDRESTART-SVC: unattended-upgrades.service master: NEEDRESTART-SVC: user@1000.service master: Rebooting. >
또는 Vagrant Manager에서 Provisioning 합니다.

VirtualBox Desktop을 실행해서 생성된 Master Node를 확인할 수 있습니다.

- 마스터 노드를 정해준 스펙대로 VirtualBox로 프로비저닝하고
- 자동적으로 쿠버네티스 마스터 노드 구성에 필요한 내용까지 완료 하도록 했습니다.
- VM에 Harbor Image Registry를 자동설치 하도록 했습니다.
- CNI는 Calico, Flannel등을 노드 구성이 완료 된후 진행하도록 주석 처리 했다. (K8s 내용으로 포스팅을 하나 해야 겠다.)
Worker Node : Mac Book에 Vagrant로 가상머신을 설치해보자.
종종 들고 다니기도 하고 집에서 작업용으로 사용하는 맥북을 Worker 노드로 구성하자. (메인 워커노드는 Window 데스크탑에 구성할 예정)
1. 설치 환경.
- macOS Big Sur 11.7.10 (Intel i7 CPU)
- iTerm2
- zsh / ohmyzsh
- Homebrew
2. Vagrant 와 Vagrant Manager 설치.
맥에서는 brew를 이용해서 설치 할수 있다.
> brew install vagrant vagrant-manager > vagrant plugin install vagrant-disksize vagrant-hostmanager vagrant-qemu vagrant-vbguest > vagrant plugin list vagrant-disksize (0.1.3, global) - Version Constraint: > 0 vagrant-hostmanager (1.8.10, global) - Version Constraint: > 0 vagrant-qemu (0.3.5, global) - Version Constraint: > 0 vagrant-vbguest (0.31.0, global) - Version Constraint: > 0
3. Virtualbox 설치.
> brew install virtualbox
4. 가상 머신 Worker Node 생성에 필요한 VagrantFile 생성.
브릿지로 사용할 네트워크 인터페이스의 정보를 먼저 확인한다.
## 인터넷 연결에 사용하는 인터페이스 이름을 확인한다. ## 나같은 경우는 'en0' 로 확인 된다. > networksetup -listallhardwareports Hardware Port: Wi-Fi Device: en0 Ethernet Address: b8:e8:52:3c:06:b6 Hardware Port: Bluetooth PAN Device: en3 Ethernet Address: b8:e8:52:3c:06:b7 Hardware Port: Thunderbolt 1 Device: en1 Ethernet Address: 82:0f:01:11:f3:00 Hardware Port: Thunderbolt 2 Device: en2 Ethernet Address: 82:0f:01:11:f3:01 Hardware Port: Thunderbolt Bridge Device: bridge0 Ethernet Address: 82:0f:01:11:f3:00 VLAN Configurations ===================
$ vim ~/vagrant/VagrantFile 으로 Vagrant 프로비저닝에 필요한 파일을 생성합니다.
- 마스터 노드를 생성하고 업데이트나 쿠버네티스 설치등의 기본적인 설정을 함께 하도록 스크립트를 포함하고 있다.
- 2cpu에 4G 메모리
- 가상머신이 호스트와 같은 네트워크에서 독립적인 호스트로 기능을 할수 있도록 IP를 "192.168.1.202" 으로하고
- config.vm.network을 "public_network"으로 설정했다.
# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure("2") do |config| # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. # config.vm.box = "base" config.vm.box = "ubuntu/jammy64" config.vbguest.auto_update = false config.hostmanager.enable = false config.hostmanager.manage_host = true config.hostmanager.include_offline = true config.hostmanager.ignore_private_ip = false # worker02 config.vm.define :worker02 do |config| config.vm.provider :virtualbox do |vb| vb.name = "worker02" vb.gui = false vb.cpus = 2 vb.memory = 4096 end config.vm.hostname = "worker02" # config.vm.synced_folder ".", "/vargrant", disabled: true config.vm.network "public_network", bridge: 'en0: Wi-Fi (AirPort)', ip: "192.168.1.202" config.disksize.size = "40GB" config.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf overlay br_netfilter EOF sudo modprobe overlay 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 DEBIAN_FRONTEND=noninteractive apt-get update -yq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates sudo rm -f /etc/apt/trusted.gpg.d/docker.gpg sudo rm -f /usr/share/keyrings/kubernetes-archive-keyring.gpg sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg sudo curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg| sudo gpg --dearmor -o /usr/share/keyrings/kubernetes-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo DEBIAN_FRONTEND=noninteractive add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo DEBIAN_FRONTEND=noninteractive apt-get update -yq sudo DEBIAN_FRONTEND=noninteractive apt-get 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 sed -i 's#registry.k8s.io/pause:3.6#registry.k8s.io/pause:3.9#g' /etc/containerd/config.toml sudo systemctl daemon-reload sudo systemctl restart containerd sudo systemctl enable containerd cat <<-'EOF' >/etc/default/kubelet KUBELET_EXTRA_ARGS=--node-ip=192.168.1.202 EOF sudo DEBIAN_FRONTEND=noninteractive apt-get update -yq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y kubelet kubeadm kubectl sudo DEBIAN_FRONTEND=noninteractive apt-mark hold kubelet kubeadm kubectl SHELL config.vm.provision "set_upgrade_reboot", type: "shell", preserve_order: true, privileged: true, inline: <<-SHELL sudo DEBIAN_FRONTEND=noninteractive apt-get -y full-upgrade [ -f /var/run/reboot-required ] && sudo reboot -f SHELL end end
5. VagrantFile 설정파일에서 Worker Node를 생성 하자.
Vagrant Manager에서 'Provisioning' 을 클릭해 생성 하거나, 쉘에서 커맨드를 통해서 로그를 확인 하면서 생성 할 수 있습니다.
* 쉘에서 Log를 보면서 생성하는것이 좋습니다. (워커노드 프로비저닝에는 10분 정도가 걸립니다.)
## 설정파일이 있는 위치로 이동후 진행 하면 됩니다. > cd ~/vagrant > vagrant up worker02 Bringing machine 'worker02' up with 'virtualbox' provider... ==> worker02: Importing base box 'ubuntu/jammy64'... ==> worker02: Matching MAC address for NAT networking... ==> worker02: Checking if box 'ubuntu/jammy64' version '20230302.0.0' is up to date... ==> worker02: There was a problem while downloading the metadata for your box ==> worker02: to check for updates. This is not an error, since it is usually due ==> worker02: to temporary network problems. This is just a warning. The problem ==> worker02: encountered was: ==> worker02: ==> worker02: dyld: Symbol not found: _iconv ==> worker02: Referenced from: /usr/lib/libarchive.2.dylib ==> worker02: Expected in: /opt/vagrant/embedded/lib/libiconv.2.dylib ==> worker02: in /usr/lib/libarchive.2.dylib ==> worker02: ==> worker02: ==> worker02: If you want to check for box updates, verify your network connection ==> worker02: is valid and try again. ==> worker02: Setting the name of the VM: worker02 ==> worker02: Fixed port collision for 22 => 2222. Now on port 2200. ==> worker02: Clearing any previously set network interfaces... ==> worker02: Preparing network interfaces based on configuration... worker02: Adapter 1: nat worker02: Adapter 2: bridged ==> worker02: Forwarding ports... worker02: 22 (guest) => 2200 (host) (adapter 1) ==> worker02: Running 'pre-boot' VM customizations... ==> worker02: Booting VM... ==> worker02: Waiting for machine to boot. This may take a few minutes... worker02: SSH address: 127.0.0.1:2200 worker02: SSH username: vagrant worker02: SSH auth method: private key ... worker02: NEEDRESTART-SVC: systemd-logind.service worker02: NEEDRESTART-SVC: systemd-manager worker02: NEEDRESTART-SVC: unattended-upgrades.service worker02: NEEDRESTART-SVC: user@1000.service worker02: Rebooting. >
또는 Vagrant Manager에서 Provisioning 합니다.

6. Worker Node를 K8s 클러스터에 Join 시킵니다.
Master 노드에 있는 ~/vagrant/join.sh 의 내용을 복사해 Worker Node에서 쿠버네티스 클러스터에 Join 합니다.
> sudo kubeadm join 192.168.1.200:6443 --token 0arcno.4t1aj5wamt88cruk --discovery-token-ca-cert-hash sha256:f16fabbc67ccf5cbf554bd7623111b785b74f21e0abec5463ddfd9ec498e7b50
생성된 가상머신에 접근할때는 vagrant ssh 명령을 통해 접근하거나 Vagrant Manager에서 SSH로 접근할 수 있다.