RHEL 9 계열(RHEL · Rocky · AlmaLinux)에 kubeadm 으로 Kubernetes 1.37.0[1] control-plane 1대 + worker 2대를 올린다. sudo 권한이 필요하다.
런타임은 containerd 를 쓴다. CRI-O 를 쓰려면 CRI-O 를 볼 것.
모든 노드에서 1~5 단계를 수행한다. 6 단계부터는 노드 역할이 갈린다.
sudo hostnamectl set-hostname k8s-cp01 # 노드마다 다르게
sudo tee -a /etc/hosts > /dev/null <<'HOSTS'
10.0.0.11 k8s-cp01
10.0.0.21 k8s-wk01
10.0.0.22 k8s-wk02
HOSTS
kubelet 은 swap 이 켜져 있으면 기동을 거부한다.
sudo swapoff -a
sudo sed -i '/[[:space:]]swap[[:space:]]/s/^/#/' /etc/fstab
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
| 노드 | 포트 |
|---|---|
| control-plane | 6443/tcp · 2379-2380/tcp · 10250/tcp · 10257/tcp · 10259/tcp |
| worker | 10250/tcp · 10256/tcp · 30000-32767/tcp |
# control-plane
sudo firewall-cmd --permanent --add-port={6443,2379-2380,10250,10257,10259}/tcp
# worker
sudo firewall-cmd --permanent --add-port={10250,10256,30000-32767}/tcp
sudo firewall-cmd --reload
sudo tee /etc/modules-load.d/k8s.conf > /dev/null <<'MOD'
overlay
br_netfilter
MOD
sudo modprobe overlay
sudo modprobe br_netfilter
sudo tee /etc/sysctl.d/k8s.conf > /dev/null <<'SYS'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
SYS
sudo sysctl --system
확인한다.
lsmod | grep -E 'overlay|br_netfilter'
sysctl net.ipv4.ip_forward net.bridge.bridge-nf-call-iptables
CONTAINERD_VER=2.3.5
RUNC_VER=1.5.1
CNI_VER=1.9.1
curl -LO https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VER}/containerd-${CONTAINERD_VER}-linux-amd64.tar.gz
sudo tar Cxzvf /usr/local containerd-${CONTAINERD_VER}-linux-amd64.tar.gz
curl -LO https://github.com/opencontainers/runc/releases/download/v${RUNC_VER}/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
curl -LO https://github.com/containernetworking/plugins/releases/download/v${CNI_VER}/cni-plugins-linux-amd64-v${CNI_VER}.tgz
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v${CNI_VER}.tgz
sudo curl -Lo /usr/local/lib/systemd/system/containerd.service --create-dirs \
https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
sudo systemctl daemon-reload
sudo systemctl enable containerd --now
kubelet 과 containerd 가 같은 cgroup 드라이버를 써야 한다. systemd 를 쓰는 배포판에서는 SystemdCgroup = true 로 맞춘다. 이 값이 어긋나면 kubelet 이 기동하다 멈춘다.
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
확인한다.
sudo ctr version
grep SystemdCgroup /etc/containerd/config.toml
예전
packages.cloud.google.com·apt.kubernetes.io저장소는 2024년 3월에 닫혔다. 지금은 커뮤니티가 운영하는pkgs.k8s.io를 쓴다. 마이너 버전마다 저장소 주소가 다르므로 올릴 버전에 맞춰 URL 을 바꾼다.
sudo tee /etc/yum.repos.d/kubernetes.repo > /dev/null <<'REPO'
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.37/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.37/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
REPO
Debian · Ubuntu 계열은 이렇게 한다.
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.37/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.37/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable kubelet
exclude 를 넣어 두었으므로 이후 dnf update 로 쿠버네티스가 멋대로 올라가지 않는다. 올릴 때만 --disableexcludes=kubernetes 를 준다.
kubeadm version -o short
kubectl version --client
control-plane 노드에서만 수행한다.
sudo kubeadm init \
--apiserver-advertise-address=10.0.0.11 \
--pod-network-cidr=10.244.0.0/16 \
--kubernetes-version=v1.37.0
--pod-network-cidr 는 뒤에 올릴 CNI 와 맞춰야 한다. Flannel 은 10.244.0.0/16, Calico 는 192.168.0.0/16 이 기본이다.
끝나면 마지막에 나오는 kubeadm join ... 줄을 받아 둔다. worker 에서 쓴다.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes
이 시점의 노드 상태는 NotReady 다. CNI 가 아직 없어서다.
Flannel 을 쓴다.
kubectl apply -f https://github.com/flannel-io/flannel/releases/download/v0.28.9/kube-flannel.yml
Calico 를 쓰려면 kubeadm init 때 --pod-network-cidr=192.168.0.0/16 으로 잡고 이렇게 한다.
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.2/manifests/calico.yaml
1~2분 뒤 노드가 Ready 로 바뀐다.
kubectl get nodes
kubectl -n kube-flannel get pods
worker 노드에서 kubeadm init 이 뱉은 join 명령을 실행한다.
sudo kubeadm join 10.0.0.11:6443 --token <토큰> \
--discovery-token-ca-cert-hash sha256:<해시>
토큰을 잃어버렸으면 control-plane 에서 다시 만든다.
kubeadm token create --print-join-command
control-plane 에서 확인한다.
kubectl get nodes -o wide
kubectl get nodes
kubectl -n kube-system get pods
NAME STATUS ROLES AGE VERSION
k8s-cp01 Ready control-plane 10m v1.37.0
k8s-wk01 Ready <none> 3m v1.37.0
k8s-wk02 Ready <none> 3m v1.37.0
파드를 하나 띄워 본다.
kubectl create deployment web --image=nginx --replicas=2
kubectl expose deployment web --port=80 --type=NodePort
kubectl get pods -o wide
kubectl get svc web
curl -s -o /dev/null -w '%{http_code}\n' http://<노드_IP>:<NodePort>
200 이 돌아오면 정상이다. 확인이 끝나면 지운다.
kubectl delete deployment web
kubectl delete svc web
kubectl top 을 쓰려면 필요하다.최신 버전 v1.37.0 — 2026-09-16 확인. 지원 계열은 1.37 · 1.36 · 1.35 다. https://kubernetes.io/releases/ ↩︎