kubernetes 를 핸즈온으로 공부하려면 로컬 머신에서 멀티 노드 클러스터를 구축하는게 가장 편리하다는 판단을 했다. 그래서 여러 가이드를 찾아보았다. 처음에는 multipass 라는 가상화 도구를 사용해서 시도해보고, 그 다음에는 kind 라는 kubernetes 를 docker 컨테이너로 올리는 도구도 사용해봤는데, 내공이 부족하여 실패하였다. 결국 docker desktop 에서 간단히 활성화 할 수 있는 kind 로의 프로비저닝 방식을 사용하여 구축에 성공했다.
하지만, Ingress 를 실습할 차례가 왔고, kind 방식으로 구축한 클러스터는 네트워크 구성이 실제 머신을 노드로 사용하는 클러스터와 달라서 실습이 불가능함을 깨달았다. 그래서, 실제 완전한 리눅스 OS와 동일하게 구성하기 위해 UTM 가상화 도구를 사용해 멀티 노드 클러스터를 구축했고, 그 과정을 기술한다.
1. UTM 설치
UTM 이라는 가상화 도구를 m1 맥북에 설치한다.
2. 가상머신 생성
가상머신 3대를 Ubuntu 24.04.3 LTS OS를 설치하며 생성한다.
1대는 control plane 용이고, 나머지 2대는 worker node 용이다.
시스템 자원은 본인이 사용하는 컴퓨팅 리소스에 맞게 할당한다.
3. 클립보드 붙여넣기 설정
개발 편의성을 위해 호스트 머신과 각 게스트 머신간 복붙을 가능하게 하여야 한다.
CLI 만 사용중이라면 아래 두가지 방법이 있다.(spice-vdagent 는 GUI 용 클립보드 공유 에이전트이므로 상관하지 않는다.)
1) 리눅스 터미널에 openssh 를 설치하여 맥북에서 직접 ssh 접속
2) 가상머신의 display 장치를 삭제하고 직렬 포트 장치로 사용
직렬 포트 장치가 간단하지만, CLI 가 이상하게 표시되는 현상이 종종 있으므로, ssh 접속하는 방법이 사용성이 더 낫다.
4. hostname 설정(모든 노드)
아래 커맨드를 통해서 각 노드에 hostname 을 지정해준다.
$ sudo hostnamectl set-hostname <새 호스트명>
아래 커맨드를 통해서 정상적으로 hostname 이 설정되었는지 확인한다.
$ cat /etc/hostname
# 또는
$ hostname
# 또는
$ hostnamectl
5. /etc/hosts 수정(모든 노드)
각 노드에서 아래 명령어를 실행하여 enp0s1 장치의 inet 에 기재된 IP 를 확인한다.
$ sudo ip addr
각 노드의 /etc/hosts 파일에 자신의 IP 를 제외한 나머지 노드의 IP 를 hostname 과 매핑해준다.
# master01 노드의 /etc/hosts 예시
...
127.0.1.1 master01
192.168.64.6 worker01
192.168.64.7 worker02
...
6. swapoff 및 영구 swapoff 적용(모든 노드)
아래 커맨드를 사용하여 각 노드에서 swapoff 를 적용한다.
$ sudo swapoff -a
아래 커맨드를 사용해 /etc/fstab 파일을 수정하여 부팅시마다 swapoff 가 자동 적용되도록 설정한다.(swap 설정을 주석처리하여 영구 비활성화 하는 행위)
$ sudo sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab
7. 커널 네트워크에 브릿지 트래픽 허용(모든 노드)
아래 커맨드를 실행하여 브릿지 네트워크로부터 들어오는 트래픽을 허용한다.
$ 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
8. containerd 설치(모든 노드)
아래 커맨드를 순차적으로 실행하여 각 노드에 containerd 를 설치한다.
# 1) 필요한 의존성 패키지 설치
$ sudo apt update
$ sudo apt install -y ca-certificates curl gnupg lsb-release
# 2) Docker의 APT repo 대신 Ubuntu 기본 repo 에서 containerd 설치
$ sudo apt install -y containerd
# 3) 기본 config 생성
$ sudo mkdir -p /etc/containerd
$ sudo containerd config default | sudo tee /etc/containerd/config.toml
# 4) 시스템에 맞춰 cgroup 설정(기본적으로 systemd cgroup 사용 권장)
# /etc/containerd/config.toml 에서 아래를 확인/적용:
# SystemdCgroup = true
# 아래 커맨드로 바로 수정 가능
$ sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 5) pause:3.10 버전으로 수정(선택)
# (이건 kubernetes 1.31.3 버전과의 호환성을 위함이며, 사용하는 kubernetes 버전의 호환성을 확인하여 맞춰주시길 바랍니다.)
$ sudo sed -i 's|sandbox_image = "registry.k8s.io/pause:3.8"|sandbox_image = "registry.k8s.io/pause:3.10"|' \
/etc/containerd/config.toml
# 6) containerd 부팅시 자동실행 설정(enable) 및 재시작(restart)
$ sudo systemctl enable containerd && sudo systemctl restart containerd
9. kubeadm, kubelet, kubectl 설치(모든 노드)
아래 커맨드를 순차적으로 실행하여 각 노드에 kubeadm, kubelet, kubectl 를 설치한다.
# 1) 필요한 의존성 패키지 설치
$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https ca-certificates curl
# 2) APT 저장소의 서명 키(GPG key)를 보관할 디렉터리를 생성
$ sudo mkdir -p /etc/apt/keyrings
# 3) Kubernetes APT 저장소의 GPG 서명 키 다운로드 및 변환하여 저장(v1.31)
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 4) Kubernetes APT 저장소 등록 및 업데이트
$ 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
# 5) 설치 (버전 고정 원하면 =<버전> 지정)
$ sudo apt-get install -y \
kubelet=1.31.3-1.1 \
kubeadm=1.31.3-1.1 \
kubectl=1.31.3-1.1
# 6) 자동 업그레이드 되지 않도록 버전 고정
$ sudo apt-mark hold kubelet kubeadm kubectl
# 7) kubelet 서비스 부팅시 자동실행 설정 및 재시작
$ sudo systemctl enable kubelet && sudo systemctl restart kubelet
10. VM에 브릿지 네트워크 설정 및 브릿지 IP 고정(모든 노드)
UTM 에서 네트워크 장치 추가 > 브릿지 네트워크 > 실제 접속중인 네트워크 인터페이스 선택 하고 저장한다.
노드 접속 후 아래 커맨드로 게이트웨이 주소를 확인한다.
$ ip route
# 출력 예시
default via 192.168.0.1 dev enp0s2 proto dhcp src 192.168.0.36
default via 뒤의 IP 가 게이트웨이의 주소이므로 메모한다.(enp0s2 인터페이스의 게이트웨이)
아래 커맨드로 DNS 주소를 확인한다.
$ resolvectl status
# 출력 예시
Link 2 (enp0s2)
Current DNS Server: 192.168.0.1
DNS Servers: 192.168.0.1 168.126.11.1 168.126.11.2
DNS Servers 목록이 DNS 주소이므로 메모한다.
/etc/netplan/*.yaml 파일에 enp0s2 설정을 추가하고 게이트웨이 주소와 DNS 주소를 아래 내용처럼 적용한다.
# /etc/netplan/*.yaml 파일을 열어서 아래처럼 enp0s1, enp0s2 을 추가/수정
network:
version: 2
renderer: networkd
ethernets:
enp0s1:
dhcp4: yes
optional: true
enp0s2:
dhcp4: no
addresses:
- 192.168.0.36/24
routes:
- to: default
via: 192.168.0.1
nameservers:
addresses:
- 192.168.0.1
- 168.126.11.1
- 168.126.11.2
$ sudo netplan apply
아래 커맨드를 실행하여 enp0s2 장치에 inet 이 잡혔는지 확인한다.
$ sudo ip addr
만약 enp0s2 가 아직 DOWN 상태라면 아래 커맨드를 실행한다.
$ sudo ip link set enp0s2 up
11. 각 노드에 필요한 패키지들 설치(모든 노드)
아래 커맨드를 실행하여 각 노드에 추가 패키지를 설치한다.(클러스터 구성 및 운영에 필요)
# k8s 구성 및 운영에 필요한 패키지들 설치
$ sudo apt-get update
$ sudo apt-get install -y \
conntrack \
ipset \
iptables \
ebtables \
ethtool \
socat \
ipvsadm
12. control-plane 초기화(master 노드)
master 노드에서 아래 커맨드를 순차적으로 실행하여 kubernetes control plane 초기화를 진행한다.
# 초기화 실행. <MASTER_NODE_BRIDGE_IP> 에는 master 노드의 브릿지 네트워크 ip를 넣는다.
# pod-network-cidr 는 고정이다.
$ sudo kubeadm init --kubernetes-version=1.31.3 \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=<MASTER_NODE_BRIDGE_IP>
# 성공 후 출력되는 메시지를 따라 진행하면 된다.(아래는 예시)
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
# 위 링크를 따라 들어가면 나오는 flannel CNI 파드 네트워크 구성 예시
$ kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Then you can join any number of worker nodes by running the following on each as root:
# 아래 join 커맨드를 복사해놓고, 각 worker node 에서 root 권한으로 실행해줍니다.
kubeadm join...
# 가이드에는 없는데, node join 후 control plane 에서 containerd 를 재시작 해줘야 한다.
$ sudo systemctl restart containerd
만약 kubeadm init 중간에 실패하거나 다시 init 하려면 아래 커맨드로 reset 실행 후 다시 init 진행한다.
$ sudo kubeadm reset -f
$ sudo systemctl stop kubelet
$ sudo iptables -F && sudo iptables -t nat -F && sudo iptables -t mangle -F && sudo iptables -X
$ sudo rm -rf /etc/cni/net.d & \
sudo ipvsadm --clear & \
sudo rm -rf $HOME/.kube/config & \
sudo rm -rf $HOME/.kube/cache
만약 flannel CNI 가 제대로 생성되지 않아 재구성해야 한다면 아래 커맨드로 삭제를 먼저 진행해야 한다.
# flannel CNI 파드 네트워크 제거 예시(CNI 파드 네트워크 구성중 문제가 발생하여 제거하고 다시 설치해야 할 때)
$ kubectl delete -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml --ignore-not-found=true
만약 flannel pod(DaemonSet)가 생성되지 않는다면 모든 노드(master/worker)에서 아래 순서대로 실행한다.
# 모듈 로드
$ sudo modprobe br_netfilter
$ sudo modprobe overlay
# 부팅시 유지
$ cat <<'EOF' | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# 브릿지 네트워크 트래픽 허용(이미 위에서 적용했으나, 재확인해보자)
$ 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
master 노드에서 아래 명령어로 flannel 재시작 후 파드를 확인한다.
# flannel 재시작
$ kubectl -n kube-flannel rollout restart ds/kube-flannel-ds
# 정상 확인
$ kubectl -n kube-flannel get pods -o wide
$ kubectl -n kube-system get pods
만약 worker node 에서 클러스터 join 시에 아래와 같은 에러가 나타난다면
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR FileAvailable--etc-kubernetes-kubelet.conf]: /etc/kubernetes/kubelet.conf already exists
[ERROR Port-10250]: Port 10250 is in use
[ERROR FileAvailable--etc-kubernetes-pki-ca.crt]: /etc/kubernetes/pki/ca.crt already exists
이미 join 했던 노드라서 클러스터 정보와 kubelet 이(10250 포트를 점유하며) 남아있기 때문이다.
해당 노드에서 아래 커맨드를 순서대로 실행하여 clean reset 한 뒤 다시 join 해야 한다.
# 1) 노드의 kubeadm 리셋
$ sudo kubeadm reset -f
# 2) CNI/네트워크 잔여물 정리
$ sudo rm -rf /etc/cni/net.d & \
sudo ipvsadm --clear & \
sudo rm -rf $HOME/.kube/config & \
sudo rm -rf /var/lib/cni & \
sudo ip link delete cni0 2>/dev/null || true & \
sudo ip link delete flannel.1 2>/dev/null || true & \
sudo ip link delete kube-ipvs0 2>/dev/null || true
# 3) kubelet 정리 (10250 점유 해소)
$ sudo systemctl stop kubelet && \
sudo rm -rf /etc/kubernetes & \
sudo rm -rf /var/lib/kubelet && \
sudo systemctl start kubelet
# 4) containerd 재시작
$ sudo systemctl restart containerd
13. host 머신에서 가상머신으로 공유 폴더 설정하기(선택)
UTM 에서 가상머신 편집 > 공유에서 아래를 설정한다.
- 디렉터리 공유 모드: VirtFS
- 경로: 공유폴더 지정
가상머신 부팅 및 로그인 후 아래 커맨드를 실행한다.
$ sudo mkdir /media/<공유폴더이름>
$ sudo mount -t 9p -o trans=virtio share /media/<공유폴더이름> -oversion=9p2000.L
$ sudo vi /etc/fstab
# 최하단에 아래 내용 추가하고 저장
share /media/<공유폴더이름> 9p trans=virtio,version=9p2000.L,rw,_netdev,nofail 0 0
이제 가상머신을 재실행하면 아래 경로에서 공유폴더를 확인 가능하다.
- /media/<공유폴더이름>
참고로, 호스트 머신에서 공유폴터 내부에서 공유폴더 외부로 심볼릭 링크 된 파일은 가상머신에서 내용을 볼 수 없다.
'Linux' 카테고리의 다른 글
| [Linux] Debian 리눅스에서 apt update 및 install 불가 현상 해결 (1) | 2025.08.07 |
|---|---|
| [LINUX] 자주쓰는 dd 명령어 옵션 정리 (0) | 2025.05.04 |
| [LINUX] swap file 사용하기 (0) | 2025.05.04 |
| [LINUX] swap partition 사용하기 (0) | 2025.05.04 |
| [LINUX] swap 이해하기 및 활성/비활성하기 (디스크 스왑, 파일 스왑) (0) | 2025.05.04 |
