라즈베리파이로 k8s 클러스터 구성하기
라즈베리파이의 온도를 확인하고 프로메테우스의 node_exporter를 사용하여 모든 노드의 상태를 모니터링하기 전에 클러스터를 구성하기 위해 몇 가지 작업을 진행해요.
- 쿠버네티스 버전:
1.30.0-1.1
- CRI:
containerd
- CNI:
cilium
커널 파라미터 설명
net.bridge.bridge-nf-call-iptables
- 쿠버네티스는 Pod 간 통신 및 네트워크 정책을 관리하기 위해 iptables를 사용하며 위 설정이 없을 경우 브릿지 인터페이스를 통해 전달되는 트래픽에 iptables 규칙이 적용되지 않으므로 위 설정을 통해 네트워크 인터페이스에서 iptables를 통해 IPv4 트래픽을 필터링
net.bridge.bridge-nf-call-ip6tables
- IPv6 트래픽도 ip6tables를 통해 필터링 및 관리
net.ipv4.ip_forward
- 쿠버네티스는 노드 또는 파드간 통신을 위해 패킷 포워딩이 필요하므로 하나의 네트워크 인터페이 스에서 수신한 패킷을 다른 네트워크 인터페이스로 전달할 수 있게 설정
모든 노드에서 아래 작업을 진행합니다.
커널 파라미터 수정, crictl, containerd 설치
# 관리자 모드로 접근
sudo su -
# swap 비활성화
$ swapoff -a && sed -i '/swap/s/^/#/' /etc/fstab
$ swapon -s
# br_netfilter, overlay 모듈을 로드
$ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# 모듈 동적 로드
$ modprobe overlay
$ 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 파라미터 적용
sysctl --system
# HTTPS를 활용해 패키지 저장소에 접근하기 위해 패키지를 설치
apt update
apt install apt-transport-https ca-certificates curl gnupg lsb-release -y
# Docker의 공식 GPG키를 시스템에 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 라즈베리파이5는 arm64 아키텍처를 사용
# Docker를 repository URL 등록
echo \
"deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 레포지토리 업데이트
apt update
# docker, containerd 설치
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
docker version
# crictl 설정 파일 생성 및 엔드포인트 지정
cat << END >> /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
END
# containerd config file 구성
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 구성파일의 systemdCgroup = true로 수정.
vi /etc/containerd/config.toml
...(생략)
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...(중략)
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
# 현재 사용자의 유저 아이디 및 그룹 아이디 확인
albert@ip-172-30-1-71:/etc$ id -u
1000
albert@ip-172-30-1-71:/etc$ id -g
1003
# crictl 명령어를 현재 사용자가 실행 가능하도록 uid, gid에 번호 할당
# vim에서 일괄 변경
# :%s/uid = 0/uid = 1000/g
# :%s/gid = 0/gid = 1003/g
[debug]
gid = 1003
uid = 1000
[grpc]
gid = 1003
uid = 1000
[ttrpc]
gid = 1003
uid = 1000
# containerd 재시작 후 서비스 동작 상태 확인
$ systemctl restart containerd
$ systemctl status containerd
kubelet, kubeadm, kubectl를 모든 노드에 설치해야 하므로 아래 작업도 모든 노드에서 진행해요.
kubelet, kubeadm, kubectl 설치
$ sudo apt-get update
$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
# Download the Google Cloud public signing key
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# Add the Kubernetes apt repository
$ echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
# Update apt package index, install kubelet, kubeadm and kubectl, and pin their version
$ apt-get update
# 설치가능한 버전 확인
$ sudo apt-cache madison kubeadm
# 1.30.0 버전 설치
$ apt-get install -y kubelet=1.30.0-1.1 kubeadm=1.30.0-1.1 kubectl=1.30.0-1.1 --allow-change-held-packages
$ apt-mark hold kubelet kubeadm kubectl
# Verifying Installed Versions
$ kubelet --version
다음은 control-plane 역할을 가질 노드에서만 실행합니다.
kubeadm init, cilium 설치
# 아래 명령어 실행 결과 join 명령어를 리턴하는데 다른 노드에서 조인할 때 사용하기 위해서 이 명령어를 저장해둡니다.
$ kubeadm init --pod-network-cidr=192.168.0.0/16 --cri-socket unix:///var/run/containerd/containerd.sock
$ cat <<EOF > token.join
kubeadm join <Control-plane_IP>:6443 --token [토큰] \
--cri-socket unix:///var/run/containerd/containerd.sock \
--discovery-token-ca-cert-hash [해쉬]
EOF
# 쿠버네티스 config 설정
$ mkdir -p $HOME/.kube
$ cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ chown 1000:1003 $HOME/.kube/config
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-30-1-71 Ready control-plane 3m45s v1.30.0
$ KUBERNETES_VERSION=v1.30
$ CRIO_VERSION=v1.30
$ curl -LO https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-arm64.tar.gz
$ sudo tar xzvf ./cilium-linux-arm64.tar.gz
$ sudo mv ./cilium /usr/local/bin
$ cilium install
ℹ️ Using Cilium version 1.15.6
🔮 Auto-detected cluster name: kubernetes
🔮 Auto-detected kube-proxy has been installed
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system cilium-fpskm 1/1 Running 0 79s
kube-system cilium-operator-65496b9554-j2dlw 1/1 Running 0 79s
kube-system cilium-rswlj 1/1 Running 0 79s
kube-system cilium-xwm8q 1/1 Running 0 79s
kube-system coredns-7db6d8ff4d-v77sm 1/1 Running 0 31m
kube-system coredns-7db6d8ff4d-wdz7b 1/1 Running 0 31m
kube-system etcd-ip-172-30-1-71 1/1 Running 0 31m
kube-system kube-apiserver-ip-172-30-1-71 1/1 Running 0 31m
kube-system kube-controller-manager-ip-172-30-1-71 1/1 Running 0 31m
kube-system kube-proxy-8mdsw 1/1 Running 0 21m
kube-system kube-proxy-vrzb5 1/1 Running 0 31m
kube-system kube-proxy-x8gdj 1/1 Running 0 21m
kube-system kube-scheduler-ip-172-30-1-71 1/1 Running 0
# 각 워커 노드로 ssh 퍼블릭키 복사
$ albert@ip-172-30-1-71:~/.ssh$ ssh-copy-id -i ~/.ssh/id_rsa.pub 172.30.1.72
$ albert@ip-172-30-1-71:~/.ssh$ ssh-copy-id -i ~/.ssh/id_rsa.pub 172.30.1.73
etcd 설치
$ export RELEASE=$(curl -s https://api.github.com/repos/etcd-io/etcd/releases/latest|grep tag_name | cut -d '"' -f 4)
$ wget https://github.com/etcd-io/etcd/releases/download/${RELEASE}/etcd-${RELEASE}-linux-arm64.tar.gz
albert@ip-172-30-1-71:~$ tar xf etcd-${RELEASE}-linux-arm64.tar.gz
albert@ip-172-30-1-71:~$ cd etcd-${RELEASE}-linux-arm64
albert@ip-172-30-1-71:~/etcd-v3.5.15-linux-arm64$ sudo mv etcd etcdctl etcdutl /usr/local/bin
albert@ip-172-30-1-71:~/etcd-v3.5.15-linux-arm64$ etcd --version
etcd Version: 3.5.15
Git SHA: 9a5533382
Go Version: go1.21.12
Go OS/Arch: linux/arm64
아래 작업은 워커 노드로 실행될 두 노드에서 진행합니다.
워커노드 클러스터 조인
# 두 노드에서 control-plane 노드와 6443 포트로 통신되는지 확인
root@ip-172-30-1-72:~# nc -vz 172.30.1.71 6443
Connection to 172.30.1.71 6443 port [tcp/*] succeeded!
root@ip-172-30-1-73:~# nc -vz 172.30.1.71 6443
Connection to 172.30.1.71 6443 port [tcp/*] succeeded!
# 이전에 control-plane 노드에서 저장했던 token.join 명령어를 각각 두 노드에서 실행합니다.
...(중략)
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-check] Waiting for a healthy kubelet. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 1.501295878s
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
아래 작업은 control-plane에서 진행해요. metrics-server를 통해서 클러스터의 리소스 사용량을 확인할거에요.
metrics-server 설치
$ git clone https://github.com/kubernetes-sigs/metrics-server.git
$ cd metrics-server/manifests/base
$ vi deployment.yaml
# args에 아래 플래그를 추가해주세요.
args:
- --kubelet-insecure-tls
# kustomize 적용
kubectl apply -k .
# 적용 후에 k top 명령어로 리소스 사용량이 잘 조회되는지 확인
albert@ip-172-30-1-71:~$ k top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-172-30-1-71 113m 2% 1285Mi 16%
ip-172-30-1-72 34m 0% 600Mi 7%
ip-172-30-1-73 28m 0% 603Mi 7%