Kubespray로 Kubernetes 클러스터 배포하기
- Kubespray는 Ansible 기반의 Kubernetes 클러스터 배포 도구다.
- 프로덕션 레벨의 클러스터를 손쉽게 구축할 수 있으며, 다양한 CNI 플러그인과 애드온을 지원한다.
- 이 글에서는 Rocky Linux 10 기반 단일 노드 클러스터를 Kubespray v2.29.1로 배포하는 과정을 정리한다.
실습 환경 개요

VM 스펙 정보
| 항목 | 값 |
|---|
| OS | Rocky Linux 10.0 (bento/rockylinux-10.0) |
| CPU | 4 vCPU |
| Memory | 4GB |
| IP | 192.168.10.10 |
| Hostname | k8s-ctr |
| SSH Port | 60100 (Host → Guest 포워딩) |
배포될 Kubernetes 구성
| 구성요소 | 설정값 |
|---|
| Kubernetes 버전 | v1.33.3 |
| 컨테이너 런타임 | containerd 2.1.5 |
| CNI 플러그인 | Flannel |
| kube-proxy 모드 | iptables |
| Service CIDR | 10.233.0.0/18 |
| Pod CIDR | 10.233.64.0/18 |
| DNS | CoreDNS |
| etcd | host (systemd unit) |
1단계: Vagrant로 VM 배포
디렉터리 생성 및 파일 다운로드
mkdir k8s-kubespary
cd k8s-kubespary
wget https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/k8s-kubespary/Vagrantfile
wget https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/k8s-kubespary/init_cfg.sh
vagrant up
vagrant status
init_cfg.sh 주요 작업
| Task | 설명 |
|---|
| Timezone 설정 | Asia/Seoul로 변경 |
| firewalld/SELinux 비활성화 | K8s 네트워킹을 위해 필수 |
| SWAP 비활성화 | kubelet 요구사항 |
| 커널 모듈 로드 | overlay, br_netfilter |
| sysctl 설정 | ip_forward, bridge-nf-call 활성화 |
| /etc/hosts 설정 | k8s-ctr 호스트명 등록 |
| 기본 라우팅 수정 | enp0s9 기본 게이트웨이 제거 |
2단계: 사전 설정 및 Kubespray 클론
필수 요구사항 확인
| 요구사항 | 확인 명령어 | 권장 버전 |
|---|
| Linux Kernel | uname -a | 5.8+ |
| Python | python3 -V | 3.10 ~ 3.12 |
| pip | pip3 -V | - |
| Ansible | ansible --version | 2.17.3+ |
SSH 설정 (Ansible 통신용)
echo "root:qwe123" | chpasswd
cat << EOF >> /etc/ssh/sshd_config
PermitRootLogin yes
PasswordAuthentication yes
EOF
systemctl restart sshd
ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa
ssh-copy-id -o StrictHostKeyChecking=no root@192.168.10.10
Kubespray 클론 및 의존성 설치
git clone -b v2.29.1 https://github.com/kubernetes-sigs/kubespray.git /root/kubespray
cd /root/kubespray
pip3 install -r requirements.txt
requirements.txt 주요 패키지
| 패키지 | 버전 | 용도 |
|---|
| ansible | 10.7.0 | 자동화 도구 |
| cryptography | 46.0.3 | community.crypto 모듈 |
| jmespath | 1.0.1 | Jinja2 json_query |
| netaddr | 1.3.0 | IP 주소 처리 |
3단계: Kubespray 설정
디렉터리 구조
inventory/mycluster/
├── group_vars/
│ ├── all/
│ │ ├── all.yml # 모든 노드 공통 설정
│ │ ├── containerd.yml # 컨테이너 런타임 설정
│ │ └── etcd.yml # etcd 설정
│ └── k8s_cluster/
│ ├── addons.yml # 애드온 설정
│ ├── k8s-cluster.yml # 클러스터 핵심 설정
│ └── k8s-net-flannel.yml # Flannel CNI 설정
└── inventory.ini # 호스트 인벤토리
inventory.ini 작성
k8s-ctr ansible_host=192.168.10.10 ip=192.168.10.10
[kube_control_plane]
k8s-ctr
[etcd:children]
kube_control_plane
[kube_node]
k8s-ctr
주요 설정 변경 사항
| 파일 | 설정 항목 | 기본값 → 변경값 |
|---|
| k8s-cluster.yml | kube_network_plugin | calico → flannel |
| k8s-cluster.yml | kube_proxy_mode | ipvs → iptables |
| k8s-cluster.yml | enable_nodelocaldns | true → false |
| k8s-cluster.yml | auto_renew_certificates | false → true |
| k8s-net-flannel.yml | flannel_interface | (추가) enp0s9 |
| addons.yml | helm_enabled | false → true |
| addons.yml | metrics_server_enabled | false → true |
| addons.yml | node_feature_discovery_enabled | false → true |
설정 변경 명령어
sed -i 's|kube_network_plugin: calico|kube_network_plugin: flannel|g' \
inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
sed -i 's|kube_proxy_mode: ipvs|kube_proxy_mode: iptables|g' \
inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
sed -i 's|enable_nodelocaldns: true|enable_nodelocaldns: false|g' \
inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
sed -i 's|auto_renew_certificates: false|auto_renew_certificates: true|g' \
inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
echo "flannel_interface: enp0s9" >> \
inventory/mycluster/group_vars/k8s_cluster/k8s-net-flannel.yml
sed -i 's|helm_enabled: false|helm_enabled: true|g' \
inventory/mycluster/group_vars/k8s_cluster/addons.yml
sed -i 's|metrics_server_enabled: false|metrics_server_enabled: true|g' \
inventory/mycluster/group_vars/k8s_cluster/addons.yml
sed -i 's|node_feature_discovery_enabled: false|node_feature_discovery_enabled: true|g' \
inventory/mycluster/group_vars/k8s_cluster/addons.yml
4단계: 클러스터 배포
배포 실행 (약 5분 소요)
ansible-playbook -i inventory/mycluster/inventory.ini -v cluster.yml \
-e kube_version="1.33.3" --list-tasks
ANSIBLE_FORCE_COLOR=true ansible-playbook \
-i inventory/mycluster/inventory.ini -v cluster.yml \
-e kube_version="1.33.3" | tee kubespray_install.log
ansible.cfg 주요 설정
| 섹션 | 설정 | 설명 |
|---|
| ssh_connection | pipelining=True | 단일 SSH 세션에서 여러 명령 실행 |
| ssh_connection | ControlPersist=30m | SSH 연결 30분 유지 |
| defaults | gathering=smart | Fact 수집 최적화 |
| defaults | fact_caching=jsonfile | /tmp에 캐시 저장 |
| defaults | callbacks_enabled=profile_tasks | Task별 실행 시간 표시 |
5단계: 설치 확인 및 도구 설정
클러스터 상태 확인
kubectl get node -owide
kubectl get pod -A
kubectl 자동완성 및 alias 설정
source <(kubectl completion bash)
source <(kubeadm completion bash)
alias k=kubectl
complete -o default -F __start_kubectl k
k9s 설치
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
wget https://github.com/derailed/k9s/releases/latest/download/k9s_linux_${CLI_ARCH}.tar.gz
tar -xzf k9s_linux_*.tar.gz
chown root:root k9s
mv k9s /usr/local/bin/
chmod +x /usr/local/bin/k9s
Kubespray 주요 Playbook 정리
| Playbook | 용도 |
|---|
| cluster.yml | 클러스터 초기 배포 |
| scale.yml | 노드 추가 |
| remove_node.yml | 노드 제거 |
| upgrade_cluster.yml | 클러스터 버전 업그레이드 |
| reset.yml | 클러스터 완전 초기화 |
| recover-control-plane.yml | 컨트롤 플레인 복구 |
배포 전후 변경사항 비교
배포 전후로 시스템 상태를 비교하면 Kubespray가 어떤 변경을 수행하는지 파악할 수 있다.
| 비교 대상 | 명령어 |
|---|
| IP/인터페이스 | ip addr |
| 리스닝 포트 | ss -tnlp |
| 디스크/파티션 | df -hT |
| 마운트 포인트 | findmnt |
| 커널 파라미터 | sysctl -a |
vi -d ip_addr-1.txt ip_addr-2.txt
vi -d ss-1.txt ss-2.txt
정리
Kubespray를 사용하면 Ansible의 강력한 자동화 기능을 활용해 프로덕션 수준의 Kubernetes 클러스터를 쉽게 배포할 수 있다. 주요 특징을 정리하면 다음과 같다.
- 유연한 구성: 다양한 CNI(Calico, Flannel, Cilium 등), 컨테이너 런타임(containerd, CRI-O) 지원
- 선언적 설정: YAML 파일로 클러스터 구성 관리
- Day-2 운영 지원: 노드 추가/제거, 버전 업그레이드, 인증서 자동 갱신 등
- 멱등성: 동일한 Playbook을 여러 번 실행해도 안전
참고: Kubespray GitHub | Variables 문서