목차
시작하기 전에
이 과정을 위해서는 가상 머신이 필요하다.
Mac M1에 우분투 설치 (UTM) 를 참고하여 가상 머신을 미리 생성하자. kubeadm을 통해 클러스터를 생성할 것이며, 공식 문서에서 제공하는 머신의 최소 스펙은 다음과 같으니 참고하여 가상 머신을 생성하도록 한다.

RAM - 2 GB per machine
CPU - 2 Cores for control plane
이번 실습에 사용되는 노드는 Master node 1개, Worker node 2개로 총 3대의 가상머신을 사용한다. 가상머신 3대를 따로 처음부터 설치할 필요 없이 Clone 기능을 통해 Master Node 구성 후 복제하면 된다. 내가 사용한 가상머신의 사양은 다음과 같다.
CPU | Memory | Disk | OS |
4 Core | 2 GB | 20 GB | Ubuntu 22.04 |
사전 설정
메모리 swap 기능 비활성화
•
컴퓨터의 메모리가 모두 사용될 때 하드 디스크의 일부분을 메모리 공간처럼 사용할 수 있는 영역이다.
•
쿠버네티스에서 성능 저하의 유려가 있어 swap을 비활성화시킨다.
•
swap 메모리를 비활성화해야 kubelet이 정상 작동한다.
sudo swapoff -a
sudo sed -i '/swap/s/^/#/' /etc/fstab
Bash
복사
NTP 설정
•
다수 VM의 시간 동기화로, 동일 시간에 작업 수행을 가능하게 한다
•
인증 & 보안: TLS 인증서의 유효 기간은 시간에 따라 결정된다
sudo apt-get install -y ntp
sudo systemctl restart ntp
sudo ntpq -p
Bash
복사
IP Forwarding 기능 활성화
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
Bash
복사
•
0: IP 포워딩 비활성화
◦
라우터 기능이 비활성화된 상태로, 시스템이 IP 패킷을 포워딩하지 않는다. 일반적인 서버나 호스트에서 사용된다.
•
1: IP 포워딩 활성화
◦
라우터 기능이 활성화된 상태로, 시스템이 IP 패킷을 포워딩할 수 있다. 패킷을 다른 네트워크 인터페이스로 전달할 수 있는 상태이다. 라우터나 게이트웨이 역할을 하는 시스템에서 필요하다.
설치
Docker 설치
sudo apt-get update
sudo apt install -y docker.io
Bash
복사
iptables bridge 설정
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
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
# 재부팅 없이 적용
sudo sysctl --system
Bash
복사
•
99-kubernetes-cri.conf
◦
컨테이너 런타임(CRI)과 관련된 설정을 포함
◦
컨테이너 간 통신과 관련된 설정을 포함
•
k8s.conf
◦
쿠버네티스 클러스터의 다른 설정과 관련된 매개변수를 설정
Containerd 환경 설정
Runtime 환경설정
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
Bash
복사
•
overlay: 컨테이너 파일 시스템을 구성하는데 사용되는 드라이버
•
br_netfilter: 브리지 네트워크에서 iptables를 사용하여 트래픽을 필터링하는데 필요한 커널 모듈
•
modprobe: 적재 가능 커널 모듈 (LKM)을 리눅스 커널에 추가하거나 커널로부터 제거하는데 사용
containerd에서 사용할 기본 설정값 생성
sudo mkdir -p /etc/containerd
sudo sh -c "containerd config default > /etc/containerd/config.toml"
Bash
복사
/etc/containerd/config.toml 파일을 수정하여 systemd cgroup 드라이버 runc 사용하도록 설정
vi /etc/containerd/config.toml
# 137번 라인에 위치한 SystemdCgroup을 true로 바꿔준다
# 명령모드에서 :137 을 입력하면 바로 이동 가능하다
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup=true
Bash
복사
도커 데몬 설정
sudo bash -c 'cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF'
Bash
복사
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo usermod -aG docker $USER
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
Bash
복사
쿠버네티스 설치
필수 패키지
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
Bash
복사
공개키 다운로드 및 레포지토리 추가
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
Bash
복사
•
1.29 버전을 사용하였으며 다른 버전을 다운받기 위해서는 버전에 대한 값을 변경해주면 된다
쿠버네티스 패키지 설치 및 활성화
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable --now kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet.service
sudo systemctl enable --now kubelet.service
Bash
복사
클러스터 구축
VM 복제
가상머신을 우클릭하여 Clone 버튼을 눌러 가상 머신을 2대 추가로 구성한다.
가상머신을 복제하게 되면 필수적으로 복제된 가상머신의 MAC 주소를 변경해야 한다. MAC 주소는 고유한 값으로, 원본 가상머신과 복제된 가상머신의 MAC 주소가 같을 수 없기 때문이다. MAC 주소를 변경하기 위한 절차는 다음과 같다:
•
복제본 우클릭 → Edit 클릭 (이 때 가상머신이 종료되어 있어야 Edit 활성화됨)
•
네트워크 항목에서 MAC Address Random 버튼 클릭
•
Emulated VLAN 네트워크 모드를 사용 중이라면 포트 매핑도 변경
네트워크 구성
네트워크 추가
UTM에는 Emulated VLAN, Shared Network, Host Only, Bridged라는 4개의 네트워크 모드를 제공한다. 호스트 내의 같은 네트워크를 가지는 가상머신끼리 접근이 가능하며 인터넷 연결이 가능한 Shared Network나 Bridged 네트워크를 추가로 구성한다.
(처음 가상머신을 만들게 되면 기본값으로 Shared Network나 Bridged가 선택되어 있어 추가 구성하지 않아도 되지만, 클러스터 네트워크 격리를 위해 추가 구성하는 것을 권장한다.)
네트워크 1 | Emulated VLAN | Shared Network | Bridged |
네트워크 2 | Shared Network | Shared Network | Shared Network |
네트워크 추가 방법은 다음과 같다:
•
가상머신 종료 → 가상머신 우클릭 → 왼쪽 항목에서 추가 → 네트워크 선택 → Shared Network 선택
•
복제본도 반복 진행
고정 IP 할당
UTM에서 IP는 기본적으로 DHCP를 통해 자동 할당되기 때문에 가상머신을 끄고 킬때마다 IP가 달라질 수 있다. 따라서 DHCP 옵션을 끄고, 고정 IP를 할당해준다. 추가로 바로 위에서 Shared Network를 추가했는데, 처음에는 IP 할당이 되어있지 않기 때문에 IP를 주어야 한다. 만들어둔 3개의 가상머신에 대해 진행한다.
•
sudo vi /etc/netplan/00-installer-config.yaml
network:
ethernets:
enp0s1:
addresses:
- [사설 IP 주소] # 10.0.2.6/24
routes:
- to: default
via: [게이트웨이 주소] # route -n 명령어로 확인 (예: 10.0.2.2)
nameservers:
addresses:
- 8.8.8.8
enp0s2:
addresses:
- 10.0.2.16/24 # kubernetes node의 IP (변경 가능)
version: 2
Bash
복사
•
네트워크 인터페이스 간의 IP 주소를 같게 설정하지 않도록 주의해야 한다.
•
서로 다른 서브넷에 두어 충돌을 피하는 것도 방법이다.
◦
enp0s1 - 10.0.3.6/24
◦
enp0s2 - 10.0.3.6/24
enp0s1 | enp0s2 | |
master | 10.0.2.6/24 | 10.0.3.6/24 |
worker1 | 10.0.2.7/24 | 10.0.3.7/24 |
worker2 | 10.0.2.8/24 | 10.0.3.8/24 |
IP 변경 적용 및 확인
sudo netplan apply
ip addr
Bash
복사
•
enp0s1, enp0s2의 inet 값이 본인이 설정한 IP로 부여되어 있으면 성공적으로 적용이 된 것이다.
•
에러가 발생했다면 밑의 명령어를 추가로 수행해보자.
TroubleShooting
# open 에러
sudo chmod 600 /etc/netplan/00-installer-config.yaml
# opencv에러
sudo apt-get install openswitch-switch
Bash
복사
호스트 등록
/etc/hosts에 호스트를 추가한다. 호스트를 추가해놓음으로써 도메인을 통해 가상머신 간에 접근이 가능하다.
sudo vi /etc/hosts
10.0.3.6 master
10.0.3.7 worker1
10.0.3.8 worker2
Bash
복사
(선택) 호스트명 변경
sudo hostnamectl set-hostname {원하는 호스트명}
sudo reboot now
Bash
복사
•
master, worker1, worker2
•
적용시키기 위해서는 reboot를 해야 함
•
변경이 완료되면 ubuntu@master, ubuntu@worker1, ubuntu@worker2 로 표기됨
방화벽 해제
쿠버네티스 포트만 인바운드 허용을 할 수 있지만, 테스트 환경이므로 서비스 간의 원활한 통신을 위해 방화벽을 비활성화하는 방법을 사용한다. 추가로 클라우드 환경에서는 ufw를 비활성화하고 CSP의 보안그룹이나 네트워크 ACL을 사용해 트래픽을 제어하는 것이 일반적이다.
1.
방화벽 비활성화
sudo ufw disable
Bash
복사
2.
쿠버네티스 포트만 방화벽 포트 개방
a.
Master Node
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 6443/tcp
sudo ufw allow 2379:2380/tcp
sudo ufw allow 10250:10252/tcp
sudo ufw allow 179/tcp
sudo ufw enable
Bash
복사
b.
Worker Node
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 10250/tcp
sudo ufw allow 30000:32767/tcp
sudo ufw allow 179/tcp
sudo ufw allow 4050/udp
sudo ufw allow 26443/tcp
sudo ufw enable
Bash
복사
클러스터 노드 구축
Master
sudo kubeadm init --apiserver-advertise-address=10.0.3.6 \
--pod-network-cidr=192.168.0.0/16 \
--cri-socket /run/containerd/containerd.sock
Bash
복사
•
kubeadm init : control plane을 설정하고 초기화
•
--apiserver-advertise-address : Control-plane의 api-server가 사용할 IP 주소 (본인이 설정한 master node의 IP 주소 입력)
•
--pod-network-cidr : Pod 간 통신할 IP 주소를 지정 (Calico의 경우 192.168.0.0/16 디폴트)
# 일반 사용자로 진행하는 경우
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# root 계정으로 진행하는 경우
export KUBECONFIG=/etc/kubernetes/admin.conf
Bash
복사
Worker
master에서 kubeadm init을 통해 나온 결과로 아래와 같은 출력이 있을텐데, worker 노드에 복사 붙여넣기를 한다. (아래 값을 복사 붙여넣기 하면 안됨)
kubeadm join 10.0.3.6:6443 --token m55xld.iw1f5o7v9f3rudvk \
--discovery-token-ca-cert-hash sha256:c77de4ebfcd8fa3b507ba2d534eae3ee321ee234a6afc17ee9aa746b31c3d033
Bash
복사
•
[ERROR IsPrivilegedUser]: user is not running as root - 에러가 발생한다면 sudo를 붙여 실행
CNI 구축
CNI 플러그인으로 Calico를 사용한다.
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/calico.yaml
Bash
복사
CNI가 정상적으로 구축되면 node의 상태가 Ready로 바뀐다. CNI 적용까지 조금의 시간이 걸리며, 이 시간동안 kubectl 이 정상 작동하지 않는다.
# calico pod 생성 확인 (-w 옵션으로 변화 지속적으로 확인)
kubectl get pods -n kube-system -w | grep calico
# 모두 Running 상태일 시 node 상태 확인
kubectl get nodes
Bash
복사
작동 확인
간단하게 nginx를 실행시켜 작동을 확인해보자
$ kubectl run nginx --image=nginx
$ kubectl expose po nginx --name=nginx-svc --port=80 --target-port=80 --type=NodePort
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 58m
nginx-svc NodePort 10.96.192.238 <none> 80:31310/TCP 7s
$ curl 127.0.0.1:31310
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Bash
복사
Shared Network / Bridged
네트워크 모드에서 Shared Network나 Bridged를 사용하였다면 웹 브라우저에서 {vm-ip}:{node-port}로 접속하면 된다.
Enulated VLAN
네트워크 모드에서 Emulated VLAN을 사용했다면 서비스에 대한 매핑을 추가적으로 하고 접속해야 한다.
1.
포트 포워딩
master를 제외한 worker 노드들을 정지시키고 Edit을 통해 포트포워딩을 한다. 주의할 점으로 워커 노드 간에 동일한 호스트 포트를 가지면 안된다.
•
Guest Address: Worker Node IP [ 10.0.3.7, 10.0.3.8 ]
•
Guest Port: Service NodePort
•
Host Address: 127.0.0.1 (본인 지정)
•
Host Port: [ 31037, 31038 ] (본인 지정)
설정이 끝나면 다시 가상 머신을 가동시킨다.
2.
웹 브라우저 접근
포트포워딩한 ip와 port를 통해 접속한다.
마치며
VirtualBox는 VM을 중지시키지 않고 네트워크 구성이 가능한 것으로 알고 있는데, UTM은 포트포워딩이나 네트워크 추가 구성을 위해서 VM을 중지시켜야 한다. 이러한 점에 있어서 NodePort 타입으로 서비스를 생성할 때 모든 워커 노드에 포트포워딩 설정을 해야 하는 것이 너무 번거롭다. Master의 포트포워딩만을 통해 접근을 시도해 보기 위해 포트 매핑도 다시 해보고, 라우팅 설정도 해보았지만 잘 작동하지 않았다. 때문에 Shared Network나 Bridged 모드로 네트워크를 구성하는 것이 나아 보인다.