[쿠버네티스 DevOps 구축] - Local PC 에 쿠버네티스 설치하기

목차

참고

📝 회고

Vitality 팀에 있을때 EKS 로 구축된 시스템을 운영했었습니다. 지금은 해당 팀이 해체 되면서 운영하고 있지는 않지만 그때 내부적으로 진행했던 프로젝트들의 기억을 되살리고자 포스트로 남기려고 합니다.

🤔 쿠버네티스 운영환경 선택

지속적으로 쿠버네티스 환경을 운영도 하면서 공부도 하고 싶어 여러가지 환경을 검토해봤는데, EKS 는 일단 컨트롤 플레인 자체만으로도 한달에 7만원 정도가 나와 Pass (너무 비싸 😭), 로컬 PC 에 Minikube 를 이용하는 방법은 노트북을 너무 핫하게 만드는 방법이라 Pass

요즘 알리에서 미니 PC 가 싸게 풀리고 있고 시스템 초기 구입 비용 빼면 운용하는데는 매월 전기세만 내면 돼 크게 부담이 안될 것 같아 미니 PC 를 이용한 서버를 구축하기로 했습니다.

✅ 1. 쿠버테니스 설치전 사전 세팅

1.1 swap 비활성화

쿠버네티스를 설치하기 전에 리눅스 메모리 swap 을 비활성화 해줘야 합니다.

sudo swapoff -a
# 부팅 시에도 swap이 활성화되지 않도록 /etc/fstab 파일에서 swap 관련 항목 주석 처리
sudo sed -i '/swap/d' /etc/fstab

1.2 iptables 설정

# 네트워크 모듈 로드
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter
# sysctl 파라미터 설정
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

1.3 Docker 설치

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

1.4 containerd 설정

쿠버네티스에서 사용하는 containerd 를 설정을 변경합니다.

sudo mkdir -p /etc/containerd 
sudo containerd config default | sudo tee /etc/containerd/config.toml
# config.toml 파일에서 SystemdCgroup 값을 변경합니다.
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd

✅ 2. 쿠버네티스 설치에 필요한 패키지 설치

쿠버네티스 설치에 필요한 패키지를 다운 받을 수 있도록 아래 명령어를 이용해 apt 저장소에 GPG 키와 Kubernetes 저장소를 추가해줍니다.

# GPG 키 다운로드 및 저장
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo tee /etc/apt/keyrings/kubernetes-apt-keyring.asc > /dev/null
# apt 저장소에 쿠버네티스 저장소 추가
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.asc] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list > /dev/null
# 위 내용이 반영될 수 있도록 apt 저장소를 업데이트합니다.
sudo apt update

쿠버네티스 저장소가 추가 됐으면 apt 명령어를 이용해 kubelet, kubeadm, kubectl 을 설치해줍니다.

# 설치 가능한 버전 확인
sudo apt-cache madison kubeadm
# 버전을 명시해서 설치가능
sudo apt-get install -y kubelet=1.27.16-1.1 kubeadm=1.27.16-1.1 kubectl=1.27.16-1.1
sudo apt-mark hold kubelet kubeadm kubectl

✅ 3. Kubernetes 클러스터 초기화

kubelet, kubeadm, kubectl 가 완료되면 kubeadm init 명령어를 이용해 쿠버네티스 컨트롤 플레인 노드를 초기화 시켜줍니다.

kubeadm init 추가적인 파라미터를 확인하고 싶을 경우 쿠버네티스 공식 문서 에서 확인할 수 있습니다.

sudo kubeadm init --pod-network-cidr=10.0.0.0/16 --v=5
# 외부 Listening 할 수 있는 IP 가 있는 경우
sudo kubeadm init --control-plane-endpoint=<접속_IP> --pod-network-cidr=<Pod_네트워크_범위>

Config 파일을 이용한 클러스터 초기화

config 파일을 별도로 생성해 쿠버네티스 클러스터를 생성하는 방법도 있습니다.

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "v1.29.3" #설치할 쿠버네티스 버전
controlPlaneEndpoint: "<접속_IP>:<접속_PORT>" #외부 IP 주소와 포트 지정
networking:
podSubnet: "10.244.0.0/16" #Pod 네트워크 범위 설정
sudo kubeadm init --config kubeadm-config.yaml

쿠버네티스 설정파일 생성

mkdir -p $HOME/.kube 
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

✅ 4. CNI (Container Network Interface) 설치

클러스터 내부의 Pod 들이 서로 통신할 수 있도록 CNI 를 설치합니다.

mkdir cni
cd cni

wget https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/tigera-operator.yaml
wget https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/custom-resources.yaml

# cidr 대역을 worker node 대역으로 변경
vi custom-resources.yaml

kubectl create -f tigera-operator.yaml
kubectl create -f custom-resources.yaml

쿠버네티스 설치 점검 확인

dpkg -l | grep kube
hi  kubeadm                                       1.29.13-1.1                              amd64        Command-line utility for administering a Kubernetes cluster
hi kubectl 1.29.13-1.1 amd64 Command-line utility for interacting with a Kubernetes cluster
hi kubelet 1.29.13-1.1 amd64 Node agent for Kubernetes clusters
ii kubernetes-cni 1.3.0-1.1 amd64 Binaries required to provision kubernetes container networking

✅ 5. Control Plain Taint 삭제

쿠버네티스를 초기화하게되면 Control Plane 노드에 Pod 설치를 못하도록 (Schedule 이 불가능) Taint 설정이 들어가 있습니다.

Control Plane 에도 Pod 설치가 가능하게 (Schedule 이 가능하게) 하려면 해당 노드에 걸려있는 Taint 설정을 해지해줘야 합니다.

Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m default-scheduler 0/1 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.
kubectl taint nodes --all node-role.kubernetes.io/master-
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

⚠️ 클러스터 초기화시 오류 발생

sudo kubeadm init --pod-network-cidr=192.168.0.0/16

I0202 21:12:59.135308 6955 version.go:256] remote version is much newer: v1.32.1; falling back to: stable-1.29
[init] Using Kubernetes version: v1.29.13
[preflight] Running pre-flight checks
[WARNING Swap]: swap is supported for cgroup v2 only; the NodeSwap feature gate of the kubelet is beta but disabled by default
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR CRI]: container runtime is not running: output: time="2025-02-02T21:12:59+09:00" level=fatal msg="validate service connection: validate CRI v1 runtime API for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"
, error: exit status 1
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
To see the stack trace of this error execute with --v=5 or higher

[ERROR CRI]: container runtime is not running

아래 파일에서 SystemdCgroup = false 해당 부분을 주석 처리 합니다.

sudo vi /etc/containerd/config.toml

파일을 수정한 후 containerd 를 재실행해줍니다.

systemctl restart containerd

[ERROR FileContent–proc-sys-net-bridge-bridge-nf-call-iptables]

sudo modprobe br_netfilter
echo "br_netfilter" | sudo tee -a /etc/modules-load.d/k8s.conf
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config

⚠️ The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ failed with error: Get “http://localhost:10248/healthz“: dial tcp 127.0.0.1:10248: connect: connection refused.

container 의 cgroups 에 systemd 를 사용하도록 Docker 데몬을 구성한다.

sudo mkdir /etc/docker
t <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF

Docker Daemon 설정을 적용하기 위해 서비스를 재시작 합니다.

sudo systemctl enable docker 
sudo systemctl daemon-reload
sudo systemctl restart docker

⚠️ [kubelet-check] It seems like the kubelet isn’t running or healthy.

kubelet 상태가 현재 정상적이지 않다는 오류가 발생하고 있어, 아래 명령어들을 이용해 kubelet 상태를 확인해봅니다.

## 서비스 상태 확인
sudo systemctl status kubelet
## 로그 확인
sudo journalctl -xeu kubelet | tail -n 50

🔎 failed to run Kubelet: running with swap on is not supported

로그를 확인해보면 현재 메모리 스왑으로 인해 kubelet 이 정상적으로 실행되지 않음을 확인할 수 있습니다.

Kubernetes는 swap 을 사용하면 정상적으로 동작하지 않으므로 반드시 비활성화 해주어야 합니다.

Feb 02 23:16:56 ddanzit-ubuntu-desktop kubelet[20910]: E0202 23:16:56.465663   20910 run.go:74] "command failed" err="failed to run Kubelet: running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: [Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority /swap.img                               file\t\t8388604\t\t0\t\t-2]"
Feb 02 23:16:56 ddanzit-ubuntu-desktop systemd[1]: kubelet.service: Main process exited, code=exited, status=1/FAILURE
░░ Subject: Unit process exited
░░ Defined-By: systemd
░░ Support: http://www.ubuntu.com/support
░░
░░ An ExecStart= process belonging to unit kubelet.service has exited.
░░
░░ The process' exit code is 'exited' and its exit status is 1.
Feb 02 23:16:56 ddanzit-ubuntu-desktop systemd[1]: kubelet.service: Failed with result 'exit-code'.
░░ Subject: Unit failed
░░ Defined-By: systemd
░░ Support: http://www.ubuntu.com/support
░░
░░ The unit kubelet.service has entered the 'failed' state with result 'exit-code'.
Share