بیشتر سازمانهای ایرانی، بهخصوص بانکها و نهادهای دولتی، نمیتوانند از Kubernetes مدیریتشدهی ابری استفاده کنند و کلاستر باید روی سرورهای خودشان اجرا شود. kubeadm ابزار رسمی Kubernetes برای همین کار است. در این مقاله مسیری را توضیح میدهم که برای راهاندازی کلاسترهای Production در پروژههای بانکی دنبال کردهام.
معماری
VIP 10.0.0.10:6443 (Keepalived)
┌───────────┴───────────┐
HAProxy-1 HAProxy-2
└───────────┬───────────┘
┌────────────────────┼────────────────────┐
master-1 master-2 master-3
(control plane + etcd, stacked topology)
└────────────────────┼────────────────────┘
worker-1 worker-2 worker-3 worker-N
| نقش | تعداد | حداقل منابع |
|---|---|---|
| Control Plane | ۳ (فرد، برای Quorum در etcd) | ۴ CPU، ۸GB RAM، دیسک SSD |
| Worker | بر اساس بار؛ حداقل ۳ | ۸ CPU، ۳۲GB RAM |
| Load Balancer | ۲ (Active/Passive) | ۲ CPU، ۲GB RAM |
۱. Load Balancer برای API Server
HAProxy روی دو سرور، با Keepalived برای جابهجایی خودکار VIP:
# /etc/haproxy/haproxy.cfg
frontend k8s-api
bind *:6443
mode tcp
default_backend k8s-masters
backend k8s-masters
mode tcp
balance roundrobin
option tcp-check
server master-1 10.0.0.11:6443 check fall 3 rise 2
server master-2 10.0.0.12:6443 check fall 3 rise 2
server master-3 10.0.0.13:6443 check fall 3 rise 2
# /etc/keepalived/keepalived.conf (on the backup node: state BACKUP, priority 100)
vrrp_instance K8S_API {
state MASTER
interface ens192
virtual_router_id 51
priority 110
virtual_ipaddress {
10.0.0.10/24
}
}
یک رکورد DNS داخلی مثل k8s-api.example.ir هم به VIP اشاره کند. این آدرس بعداً controlPlaneEndpoint کلاستر میشود.
۲. آمادهسازی همهی Nodeها
# swap must be off
sudo swapoff -a && sudo sed -i '/ swap / s/^/#/' /etc/fstab
# kernel modules and sysctl
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
sudo sysctl --system
containerd با cgroup driver از نوع systemd:
sudo apt-get install -y containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
kubeadm، kubelet و kubectl با نسخهی ثابت:
K8S=v1.34
curl -fsSL https://pkgs.k8s.io/core:/stable:/$K8S/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:/$K8S/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
همهی این مراحل را در یک Ansible Role بنویسید. اضافه کردن Worker جدید باید یک دستور باشد، نه یک روز کار.
۳. راهاندازی اولین Control Plane
# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.34.1
controlPlaneEndpoint: "k8s-api.example.ir:6443"
imageRepository: harbor.example.ir/k8s
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
apiServer:
certSANs: [k8s-api.example.ir, 10.0.0.10]
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
sudo kubeadm init --config kubeadm-config.yaml --upload-certs
خروجی دو دستور kubeadm join میدهد: یکی برای Control Planeهای دیگر (با --control-plane --certificate-key) و یکی برای Workerها. آنها را روی Nodeهای مربوطه اجرا کنید.
۴. شبکهی Podها (CNI)
بدون CNI، Nodeها در وضعیت NotReady میمانند. دو انتخاب رایج:
| CNI | ویژگی |
|---|---|
| Calico | پایدار و جاافتاده، Network Policy کامل، BGP برای شبکههای سازمانی |
| Cilium | مبتنی بر eBPF، کارایی بالا، Observability با Hubble، جایگزین kube-proxy |
بعد از نصب، kubectl get nodes باید همه را Ready نشان دهد.
۵. بکاپ etcd را خودکار کنید
همهی وضعیت کلاستر در etcd است. بدون بکاپ، خراب شدن etcd یعنی ساختن کلاستر از صفر:
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%F-%H%M).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
این دستور را با یک CronJob یا systemd timer هر چند ساعت اجرا کنید، فایل را به MinIO یا یک سرور دیگر منتقل کنید و بازگردانی را حداقل یکبار روی یک کلاستر تست امتحان کنید. بکاپی که تست نشده، بکاپ نیست.
۶. گواهیها: بمب ساعتی یکساله
گواهیهایی که kubeadm میسازد یک سال اعتبار دارند. اگر منقضی شوند، API Server از کار میافتد:
sudo kubeadm certs check-expiration
sudo kubeadm certs renew all
# then restart the control plane static pods (kube-apiserver, controller-manager, scheduler, etcd)
چکلیست قبل از تحویل به تیمها
- سه Control Plane روی Hostهای فیزیکی مختلف
- VIP تست شده: خاموش کردن HAProxy اصلی نباید دسترسی را قطع کند
- بکاپ خودکار etcd و یکبار تست بازگردانی
- containerd و kubeadm از Mirror داخلی
- مانیتورینگ با kube-prometheus-stack و Alert انقضای گواهی
- Network Policy پیشفرض و محدود کردن دسترسی بین Namespaceها
- مستندات Upgrade و بازیابی در Wiki تیم
جمعبندی
kubeadm کلاستر را بالا میآورد، اما Production بودن آن به جزئیاتی بستگی دارد که در دستور init دیده نمیشوند: Load Balancer درست، دیسک سریع برای etcd، بکاپ تستشده، مدیریت گواهیها و استقلال از اینترنت خارجی. با این موارد، کلاستری دارید که سالها بدون غافلگیری کار میکند.