Ansible로 Kubernetes 클러스터를 코드 한 줄로 (홈랩 k8s 구축기 2편)
지난 편에서 Terraform으로 VM 3개를 만들었다. 이번에는 그 VM들 위에 Kubernetes 클러스터를 올리는 과정이다. kubeadm으로 클러스터를 직접 구성하고, 그 과정 전체를 Ansible로 자동화했다.
왜 Ansible인가
VM이 3개다. Control Plane 1개, Worker 2개. 패키지 설치, 커널 모듈 설정, swap 비활성화 같은 작업을 각 노드에 SSH로 접속해서 일일이 하는 건 귀찮은 일이기도 하지만, 나중에 다시 구성해야 할 때 무엇을 했는지 기억하기 어렵다는 게 더 큰 문제다.
Ansible은 이런 상황에 잘 맞는 도구다. 플레이북에 순서대로 작성해두면 다음에 같은 과정을 반복할 때 명령 하나로 끝난다.
플레이북 구조
역할(role) 기반으로 구성했다.
infrastructure/ansible/
├── ansible.cfg
├── inventory.ini
├── site.yml
└── roles/
├── common/ # VM 공통 초기화
├── containerd/ # 컨테이너 런타임 설치
├── kubernetes/ # kubeadm / kubelet / kubectl 설치
├── control-plane/ # kubeadm init + Flannel CNI + kube-proxy 설정
└── worker/ # kubeadm join
site.yml을 실행하면 이 순서대로 모든 노드에 적용된다.
| 순서 | 대상 | 역할 |
|---|---|---|
| 1 | 전체 노드 | common — 기본 패키지, swap 비활성화, 커널 모듈, sysctl |
| 2 | 전체 노드 | containerd — 컨테이너 런타임 설치 및 설정 |
| 3 | 전체 노드 | kubernetes — kubeadm / kubelet / kubectl 설치 |
| 4 | control-plane | control-plane — kubeadm init + Flannel CNI + kube-proxy 설정 |
| 5 | workers | worker — kubeadm join |
ansible-playbook site.yml 한 줄이면 끝이다.
containerd CRI 플러그인 문제
처음 실행에서 클러스터가 제대로 올라오지 않았다. kubeadm이 containerd와 통신을 못 했는데, 오류 메시지를 보면 이렇게 나온다.
failed to create new CRI runtime service: validate service connection:
validate CRI v1 runtime API for endpoint "unix:///var/run/containerd/containerd.sock":
rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService
CRI 플러그인이 비활성화된 상태라는 뜻이었다. Ubuntu 24.04에는 containerd가 기본 설치되어 있는데, 그 기본 설정이 CRI 플러그인을 꺼두거나, config.toml 파일이 이미 존재해서 내 설정이 덮어씌워지지 않은 것이 원인이었다.
Ansible task에서 creates: 조건이 문제였다.
# 수정 전 — 기존 파일이 있으면 건너뜀
- name: Generate containerd default config
ansible.builtin.shell: containerd config default > /etc/containerd/config.toml
args:
creates: /etc/containerd/config.toml
# 수정 후 — 항상 재생성
- name: Generate containerd default config (force regenerate)
ansible.builtin.shell: containerd config default > /etc/containerd/config.toml
changed_when: true
creates: 조건을 제거하고 항상 재생성하도록 바꾸었다. 이후 SystemdCgroup = true로 설정해서 kubeadm과 cgroup 드라이버를 맞춰주는 것도 함께 진행했다.
kubeadm config 파일 방식
처음에는 kubeadm init을 명령줄 인자 방식으로 실행했다.
kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.50.110
이렇게 해도 클러스터는 올라온다. 그런데 나중에 모니터링을 설치하면서 문제가 생겼다. Prometheus가 kube-controller-manager, kube-scheduler, etcd, kube-proxy의 메트릭을 수집하지 못하는 것이었다. 원인을 파보니 kubeadm 기본 설정에서 이 컴포넌트들이 127.0.0.1에만 바인딩되어 있어서 Prometheus Pod이 접근할 수 없었던 것이다.
이걸 코드로 관리하려면 config 파일 방식이 맞다.
# infrastructure/ansible/roles/control-plane/files/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
networking:
podSubnet: 10.244.0.0/16
apiServer:
advertiseAddress: 192.168.50.110
controllerManager:
extraArgs:
- name: bind-address
value: '0.0.0.0'
scheduler:
extraArgs:
- name: bind-address
value: '0.0.0.0'
etcd:
local:
extraArgs:
- name: listen-metrics-urls
value: 'http://0.0.0.0:2381'
kube-proxy는 Ansible task에서 ConfigMap 패치로 따로 처리한다.
- name: Patch kube-proxy metricsBindAddress
ansible.builtin.shell: |
kubectl get configmap kube-proxy -n kube-system -o yaml \
| sed 's/metricsBindAddress: ""/metricsBindAddress: "0.0.0.0:10249"/' \
| kubectl apply -f -
이렇게 해두면 다음에 클러스터를 다시 구성할 때 Prometheus 연동 문제 없이 바로 올라온다.
클러스터 확인
ansible-playbook site.yml이 완료되면 아래와 같이 3개 노드가 Ready 상태로 올라온다.
NAME STATUS ROLES AGE VERSION
k8s-control-plane Ready control-plane 96s v1.32.13
k8s-worker-1 Ready <none> 83s v1.32.13
k8s-worker-2 Ready <none> 83s v1.32.13
VM 3개에 이걸 일일이 손으로 했다면 시간도 오래 걸리고 실수도 생기기 쉬웠을 것이다. Ansible에 한 번 정리해두고 나니, 클러스터를 처음부터 다시 만드는 일이 이제는 부담스러운 일이 아니었다.
다음 편에서는 이 클러스터 위에 네트워크 컴포넌트와 스토리지를 올리는 과정을 이야기 하겠다.
이 저작물은 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스 에 따라 이용할 수 있습니다.
Comments
Related Posts
집에 Kubernetes 클러스터를 구축해 봤습니다
퇴근하고 집에 돌아와 미니 PC 한 대를 책상 위에 올려두고는 여기다가 Kubernetes 클러스터를 직접 구축해 보겠다고 마음먹은 게 몇 달 전이었다. 그리고 지금, 그 미니 P…
MetalLB, ingress-nginx, Longhorn으로 네트워크와 스토리지 구성하기 (홈랩 k8s 구축기 3편)
지난 편에서 Ansible로 Kubernetes 클러스터를 구성했다. 클러스터는 올라왔지만, 이 상태로는 아무것도 할 수 없다. 외부에서 트래픽을 받는 방법도 없고, 데이터를 저장…
Proxmox 설치부터 Terraform으로 VM 찍어내기까지 (홈랩 k8s 구축기 1편)
집에 Kubernetes 클러스터를 구축해 봤습니다에서 전체 구성과 삽질의 개요를 간략하게 정리했다. 이번 편부터는 각 단계를 좀 더 구체적으로 풀어볼 생각이다. 1편의 주제는 P…