Kubespray로 쿠버네티스 클러스터 구축하기
Kubespray로 쿠버네티스 클러스터 구축하기
moseoh
kubernetes

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

moseoh · 2024년 12월 25일

Kubespray를 선택한 이유

회사에서 개발, 배포, 실습 환경 등 다양한 목적으로 서버를 사용하는데, 각자 서버를 개별적으로 관리하다 보니 자원 충돌이나 관리 부실 같은 문제들이 종종 발생했습니다. 이런 문제를 체계적으로 해결하고 싶었고, ‘If Kakao 2024’에서 카카오의 사내 서버 관리 방식을 흥미롭게 본 것이 계기가 되었습니다. 카카오는 Packer, Ansible 등 다양한 도구를 활용해 복잡하고 자동화된 프로비저닝 시스템을 구축했지만, 저희 상황에서는 그 정도까지는 과하다고 판단했습니다. 그래서 핵심인 쿠버네티스만 먼저 도입하여 서버 관리를 시작해보기로 했습니다.

쿠버네티스 클러스터를 구축하는 도구는 kubeadm, kops 등 여러 가지가 있지만, 저희는 Kubespray를 선택했습니다. 이유는 다음과 같습니다.

  • Ansible 기반 자동화: 저희 팀은 이미 Ansible에 익숙했기 때문에, 플레이북 기반으로 설치와 구성을 자동화하는 Kubespray가 가장 편하게 다가왔습니다.
  • 다양한 환경 지원: 베어메탈 서버부터 AWS, GCP 같은 클라우드 환경까지 폭넓게 지원해서, 현재의 사내 인프라뿐만 아니라 미래의 클라우드 확장까지 고려할 수 있었습니다.
  • 유연한 커스터마이징: Ansible의 장점을 그대로 살려, 클러스터 설정을 저희 요구에 맞게 세밀하게 조정하기 용이했습니다.

간단한 쿠버네티스 관리 도구 비교표

특징kubeadmKubespraykops
관리 방식CLI 도구Ansible 플레이북 기반CLI 도구
주요 지원 환경온프레미스, 클라우드온프레미스, 클라우드 (가장 폭넓음)주로 AWS, GCE 등 클라우드
자동화 수준클러스터 초기화 및 노드 추가에 중점설치, 구성, 업그레이드 등 전체 라이프사이클 관리클라우드 네이티브 자동화
특징Kubernetes 공식 도구, 간단한 클러스터용다양한 구성 요소 선택 가능, Ansible 익숙 사용자에게 적합클라우드 환경에서 가장 간편함

실습 환경 구성하기 (Vagrant + VMware)

본격적으로 사내 서버에 적용하기 전에, 로컬에서 안전하게 테스트해볼 환경이 필요했습니다. Vagrant와 VMware를 이용해 1개의 마스터 노드와 2개의 워커 노드로 구성된 가상 클러스터 환경을 만들었습니다.

이 글은 Kubespray에 초점을 맞추고 있으므로, Vagrant 설정에 대한 상세한 설명은 생략합니다. 단, VM 사용 시 관련 라이선스를 꼭 확인하시기 바랍니다.

사전 준비

  • VMware Fusion, Vagrant, 관련 플러그인 설치
  • SSH 키 생성 (~/.ssh/id_rsa.pub)

Vagrantfile 작성

Ubuntu 24.04 LTS 이미지를 기반으로 3개의 VM(master, worker1, worker2)을 생성하는 Vagrantfile을 작성했습니다. 각 노드에는 외부 통신용과 클러스터 내부 통신용으로 두 개의 네트워크 인터페이스를 할당했습니다.

Vagrantfile 전체 코드 보기
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
BOX_IMAGE = "gutehall/ubuntu24-04"
# VM 구성
NODES = [
{ :hostname => "master", :ip => "192.168.56.10", :ip_internal => "10.3.0.1", :memory => 2048, :cpus => 2 },
{ :hostname => "worker1", :ip => "192.168.56.11", :ip_internal => "10.3.0.2", :memory => 2048, :cpus => 2 },
{ :hostname => "worker2", :ip => "192.168.56.12", :ip_internal => "10.3.0.3", :memory => 2048, :cpus => 2 }
]
# 각 노드 설정
NODES.each do |node|
config.vm.define node[:hostname] do |nodeconfig|
nodeconfig.vm.box = BOX_IMAGE
nodeconfig.vm.hostname = node[:hostname]
nodeconfig.vm.provider "vmware_desktop" do |v|
v.memory = node[:memory]
v.cpus = node[:cpus]
v.gui = false
end
nodeconfig.ssh.insert_key = false
nodeconfig.vm.network "private_network", ip: node[:ip]
nodeconfig.vm.network "private_network", ip: node[:ip_internal]
nodeconfig.vm.provision "shell" do |s|
ssh_pub_key = File.readlines("#{Dir.home}/.ssh/id_rsa.pub").first.strip
s.args = [ssh_pub_key]
s.inline = <<-SHELL
mkdir -p /root/.ssh
echo $1 >> /root/.ssh/authorized_keys
mkdir -p /home/vagrant/.ssh
echo $1 >> /home/vagrant/.ssh/authorized_keys
chown -R vagrant:vagrant /home/vagrant/.ssh
SHELL
end
end
end
end

이제 터미널에서 vagrant up 명령어를 실행하면, 설정된 3개의 VM이 자동으로 생성되고 실행됩니다.

Kubespray로 클러스터 구축하기

VM 환경이 준비되었으니, 이제 Kubespray를 사용해 쿠버네티스를 설치할 차례입니다.

1. Kubespray 저장소 복제 및 인벤토리 설정

먼저 Kubespray 소스 코드를 가져오고, 클러스터 구성을 정의할 인벤토리 파일을 준비합니다.

git clone <https://github.com/kubernetes-sigs/kubespray.git>
cd kubespray
cp -r inventory/sample inventory/mycluster

inventory/mycluster/inventory.ini 파일은 Ansible이 어떤 노드에 어떤 역할을 할당할지 알려주는 설계도와 같습니다. 저희는 Vagrant로 만든 환경에 맞춰 아래와 같이 수정했습니다.

# 노드 정보 정의
node1 ansible_user=vagrant ansible_host=192.168.56.10 ip=10.3.0.1
node2 ansible_user=vagrant ansible_host=192.168.56.11 ip=10.3.0.2
node3 ansible_user=vagrant ansible_host=192.168.56.12 ip=10.3.0.3
# 컨트롤 플레인 그룹
[kube_control_plane]
node1
# etcd 그룹 (데이터 안정성을 위해 홀수 개 노드로 구성)
[etcd]
node1
node2
node3
# 워커 노드 그룹
[kube_node]
node2
node3
  • ansible_host: Ansible이 SSH로 접속할 IP (호스트-게스트 통신용)
  • ip: 쿠버네티스 내부 통신용 IP (내부 네트워크용)

2. Kubespray 실행 환경 설정

의존성 충돌을 피하기 위해 Python 가상 환경을 만들고 필요한 라이브러리를 설치합니다.

# kubespray 디렉토리에서 실행
python3 -m venv venv
source venv/bin/activate
pip install -U -r requirements.txt

3. 호스트 연결 확인 및 클러스터 배포

배포 전에 Ansible이 모든 노드에 정상적으로 SSH 접속이 가능한지 ping 모듈로 확인합니다.

ansible all -i inventory/mycluster/inventory.ini -m ping --private-key=~/.ssh/id_rsa

SUCCESS 응답을 확인했다면, 이제 cluster.yml 플레이북을 실행하여 클러스터 배포를 시작합니다.

ansible-playbook -i inventory/mycluster/inventory.ini cluster.yml -b -v --private-key=~/.ssh/id_rsa

제 M3 Pro 맥북 기준으로 약 20분 정도 소요되었습니다. PLAY RECAPfailed=0이 표시되면 성공적으로 배포가 완료된 것입니다.

클러스터 접근 설정 (kubeconfig)

클러스터가 성공적으로 구축되었지만, kubectl로 클러스터에 명령을 내리려면 인증 정보가 담긴 kubeconfig 파일이 필요합니다.

1. kubeconfig 파일 가져오기

이 파일은 기본적으로 마스터 노드의 /etc/kubernetes/admin.conf에 생성됩니다. 먼저 마스터 노드에 접속하여 파일 소유권을 변경한 뒤, 로컬 PC로 복사해옵니다.

# 마스터 노드 접속 및 권한 변경
sudo chown vagrant:vagrant /etc/kubernetes/admin.conf
exit
# 로컬 PC에서 파일 복사
mkdir -p ~/.kube
scp [email protected]:/etc/kubernetes/admin.conf ~/.kube/config
chmod 600 ~/.kube/config

팁: 여러 클러스터를 관리한다면, ~/.kube/config 파일을 직접 덮어쓰기보다 /.kube/mycluster.config처럼 별도 파일로 관리하고, export KUBECONFIG=/.kube/mycluster.config 환경 변수를 사용하는 것이 안전합니다.

2. kubeconfig 파일 수정

로컬로 가져온 kubeconfig 파일에는 클러스터 API 서버 주소가 내부 IP로 되어 있을 수 있습니다. 외부에서 접속하려면 이 주소를 실제 접속 가능한 IP로 수정해야 합니다.

실습 환경에서는 Vagrant가 VM에 할당한 NAT IP를 사용해야 합니다. 먼저 마스터 노드의 NAT IP를 확인합니다.

ssh [email protected] "ip -4 addr show eth0 | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'"
# 예시 출력: 192.168.63.148

이제 ~/.kube/config 파일을 열어 server 주소를 확인된 IP로 수정합니다.

# vi ~/.kube/config
...
clusters:
- cluster:
certificate-authority-data: ...
server: <https://192.168.63.148:6443> # <-- 이 부분을 확인된 IP로 수정
...

3. 클러스터 상태 확인

모든 설정이 끝났습니다. 이제 로컬 터미널에서 kubectl 명령어로 클러스터의 노드 상태를 확인해 봅니다.

kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready control-plane 165m v1.31.3
node2 Ready <none> 164m v1.31.3
node3 Ready <none> 164m v1.31.3

위와 같이 모든 노드가 Ready 상태로 보인다면, Kubespray를 이용한 쿠버네티스 클러스터 구축이 성공적으로 완료된 것입니다. 다음 포스팅에서는 이 클러스터 위에 CI/CD를 위한 GitHub Actions Runner를 배포해보겠습니다.