본 포스트에서는 VirtualBox와 Ubuntu 22.04 LTS 환경에서 Docker, containerd 기반의 쿠버네티스(Kubernetes) 3-노드 클러스터를 구축할 예정이다.

1. 환경 구성 개요
- 가상화 소프트웨어: VirtualBox
- 운영체제: Ubuntu 22.04 LTS
- 사용 도구: Docker, containerd, kubeadm, kubectl, kubelet
- 클러스터 구성: 1 Master + 2 Worker (총 3개 노드)
| 노드 역할 | Hostname | IP 주소 |
| Master | k8s-master | 10.0.2.6 |
| Worker 1 | k8s-worker1 | 10.0.2.7 |
| Worker 2 | k8s-worker2 | 10.0.2.8 |
2. 클러스터 아키텍처 및 VM 세팅
환경 구성 개요에 설명했듯이 1개의 마스터 노드(컨트롤 플레인)과 2개의 워커 노드를 이용하여 아키텍처를 구성한다. 먼저 마스터 노드를 만들어서 쿠버네티스에 필요한 설정을 미리 세팅한 후 마스터 노드의 복제본 2개를 통해 worker node를 구축할 예정이다.
termius 접속을 위해 초반 접속을 위한 포트포워딩 수행 필요
127.0.0.1:9996 -> 10.0.2.15:22
3. master node 기본 시스템 설정
3.1. 공통 패키지 설치
# 패키지 업데이트
sudo apt-get update
# 기본적인 툴 설치
sudo apt-get install -y net-tools openssh-server vim tree htop
3.2. 방화벽 비활성화
Kubernetes 구성 요소 간 통신이 원활해야 하므로 ufw 방화벽을 비활성화한다.
sudo ufw disable
sudo ufw status
3.3. Swap 비활성화
Kubernetes는 swap 사용 시, kubelet이 동작하지 않거나 최대 100배의 성능차이가 발생하기 때문에 swap 메모리 비활성화를 권장한다.
sudo swapoff -a
free # 명령어 수행 시 Swap: 0 0 0 확인
sudo vi /etc/fstab # swap 항목 주석처리

📌 Swap이란?
Swap은 컴퓨터의 RAM(주 기억장치)이 가득 찼을 때 사용하는 비상용 보조 기억 공간으로, 하드 디스크(HDD)나 SSD의 일부를 마치 RAM처럼 사용하는 기술을 말한다. 즉, Swap의 주된 목적은 '메모리 부족(Out of Memory)'으로 인해 시스템이 갑자기 멈추거나 충돌하는 것을 방지하는 것이다.
3.4. IP Forwarding 기능 활성화
쿠버네티스 환경에서는 컨테이너(Pod)들이 서로 다른 IP 주소를 가지고 통신한다. 서버(노드)에 도착한 네트워크 패킷의 최종 목적지가 서버 자신이 아니라 서버 안에서 실행 중인 다른 컨테이너일 수 있다. IP 포워딩 기능이 꺼져있으면, 서버는 "이건 내 것이 아니네"라며 패킷을 버려 버린다. 이 기능을 켜야 서버가 "아, 이 패킷은 A 컨테이너로 가야 하는구나"라며 목적지까지 안전하게 전달해 줄 수 있다.
cat /proc/sys/net/ipv4/ip_forward
vi /proc/sys/net/ipv4/ip_forward # 1 입력 후 wq
3.5. 시간 동기화
클러스터를 구성하는 모든 서버들의 시계를 정확히 똑같이 맞춘다.
sudo apt-get install -y ntp
sudo systemctl restart ntp
sudo ntpq -p
3.6. containerd 런타임 환경 설정
Kubernetes는 containerd를 기본 컨테이너 런타임으로 권장하고 있다. 먼저 커널 모듈과 네트워크 설정부터 적용한다.
# /etc/modules-load.d/containerd.conf라는 파일에 overlay와 br_netfilter 작성
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
# 즉, 위의 명렁어는 아래와 동일
sudo vi /etc/modules-load.d/containerd.conf
# containerd.conf
overlay
br_netfilter
overlay: 이미지 레이어를 합쳐서 파일시스템처럼 사용할 수 있도록 하는 설정
be_netfilter: 브리지 네트워크 필터링 기능을 활성화하여 쿠버네티스의 CNI 플러그인(Calico)에서 사용할 수 있도록 해주는 설정
3.7. 통신을 위한 iptables bridge 설정
k8s.conf : 쿠버네티스 클러스터의 다른 설정과 관련된 매개변수를 설정
99-kubernetes-cri.conf : 컨테이너 런타임(CRI)와 관련된 설정과 컨테이너 간 통신과 관련된 설정
3.7.1. k8s.conf 설정
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
3.7.2. 재부팅 후에도 k8s.conf와 99-kubernetes-cri.conf 값 유지
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
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
ls /etc/sysctl.d # 명령어 수행 시, k8s.conf와 99-kubernetes-cri.conf가 있어야 함
sudo sysctl --system # 재부팅 없이 설정 즉시 적용
3.8. Docker 설정
Docker가 설치되어 있지 않다면, Docker를 설치
sudo docker version # 도커 버전 확인
3.9. containerd 환경 설정
컨테이너를 실행할 엔진(containerd)을 설치하고, 쿠버네티스와 '같은 언어'를 사용하도록 설정을 통일한다.
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
sudo sh -c "containerd config default > /etc/containerd/config.toml"
ls /etc/containerd/ # 명령어 수행 시, config.toml이 존재해야 함
vi /etc/containerd/config.toml
# config.toml 파일에서 다음 항목을 찾아 SystemdCgroup = true로 변경:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
변경 후 containerd를 재시작하고 부팅 시 자동 시작되도록 설정:
sudo systemctl restart containerd
sudo systemctl enable containerd
3.10. 도커 데몬 설정
sudo vi /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo usermod -aG docker [계정명] # [계정명]에 ubuntu 입력
sudo systemctl daemon-reload
sudo systemctl enable docker
sudo systemctl restart docker
sudo systemctl status docker
sudo systemctl restart containerd.service
sudo systemctl status containerd.service
sudo reboot
3.11. Kubernates 설치 및 설정
# 패키지 업데이트
sudo apt-get update
# 쿠버네티스 인증서 패키지 업데이트
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 키 정보와 repo url에 대한 정보를 local에 저장
# 어디서부터 resource를 받아올 수 있는지 설정
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
# kubelet, kubeadm, kubectl 설치
sudo apt-get install -y kubelet kubeadm kubectl
# 자동 업데이트 금지 설정 : 현재 버전 유지
sudo apt-mark hold kubelet kubeadm kubectl
# kubelet 활성화
sudo systemctl enable --now kubelet
#버전 확인
kubeadm version
kubectl version
kubelet --version
#자동 시작 등록
sudo systemctl daemon-reload
sudo systemctl restart kubelet.service
sudo systemctl enable --now kubelet.service
4. k8s-master 복제
앞에서 쿠버네티스를 사용할 수 있도록 설정한 k8s-master를 2개 복제하여 각각 k8s-worker1, k8s-worker2로 생성

termius 접속을 위해 초반 접속을 위한 포트포워딩 수행 필요
127.0.0.1:9997 -> 10.0.2.15:22 (k8s-worker1)
127.0.0.1:9998 -> 10.0.2.15:22 (k8s-worker2)
5. hostname, ip, hosts 파일 설정
5.1. 고정 IP 사용
# 고정 IP 사용
sudo vi /etc/netplan/00-installer-config.yaml
# /etc/netplan/00-installer-config.yaml
# ifconfig 했을 때, 이더넷이 enp0s3인지 확인 필요
network:
ethernets:
enp0s3:
addresses:
- 10.0.2.6/24
routes:
- to: default
via: 10.0.2.2
nameservers:
addresses:
- 8.8.8.8
version: 2
# IP 변경 적용
sudo netplan apply
# 만약 WARNING(open/openv error) 뜬다면 아래 명령어 순서대로 수행
sudo chmod 600 /etc/netplan/00-installer-config.yaml
sudo apt-get install openvswitch-switch
sudo systemctl disable ovsdb-server
5.2. DNS 서버 설정
# DNS 서버 설정
# nameserver를 8.8.8.8로 변경
sudo vi /etc/resolv.cnof

5.3. 호스트명 변경 (노드 별로 설정)
# 호스트명 변경
sudo hostnamectl set-hostname {변경하는 호스트명} # k8s-master, k8s-worker1, k8s-worker2
5.4. 호스트 파일 변경 (노드 별로 설정)
# 호스트 파일 변경
vi /etc/hosts

위의 사진은 k8s-master의 예시이고, k8s-worker1과 k8s-worker2의 설정은 아래를 참고해서 설정해야 한다.

6. NAT 네트워크 설정
막상 k8s-master, k8s-worker1, k8s-worker2에 접속해서 서로 ping 테스트를 해보면 네트워크 통신이 되지 않는다는것을 알 수 있다. 그 이유는 현재 NAT를 통한 포트포워딩 시 가상머신끼리의 통신이 되지 않기 때문이다.

따라서 모두 NAT 네트워크로 변경해야 한다.
VirtualBox > 도구 > NAT 네트워크 > 포트포워딩

추가적으로 각 가상머신마다 네트워크 설정에서 NAT를 NAT 네트워크로 변경해야 한다.

7. 노드 클러스터 구축
7.1.1. [k8s-master] 클러스터 초기화
# 아래 명령어를 입력하면 kubeadm join ... 명령어가 출력되는데,
# 해당 명령은 워커 노드에서 사용할 것이므로 "반드시 복사"하여 따로 보관해둔다.
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
초기화가 완료되면 kubeadm join ... 명령어가 출력되며, 이 명령은 워커 노드에서 사용할 것이므로 복사해둔다.
7.1.2. [k8s-master] kubeconfig 설정
# .kube 디렉토리 생성
mkdir -p $HOME/.kube
# admin.conf를 .kube/config로 등록(이동)
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# 유저가 kube 명령어를 수행할 수 있도록 권한 설정
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 이제 kubectl 사용 가능
7.1.3.[k8s-worker1], [k8s-worker2] 루트 권한으로 전역변수를 통해 권한 흭득
# 루트 계정으로 이동
sudo -s
# 권한 흭득
export KUBECONFIG=/etc/kubernetes/admin.conf
# 원래 계정으로 이동
sudo -ubuntu
# .kube 디렉토리 생성
mkdir -p $HOME/.kube
# k8s-master의 .kube/config 가져오기
scp -p ubuntu@10.0.2.6:~/.kube/config ~/.kube/config
# 유저가 kube 명령어를 수행할 수 있도록 권한 설정
sudo chown $(id -u):$(id -g) $HOME/.kube/config
7.1.3.[k8s-worker1], [k8s-worker2] 클러스터 조인 수행
# 루트 계정으로 이동
sudo -i
# 아까 저장해두었던 조인 명령어 수행
sudo kubeadm join <MASTER_IP>:6443 --token ... --discovery-token-ca-cert-hash sha256:...
7.1.4. [k8s-master] 클러스터 상태 확인
# 조인 상태 확인
kubectl get nodes

7.1.3. CNI (Container Network Interface) 구축
- 컨테이너 간 네트워킹을 제어할 수 있는 플러그인을 만들기 위한 표준
- 다양한 형태의 컨테이너 런타임과 오케스트레이터 사이의 네트워크 계층을 구현하는 방식이 다양하게 분리되는 것을 방지
- 파드 Pod간 통신을 위해 CNI 필요
- 기본 kubenet 을 제공하나 기능이 제한적 → third-party 플러그인 사용
# calico 플러그인 설치
curl https://raw.githubusercontent.com/projectcalico/calico/v3.30.1/manifests/calico.yaml -O
# kubectl 명령어를 통해 calico 실행
kubectl apply -f calico.yaml
# 확인
watch kubectl get pods -n calico-system
watch kubectl get pods -o wide
위에서 kubectl get nodes를 했을 때 Not Ready 상태였지만, calico를 통해 이제 통신이 가능해졌으므로 다시 kubectl get nods를 하면 모두 Ready 상태로 변경되어 있어야 한다.

'Kubernetes > Ops' 카테고리의 다른 글
| [17] Helm (0) | 2025.06.17 |
|---|---|
| [16] Kubernetes Autoscailing (0) | 2025.06.17 |
| [15] Kubernetes Deployment Strategy (0) | 2025.06.16 |
| [14] Kubernetes Scheduler (0) | 2025.06.16 |
| [13] Kubernetes Security (5) | 2025.06.14 |