Kubernetes سطح: پیشرفته

راه‌اندازی کلاستر Kubernetes Production با kubeadm روی سرورهای داخلی

طراحی و نصب کلاستر High Availability با سه Control Plane، HAProxy و Keepalived، containerd، CNI، بکاپ etcd و تمدید گواهی‌ها؛ همراه با نکات مخصوص شبکه‌ی ایران.

۴ دقیقه مطالعه

بیشتر سازمان‌های ایرانی، به‌خصوص بانک‌ها و نهادهای دولتی، نمی‌توانند از 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، بکاپ تست‌شده، مدیریت گواهی‌ها و استقلال از اینترنت خارجی. با این موارد، کلاستری دارید که سال‌ها بدون غافلگیری کار می‌کند.