현재 comppi 는 dev 환경만 구축이 되어있는 상태인데, 이제 배포가 임박하여 prod 환경을 구축하고 배포하려고 한다. 지금은 컨트롤 플레인까지 총 4개의 노드에서 dev 어플리케이션을 구동하고 있는데, 이제 배포할 prod 는 dev 를 동일한 노드에서 운용해도 될 정도로 하드웨어 리소스가 충분하지도 않고, 가능한 개발 서버와 운영 서버의 환경을 분리하고 싶었다. 개발 PC 를 클러스터에 포함시켜서 별도로 3개 정도의 worker 노드를 추가하여 그쪽에 dev 환경을 구축/배포하고, 기존의 운영 서버에서는 운영 환경을 격리시켜 놓으려고 한다.
여튼 오늘 정리하려는 글은 쿠버네티스 클러스터에 개발 PC 를 추가하기 위해서 또다시 VM 을 올리고, 쿠버네티스 환경을 프로비저닝해줘야 했는데, 해당 과정을 vagrant 로 자동화 한 이야기이다.
1. Vagrant
프로비저닝 및 인프라 관리라는 키워드로 가장 핫한 기술이 Terraform 과 Ansible 이다. (많은 회사에서 채택 중) 나는 뭐 하나 써본게 없어서 어떤건가 해서 검색해봤는데, 사실 써보기 전까지 무슨 목적인지 어떤 차이가 있는지 구체적으로는 모를 것 같다. 대충 Terraform 은 클라우드 환경에서 인프라를 구성해주고 코드로 상태관리를 해주는 도구(IaC) 라고 하고, Ansible 은 어플리케이션 설정, 배포 관리 등을 한다는데 ㅎㅎ ;; 둘 다 현재 프로젝트에 도입은 할 수 있겠지만 그렇게 큰 효용은 없어 보였다.
짧게 설명을 남기자면 Terraform 은 클라우드 환경에서 서버, 네트워크, 리소스 등을 깃처럼 코드로 관리하고, 클라우드 상태와 코드를 동기화하여 인프라를 관리하는 도구라고 한다. 그에 반해 Ansible 은 서버 인프라보다는 생성된 인스턴스의 내부를 지속적으로 프로비저닝 해주는 도구로 보임. 둘 다 멱등하게 동작하기 때문에 인프라를 지속적으로 구성하고 유지하는데에 좋은 것 같다. 후술할 Vagrant 는 지속적인 상태 관리는 불가능하고(ansible 과 연동하면 가능) 초기 VM 생성과 프로비저닝에 특화 되어있다.
나같은 경우에는 온프레미스 환경에서 빠르게 쿠버네티스 환경을 구축해서 노드를 추가하는 게 필요하고, 그 이후의 상태 관리가 필요할 정도의 규모는 아니기 때문에 그냥 Vagrant 만 활용하기로 했다. 만약에 필요하면 그때 가서 하지 뭐.
2. Vagrantfile
Vagrant 는 Vagrantfile 이라는 스크립트에 정의된 대로 VM 을 자동 생성해준다. 문법은 Ruby 를 쓰는데, 따로 배울 필요는 없는 거 같고 대강 공식 문서보고 더듬더듬 찾아가면서 쓰면 된다.
Vagrant.configure("2") do |config|
config.vm.box = "bento/ubuntu-24.04"
config.vbguest.auto_update = false
config.vm.synced_folder "./", "/vagrant", disabled: true
# Master Node
config.vm.define "master.comppi" do |node|
node.vm.hostname = "master"
node.vm.network "public_network", ip: "수동_할당", bridge: "네트워크_인터페이스_명"
node.disksize.size = "64GB"
node.vm.provision :shell, path: "./install_k8s_environment.sh"
node.vm.provision :shell, path: "./init_k8s_cluster.sh"
node.vm.provider :virtualbox do |vb|
vb.memory = 6144
vb.cpus = 4
end
# Worker Node 1
config.vm.define "worker1.comppi", autostart: false do |node|
node.vm.hostname = "worker1"
node.vm.network "public_network", ip: "수동_할당", bridge: "네트워크_인터페이스_명"
node.disksize.size = "64GB"
node.vm.provision :shell, path: "./install_k8s_environment.sh"
node.vm.provider :virtualbox do |vb|
vb.memory = 6144
vb.cpus = 4
end
end
# Worker Node 2
config.vm.define "worker2.comppi", autostart: false do |node|
node.vm.hostname = "worker2"
node.vm.network "public_network", ip: "수동_할당", bridge: "네트워크_인터페이스_명"
node.disksize.size = "64GB"
node.vm.provision :shell, path: "./install_k8s_environment.sh"
node.vm.provider :virtualbox do |vb|
vb.memory = 6144
vb.cpus = 4
end
end
# Worker Node 3
config.vm.define "worker3.comppi", autostart: false do |node|
node.vm.hostname = "worker3"
node.vm.network "public_network", ip: "172.30.1.53", bridge: "wlx588694fb5b61"
node.disksize.size = "64GB"
node.vm.provision :shell, path: "./install_k8s_environment.sh"
node.vm.provider :virtualbox do |vb|
vb.memory = 6144
vb.cpus = 4
end
end
end
나는 대충 위와 같이 정의했다. 세부 설정은 전혀 다르고 예시 코드다. 각 노드에 컨테이너 런타임과 쿠버네티스를 설치하고 마스터 노드에만 쿠버네티스 클러스터를 초기화 및 네트워크 인터페이스를 설치하는 스크립트를 실행하게 해두었다. 마스터 노드에 join 하는 스크립트도 추가해주고 싶었는데, Vagrant 에는 노드간 의존성같은 걸 제공하지는 않아서 (trigger 라는게 있긴 한데, 다른 노드에 뭘 지시하거나 그런건 공식문서에서 잘 안보임) 그냥 그건 수동으로 스크립트를 실행시켜준다. Ansible 은 여러 노드에 한번에 명령을 보낼 수 있기 때문에 더 간편할 것 같다.
#!/bin/bash
username="comppi"
# 새로운 사용자 추가
echo "방화벽을 비활성화하는 중..."
sudo useradd -m -s /bin/bash $username # 유저 이름
echo "$username:mypassword" | sudo chpasswd
sudo usermod -aG sudo $username
# 방화벽 끄기
echo "방화벽을 비활성화하는 중..."
sudo ufw disable
# 서버 시간대 설정 (서울)
echo "서버의 시간대를 서울로 설정하는 중..."
sudo timedatectl set-timezone Asia/Seoul
# 스왑 메모리 해제
echo "스왑 메모리를 비활성화하는 중..."
sudo swapoff -a
# /etc/fstab 파일에서 스왑 파티션 제거하여 부팅 시 스왑이 사용되지 않도록 설정
echo "부팅 시 스왑을 비활성화하도록 설정하는 중..."
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
echo "호스트 이름 설정중..."
cat << EOF >> /etc/hosts
********* master
********* worker1
********* worker2
********* worker3
********* worker4
********* worker5
********* cicd
********* nfs
EOF
echo "컨테이너 런타임(도커) 설치중..."
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
sudo apt-get update
sudo apt-get install ca-certificates curl -y
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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 docker-ce docker-ce-cli containerd.io -y
echo "쿠버네티스(1.31v) 설치중..."
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/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.31/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
sudo systemctl enable --now kubelet
이건 쿠버네티스 환경 구축 스크립트. 이런거야 뭐... 쿠버네티스 getting started 에 다 나와있음
음... 확실히 현재 프로젝트에서는 Vagrant 가 적절한 도구인 것 같긴한데, 어쩐지 아쉽다. Ansible, Terraform 을 이용해 더 세련된 방법으로 인프라를 자동화 구성하고 관리하는걸 적용 해보고 싶다.