نصب Kubernetes با kubeadm روی اوبونتو گام به گام

نصب Kubernetes با kubeadm روی اوبونتو در هشت مرحله انجام می‌شود: آماده‌سازی نودها، غیرفعال کردن Swap، تنظیم ماژول‌ها و شبکه هسته، نصب containerd، نصب kubeadm و kubelet و kubectl از مخزن رسمی، اجرای kubeadm init روی Control Plane، نصب CNI و اتصال Workerها. نتیجه یک کلاستر استاندارد و بدون افزونه اضافی است که برای آزمایش، آموزش تیم و پایه یک کلاستر عملیاتی به کار می‌آید.

دستورها بر اساس مستندات kubernetes.io برای Kubernetes 1.37 (منتشرشده در شهریور ۱۴۰۵) و Ubuntu Server 24.04 یا 26.04 LTS نوشته شده‌اند. همه دستورها با کاربر دارای sudo و از طریق SSH اجرا می‌شوند؛ اگر ورود با کلید را هنوز تنظیم نکرده‌اید، آموزش SSH Key و اتصال امن به سرور لینوکس را ببینید. نسخه اوبونتو را هم از دانلود اوبونتو سرور تهیه کنید.

پیش‌نیازهای نصب Kubernetes با kubeadm

طبق مستندات، هر نود دست‌کم 2 گیگابایت حافظه لازم دارد و نود Control Plane دست‌کم 2 هسته CPU. نام هاست، آدرس MAC و product_uuid هر نود باید یکتا باشد؛ این مورد در ماشین‌های مجازی Clone‌شده زیاد مشکل‌ساز می‌شود. در این راهنما یک Control Plane و دو Worker با این مشخصات فرض شده است:

نقشنام هاستIP نمونهحداقل منابع
Control Planek8s-cp1192.168.10.112 هسته، 2 گیگابایت حافظه
Workerk8s-w1192.168.10.212 گیگابایت حافظه
Workerk8s-w2192.168.10.222 گیگابایت حافظه
# run on every node and compare the results
ip link
sudo cat /sys/class/dmi/id/product_uuid

اگر بین نودها فایروال دارید، پورت‌های Control Plane یعنی 6443، 2379 تا 2380، 10250، 10257 و 10259 و پورت‌های Worker یعنی 10250، 10256 و بازه 30000 تا 32767 برای NodePort را باز کنید. نوشتن این قواعد در آموزش کانفیگ iptables در لینوکس آمده است.

مرحله ۱: نام هاست و فایل hosts

روی هر نود نام هاست را تنظیم و نام همه نودها را به فایل hosts اضافه کنید. نام k8s-api هم آدرس ثابت API کلاستر است که بعداً اجازه می‌دهد Control Plane را بدون ساخت دوباره کلاستر چندنودی کنید. IP ثابت هر نود را هم پیش از شروع با Netplan تنظیم کنید؛ روش آن در راهنمای تنظیمات شبکه لینوکس آمده است.

sudo hostnamectl set-hostname k8s-cp1   # k8s-w1 and k8s-w2 on the workers

cat <<EOF | sudo tee -a /etc/hosts
192.168.10.11 k8s-cp1 k8s-api
192.168.10.21 k8s-w1
192.168.10.22 k8s-w2
EOF

مرحله ۲: غیرفعال کردن Swap

kubelet به‌صورت پیش‌فرض با Swap فعال اجرا نمی‌شود. مستندات دو راه پیش پا می‌گذارد: خاموش کردن Swap، یا تنظیم kubelet برای تحمل آن. برای نصب ساده، Swap را روی همه نودها خاموش کنید و خط آن را در fstab غیرفعال کنید تا بعد از ری‌استارت برنگردد:

sudo swapoff -a
sudo sed -i '/\sswap\s/ s/^/#/' /etc/fstab
free -h

مرحله ۳: ماژول‌های هسته و IP Forwarding

مستندات Kubernetes فعال بودن IPv4 Forwarding را الزامی می‌داند. ماژول br_netfilter هم برای Flannel لازم است و طبق مستندات Flannel، kubeadm از نسخه 1.30 وجود آن را بررسی نمی‌کند؛ پس اگر بارگذاری نشود، خطا را بعد از نصب CNI می‌بینید. این دستورها را روی همه نودها اجرا کنید:

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.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
sysctl net.ipv4.ip_forward

مرحله ۴: نصب و تنظیم containerd

از Kubernetes 1.24، dockershim حذف شده و kubelet مستقیم با Runtime سازگار با CRI کار می‌کند؛ containerd ساده‌ترین گزینه است. نکته مهم این مرحله Cgroup Driver است: kubelet و containerd باید هر دو systemd را استفاده کنند. kubeadm برای kubelet به‌صورت پیش‌فرض systemd را تنظیم می‌کند، اما فایل پیش‌فرض containerd مقدار SystemdCgroup را false می‌گذارد.

sudo apt-get update
sudo apt-get install -y containerd

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
grep -n SystemdCgroup /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

در containerd نسخه 2 مسیر این تنظیم در فایل تغییر کرده، اما دستور sed در هر دو نسخه کار می‌کند؛ مهم این است که خروجی grep مقدار true را نشان دهد. اگر هنگام kubeadm init هشدار ناهماهنگی ایمیج pause (Sandbox Image) دیدید، همان نسخه‌ای را که kubeadm پیشنهاد می‌کند در config.toml تنظیم و containerd را ری‌استارت کنید. اگر روی نودها Docker Engine هم دارید، برای استفاده مستقیم Kubernetes از آن به cri-dockerd نیاز است؛ جداسازی این دو در خدمات Docker و کانتینرسازی سرور هم بررسی می‌شود.

مرحله ۵: نصب kubeadm، kubelet و kubectl

مخزن قدیمی apt.kubernetes.io حذف شده و بسته‌ها فقط از pkgs.k8s.io منتشر می‌شوند. هر نسخه فرعی مخزن جدا دارد و عدد v1.37 در آدرس، نسخه نصب را تعیین می‌کند. روی همه نودها اجرا کنید:

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

sudo mkdir -p -m 755 /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 apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable kubelet

دستور apt-mark hold جلوی ارتقای ناخواسته این بسته‌ها با apt upgrade را می‌گیرد، چون ارتقای Kubernetes باید با فرایند kubeadm upgrade و نود به نود انجام شود. تا پیش از kubeadm init، سرویس kubelet هر چند ثانیه ری‌استارت می‌شود و این رفتار عادی است.

مرحله ۶: راه‌اندازی Control Plane با kubeadm init

این مرحله فقط روی k8s-cp1 اجرا می‌شود. محدوده 10.244.0.0/16 همان محدوده پیش‌فرض Flannel است و نباید با شبکه‌های فعلی سازمان هم‌پوشانی داشته باشد. دریافت ایمیج‌ها را جدا انجام دهید تا خطای دسترسی به Registry پیش از init دیده شود:

sudo kubeadm config images pull

sudo kubeadm init --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=192.168.10.11 \
  --control-plane-endpoint=k8s-api

mkdir -p ~/.kube
sudo cat /etc/kubernetes/admin.conf | tee ~/.kube/config > /dev/null
chmod 600 ~/.kube/config

kubectl get nodes

در پایان خروجی init، دستور kubeadm join با Token و Hash نمایش داده می‌شود؛ آن را نگه دارید. Token پیش‌فرض بعد از 24 ساعت منقضی می‌شود. وضعیت نود تا نصب CNI روی NotReady می‌ماند.

اگر نودها به registry.k8s.io دسترسی ندارند

ایمیج‌های Control Plane به‌صورت پیش‌فرض از registry.k8s.io دریافت می‌شوند و ایمیج‌های Flannel و اپلیکیشن‌ها معمولاً از Docker Hub که IPهای ایران را مسدود می‌کند. در شبکه‌های داخلی، فهرست ایمیج‌های لازم را با kubeadm config images list بگیرید، آن‌ها را در Registry داخلی سازمان قرار دهید و آدرس آن را با گزینه –image-repository به kubeadm init و config images pull بدهید.

مرحله ۷: نصب شبکه Pod با Flannel

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

kubectl get pods -n kube-flannel
kubectl get pods -n kube-system
kubectl get nodes

پس از Running شدن Podهای Flannel، CoreDNS هم از Pending خارج می‌شود و نود Ready می‌شود. Flannel ساده است اما NetworkPolicy را اعمال نمی‌کند؛ اگر باید ترافیک بین Namespaceها را محدود کنید، از ابتدا Calico یا Cilium را انتخاب کنید، چون تعویض CNI در کلاستر فعال کار ساده‌ای نیست.

مرحله ۸: اتصال Workerها و تست کلاستر

دستور join ذخیره‌شده را روی هر Worker با sudo اجرا کنید. اگر Token منقضی شده، روی Control Plane دستور جدید بسازید:

# on k8s-cp1: print a fresh join command
kubeadm token create --print-join-command

# on k8s-w1 and k8s-w2
sudo kubeadm join k8s-api:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

# on k8s-cp1
kubectl get nodes -o wide

برای تست، یک Deployment با دو Replica بسازید و آن را با NodePort منتشر کنید. ایمیج nginx از Docker Hub دریافت می‌شود؛ اگر Mirror یا Registry داخلی ندارید، آدرس ایمیج را با نسخه موجود در Registry خودتان عوض کنید.

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 http://192.168.10.21:<node-port>

خطاهای رایج نصب با kubeadm

پس از نصب، دستور kubectl get pods -A باید همه Podهای سیستمی را در وضعیت Running نشان دهد. اگر Podی در وضعیت دیگری ماند، اول kubectl describe pod را روی آن اجرا کنید و بخش Events را بخوانید. اگر مشکل از خود نود است، لاگ kubelet را با journalctl -u kubelet ببینید. بیشتر مشکلات نصب اول در یکی از ردیف‌های جدول زیر قرار می‌گیرند:

نشانهعلت محتملراه‌حل
نود NotReady و CoreDNS در وضعیت PendingCNI نصب نشده استFlannel یا CNI دیگر را نصب کنید
ErrImagePull یا ImagePullBackOffدسترسی نداشتن به registry.k8s.io یا Docker HubRegistry داخلی و گزینه –image-repository
خطای Swap در PreflightSwap هنوز فعال استswapoff -a و غیرفعال کردن خط fstab
Podهای Flannel در CrashLoopBackOffbr_netfilter بارگذاری نشده یا CIDR با init یکی نیستmodprobe br_netfilter و بررسی مقدار pod-network-cidr
ری‌استارت پیاپی Podهای Control Planeناهماهنگی Cgroup DriverSystemdCgroup = true و ری‌استارت containerd
خطای Token در joinToken منقضی شده استkubeadm token create –print-join-command

اگر نیاز شد نصب را از اول انجام دهید، روی نود مورد نظر sudo kubeadm reset را اجرا کنید. این دستور تنظیمات CNI در /etc/cni/net.d و فایل kubeconfig کاربر را پاک نمی‌کند؛ آن‌ها را دستی حذف کنید.

از کلاستر آزمایشی تا محیط عملیاتی

  • سه نود Control Plane پشت یک Load Balancer مثل HAProxy برای آدرس k8s-api.
  • بکاپ منظم etcd و تست بازیابی آن.
  • Ingress Controller یا Gateway API، cert-manager و ذخیره‌سازی پایدار برای سرویس‌های Stateful.
  • مانیتورینگ نودها و Podها با Prometheus و Grafana.
  • برنامه ارتقا: هر نسخه فرعی حدود یک سال وصله دریافت می‌کند و ارتقا باید یک نسخه فرعی در هر مرحله باشد.
  • استقرار اپلیکیشن‌ها از طریق پایپ‌لاین CI/CD به جای kubectl دستی، همراه RBAC برای دسترسی تیم‌ها.

انتخاب توزیع، طراحی این لایه‌ها و نگهداری کلاستر در صفحه استقرار و مدیریت Kubernetes سازمانی شرح داده شده است.

سوالات متداول

kubeadm را انتخاب کنیم یا k3s؟

kubeadm کلاستر استاندارد بالادستی را با کنترل کامل روی هر جزء می‌سازد و CNI و Ingress را خودتان انتخاب می‌کنید. k3s سبک‌تر است و چند جزء آماده دارد و برای Edge، آزمایشگاه یا منابع محدود مناسب‌تر است.

آیا Kubernetes روی یک نود قابل نصب است؟

بله. پس از init، با دستور kubectl taint nodes –all node-role.kubernetes.io/control-plane- محدودیت اجرای Pod روی Control Plane را بردارید. این حالت فقط برای آزمایش مناسب است.

آیا می‌توان از Docker به‌عنوان Runtime استفاده کرد؟

از نسخه 1.24 پشتیبانی داخلی Docker حذف شده است. استفاده از Docker Engine به cri-dockerd نیاز دارد؛ containerd مستقیم و با تنظیم کمتر کار می‌کند.

کلاستر kubeadm را چطور ارتقا دهیم؟

نسخه مخزن pkgs.k8s.io را یک نسخه فرعی جلو ببرید، ابتدا kubeadm را روی Control Plane ارتقا دهید و kubeadm upgrade plan و apply را اجرا کنید، سپس kubelet و kubectl را نود به نود ارتقا دهید. پرش از روی نسخه‌های فرعی پشتیبانی نمی‌شود.

Kubernetes 1.37 تا چه زمانی وصله دریافت می‌کند؟

طبق صفحه انتشارهای kubernetes.io، پایان پشتیبانی نسخه 1.37 آبان ۱۴۰۶ (اکتبر ۲۰۲۷) است. پیش از آن کلاستر را به نسخه‌های بعدی ارتقا دهید تا وصله‌های امنیتی را از دست ندهید.

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *