هنگامی که کلاستر Kubernetes (k8s) را برای محیط محصول (Production) راه اندازی می کنیم، توصیه می شود که آن با قابلیت در دسترسی بالا ایجاد کنیم. در اینجا قابلیت دسترسی بالا به معنای نصب Master یا control plane کلاستر بصورت HA است. در این مقاله نشان خواهم داد که چگونه می توان کلاستر Kubernetes را با استفاده از ابزار kubeadm بصورت HA تنظیم کرد.
من از پنج سیستم CentOS 8 با جزئیات زیر استفاده کرده ام:
k8s-master-1 – Minimal CentOS 8 – 192.168.122.50 – 2GB RAM, 2vCPU, 40 GB Disk
k8s-master-2 – Minimal CentOS 8 – 192.168.122.51 – 2GB RAM, 2vCPU, 40 GB Disk
k8s-master-3 – Minimal CentOS 8 – 192.168.122.52 – 2GB RAM, 2vCPU, 40 GB Disk
k8s-worker-1 – Minimal CentOS 8 – 192.168.122.53 – 2GB RAM, 2vCPU, 40 GB Disk
k8s-worker-2 – Minimal CentOS 8 – 192.168.122.54 – 2GB RAM, 2vCPU, 40 GB Disk
توجه: کلاستر etcd می تواند خارج از node های master تشکیل شود اما برای این منظور به سخت افزار اضافی نیاز داریم، بنابراین من etcd را در داخل node های master نصب می کنم.
حداقل نیاز برای تنظیم کلاستر K8s:
- نصب Kubeadm ، kubelet و kubectl روی همه node های master و worker
- اتصال شبکه در بین node های master و worker
- اتصال به اینترنت در همه node ها
- کاربر root یا کاربر با دسترسی sudo در همه node ها
مرحله 1) تنظیم Hostname و تغییر فایل /etc/hosts
دستور hostnamectl را برای تنظیم نام host در هر node اجرا میکنیم.
مثال برای k8s-master-1:
hostnamectl set-hostname "k8s-master-1"
به همین ترتیب، در node های باقی مانده دستور را اجرا کرده و Hostname را تنظیم میکنیم. پس از تنظیم Hostname بر روی همه node های master و worker، ورودی های زیر را در فایل /etc/hosts
در همه node ها اضافه میکنیم:
192.168.122.50 k8s-master-1
192.168.122.51 k8s-master-2
192.168.122.52 k8s-master-3
192.168.122.53 k8s-worker-1
192.168.122.54 k8s-worker-2
192.168.122.45 vip-k8s-master
من از یک ورودی اضافی “192.168.122.45 vip-k8s-master” استفاده کرده ام. از این IP و Hostname موقع پیکربندی haproxy و keepalived روی همه node های master، به عنوان kube-apiserver load balancer استفاده خواهم کرد. تمام درخواست های kube-apiserver به این IP می آیند و سپس این درخواست در بین kube-apiserver های واقعی توزیع می شود.
مرحله 2) پیکربندی Keepalive و HAProxy
با استفاده از دستور زیر Keepalived و haproxy را روی همهی node های master نصب میکنیم:
dnf install haproxy keepalived -y
ابتدا Keepalived را بر روی k8s-master-1 پیکربندی میکنیم، اسکریپت check_apiserver.sh را ایجاد کرده و محتوای زیر را وارد میکنیم:
vim /etc/keepalived/check_apiserver.sh
#!/bin/sh
APISERVER_VIP=192.168.122.45
APISERVER_DEST_PORT=6443
errorExit() {
echo "*** $*" 1>&2
exit 1
}
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi
مجوز اجرایی را تنظیم میکنیم
chmod +x /etc/keepalived/check_apiserver.sh
از فایل keepalived.conf پشتیبان تهیه میکنیم و سپس فایل را کوتاه میکنیم.
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf-org
sh -c '> /etc/keepalived/keepalived.conf'
اکنون محتوای زیر را در پرونده /etc/keepalived/keepalived.conf
جایگذاری میکنیم:
vim /etc/keepalived/keepalived.conf
<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><code>! /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 3
weight -2
fall 10
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface enp1s0
virtual_router_id 151
priority 255
authentication {
auth_type PASS
auth_pass P@##D321!
}
virtual_ipaddress {
192.168.122.45/24
}
track_script {
check_apiserver
}
}</code></pre>
<!-- /wp:preformatted -->
ذخیره میکنیم و فایل را میبندیم.
توجه: فقط دو پارامتر این فایل برای node های master-2 و master-3 باید تغییر کند. STATE برای master-2 و master-3 تبدیل به SLAVE می شود ، اولویت به ترتیب 254 و 253 خواهد بود.
HAProxy را روی k8s-master-1 پیکربندی میکنیم، فایل پیکربندی آن را ویرایش کرده و محتوای زیر را اضافه میکنیم:
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg-org
تمام خطوط بعد از بخش پیش فرض را حذف کرده و خطوط زیر را اضافه میکنیم:
vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# apiserver frontend which proxys to the masters
#---------------------------------------------------------------------
frontend apiserver
bind *:8443
mode tcp
option tcplog
default_backend apiserver
#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
backend apiserver
option httpchk GET /healthz
http-check expect status 200
mode tcp
option ssl-hello-chk
balance roundrobin
server k8s-master-1 192.168.122.50:6443 check
server k8s-master-2 192.168.122.51:6443 check
server k8s-master-3 192.168.122.52:6443 check
ذخیره میکنیم و فایل را میبندیم.
اکنون این سه پرونده (check_apiserver.sh، keepalived.conf و haproxy.cfg) را از k8s-master-1 به k8s-master-2 & 3 کپی میکنیم.
موارد زیر را برای حلقه اجرا میکنیم:
for f in k8s-master-2 k8s-master-3; do scp /etc/keepalived/check_apiserver.sh /etc/keepalived/keepalived.conf root@$f:/etc/keepalived; scp /etc/haproxy/haproxy.cfg root@$f:/etc/haproxy; done
توجه: فراموش نکنید که دو پارامتری که در بالا بحث کردیم را در پرونده keepalived.conf برای k8s-master-2 & 3 تغییر دهید
در صورتی که فایروال روی node های master اجرا می شود ، قوانین فایروال را بر روی هر سه master node اضافه میکنیم:
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
firewall-cmd --permanent --add-port=8443/tcp
firewall-cmd --reload
حالا با استفاده از دستورات زیر سرویس Keepalived و haproxy را در هر سه master شروع و فعال میکنیم:
systemctl enable keepalived --now && systemctl enable haproxy --now
پس از شروع موفقیت آمیز این سرویس ها، بررسی کنید که آیا VIP (IP مجازی) در k8s-master-1 فعال است یا خیر زیرا ما k8s-master-1 را به عنوان MASTER NODE در پرونده پیکربندی Keepalived مشخص کرده ایم.
خروجی فوق تأیید می کند که VIP در k8s-master-1 فعال شده است.
مرحله 3) Swap را غیرفعال ، SELinux و فایروال را تنظیم کنید
Swap Space را در همه node ها از جمله node های worker غیرفعال میکنیم، دستورات زیر را اجرا میکنیم:
swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
SELinux را به عنوان Permissive در همه node های master و worker تنظیم میکنیم.
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
تنظیمات فایروال روی node های Master
اگر فایروال در node های Master اجرا می شود ، پورت های زیر را در فایروال باز میکنیم:
دستور firewall-cmd زیر را روی همه node های master اجرا میکنیم
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10251/tcp
firewall-cmd --permanent --add-port=10252/tcp
firewall-cmd --permanent --add-port=179/tcp
firewall-cmd --permanent --add-port=4789/udp
firewall-cmd --reload
modprobe br_netfilter
sh -c "echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables"
sh -c "echo '1' > /proc/sys/net/ipv4/ip_forward"
تنظیمات فایروال روی node های Worker
اگر فایروال در node های Worker اجرا می شود ، پورت های زیر را در فایروال باز میکنیم:
دستورات زیر را بر روی تمام node های worker اجرا میکنیم،
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=30000-32767/tcp
firewall-cmd --permanent --add-port=179/tcp
firewall-cmd --permanent --add-port=4789/udp
firewall-cmd --reload
modprobe br_netfilter
sh -c "echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables"
sh -c "echo '1' > /proc/sys/net/ipv4/ip_forward"
مرحله 4) نصب Docker به عنوان Container Runtime (CRI) روی node های master و worker
Docker را روی همه node های master و node های worker نصب میکنیم:
# (Install Docker CE)
## Set up the repository
### Install required packages
yum install -y yum-utils device-mapper-persistent-data lvm2
## Add the Docker repository
yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker CE
yum update -y && sudo yum install -y \
containerd.io \
docker-ce \
docker-ce-cli
## Create /etc/docker
mkdir /etc/docker
# Set up the Docker daemon
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
# Create /etc/systemd/system/docker.service.d
mkdir -p /etc/systemd/system/docker.service.d
# Restart Docker
systemctl daemon-reload
systemctl restart docker && systemctl enable docker
برای اطلاع بیشتر از Container runtimes میتونید این لینک را مطالعه کنید.
توجه: اگر هنگام نصب داکر با خطای podman مواجه شدید و داکر نصب نشد، دستور زیر را وارد کنید:
dnf install docker-ce --nobest -y --allowerasing
مرحله 5) نصب Kubeadm ، kubelet و kubectl
kubeadm ، kubelet و kubectl را روی node های master و node های workerنصب میکنیم. قبل از نصب این بسته ها، باید مخزن Kubernetes را پیکربندی کنیم، دستور زیر را بر روی node های master و node های worker اجرا میکنیم:
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
برای نصب این بسته ها، زیر دستور را اجرا میکنیم:
dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
برای فعال کردن سرویس kubelet در همه node ها، دستور systemctl زیر را اجرا میکنیم:
systemctl enable kubelet --now
مرحله 6) راهاندازی کلاستر Kubernetes
اکنون به اولین master node / control plane node میرویم و دستور زیر را اجرا میکنیم:
kubeadm init --control-plane-endpoint "vip-k8s-master:8443" --upload-certs
در دستور بالا ، --control-plane-endpoint
نام در dns و پورت را برای لودبالانسر (kube-apiserver) تنظیم می کند، در اینجا “vip-k8s-master” نام و پورت “8443” است، علاوه بر این، گزینه --upload-certs
گواهینامه ها را به طور خودکار بین node های master به اشتراک می گذارد.
خروجی دستور kubeadm چیزی مانند زیر است:
خروجی بالا تأیید می کند که کلاستر Kubernetes با موفقیت تنظیم شده است. در خروجی همچنین دستوراتی را برای دیگر node های master و worker برای پیوستن به کلاستر دریافت کردیم.
توجه: توصیه می شود این خروجی را برای ارجاع در آینده در یک فایل متنی کپی کنید.
دستورات زیر را در k8s-master-1 اجرا میکنیم تا به کاربر محلی اجازه دهد از دستور kubectl برای تعامل با کلاستر استفاده کند:
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
حالا باید pod شبکه (CNI – Container Network Interface) را deploy (مستقر) کنیم، در اینجا من از calico استفاده میکنم. طبق دستور kubectl را اجرا میکنیم:
kubectl apply -f https://docs.projectcalico.org/v3.14/manifests/calico.yaml
هنگامی که pod شبکه با موفقیت استقرار یافت، دو master node باقی مانده را به کلاستر اضافه میکنیم.
kubeadm join vip-k8s-master:8443 --token ugm2kb.qbkggfo8rjfn3mzz \
--discovery-token-ca-cert-hash sha256:cdf84253458bdcd44de7fcdd876f10a24cfac06f8fc161a2e1bbb6a44f74f9c3 \
--control-plane --certificate-key 9a7c642d366255f4b9bc01379f8579ed8ba4ad9affc8292be59d62f31330e444
و همینطور روی master node 3 :
kubeadm join vip-k8s-master:8443 --token ugm2kb.qbkggfo8rjfn3mzz \
--discovery-token-ca-cert-hash sha256:cdf84253458bdcd44de7fcdd876f10a24cfac06f8fc161a2e1bbb6a44f74f9c3 \
--control-plane --certificate-key 9a7c642d366255f4b9bc01379f8579ed8ba4ad9affc8292be59d62f31330e444
خروجی شبیه زیر خواهد بود:
خروجی بالا تایید می کند که k8s-master-3 نیز با موفقیت به کلاستر پیوسته است. بیایید وضعیت node ها را با دستور kubectl بررسی کنیم، به k8s-master-1 میرویم و دستور زیر را اجرا میکنیم:
هر سه master node ما آماده هستند و به کلاستر اضافه شده اند.
مرحله 7) اضافه کردن Worker به کلاستر Kubernetes
برای پیوستن node های worker به کلاستر، دستور مربوط به worker node ها را از خروجی کپی کرده و آن را روی هر دو worker node قرار دهید:
kubeadm join vip-k8s-master:8443 --token ugm2kb.qbkggfo8rjfn3mzz \
--discovery-token-ca-cert-hash sha256:cdf84253458bdcd44de7fcdd876f10a24cfac06f8fc161a2e1bbb6a44f74f9c3
kubeadm join vip-k8s-master:8443 --token ugm2kb.qbkggfo8rjfn3mzz \
--discovery-token-ca-cert-hash sha256:cdf84253458bdcd44de7fcdd876f10a24cfac06f8fc161a2e1bbb6a44f74f9c3
اکنون به k8s-master-1 بروید و دستور kubectl را اجرا کنید:
kubectl get nodes
خروجی بالا تأیید می کند که هر دو worker نیز به کلاستر پیوسته اند و در حالت آماده هستند.
برای تایید وضعیت Pod های مستقر شده در فضای نام kube-system دستور زیر را اجرا کنید:
kubectl get pods -n kube-system
مرحله 8) تست HA کلاستر Kubernetes
بیایید سعی کنیم از طریق ماشین از راه دور (من از یک ماشین centos 8 با آدرس 192.168.122.60 با اسم k8s-cli استفاده کرده ام) با استفاده از نام و پورت load balancer به کلاستر متصل شویم. ابتدا بر روی دستگاه از راه دور، ما باید بسته kubectl را نصب کنیم. برای تنظیم مخازن kubernetes زیر دستور را اجرا میکنیم:
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
sudo yum install -y kubectl --disableexcludes=kubernetes
حالا خط زیر را به فایل /etc/host
اضافه میکنیم:
192.168.122.45 vip-k8s-master
دایرکتوری kube را ایجاد کرده و پرونده /etc/kubernetes/admin.conf
را از k8s-master-1 در $HOME/.kube/config
کپی میکنیم
mkdir -p $HOME/.kube
scp [email protected]:/etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
حالا دستور kubectl get nodes
را اجرا میکنیم
root@k8s-cli:~# kubectl get nodes
حالا یک deployment با نام nginx-lab با ایمیج “nginx” ایجاد کنیم و سپس این deployment را به عنوان سرویس از نوع “NodePort” منتشر میکنیم.
root@k8s-cli:~# kubectl create deployment nginx-lab --image=nginx
root@k8s-cli:~# kubectl get deployments.apps nginx-lab
root@k8s-cli:~# kubectl get pods
بیایید سعی کنیم کپی ها را از 1 تا 4 مقیاس بندی کنیم (SCALE)، دستور زیر را اجرا میکنیم:
root@k8s-cli:~# kubectl scale deployment nginx-lab --replicas=4
root@k8s-cli:~# kubectl get deployments.apps nginx-lab
اکنون deployment را به عنوان سرویس expose میکنیم:
root@k8s-cli:~# kubectl expose deployment nginx-lab --name=nginx-lab --type=NodePort --port=80 --target-port=80
جزئیات پورت را دریافت میکنیم و سعی میکنیم با استفاده از curl به وب سرور nginx دسترسی پیدا کنیم:
root@k8s-cli:~# kubectl get svc nginx-lab
برای دسترسی به وب سرور nginx می توانیم از IP هر master node یا worker و پورت “30166” استفاده کنیم.
root@k8s-cli:~# curl http://192.168.122.54:30166
خروجی:
این تایید می کند که ما با موفقیت کلاستر Kubernetes را با استفاده از kubeadm در سرورهای CentOS 8 ایجاد کرده ایم.