Wie unterstützt der APISIX Ingress Controller Tausende von Pod-Replikaten?
Xin Rong
October 21, 2022
1.000+ Kubernetes Pods
Pods sind die kleinsten bereitstellbaren Objekte in Kubernetes. Wir verwenden einen Pod, um eine einzelne Instanz einer Anwendung auszuführen, weshalb wir dem Pod aufgrund der Skalierbarkeit nur begrenzte Ressourcen zuweisen. Wenn wir jedoch Szenarien mit hohem Datenverkehr haben, verwenden wir horizontale Skalierung, um diese zu bewältigen.
Beispielsweise wird der Black Friday bei Online-Händlern zu einem raschen Anstieg des Datenverkehrs führen. Um dieses Szenario zu bewältigen, müssen wir die Dienste automatisch skalieren, um mehr Datenverkehr zu verarbeiten. Basierend auf der Autoscaling-Strategie würden wir mehr Replikationen bereitstellen, was zu mehr Pods führt.
Jeder Pod hat eine dynamische IP-Adresse. Die Endpoints API bietet eine einfache Möglichkeit, Netzwerkendpunkte in Kubernetes zu verfolgen, sodass wir durch die rechtzeitige Überwachung der Änderungen der Pod-IPs Lastenausgleich erreichen können. Da jedoch Kubernetes-Cluster und Services gewachsen sind, um mehr Datenverkehr zu mehr Pods zu bewältigen, beispielsweise im oben genannten Black-Friday-Szenario, steigt die Anzahl der Pods kontinuierlich an, und die Endpoints API wird größer. Folglich sind die Einschränkungen der Endpoints API deutlicher geworden, und sie ist sogar zum Leistungsengpass geworden.
Um die Einschränkungen der Endpoints API zu beheben, unterstützt Kubernetes ab Version v1.21 die EndpointSlice API. Die EndpointSlice API hilft, das Leistungsproblem bei der Verarbeitung einer großen Anzahl von Netzwerkendpunkten in der Endpoints API zu lösen und bietet hervorragende Skalierbarkeit und Erweiterbarkeit.
Die Unterschiede zwischen ihnen können wir direkt aus dem folgenden Diagramm ablesen:
- Die Änderungen der Endpoints während eines Datenverkehrsspitzen
- Die Änderungen der Endpointslices während eines Datenverkehrsspitzen
In Kubernetes: Wie kommunizieren Anwendungen miteinander? Was sind die spezifischen Unterschiede zwischen Endpoints und EndpointSlice? Wie ist die Beziehung zwischen Pod und Endpoints/EndpointSlice? Wie unterstützt APISIX diese Funktionen, und wie werden sie installiert und verwendet? Diese Fragen werden wir in diesem Artikel behandeln.
Wie man auf Anwendungen in Kubernetes zugreift
Über Service
Jeder Pod hat seine eigene eindeutige IP-Adresse in Kubernetes. Normalerweise stellt Service Verbindungen zu Pods her, indem er selector
verwendet, stellt denselben DNS-Subdomain-Namen bereit und erreicht Lastenausgleich. Darüber hinaus können Anwendungen innerhalb des Kubernetes-Clusters über DNS miteinander kommunizieren.
Wenn ein Service erstellt wird, verbindet Kubernetes den Service mit einer Endpoints-Ressource. Wenn der Service jedoch keine Selektoren angegeben hat, erstellt Kubernetes keine Endpoints für den Service.
Was ist Endpoints und wie ist die Beziehung zu Pod
Endpoints ist ein Ressourcenobjekt in Kubernetes, das in etcd gespeichert ist und Verweise auf eine Reihe von Zugriffsadressen von Pods enthält, die einem Service entsprechen. Daher kann jeder Service nur eine Endpoints-Ressource haben. Die Endpoints-Ressource überwacht Pod-Cluster und aktualisiert sich synchron, sobald sich ein Pod im Service ändert.
- Stellen Sie 3
httpbin
-Replikationen bereit und überprüfen Sie den Status der Pods, einschließlich der IP-Informationen
$ 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>
- Erstellen Sie den
httpbin
-Service und überprüfen Sie den Zustand der Endpoints-Endpunkte
$ kubectl get endpoints httpbin
NAME ENDPOINTS AGE
httpbin 10.1.36.125:80,10.1.36.131:80,10.1.36.133:80 23d
Aus den beiden obigen Beispielen können wir sehen, dass jeder einzelne Netzwerkendpunkt der httpbin
-Ressource in Endpoints mit einer Pod-IP-Adresse übereinstimmt.
Nachteile von Endpoints
- Endpoints hat eine Speicherbegrenzung. Wenn eine Endpoints-Ressource mehr als 1000 Endpunkte hat, kürzt der Endpoints-Controller die Endpunkte auf 1000.
- Ein Service kann nur eine Endpoints-Ressource haben, was bedeutet, dass die Endpoints-Ressource die IP-Adressen und andere Netzwerkinformationen für jeden Pod speichern muss, der den entsprechenden Service unterstützt. Dadurch wird die Endpoint-API-Ressource sehr groß und muss aktualisiert werden, wenn sich ein einzelner Netzwerkendpunkt in der Ressource ändert. Wenn das Geschäft häufige Änderungen der Endpunkte erfordert, wird eine große API-Ressource aneinander gesendet, was die Leistung der Kubernetes-Komponenten beeinträchtigt.
Was ist Endpointslices
Endpointslices ist eine skalierbarere und erweiterbarere Alternative zu Endpoints und hilft, das Leistungsproblem bei der Verarbeitung einer großen Anzahl von Netzwerkendpunkten zu lösen. Es bietet auch eine erweiterbare Plattform für zusätzliche Funktionen wie topologisches Routing. Diese Funktion wird ab Kubernetes v1.21 unterstützt.
Die EndpointSlice API wurde entwickelt, um dieses Problem mit einem Ansatz ähnlich dem Sharding zu lösen. Anstatt alle Pod-IPs für einen Service mit einer einzigen Endpoints-Ressource zu verfolgen, teilen wir sie in mehrere kleinere EndpointSlices auf.
Standardmäßig erstellt und verwaltet die Steuerungsebene EndpointSlices, sodass sie nicht mehr als 100 Endpunkte pro Slice haben. Sie können dies mit dem --max-endpoints-per-slice
-Flag des kube-controller-managers konfigurieren, bis zu 1000.
Warum brauchen wir das?
Betrachten Sie ein Szenario
Angenommen, es gibt einen Service, der von 2000 Pods unterstützt wird, was zu einer 1,0 MB großen Endpoints-Ressource führen könnte. In der Produktionsumgebung, wenn dieser Service Rolling Updates oder Endpunktmigrationen durchführt, werden die Endpoint-Ressourcen häufig aktualisiert. Denken Sie daran, dass Rolling Updates dazu führen, dass alle Pods ersetzt werden aufgrund der maximalen Größenbeschränkung für jede Anfrage in etcd. Kubernetes hat eine maximale Grenze von 1000 Endpunkten für Endpoints festgelegt. Wenn es mehr als 1000 Endpunkte gibt, hat die Endpoints-Ressource keine Verweise auf zusätzliche Netzwerkendpunkte.
Wenn der Service aufgrund einiger spezieller Anforderungen mehrere Rolling Updates benötigt, wird ein großes API-Ressourcenobjekt zwischen den Kubernetes-Komponenten übertragen, was die Leistung der Kubernetes-Komponenten erheblich beeinträchtigt.
Was passiert, wenn wir EndpointSlice verwenden?
Angenommen, es gibt einen Service, der von 2000 Pods unterstützt wird, und wir weisen in der Konfiguration 100 Endpunkte pro Endpointslices zu, dann erhalten wir 20 Endpointslices. Wenn nun ein Pod hinzugefügt oder entfernt wird, muss nur ein kleiner EndpointSlice aktualisiert werden. Offensichtlich ist dies eine bemerkenswerte Verbesserung in Bezug auf Skalierbarkeit und Netzwerkerweiterbarkeit. Wenn jeder einzelne Service eine Autoscaling-Anforderung hat, wird der Service mehr Pods bereitstellen, und die Endpoints-Ressource wird häufig aktualisiert, um den steigenden Datenverkehr bei einem Datenverkehrsspitzen zu bewältigen, und der Unterschied wird deutlicher. Noch wichtiger ist, dass jetzt nicht alle Pod-IPs für einen Service in einer einzigen Ressource gespeichert werden müssen, sodass wir uns keine Sorgen über die Größenbeschränkung für in etcd gespeicherte Objekte machen müssen.
Fazit von Endpoints vs. EndpointSlice
Da EndpointSlice ab Kubernetes v1.21 unterstützt wird, beziehen sich alle Schlussfolgerungen auf Kubernetes v1.21.
Anwendungsfälle von Endpoints:
- Es besteht eine Autoscaling-Anforderung, aber die Anzahl der Pods ist relativ gering, und Ressourcentransfers verursachen keinen großen Netzwerkverkehr und zusätzlichen Handlungsbedarf.
- Es besteht keine Autoscaling-Anforderung, und die Anzahl der Pods wird nicht sehr groß sein. Obwohl die Anzahl der Pods festgelegt ist, kann der Service Rolling Updates und Fehler nicht vermeiden.
Anwendungsfälle von EndpointSlice:
- Es besteht eine Autoscaling-Anforderung, und die Anzahl der Pods ist sehr groß (Hunderte von Pods).
- Die Anzahl der Pods ist aufgrund der maximalen Endpunktebegrenzung von Endpoints auf 1000 sehr groß; jeder Pod, der mehr als 1000 Endpunkte hat, muss EndpointSlice verwenden.
Praxis im APISIX Ingress Controller
Der APISIX Ingress Controller erreicht Lastenausgleich und Gesundheitsprüfungen, indem er die Änderungen der Endpoints- oder EndpointSlice-Ressource überwacht. Um Kubernetes v1.16+ zu unterstützen, verwendet der APISIX Ingress Controller standardmäßig Endpoints während der Installation.
Wenn die Version Ihres Clusters Kubernetes v1.21+ ist, müssen Sie das Flag watchEndpointSlice=true
angeben, um die EndpointSlice-Funktion während der Installation des APISIX Ingress Controllers zu unterstützen.
Hinweis: In Clustern mit Kubernetes v1.21+ empfehlen wir die Verwendung der Endpointslice-Funktion, da sonst, wenn die Anzahl der Pods den konfigurierten Wert des
--max-endpoints-per-slice
-Flags überschreitet, die Konfiguration verloren geht, da der APISIX Ingress Controller das Endpoints-Ressourcenobjekt überwacht.
Erstellen eines Services mit 20 Pod-Replikationen
Konfigurieren Sie den httpbin
-Anwendungsservice in Kubernetes und erstellen Sie 20 Pod-Replikationen.
- 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
Proxy über APISIX Ingress
- Verwenden Sie Helm, um den APISIX Ingress Controller zu installieren
Verwenden Sie --set ingress-controller.config.kubernetes.watchEndpointSlice=true
, um die Unterstützung der EndpointSlice-Funktion zu aktivieren.
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
- Verwenden Sie CRD-Ressourcen für den Proxy
Benutzer bemerken die Unterstützung der Endpoints- und EndpointSlice-Funktionen im APISIX Ingress Controller nicht, und ihre Konfigurationen sind gleich.
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
- Durch Überprüfen des APISIX-Pods können wir sehen, dass das nodes-Feld des Upstream-Objekts von APISIX die IP-Adressen von 20 Pods enthält.
kubectl exec -it ${Pod für 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 weitere Nodes werden ignoriert
// 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
}
}
- Abgleich mit den Netzwerkendpunkten von 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
Fazit
Dieser Artikel stellt Szenarien vor, in denen Kubernetes eine große Anzahl von Pods bereitstellen muss, und die Probleme, auf die wir stoßen. Er vergleicht auch die Unterschiede zwischen Endpoints und EndpointSlice und stellt die Möglichkeit vor, die EndpointSlice-Funktion während der Installation des APISIX Ingress Controllers zu aktivieren. Wenn die Version Ihres Clusters Kubernetes v1.21+ ist, empfehlen wir, die EndpointSlice-Funktion während der Installation des APISIX Ingress Controllers zu aktivieren. Dadurch kann der Verlust von Konfigurationen vermieden werden, und wir müssen uns keine Sorgen über den konfigurierten Wert des --max-endpoints-per-slice
-Flags machen.