라즈베리파이로 쿠버네티스 구축하기

od·2025년 3월 15일

kubernates

목록 보기
3/3

사내 쿠버네티스 스터디를 마친 후 직접 인프라를 구축하고 운영해보고 싶던 차에, 라즈베리파이로 온프레미스 기반의 토이 서비스를 운영하는 사례를 접하게 되었습니다.

이에 세 대의 라즈베리파이를 활용해 온프레미스 서버를 구축하고 쿠버네티스 클러스터를 구성하면 매달 발생하는 클라우드 비용을 절감할 수 있을 뿐만 아니라 서버 기반 방화벽 및 네트워크 설정 경험도 쌓을 수 있을 것으로 판단해 실행에 나서게 되었습니다.


최종 완성할 아키텍쳐는 다음과 같습니다.

기기명역할오픈 포트비고
PI-01Control Plane101122Pod 배포를 위한 SSH 포트 오픈
PI-02Worker Node443서비스 API 외부 호출을 위한 NginX Ingress Port 오픈
PI-03Worker NodeN/A서비스 모니터링을 위한 그라파나 고정 구축





Raspberry Pi On-premise

About Raspberry Pi

라즈베리파이는 영국에서 개발된 저가형 싱글보드 컴퓨터로, 저렴한 가격과 낮은 전력 소비로 인해 교육, 연구, IoT, DIY 프로젝트, 서버 구축 등 다양한 용도로 활용됩니다.
메인 저장장치로 MicroSD 카드를 사용하며 필요에 따라 SSD 를 사용할 수도 있습니다.

버전 3까지는 1GB 메모리 고정이었으나, 버전 4부터는 2GB, 4GB, 8GB 옵션을 선택할 수 있게 변경되었으며 CPU 및 메모리 성능 향상, 4K 지원 등 전반적인 업그레이드가 이루어져 큰 인기를 끌었습니다.

이번 프로젝트에서는 라즈베리파이 4를 사용하였으며 데이터베이스는 외부 서버를 활용할 예정이므로 I/O 성능이 크게 중요하지 않아 SSD 대신 MicroSD 카드를 저장장치로 선택하였습니다.


구매비용

요즘 대학에서 수업용으로 라즈베리파이를 많이 사용하기 때문에 당근에서 중고 매물을 쉽게 구할 수 있습니다.
메인 보드는 당근에서 구매했고 랜선, 마이크로 SD 카드를 포함한 총 구매비용은 244,000이 소요되었습니다.
초기 구축비용이 조금 들지만 EC2에서 동일한 인스턴스를 대여할 경우 월 32,400원의 비용이 발생합니다. 이를 바탕으로 온프레미스 서버를 구축하는 것이 약 8개월 동안의 인스턴스 대여비용과 비슷하다고 생각하니 나쁘지 않은 소비라고 판단했습니다.

물품명스펙수량구매경로금액
라즈베리파이라즈베리파이 4
4G RAM , 8G RAM
4G RAM 2개
8G RAM 1개
당근165,000
라즈베리파이 파워용 USB 충전기DC 5V 3.1A3개네이버페이20,000
마이크로 SD 카드128GB EVO PLUS3개네이버페이45,000
라즈베리파이 클러스터케이스1개알리10,000



우분투 설치

우선 라즈베리파이 홈페이지 에서 rpi-imager 다운로드를 받습니다.
rpi-imager는 라즈베리파이에서 사용할 운영 체제를 쉽게 설치할 수 있도록 돕는 도구입니다.
rpi-imager 를 실행하면 설치할 운영체제와 저장소를 선택하도록 되어있습니다.
저장소는 라즈베리파이에서 디스크로 사용할 MicroSD 카드를 PC 에 연결한 후 선택하시면 됩니다.
저는 Ubuntu Server 22.04.5 LTS 64 bit 를 선택하였습니다.



OS 커스터마이징을 클릭하면 우분투의 기본 설정을 할 수 있도록 도와줍니다.

  • hostname : 서버명
  • 사용자이름 : 우분투 접속 아이디
  • 비밀번호 : 우분투 접속 비밀번호
  • 무선 LAN 국가 : US
  • 로케일 시간대 : Asia/Seoul
  • 키보드 레이아웃 : US
  • SSH 사용 : 비밀번호 인증 사용

설정 완료 후 다음을 클릭하면 마이크로 SD 카드에 우분투를 설치를 위한 이미지가 저장됩니다.
저장이 완료되면 마이크로 SD 카드를 라즈베리파이에 삽입한 후 전원을 연결하면 우분투가 설치됩니다.



우분투 설정

우분투 설치가 완료되면 다음의 설정을 해줍니다.

# root 비밀번호 변경 
sudo passwd root 

# Wifi 설정 (필요시)
sudo vi /etc/netplan/50-cloud-init.yaml # 공유기 비밀번호 변경
sudo netplan -debug generate
sudo netplan apply
sudo reboot
ip a # private ip 확인 (inet 부분 확인)

# SSH 외부 접속을 위한 방화벽 설정
sudo ufw enable                 # 방화벽 활성화 
sudo ufw default deny incoming  # 들어오는 트래픽 기본 차단
sudo ufw default allow outgoing # 나가는 트래픽 기본 허용
sudo ufw allow 22/tcp           # SSH 허용
sudo ufw reload                 # 방화벽 규칙 적용
sudo ufw status                 # 방화벽 설정 확인

Private IP 를 고정 IP로 설정

네트워크에서 사용하는 Private IP는 기본적으로 유동적으로 할당되기 때문에 서비스 운영을 위해서는 IP 고정이 필요합니다. 집에서 사용하는 공유기 뒷면을 보면 네트워크 설정을 위한 페이지 주소와 비밀번호가 기록되어 있습니다.
저는 LG U+ 를 사용하고 있으므로 LG U+ 를 기준으로 설명 드리겠습니다.

LG U+ 의 네트워크 설정 주소는 http://192.168.219.1 입니다.
해당 페이지에 접속하여 로그인 한 후 상태정보 > DHCP 할당정보 DHCP 고정할당 을 클릭 합니다.

해당 페이지에서 맥주소 검색을 클릭하면 현재 LAN 에 연결된 기기의 MAC 주소와 IP 주소를 한 번에 볼 수 있는데요
여기서 고정하고자 하는 기기를 찾아 등록 해줍니다.
( 참고! 설정을 적용하면 네트워크가 잠깐 끊기게 됩니다. )![]

Notice
DHCP(Dynamic Host Configuration Protocol)
네트워크 장치의 IP 를 자동으로 할당받을 수 있도록 도와주는 프로토콜






쿠버네티스 구축

방화벽 설정

쿠버네티스가 사용하는 기본 포트는 다음과 같습니다.
클러스터 종류에 따라 다음의 포트를 오픈해줍니다.

클러스터프로토콜포트번호용도
CommonTCP10250Kubelet API
CNI (Common)UDP4789CNI VXLAN 사용시 (Flannel 0.10.x 이상 디폴트)
UDP8472CNI VXLAN 사용시 (Flannel 0.7.x ~ 0.9.x 디폴트)
UDP8285CNI 백엔드 모드 사용시 (Flannel 0.7.x 이하 디폴트)
TCP179CNI BGP 사용시
IP to IPCNI IPIP 사용시 (calico 디폴트)
Control PlaneTCP10251Kube-controller-manager 가 클러스터 상태를 확인
TCP10252Kube-scheduler 가 작업을 스케쥴링하는 포트
TCP6443쿠버네티스 API 서버
TCP10257kube-controller-manager 의 추가적인 통신에 사용
TCP2379-2380etcd (클러스터 상태 저장소)서버 클라이언트 API
TCP10259kube-scheduler 통신
TCP31000대시보드를 위한 포트
Worker NodeTCP30000-32767NodePort 서비스

Control plane 포트 오픈

# Control Plane Port
sudo ufw allow 2379:2380/tcp  
sudo ufw allow 10250:10252/tcp 
sudo ufw allow 6443/tcp
sudo ufw allow 10257/tcp  
sudo ufw allow 2379:2380/tcp 
sudo ufw allow 10259/tcp  
sudo ufw allow 31000/tcp

# CNI Port (이번 프로젝트에서는 CNI 로 Fannel 을 사용할 예정입니다)
sudo ufw allow 8472/udp  

# 방화벽 적용
sudo ufw reload 
sudo ufw status

# 만약 방화벽 설정을 삭제해야한다면 
sudo ufw status numbered # 방화벽 넘버 확인
sudo ufw delete [number]

Worker Node 포트 오픈

# Worker Node
sudo ufw allow 10250/tcp  
sudo ufw allow 8472/udp  
sudo ufw allow 30000:32767/tcp  

# 방화벽 적용
sudo ufw reload 
sudo ufw status

# 

swap 기능 비활성화

쿠버네티스는 Pod를 생성할 때 필요한 만큼의 리소스를 할당 받아서 사용하는 구조 입니다.
따라서 메모리 Swap을 고려하지 않고 설계되었기 때문에 Swap 메모리를 비활성화 해줘야 합니다.

# 스왑 메모리 즉시 비활성화
sudo swapoff -a

# 서버 재실행시 스왑메모리 비활성화 되도록 주석처리
sudo sed -i '/swap/s/^/#/' /etc/fstab

# 메모리 상태 확인 (swap 이 0 인지)
sudo free -m

네트워크 옵션 설정

쿠버네티스는 기본적으로 Iptables를 이용하기 때문에 iptables가 정상 작동하도록 설정해줍니다.

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

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

sysctl --system

컨테이너 런타임 (CRI) 설치

CRI 는 컨테이너를 실행하고 관리하는 소프트웨어입니다.
쿠버네티스 초기 버전에서는 CRI 로 도커만 써야 했지만 현재는 OCI 표준을 준수하는 CRI 는 무엇이든 쓸 수 있도록 변경되었습니다. 현재 가장 많이 사용되는 CRI 는 containerd 입니다.

# root 권한으로 작업
su

apt update && sudo apt upgrade

sudo apt-get install \ 
	ca-certificates \ 
	apt-transport-https \ 
	curl \ 
	gnupg \ 
	lsb-release

K8S_VERSION_MINOR=1.29

curl -fsSL https://pkgs.k8s.io/core:/stable:/v${K8S_VERSION_MINOR}/deb/Release.key | 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:/v${K8S_VERSION_MINOR}/deb/ /" | 
	tee /etc/apt/sources.list.d/kubernetes.list

apt update

sudo apt install -y containerd

# 기본 설정 파일 생성 
sudo mkdir -p /etc/containerd 
sudo containerd config default | sudo tee /etc/containerd/config.toml 

Cgroup 드라이버 systemd로 변경

Cgroup은 리눅스에서 프로세스별 자원 할당을 관리하는 도구 입니다.
쿠버네티스는 이를 활용하여 컨테이너의 자원을 제어합니다.
Cgroup을 관리하기 위한 기술은 크게 cgroupfs와 systemd가 있는데 쿠버네티스 1.22부터는 Cgroup 드라이버를 systemd를 이용하도록 변경되었습니다.

# cgroup 설정
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml 

# containerd 시작 및 활성화 
sudo systemctl restart containerd 
sudo systemctl enable containerd

kubeadm & kubectl 설치

kubeadm 은 쿠버네티스 클러스터를 초기화하고 설정하는 데 사용되는 도구 입니다.
kubectl 은 클러스터의 상태를 확인하고, 리소스를 관리하며, 디버깅 작업을 수행하는 데 사용되는 도구 입니다.

# kubelet kubeadm kubectl 설치
apt-get install -y kubelet kubeadm kubectl

control plane 설정

위의 설정 까지는 클러스터 종류와 상관없는 공통 설정이었고 다음의 설정은 Control plane 클러스터에만 해주셔야 합니다.

# 클러스터 초기화
# --pod-network-cidr: Pod 네트워크 범위 설정
# --apiserver-advertise-address: API 서버가 수신중임을 알릴 IP 주소
# --control-plane-endpoint: 하나의 공용 IP 로 여러 컨트롤 플레인 노드를 구축하는경우 필요한 설정 입니다.
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 \
	--apiserver-advertise-address=<Private IP> \
	--control-plane-endpoint=<Public IP>

# 편의를 위해 워커노드 역할도 부여 (스케쥴러가 컨트롤 플레인의 Job 스케쥴링을 하도록 설정)
kubectl taint nodes [서버명] node-role.kubernetes.io/control-plane:NoSchedule-

# 사용자가 kubectl 명령어를 사용할 수 있도록 설정
mkdir -p $HOME/.kube  
sudo cp -i /etc/kubernetes/kubelet.conf $HOME/.kube/config  
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# CRI 통신을 위한 인증서 설정
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# calico 를 사용하는 경우 설치 (더 범용적)
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

# Fannel 를 사용하는 경우 (더 가벼움)
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

편의기능 설치 (control plane)

쿠퍼네티스의 편리한 관리를 위한 대시보드와 메트릭 서버를 추가합니다.

# Metrics Server 설치
kubectl create -f https://raw.githubusercontent.com/k8s-1pro/install/main/ground/k8s-1.27/metrics-server-0.6.3/metrics-server.yaml

# 대시보드 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

대시보드를 접근할 수 있도록 포트 설정을 해줍니다.

# kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort  # 추가
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 3500  # 추가
  selector:
    k8s-app: kubernetes-dashboard

대시보드에 접근할 수 있도록 계정과 권한을 생성 합니다.

# 계정 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
EOF

# 권한 부여
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
EOF

# 토큰 생성 
kubectl -n kubernetes-dashboard create token admin-user

생성한 파드가 정상적으로 조회되는지 확인합니다.

# 노드 조회
kubectl get nodes

# 설치된 Pod 확인 (조회 값에 name 이 pod 의 이름)
kubectl get pods -A



worker node 설정

다음은 worker node 구성시 필요한 설정 입니다.

# 컨트롤 플레인에서 다음의 명령어를 입력합니다.
kubeadm token create --print-join-command

# 위에서 응답받은 결과를 워커 노드에 그대로 붙여넣기 합니다. (다음 아래의 형태와 같습니다)
# root 권한으로 실행합니다.
kubeadm join 192.168.56.30:6443 --token wv5ue1.4nvn56gbbuhp8p3c --discovery-token-ca-cert-hash sha256:433ad2b701db15b0565de884922cc7feaeca04bdbd0e41b5574d87cc1bf4604c 

# 노드 조인에 성공했는지 컨트롤 플레인에서 확인합니다
kubectl get nodes

# (필요시) 노드 연결 해제 명령어
kubectl delete node <노드이름>






마무리 하며

대시보드 페이지 https://{PI-01-IP}:31000 에 접속하면
세 개의 노드가 정상적으로 연동되었음을 확인할 수 있습니다.


Next Steps

  • Github Action 을 이용한 Service Pod CI/CD 구축
  • NginX Ingress Setting
  • Grafana Monitoring
profile
차분하게 단단히 쌓아가는 개발자

0개의 댓글