들어가며

이전 글에서 VNC와 KVM 환경을 구축했습니다. 이번 글에서는 실제로 VM 3개를 생성하고 Kubernetes 클러스터를 설치하는 과정을 다룹니다.

문제 발견: macvlan의 한계

Part 1에서 WiFi 브릿지를 위해 macvlan을 설정했지만, 실제 VM에서 apt 업데이트가 불가능한 문제가 발생했습니다.

원인: WiFi는 Layer 2 브릿지를 완벽히 지원하지 않아, macvlan으로 설정한 VM이 외부 네트워크에 제대로 접근하지 못했습니다.

해결: NAT 네트워크(libvirt default)로 전환

1
2
3
# macvlan 대신 NAT 네트워크 사용
# VM은 192.168.122.0/24 대역 사용
# 호스트를 통해 외부 통신

VM 생성 (3개 노드)

VM 사양

VM역할IPCPUMemoryDisk
k8s-mastercontrol-plane192.168.122.104 cores8GB50GB
k8s-worker1worker192.168.122.114 cores8GB50GB
k8s-worker2worker192.168.122.124 cores8GB50GB

Ubuntu ISO 준비

1
2
3
4
# Ubuntu Server 24.04 ARM64 ISO 다운로드
mkdir -p ~/iso
cd ~/iso
wget https://cdimage.ubuntu.com/releases/24.04.4/release/ubuntu-24.04.4-live-server-arm64.iso

VNC로 VM 생성

VNC 클라이언트로 접속 후 virt-manager 실행:

  1. virt-manager 실행
  2. “New Virtual Machine” 클릭
  3. 설정:
    • Installation media: ubuntu-24.04.4-live-server-arm64.iso 선택
    • Memory: 8192 MB
    • CPUs: 4
    • Storage: 50 GB
    • Network: default (NAT)
  4. 3개 VM 생성 (k8s-master, k8s-worker1, k8s-worker2)

네트워크 고정 IP 설정

DHCP로 할당받은 IP를 고정으로 변경합니다.

주의사항

⚠️ 인터페이스 이름 확인: Ubuntu VM의 기본 네트워크 인터페이스는 enp1s0입니다 (eth0가 아님!)

1
2
3
4
# 인터페이스 확인
ip link show
# 1: lo: ...
# 2: enp1s0: ...  ← 이것 사용

netplan 설정

각 VM에서 실행:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# /etc/netplan/99-static.yaml 생성
sudo tee /etc/netplan/99-static.yaml > /dev/null << 'EOF'
network:
  version: 2
  ethernets:
    enp1s0:
      dhcp4: false
      addresses: [192.168.122.10/24]  # VM마다 .10, .11, .12
      routes:
        - to: default
          via: 192.168.122.1
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]
EOF

# 권한 설정
sudo chmod 600 /etc/netplan/99-static.yaml

# 적용
sudo netplan apply

SSH 키 설정

호스트에서 각 VM에 접속하기 위한 SSH 키 설정:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# SSH 키 생성 (호스트)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ''

# 공개키 복사 (각 VM)
ssh-copy-id ubuntu@192.168.122.10
ssh-copy-id ubuntu@192.168.122.11
ssh-copy-id ubuntu@192.168.122.12

# sudo NOPASSWD 설정 (각 VM에서)
echo "ubuntu ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ubuntu
sudo chmod 440 /etc/sudoers.d/ubuntu

Kubernetes 설치

1단계: 시스템 준비 (모든 노드)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 스왑 비활성화
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab

# 커널 모듈 로드
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl 설정
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

2단계: containerd 설치 (모든 노드)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 필수 패키지
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg

# containerd 설치
sudo apt-get install -y containerd

# containerd 설정
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# SystemdCgroup 활성화
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# 재시작
sudo systemctl restart containerd
sudo systemctl enable containerd

3단계: Kubernetes 패키지 설치 (모든 노드)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# GPG 키 추가
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/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.29/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

# kubelet 활성화
sudo systemctl enable kubelet

4단계: Master 노드 초기화

k8s-master (192.168.122.10)에서만 실행:

1
2
3
4
sudo kubeadm init \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=192.168.122.10 \
  --control-plane-endpoint=192.168.122.10

출력된 join 명령어를 복사해둡니다:

1
2
kubeadm join 192.168.122.10:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

5단계: kubectl 설정 (Master)

1
2
3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

6단계: Flannel CNI 설치 (Master)

1
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

7단계: Worker 노드 Join

k8s-worker1, k8s-worker2에서 실행:

1
2
3
# Master에서 복사한 join 명령어 실행
sudo kubeadm join 192.168.122.10:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

검증

노드 상태 확인

1
kubectl get nodes -o wide

예상 출력:

NAME          STATUS   ROLES           AGE   VERSION
k8s-master    Ready    control-plane   5m    v1.29.15
k8s-worker1   Ready    <none>          4m    v1.29.15
k8s-worker2   Ready    <none>          4m    v1.29.15

Pod 상태 확인

1
kubectl get pods --all-namespaces

모든 Pod가 Running 상태여야 합니다.

nginx 테스트 배포

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Deployment 생성
kubectl create deployment nginx-test --image=nginx

# Service 노출
kubectl expose deployment nginx-test --port=80 --type=NodePort

# 접속 테스트
NODEPORT=$(kubectl get svc nginx-test -o jsonpath='{.spec.ports[0].nodePort}')
curl http://192.168.122.10:$NODEPORT
# "Welcome to nginx!" 출력되면 성공

트러블슈팅

Pod이 Pending 상태

1
2
3
4
5
# Pod 상세 정보 확인
kubectl describe pod <pod-name>

# 노드 이벤트 확인
kubectl get events --all-namespaces --sort-by='.lastTimestamp'

containerd 문제

1
2
sudo systemctl status containerd
sudo journalctl -u containerd -f

kubelet 문제

1
2
sudo systemctl status kubelet
sudo journalctl -u kubelet -f

클러스터 초기화 (재시작)

1
2
3
4
5
6
7
8
# Master 노드
sudo kubeadm reset -f
sudo rm -rf /etc/cni/net.d
sudo rm -rf ~/.kube

# Worker 노드
sudo kubeadm reset -f
sudo rm -rf /etc/cni/net.d

소요 시간

단계시간
VM 3개 생성20분
네트워크 설정10분
Kubernetes 패키지 설치5분
클러스터 초기화3분
검증2분
총합약 40분

Bonus: Ansible 자동화

수동 설치가 번거롭다면 Ansible playbook으로 자동화할 수 있습니다. 전체 클러스터 구축을 10분 안에 완료할 수 있는 playbook을 작성할 수 있습니다.

필요한 파일:

  • inventory/hosts: 노드 IP 정보
  • group_vars/all.yml: 설정 변수 (k8s 버전, 네트워크)
  • k8s-cluster.yml: 메인 playbook
  • test-nginx.yml: nginx 테스트 playbook

실행 방법:

1
2
3
4
5
# 클러스터 구축
ansible-playbook -i inventory/hosts k8s-cluster.yml

# nginx 테스트
ansible-playbook -i inventory/hosts test-nginx.yml

다음 단계

Kubernetes 클러스터가 준비되었으니, 이제 실전 애플리케이션을 배포해볼 차례입니다:

  • Persistent Volume 설정
  • Ingress Controller 설치
  • Monitoring (Prometheus + Grafana)
  • CI/CD 파이프라인 구축

다음 글에서는 실제 애플리케이션 배포와 모니터링 환경 구축을 다루겠습니다.

참고 자료