بلاگ/راه‌اندازی MetalLB برای Load Balancer در کلاستر Kubernetes خودمیزبان روی سرور اختصاصی و VPS
به‌روز شده

راه‌اندازی MetalLB برای Load Balancer در کلاستر Kubernetes خودمیزبان روی سرور اختصاصی و VPS

1405/05/300 بازدید
راه‌اندازی MetalLB برای Load Balancer در کلاستر Kubernetes خودمیزبان روی سرور اختصاصی و VPS

راه‌اندازی MetalLB برای Load Balancer در کلاستر Kubernetes خودمیزبان روی سرور اختصاصی و VPS

نمای کلی MetalLB در کلاستر Kubernetes خودمیزبان در سرویس‌های مدیریت‌شده Kubernetes، ایجاد یک Service از نوع LoadBalancer معمولاً کافی است تا ارائه‌دهنده ابری یک آدرس IP عمومی و Load Balancer در اختیار کلاستر قرار دهد. اما در کلاستر خودمیزبان که روی سرور اختصاصی، ماشین مجازی یا VPS اجرا می‌شود، چنین یکپارچگی‌ای به‌صورت پیش‌فرض وجود ندارد. نتیجه این است که پس از ساخت سرویس، مقدار EXTERNAL-IP برای مدت نامحدود در وضعیت <pending> باقی می‌ماند. MetalLB این خلأ را پر می‌کند و امکان تخصیص IP به سرویس‌های LoadBalancer را در محیط‌های فاقد Load Balancer ابری فراهم می‌سازد. در این آموزش، راه‌اندازی MetalLB در Kubernetes را با تمرکز بر حالت Layer2 بررسی می‌کنیم، یک بازه IP برای آن تعریف می‌کنیم و روش عیب‌یابی مشکلات رایج را توضیح می‌دهیم.

MetalLB چیست و چه مشکلی را حل می‌کند؟

MetalLB یک پیاده‌سازی Load Balancer شبکه برای کلاسترهای Kubernetes بدون زیرساخت ابری یکپارچه است. این ابزار به Serviceهای نوع LoadBalancer آدرس IP اختصاص می‌دهد و ترافیک ورودی را به یکی از نودهای کلاستر هدایت می‌کند. فرض کنید سرویس زیر را بدون MetalLB در یک کلاستر خودمیزبان ایجاد کرده‌اید:

apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - name: http
      port: 80
      targetPort: 8080

پس از اجرای دستور زیر:

kubectl get service web-service

احتمالاً چنین خروجی‌ای می‌بینید:

NAME          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)
web-service   LoadBalancer   10.96.120.15    <pending>     80:31482/TCP

کنترل‌پلین Kubernetes منتظر یک مؤلفه خارجی است تا برای سرویس IP فراهم کند. در سرویس‌های ابری، Cloud Controller Manager این وظیفه را انجام می‌دهد؛ در کلاستر خودمیزبان، MetalLB می‌تواند آن را بر عهده بگیرد. MetalLB جایگزین Ingress Controller نیست. MetalLB دسترسی شبکه به سرویس را فراهم می‌کند، در حالی که Ingress Controller معمولاً مسیریابی HTTP و HTTPS را بر اساس دامنه و مسیر انجام می‌دهد. در بسیاری از معماری‌ها، MetalLB یک IP به سرویس NGINX Ingress یا Traefik می‌دهد و سپس Ingress ترافیک چند دامنه را مدیریت می‌کند.

پیش‌نیازهای نصب MetalLB

پیش از نصب، این موارد را بررسی کنید: - یک کلاستر Kubernetes سالم با دسترسی مدیریتی kubectl (در صورت نیاز به ساخت چنین کلاستری، راهنمای راه‌اندازی کلاستر Kubernetes روی سرور اختصاصی و VPS با kubeadm را ببینید) - دست‌کم یک بازه IP آزاد و خارج از محدوده DHCP - دسترسی شبکه‌ای نودها به بازه انتخاب‌شده - فعال بودن ارتباط موردنیاز بین نودها - سازگاری افزونه CNI و تنظیمات kube-proxy با روش انتخابی - امکان ارسال و دریافت ترافیک برای IPهای اضافه در شبکه دیتاسنتر یا ارائه‌دهنده VPS وضعیت کلاستر را ابتدا بررسی کنید:

kubectl get nodes -o wide
kubectl get pods -A

همه نودهای مورد استفاده باید در وضعیت Ready باشند. اگر شبکه داخلی کلاستر یا CNI مشکل دارد، نصب MetalLB آن مشکل را برطرف نخواهد کرد.

انتخاب بازه IP مناسب

در حالت Layer2 باید مجموعه‌ای از IPهای آزاد همان شبکه محلی را در اختیار MetalLB قرار دهید. برای مثال، اگر شبکه سرورها 192.168.10.0/24 است و DHCP تنها آدرس‌های 192.168.10.10 تا 192.168.10.150 را توزیع می‌کند، می‌توان بازه‌ای مانند زیر را رزرو کرد:

192.168.10.200-192.168.10.220

این آدرس‌ها نباید به سرور، روتر، ماشین مجازی یا دستگاه دیگری اختصاص داشته باشند. هم‌پوشانی Pool با DHCP می‌تواند باعث تعارض IP و قطعی‌های نامنظم شود. در VPS عمومی، صرفاً انتخاب چند IP دلخواه از subnet ارائه‌دهنده کافی نیست. بسیاری از ارائه‌دهندگان، آدرس‌های IP را با MAC، پورت مجازی یا مسیر مشخص محدود می‌کنند و ممکن است ARP اعلام‌شده توسط MetalLB را نپذیرند. در این شرایط باید IP اضافه یا Floating IP تهیه و شیوه مسیریابی آن را با مستندات ارائه‌دهنده هماهنگ کنید.

مقایسه حالت Layer2 و BGP در MetalLB

MetalLB می‌تواند آدرس سرویس‌ها را با دو رویکرد اصلی در شبکه اعلام کند: | ویژگی | Layer2 | BGP | |---|---|---| | پیچیدگی راه‌اندازی | کم | بیشتر | | نیاز به روتر سازگار | ندارد | دارد | | روش اعلام IP | ARP در IPv4 یا NDP در IPv6 | پروتکل مسیریابی BGP | | مسیر ورود ترافیک | از طریق یک نود منتخب | امکان توزیع میان چند نود | | مناسب برای | آزمایشگاه، شبکه محلی و کلاستر کوچک | دیتاسنتر و شبکه حرفه‌ای | | ظرفیت ورودی | محدود به مسیر نود اعلان‌کننده | مقیاس‌پذیرتر | | Failover | با انتخاب نود جدید | بر اساس تغییر مسیرهای BGP | برای بیشتر کلاسترهای کوچک روی سرور اختصاصی، Layer2 نقطه شروع مناسبی است. راه‌اندازی آن به تغییر تنظیمات روتر نیاز ندارد و عیب‌یابی ساده‌تری دارد. BGP زمانی ارزشمند است که کنترل روتر شبکه را در اختیار دارید و به مسیریابی چندمسیره یا مقیاس بالاتر نیاز دارید.

نصب MetalLB در کلاستر Kubernetes

پیش از اجرا، نسخه انتشار را از مستندات رسمی MetalLB بررسی و نسخه مشخصی را در محیط عملیاتی pin کنید. استفاده بدون بررسی از یک آدرس متغیر مانند main می‌تواند باعث تغییر ناخواسته منابع نصب شود. نمونه نصب با manifest نسخه مشخص:

kubectl apply -f \
  https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml

سپس منتظر آماده شدن Deployment کنترلر بمانید:

kubectl rollout status deployment/controller -n metallb-system

و وضعیت تمام Podها را ببینید:

kubectl get pods -n metallb-system -o wide

MetalLB معمولاً شامل این مؤلفه‌هاست: - controller: تخصیص IP به Serviceها را مدیریت می‌کند. - speaker: به‌صورت DaemonSet روی نودها اجرا می‌شود و IP سرویس را در شبکه اعلام می‌کند. اگر Podهای speaker روی بعضی نودها ساخته نشده‌اند، وضعیت DaemonSet، محدودیت‌های node selector، taintها و رویدادهای namespace را بررسی کنید:

kubectl get daemonset -n metallb-system
kubectl get events -n metallb-system --sort-by=.lastTimestamp

پیکربندی IPAddressPool و L2Advertisement

نسخه‌های جدید MetalLB از منابع سفارشی مانند IPAddressPool و L2Advertisement استفاده می‌کنند. آموزش‌های قدیمی ممکن است هنوز تنظیمات مبتنی بر ConfigMap را نشان دهند؛ برای نصب‌های جدید بهتر است از CRDهای فعلی استفاده شود. فایل metallb-pool.yaml را با محتوای زیر بسازید و بازه آدرس را متناسب با شبکه خود تغییر دهید:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: production-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.10.200-192.168.10.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: production-l2
  namespace: metallb-system
spec:
  ipAddressPools:
    - production-pool

پیکربندی را اعمال کنید:

kubectl apply -f metallb-pool.yaml

سپس منابع ایجادشده را بررسی کنید:

kubectl get ipaddresspools -n metallb-system
kubectl get l2advertisements -n metallb-system

اگر چند subnet یا محیط جداگانه دارید، می‌توانید چند Pool تعریف کنید. همچنین می‌توان با selectorها تخصیص IP را به namespaceها یا Serviceهای خاص محدود کرد. این تفکیک برای جدا کردن سرویس‌های داخلی، آزمایشی و عمومی مفید است.

ساخت یک سرویس آزمایشی LoadBalancer

برای آزمایش، یک Deployment ساده NGINX ایجاد کنید:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: metallb-test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: metallb-test
  template:
    metadata:
      labels:
        app: metallb-test
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: metallb-test
spec:
  type: LoadBalancer
  selector:
    app: metallb-test
  ports:
    - name: http
      port: 80
      targetPort: 80

آن را اعمال کنید:

kubectl apply -f metallb-test.yaml
kubectl get service metallb-test --watch

پس از چند لحظه، یکی از IPهای Pool باید در ستون EXTERNAL-IP ظاهر شود:

NAME           TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)
metallb-test   LoadBalancer   10.96.44.21    192.168.10.200   80:32018/TCP

از دستگاهی در همان شبکه، سرویس را آزمایش کنید:

curl http://192.168.10.200

اختصاص IP به‌تنهایی تضمین نمی‌کند که مسیر شبکه بیرونی درست است. اگر IP نمایش داده می‌شود اما پاسخ دریافت نمی‌کنید، فایروال نودها، Security Group، مسیر بازگشت ترافیک و سیاست‌های شبکه را بررسی کنید.

درخواست یک IP مشخص

اگر برنامه باید آدرس ثابتی داشته باشد، می‌توانید IP مشخصی از Pool را درخواست کنید:

apiVersion: v1
kind: Service
metadata:
  name: ingress-public
  annotations:
    metallb.io/loadBalancerIPs: 192.168.10.205
spec:
  type: LoadBalancer
  selector:
    app: ingress-controller
  ports:
    - name: http
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 443

IP انتخاب‌شده باید در Pool تعریف شده و در اختیار سرویس دیگری نباشد. برای محیط عملیاتی بهتر است نگاشت IPها، سرویس‌ها و رکوردهای DNS مستند شود.

رفع مشکل EXTERNAL-IP در حالت pending

مراحل عیب‌یابی خطای EXTERNAL-IP در وضعیت pending هنگام استفاده از MetalLB در Kubernetes اگر EXTERNAL-IP همچنان <pending> است، بررسی را از Service آغاز کنید:

kubectl describe service metallb-test

بخش Events معمولاً نشان می‌دهد که تخصیص IP انجام نشده یا هیچ Pool سازگاری وجود ندارد. سپس لاگ کنترلر را ببینید:

kubectl logs -n metallb-system deployment/controller

لاگ Speakerها نیز برای مشکلات اعلان شبکه مفید است:

kubectl logs -n metallb-system daemonset/speaker --all-containers

دلایل متداول عبارت‌اند از: 1. هیچ IPAddressPool معتبری تعریف نشده است. 2. بازه IP تمام شده یا آدرس‌ها قبلاً تخصیص یافته‌اند. 3. L2Advertisement به Pool درست اشاره نمی‌کند. 4. namespace منابع اشتباه است و CRDها خارج از metallb-system ایجاد شده‌اند. 5. نسخه manifest و ساختار CRDهای پیکربندی با هم سازگار نیستند. 6. selectorهای Pool اجازه تخصیص به Service موردنظر را نمی‌دهند. برای مشاهده وضعیت همه تخصیص‌ها این دستورات مفیدند:

kubectl get services -A \
  -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,EXTERNAL-IP:.status.loadBalancer.ingress[*].ip'
kubectl describe ipaddresspool production-pool -n metallb-system

وقتی IP تخصیص یافته اما سرویس در دسترس نیست

اگر EXTERNAL-IP مقدار دارد ولی اتصال برقرار نمی‌شود، مشکل معمولاً در لایه شبکه، فایروال یا Endpointهای سرویس است. ابتدا مطمئن شوید Service به Podهای صحیح متصل است:

kubectl get endpoints metallb-test
kubectl get pods -l app=metallb-test -o wide

اگر Endpoint خالی است، selector سرویس با label پادها تطبیق ندارد یا Podها آماده نیستند. در حالت Layer2 بررسی کنید که کلاینت می‌تواند IP را از طریق ARP پیدا کند:

ip neigh show
arping 192.168.10.200

همچنین قوانین فایروال و NAT میزبان، nftables یا iptables را کنترل کنید. پورت سرویس باید در مسیر ورودی مجاز باشد و شبکه باید امکان بازگشت پاسخ به کلاینت را داشته باشد. اگر kube-proxy در حالت IPVS اجرا می‌شود، تنظیم strictARP ممکن است برای جلوگیری از پاسخ‌های ARP نادرست لازم باشد. وضعیت فعلی را بررسی کنید:

kubectl get configmap kube-proxy -n kube-system -o yaml

در صورت استفاده از IPVS، مقدار مربوطه باید در تنظیمات kube-proxy به شکل زیر باشد:

ipvs:
  strictARP: true

پس از تغییر ConfigMap، Podهای kube-proxy باید با روشی متناسب با شیوه استقرار کلاستر بازآفرینی شوند. پیش از اعمال این تغییر در محیط عملیاتی، تنظیمات فعلی را ذخیره و اثر آن را روی شبکه بررسی کنید.

محدودیت‌های مهم در VPS

روی سرور اختصاصی با شبکه Layer2 واقعی، MetalLB معمولاً ساده‌تر کار می‌کند. اما شبکه بسیاری از VPSها مجازی و محدودشده است. ارائه‌دهنده ممکن است: - ARP مربوط به IPهای ثبت‌نشده را مسدود کند. - هر IP را به یک MAC مشخص متصل کرده باشد. - فقط IP اصلی ماشین را به پورت مجازی تحویل دهد. - IP اضافه را با route ثابت، vMAC یا Floating IP ارائه کند. - ترافیک ورودی را پشت NAT قرار دهد. در چنین محیطی، ابتدا مشخص کنید ارائه‌دهنده چه روشی برای IP اضافه دارد. گاهی باید IP را به سمت یک نود route کرد، از BGP خصوصی استفاده کرد یا Load Balancer مدیریت‌شده ارائه‌دهنده را به کار گرفت. MetalLB نمی‌تواند محدودیت اعمال‌شده در لایه شبکه دیتاسنتر را دور بزند.

نکات امنیتی و عملیاتی

برای سرویس‌های عمومی، فقط پورت‌های موردنیاز را در فایروال باز کنید. اختصاص یک IP خارجی به Service به معنی امن بودن برنامه نیست. TLS، احراز هویت، محدودسازی دسترسی و به‌روزرسانی منظم همچنان ضروری هستند. برای دسترس‌پذیری بهتر نیز این موارد را در نظر بگیرید: - بیش از یک نود worker داشته باشید تا اعلان IP پس از خرابی نود منتقل شود. - برای Podهای حیاتی چند replica و PodDisruptionBudget تعریف کنید. - وضعیت controller و speaker را با ابزارهایی مانند Prometheus و Grafana مانیتور کنید. - ظرفیت IP Pool را زیر نظر داشته باشید. - IPهای اختصاص‌یافته را در DNS و مستندات زیرساخت ثبت کنید. - پس از هر تغییر شبکه، Failover را به‌صورت عملی آزمایش کنید. در حالت Layer2، یک نود ترافیک ورودی هر IP را اعلام می‌کند. Kubernetes ممکن است سپس ترافیک را به Pod روی نود دیگری منتقل کند. بنابراین این روش Failover فراهم می‌کند، اما الزاماً ترافیک ورودی را میان چند نود به‌صورت هم‌زمان توزیع نمی‌کند.

انتخاب زیرساخت مناسب برای کلاستر خودمیزبان

موفقیت راه‌اندازی MetalLB در Kubernetes تا حد زیادی به کنترل شما بر شبکه بستگی دارد. برای محیط آزمایشی، چند VPS با شبکه خصوصی می‌توانند کافی باشند؛ به شرط آنکه روش ارائه IP اضافه با MetalLB سازگار باشد. برای بارهای پرترافیک یا سناریوهایی که به کنترل بیشتر روی شبکه، منابع و مجازی‌سازی نیاز دارند، سرور اختصاصی انتخاب قابل پیش‌بینی‌تری است (تفاوت‌های دو گزینه در مقاله سرور اختصاصی چه تفاوتی با سرور مجازی دارد؟ بررسی شده است). اگر قصد دارید کلاستر Kubernetes خودمیزبان را با منابع اختصاصی و کنترل کامل‌تر راه‌اندازی کنید، می‌توانید مشخصات و گزینه‌های موجود در صفحه سرور اختصاصی آریانت را بررسی کنید. برای کلاسترهای کوچک‌تر یا محیط توسعه نیز سرور ابری می‌تواند نقطه شروع مناسبی باشد.

جمع‌بندی

MetalLB راه‌حلی کاربردی برای فعال‌سازی Service از نوع LoadBalancer در Kubernetes خودمیزبان است. برای شروع، نصب مؤلفه‌های MetalLB، تعریف IPAddressPool و ایجاد L2Advertisement کافی است. پس از آن، سرویس‌های LoadBalancer می‌توانند به‌جای ماندن در وضعیت <pending>، یک IP واقعی دریافت کنند. مهم‌ترین بخش کار انتخاب IP آزاد و اطمینان از پشتیبانی شبکه زیرساخت است. در شبکه محلی یا سرور اختصاصی، حالت Layer2 معمولاً کم‌دردسر است؛ اما روی VPS باید محدودیت‌های ARP، مسیریابی و IPهای اضافه را از قبل بررسی کرد. اگر IP تخصیص داده شد ولی سرویس در دسترس نبود، Endpointها، اعلان ARP، فایروال، تنظیمات kube-proxy و مسیر بازگشت ترافیک بهترین نقاط برای شروع عیب‌یابی هستند.