كيف يدعم APISIX Ingress Controller آلاف نسخ الـ Pod؟

Xin Rong

October 21, 2022

Technology

1000+ من الـ Kubernetes Pods

تُعتبر الـ Pods أصغر كائنات قابلة للنشر في Kubernetes. نستخدم الـ Pod لتشغيل نسخة واحدة من التطبيق، لذلك نقوم بتخصيص موارد محدودة للـ Pod بسبب قابلية التوسع. ومع ذلك، إذا واجهنا سيناريوهات ذات حركة مرور عالية، سنستخدم التوسع الأفقي للتعامل معها.

على سبيل المثال، بالنسبة لتجار التجزئة عبر الإنترنت، سيؤدي يوم الجمعة الأسود إلى زيادة سريعة في حركة المرور. للتعامل مع هذا السيناريو، يجب علينا توسيع الخدمات تلقائيًا للتعامل مع المزيد من حركة المرور. سنقوم بنشر المزيد من النسخ بناءً على استراتيجية التوسع التلقائي، مما يؤدي إلى المزيد من الـ Pods.

كل Pod لديه عنوان IP ديناميكي. وفرت واجهة برمجة التطبيقات (API) الخاصة بـ Endpoints طريقة مباشرة لتتبع نقاط نهاية الشبكة في Kubernetes حتى نتمكن من تحقيق موازنة الحمل من خلال مراقبة التغييرات في عنوان IP الخاص بالـ Pod بشكل منتظم. ومع ذلك، مع نمو مجموعات Kubernetes والخدمات للتعامل مع المزيد من حركة المرور إلى المزيد من الـ Pods، على سبيل المثال، سيناريو الجمعة الأسود المذكور أعلاه، يستمر عدد الـ Pods في الزيادة، وتصبح واجهة برمجة التطبيقات (API) الخاصة بـ Endpoints أكبر. وبالتالي، أصبحت قيود واجهة برمجة التطبيقات (API) الخاصة بـ Endpoints أكثر وضوحًا، بل وأصبحت عائقًا للأداء.

لحل مشكلة القيود في واجهة برمجة التطبيقات (API) الخاصة بـ Endpoints، بدأت Kubernetes بدعم واجهة برمجة التطبيقات (API) الخاصة بـ EndpointSlice في الإصدار v1.21. تساعد واجهة برمجة التطبيقات (API) الخاصة بـ EndpointSlice في حل مشكلة الأداء في التعامل مع عدد كبير من نقاط نهاية الشبكة في واجهة برمجة التطبيقات (API) الخاصة بـ Endpoints ولديها قابلية توسع وامتداد ممتازة.

يمكننا معرفة الفروق بينهما مباشرة من الرسم البياني أدناه:

  • التغييرات في Endpoints أثناء ذروة حركة المرور

Endpoints أثناء ذروة حركة المرور

  • التغييرات في Endpointslices أثناء ذروة حركة المرور

Endpointslices أثناء ذروة حركة المرور

في Kubernetes، كيف تتواصل التطبيقات مع بعضها البعض؟ ما هي الفروق المحددة بين Endpoints و EndpointSlice؟ ما هي العلاقة بين Pod و Endpoints/EndpointSlice؟ كيف يدعم APISIX هذه الميزات، وكيفية تثبيتها واستخدامها؟ سنركز على هذه الأسئلة في هذه المقالة.

كيفية الوصول إلى التطبيقات في Kubernetes

عبر Service

كل Pod لديه عنوان IP فريد في Kubernetes. عادةً، سيقوم Service ببناء اتصالات مع Pod باستخدام selector، ويوفر نفس اسم النطاق الفرعي لـ DNS، ويحقق موازنة الحمل. بالإضافة إلى ذلك، يمكن للتطبيقات داخل مجموعة Kubernetes استخدام DNS للتواصل مع بعضها البعض.

عند إنشاء Service، ستقوم Kubernetes بتوصيل Service مع مورد Endpoints. ومع ذلك، إذا لم يحدد Service أي selectors، فلن تقوم Kubernetes بإنشاء Endpoints تلقائيًا لـ Service.

ما هو Endpoints، وما هي العلاقة مع Pod

Endpoints هو كائن مورد في Kubernetes، يتم تخزينه في etcd، ويشمل مراجع لعناوين الوصول إلى مجموعة من الـ Pods التي تطابق Service. لذلك، يمكن أن يكون لكل Service مورد Endpoints واحد فقط. سيقوم مورد Endpoints بمراقبة مجموعات الـ Pods وتحديثها بشكل متزامن بمجرد تغيير أي Pod في Service.

  1. نشر 3 نسخ من httpbin، والتحقق من حالة الـ Pods، بما في ذلك معلومات IP
$ kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS        AGE   IP            NODE             NOMINATED NODE   READINESS GATES
httpbin-deployment-fdd7d8dfb-8sxxq   1/1     Running   0               49m   10.1.36.133   docker-desktop   <none>           <none>
httpbin-deployment-fdd7d8dfb-bjw99   1/1     Running   4 (5h39m ago)   23d   10.1.36.125   docker-desktop   <none>           <none>
httpbin-deployment-fdd7d8dfb-r5nf9   1/1     Running   0               49m   10.1.36.131   docker-desktop   <none>           <none>
  • إنشاء خدمة httpbin، والتحقق من حالة نقاط نهاية Endpoints
$ kubectl get endpoints httpbin
NAME      ENDPOINTS                                      AGE
httpbin   10.1.36.125:80,10.1.36.131:80,10.1.36.133:80   23d

من المثالين أعلاه، يمكننا أن نرى أن كل نقطة نهاية شبكة واحدة لـ httpbin في Endpoints تطابق عنوان IP لـ Pod.

عيوب Endpoints

  1. لدى Endpoints حد تخزين، إذا كان أي مورد Endpoints يحتوي على أكثر من 1000 نقطة نهاية، فسيقوم متحكم Endpoints بقطع النقاط النهائية إلى 1000.
  2. يمكن أن يكون لكل Service مورد Endpoints واحد فقط، مما يعني أن مورد Endpoints يحتاج إلى تخزين عناوين IP ومعلومات شبكة أخرى لكل Pod الذي يدعم Service المقابل. نتيجة لذلك، يصبح مورد API الخاص بـ Endpoints كبيرًا، ويجب تحديثه عند تغيير نقطة نهاية شبكة واحدة في المورد. عندما تحتاج الأعمال إلى تغييرات متكررة في النقاط النهائية، سيتم إرسال مورد API كبير إلى بعضها البعض، مما يؤثر على أداء مكونات Kubernetes.

ما هو Endpointslices

Endpointslices هو بديل أكثر قابلية للتوسع والامتداد لـ Endpoints ويساعد في التعامل مع مشكلة الأداء الناتجة عن معالجة عدد كبير من نقاط نهاية الشبكة. كما يساعد في توفير منصة قابلة للامتداد لميزات إضافية مثل التوجيه الطوبولوجي. تم دعم هذه الميزة في Kubernetes v1.21.

تم تصميم واجهة برمجة التطبيقات (API) الخاصة بـ EndpointSlice لمعالجة هذه المشكلة باستخدام نهج مشابه للتجزئة. بدلاً من تتبع جميع عناوين IP الخاصة بـ Pods لـ Service باستخدام مورد Endpoints واحد، نقوم بتقسيمها إلى عدة EndpointSlices أصغر.

بشكل افتراضي، تقوم لوحة التحكم بإنشاء وإدارة EndpointSlices بحيث لا تحتوي على أكثر من 100 نقطة نهاية لكل منها. يمكنك تكوين هذا باستخدام علامة --max-endpoints-per-slice الخاصة بـ kube-controller-manager، حتى 1000.

لماذا نحتاج إليها

فكر في سيناريو

افترض أن هناك Service مدعومًا بـ 2000 Pod، مما قد يؤدي إلى مورد Endpoints بحجم 1.0 ميجابايت. في بيئة الإنتاج، إذا كان هذا Service يحتاج إلى تحديثات متتالية أو هجرة نقاط نهاية، فسيتم تحديث موارد Endpoints بشكل متكرر. فكر في أن التحديثات المتتالية ستؤدي إلى استبدال جميع الـ Pods بسبب الحد الأقصى لحجم أي طلب في etcd. قام Kubernetes بتعيين حد أقصى لـ 1000 نقطة نهاية لـ Endpoints. إذا كان هناك أكثر من 1000 نقطة نهاية، فلن يكون لدى مورد Endpoints أي مراجع على نقاط نهاية شبكة إضافية.

إذا كان Service يحتاج إلى تحديثات متتالية متعددة بسبب بعض الاحتياجات الخاصة؛ في هذه الحالة، سيتم نقل كائن مورد API كبير بين مكونات Kubernetes، مما يؤثر بشكل كبير على أداء مكونات Kubernetes.

ماذا لو استخدمنا EndpointSlice

افترض أن هناك Service مدعومًا بـ 2000 Pod، وقمنا بتعيين 100 نقطة نهاية لكل EndpointSlices في التكوين، فسينتهي بنا الأمر بـ 20 EndpointSlices. الآن عند إضافة أو إزالة Pod، يحتاج فقط EndpointSlice صغير واحد إلى التحديث. من الواضح أن هذا تحسن ملحوظ في قابلية التوسع وامتداد الشبكة. افترض أن كل Service لديه متطلبات توسع تلقائي. في هذه الحالة، سيقوم Service بنشر المزيد من الـ Pods، وسيتم تحديث مورد Endpoints بشكل متكرر للتعامل مع زيادة حركة المرور عند حدوث ذروة حركة المرور، وسيصبح الفرق أكثر وضوحًا. والأهم من ذلك، الآن لا نحتاج إلى تخزين جميع عناوين IP الخاصة بـ Pods لـ Service في مورد واحد، ولا داعي للقلق بشأن الحد الأقصى لحجم الكائنات المخزنة في etcd.

استنتاج Endpoints مقابل EndpointSlice

لأن EndpointSlice مدعوم منذ Kubernetes v1.21، فإن جميع الاستنتاجات تشير إلى Kubernetes v1.21.

حالات استخدام Endpoints:

  • هناك حاجة للتوسع التلقائي، ولكن عدد الـ Pods صغير نسبيًا، ولن تسبب تحويلات الموارد حركة مرور شبكية كبيرة واحتياجات معالجة إضافية.
  • لا توجد حاجة للتوسع التلقائي، ولن يكون عدد الـ Pods كبيرًا. ومع ذلك، حتى إذا كان عدد الـ Pods ثابتًا، فلا يمكن لـ Service تجنب التحديثات المتتالية والأعطال.

حالات استخدام EndpointSlice:

  • هناك حاجة للتوسع التلقائي، وعدد الـ Pods كبير (مئات الـ Pods)
  • عدد الـ Pods كبير جدًا (مئات الـ Pods) بسبب الحد الأقصى لنقاط النهاية لـ Endpoints وهو 1000؛ أي Pod يحتوي على أكثر من 1000 نقطة نهاية يجب أن يستخدم EndpointSlice.

الممارسة في APISIX Ingress Controller

يحقق APISIX Ingress Controller موازنة الحمل والتحقق من الصحة من خلال مراقبة تغييرات مورد Endpoints أو EndpointSlice. لدعم Kubernetes v1.16+، سيستخدم APISIX Ingress Controller Endpoints بشكل افتراضي أثناء التثبيت.

إذا كان إصدار المجموعة لديك هو Kubernetes v1.21+، فستحتاج إلى تحديد علامة watchEndpointSlice=true لدعم ميزة EndpointSlice أثناء تثبيت APISIX Ingress Controller.

ملاحظة: في المجموعات التي تعمل بإصدار Kubernetes v1.21+، نوصي باستخدام ميزة Endpointslice، وإلا عندما يتجاوز عدد الـ Pods قيمة التكوين لعلامة --max-endpoints-per-slice، سيتم فقد التكوين بسبب أن APISIX Ingress Controller يراقب كائن مورد Endpoints.

إنشاء Service مدعوم بـ 20 نسخة من الـ Pods

تكوين تطبيق httpbin Service في Kubernetes، وإنشاء 20 نسخة من الـ Pods

  • - kubectl apply -f httpbin-deploy.yaml
# htppbin-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-deployment
spec:
  replicas: 20
  selector:
    matchLabels:
      app: httpbin-deployment
  strategy:
    rollingUpdate:
      maxSurge: 50%
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: httpbin-deployment
    spec:
      terminationGracePeriodSeconds: 0
      containers:
        - livenessProbe:
            failureThreshold: 3
            initialDelaySeconds: 2
            periodSeconds: 5
            successThreshold: 1
            tcpSocket:
              port: 80
            timeoutSeconds: 2
          readinessProbe:
            failureThreshold: 3
            initialDelaySeconds: 2
            periodSeconds: 5
            successThreshold: 1
            tcpSocket:
              port: 80
            timeoutSeconds: 2
          image: "kennethreitz/httpbin:latest"
          imagePullPolicy: IfNotPresent
          name: httpbin-deployment
          ports:
            - containerPort: 80
              name: "http"
              protocol: "TCP"

---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  selector:
    app: httpbin-deployment
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  type: ClusterIP

التوجيه عبر APISIX Ingress

  • استخدام Helm لتثبيت APISIX Ingress Controller

استخدم --set ingress-controller.config.kubernetes.watchEndpointSlice=true لتمكين دعم ميزة EndpointSlice.

helm repo add apisix https://charts.apiseven.com
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

kubectl create ns ingress-apisix
helm install apisix apisix/apisix \
  --set gateway.type=NodePort \
  --set ingress-controller.enabled=true \
  --namespace ingress-apisix \
  --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix \
  --set ingress-controller.config.kubernetes.watchEndpointSlice=true
  • استخدام مورد CRD للتوجيه

لا يمكن للمستخدمين ملاحظة دعم ميزات Endpoints و EndpointSlice في APISIX Ingress Controller، وتكويناتها هي نفسها

apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: httpbin-route
spec:
  http:
    - name: rule
      match:
        hosts:
          - httpbin.org
        paths:
          - /get
      backends:
        - serviceName: httpbin
          servicePort: 80
  • بالتحقق من Pod الخاص بـ APISIX، يمكننا أن نرى أن حقل nodes الخاص بكائن upstream في APISIX يحتوي على عناوين IP لـ 20 Pods.
kubectl exec -it ${Pod for APISIX} -n ingress-apisix -- curl "http://127.0.0.1:9180/apisix/admin/upstreams" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1'
{
    "action": "get",
    "count": 1,
    "node": {
        "key": "\/apisix\/upstreams",
        "nodes": [
            {
                "value": {
                    "hash_on": "vars",
                    "desc": "Created by apisix-ingress-controller, DO NOT modify it manually",
                    "pass_host": "pass",
                    "nodes": [
                        {
                            "weight": 100,
                            "host": "10.1.36.100",
                            "priority": 0,
                            "port": 80
                        },
                        {
                            "weight": 100,
                            "host": "10.1.36.101",
                            "priority": 0,
                            "port": 80
                        },
                        {
                            "weight": 100,
                            "host": "10.1.36.102",
                            "priority": 0,
                            "port": 80
                        },
                        {
                            "weight": 100,
                            "host": "10.1.36.103",
                            "priority": 0,
                            "port": 80
                        },
                        {
                            "weight": 100,
                            "host": "10.1.36.104",
                            "priority": 0,
                            "port": 80
                        },
                        {
                            "weight": 100,
                            "host": "10.1.36.109",
                            "priority": 0,
                            "port": 80
                        },
                        {
                            "weight": 100,
                            "host": "10.1.36.92",
                            "priority": 0,
                            "port": 80
                        }
                        ... // تجاهل 13 عقدة أدناه
                        // 10.1.36.118
                        // 10.1.36.115
                        // 10.1.36.116
                        // 10.1.36.106
                        // 10.1.36.113
                        // 10.1.36.111
                        // 10.1.36.108
                        // 10.1.36.114
                        // 10.1.36.107
                        // 10.1.36.110
                        // 10.1.36.105
                        // 10.1.36.112
                        // 10.1.36.117
                    ],
                    "labels": {
                        "managed-by": "apisix-ingress-controller"
                    },
                    "type": "roundrobin",
                    "name": "default_httpbin_80",
                    "scheme": "http"
                },
                "key": "\/apisix\/upstreams\/5ce57b8e"
            }
        ],
        "dir": true
    }
}
  • المطابقة مع نقاط نهاية شبكة EndpointSlice
addressType: IPv4
apiVersion: discovery.k8s.io/v1
endpoints:
- addresses:
  - 10.1.36.92
  ...
- addresses:
  - 10.1.36.100
  ...
- addresses:
  - 10.1.36.104
  ...
- addresses:
  - 10.1.36.102
  ...
- addresses:
  - 10.1.36.101
  ...
- addresses:
  - 10.1.36.103
  ...
- addresses:
  - 10.1.36.109
  ...
- addresses:
  - 10.1.36.118
  ...
- addresses:
  - 10.1.36.115
  ...
- addresses:
  - 10.1.36.116
  ...
- addresses:
  - 10.1.36.106
  ...
- addresses:
  - 10.1.36.113
  ...
- addresses:
  - 10.1.36.111
  ...
- addresses:
  - 10.1.36.108
  ...
- addresses:
  - 10.1.36.114
  ...
- addresses:
  - 10.1.36.107
  ...
- addresses:
  - 10.1.36.110
  ...
- addresses:
  - 10.1.36.105
  ...
- addresses:
  - 10.1.36.112
  ...
- addresses:
  - 10.1.36.117
  ...
kind: EndpointSlice
metadata:
  labels:
    endpointslice.kubernetes.io/managed-by: endpointslice-controller.k8s.io
    kubernetes.io/service-name: httpbin
  name: httpbin-dkvtr
  namespace: default
ports:
- name: http
  port: 80
  protocol: TCP

استنتاج

تقدم هذه المقالة سيناريوهات حيث يحتاج Kubernetes إلى نشر عدد كبير من الـ Pods والمشاكل التي نواجهها. كما تقارن الفروق بين Endpoints و EndpointSlice، وتقدم طريقة تمكين ميزة EndpointSlice أثناء تثبيت APISIX Ingress Controller. إذا كان إصدار المجموعة لديك هو Kubernetes v1.21+، نوصي بتمكين ميزة EndpointSlice أثناء تثبيت APISIX Ingress Controller. وبالتالي، يمكن تجنب فقد التكوين، ولا داعي للقلق بشأن قيمة التكوين لعلامة --max-endpoints-per-slice.

Tags: