Autoskalowanie oparte na żądaniach HTTP na K8S przy użyciu Prometheus i Keda na NSIS
Autoskaler podów Kubernetes (HPA) natywnie wykorzystuje metryki CPU i RAM jako domyślne wyzwalacze dla zwiększania lub zmniejszania liczby podów. Chociaż często jest to wystarczające, mogą istnieć przypadki użycia, w których preferowane jest skalowanie na podstawie niestandardowych metryk.
KEDA to narzędzie do automatycznego skalowania w oparciu o zdarzenia/metryki dostarczane z popularnych źródeł/technologii, takich jak Prometheus, Kafka, Postgres i wiele innych.
W tym artykule wdrożymy przykładową aplikację w chmurze NSIS. Będziemy zbierać żądania HTTP z NGINX Ingress na naszym klastrze Kubernetes i, używając Keda ze skalerem Prometheus, zastosujemy niestandardowe skalowanie oparte na żądaniach HTTP.
Informacja
Użyjemy NGINX web server do zademonstrowania aplikacji i NGINX ingress do jej wdrożenia i zbierania metryk. Należy pamiętać, że NGINX web server i NGINX ingress to dwa oddzielne elementy oprogramowania, mające dwa różne cele.
Co będziemy omawiać
Zainstaluj NGINX ingress na klastrze Magnum
Zainstaluj Prometheus
Zainstaluj Keda
Wdrożenie przykładowej aplikacji
Wdrożenie naszej aplikacji ingress
Dostęp do pulpitu Prometheus
Wdrożenie KEDA ScaledObject
Test z Locust
Wymagania wstępne
Nr 1 Konto
Potrzebne jest konto hostingowe NSIS z dostępem do interfejsu Horizon: https://horizon.cloudferro.com.
Nr 2 Utwórz nowy klaster Kubernetes bez preinstalowanego Magnum NGINX z Horizon UI.
Domyślny ingress NGINX wdrożony z Magnum z Horizon UI nie implementuje jeszcze eksportu metryk Prometheus. Zamiast próbować skonfigurować ingress Magnum dla tego przypadku użycia, raczej zainstalujemy nowy ingress NGINX. Aby uniknąć konfliktów, najlepiej postępować zgodnie z poniższą instrukcją na klastrze Kubernetes bez Magnum NGINX preinstalowanego z Horizon UI.
Nr 3 kubectl wskazał klaster Kubernetes
Poniższy artykuł zawiera opcje tworzenia nowego klastra i aktywacji polecenia kubectl:
Jak uzyskać dostęp do klastra Kubernetes po wdrożeniu przy użyciu Kubectl na NSIS OpenStack Magnum?.
Jak wspomniano, utwórz klaster bez instalowania opcji NGINX ingress.
Nr 4 Znajomość obsługi wykresów Helm
W tym artykule przedstawiono wykresy Helm na platformie Kubernetes:
Wdrażanie Helm Charts na klastrach Magnum Kubernetes w chmurze NSIS Cloud
Zainstaluj NGINX ingress na klastrze Magnum
Wpisz następujące polecenia, aby pobrać repozytorium Helm ingress-nginx, a następnie zainstaluj wykres. Należy pamiętać, że używamy niestandardowej przestrzeni nazw ingress-nginx, a także ustawiamy opcje, aby włączyć metryki Prometheus.
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
kubectl create namespace ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--set controller.metrics.enabled=true \
--set-string controller.podAnnotations."prometheus\.io/scrape"="true" \
--set-string controller.podAnnotations."prometheus\.io/port"="10254"
Teraz uruchom następujące polecenie, aby uzyskać zewnętrzny adres IP kontrolera ingress, który będzie używany przez zasoby ingress utworzone w dalszych krokach tego artykułu.
$ kubectl get services -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.254.118.18 64.225.135.67 80:31573/TCP,443:30786/TCP 26h
Otrzymamy 64.225.135.67. Zamiast tej wartości użyj wartości EXTERNAL-IP, którą otrzymasz w terminalu po uruchomieniu powyższego polecenia.
Zainstaluj Prometheus
Aby zainstalować Prometheus, należy wykonać następujące polecenie na klastrze:
kubectl apply --kustomize github.com/kubernetes/ingress-nginx/deploy/prometheus/
Należy pamiętać, że jest to instalacja Prometheus dostosowana do NGINX Ingress i już domyślnie instaluje się w przestrzeni nazw ingress-nginx, więc nie ma potrzeby podawania flagi przestrzeni nazw ani jej tworzenia.
Zainstaluj Keda
Wykonując poniższe kroki, utwórz oddzielną przestrzeń nazw dla artefaktów Keda, pobierz repozytorium i zainstaluj wykres Keda-Core:
kubectl create namespace keda
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --version 2.3.0 --namespace keda
Wdrożenie przykładowej aplikacji
Po wykonaniu powyższych kroków możemy wdrożyć prostą aplikację. Będzie to serwer WWW NGINX, obsługujący prostą stronę „Welcome to nginx!”. Uwaga, tworzymy wdrożenie, a następnie udostępniamy je jako usługę typu ClusterIP. Utwórz plik app-deployment.yaml w swoim ulubionym edytorze:
app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 80
Następnie zastosuj poniższe polecenie:
kubectl apply -f app-deployment.yaml -n ingress-nginx
Wdrażamy tę aplikację w przestrzeni nazw ingress-nginx, w której hostowana jest również instalacja ingress i Prometheus. W przypadku scenariuszy produkcyjnych możesz chcieć mieć lepszą izolację aplikacji od infrastruktury, jednak wykracza to poza zakres tego artykułu.
Wdrożenie naszej aplikacji ingress
Nasza aplikacja jest już uruchomiona i udostępniona w naszym klastrze, ale chcemy również udostępnić ją publicznie. W tym celu użyjemy NGINX ingress, który będzie również działał jako proxy do rejestrowania metryk żądań. Utwórz plik app-ingress.yaml z następującą zawartością:
app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: "64.225.135.67.nip.io"
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /app
pathType: Prefix
Następnie zastosuj:
kubectl apply -f app-ingress.yaml -n ingress-nginx
Po chwili można uzyskać publiczny adres IP, pod którym aplikacja jest dostępna:
$ kubectl get ingress -n ingress-nginx
NAME CLASS HOSTS ADDRESS PORTS AGE
app-ingress nginx 64.225.135.67.nip.io 64.225.135.67 80 18h
Po wpisaniu adresu IP z prefiksem (zastąp własnym pływającym adresem IP z sufiksem /app), możemy zobaczyć odsłoniętą aplikację. Używamy usługi nip.io, która działa jako resolver DNS, więc nie ma potrzeby konfigurowania rekordów DNS do celów demonstracyjnych.
Dostęp do pulpitu Prometheus
Aby uzyskać dostęp do pulpitu Prometheus, możemy przekierować port działającego serwera prometheus na nasz localhost. Może to być przydatne do rozwiązywania problemów. Mamy prometheus-server działający jako usługa NodePort, co można zweryfikować poniżej:
$ kubectl get services -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.254.3.172 64.225.135.67 80:30881/TCP,443:30942/TCP 26h
ingress-nginx-controller-admission ClusterIP 10.254.51.201 <none> 443/TCP 26h
ingress-nginx-controller-metrics ClusterIP 10.254.15.196 <none> 10254/TCP 26h
nginx ClusterIP 10.254.160.207 <none> 80/TCP 25h
prometheus-server NodePort 10.254.24.85 <none> 9090:32051/TCP 26h
W poniższym poleceniu przekierujemy port do lokalnego hosta:
kubectl port-forward deployment/prometheus-server 9090:9090 -n ingress-nginx
Następnie wpisz localhost:9090 w przeglądarce, a zobaczysz pulpit nawigacyjny Prometheus. W tym widoku będziemy mogli zobaczyć różne metryki udostępniane przez nginx-ingress. Można to zweryfikować, wpisując „nginx-ingress” w pasku wyszukiwania, a następnie zaczną pojawiać się różne powiązane metryki.
Wdrożenie KEDA ScaledObject
Keda ScaledObject to niestandardowy zasób, który umożliwi skalowanie naszej aplikacji w oparciu o niestandardowe metryki. W manifeście YAML definiujemy, co będzie skalowane (wdrożenie nginx), jakie są warunki skalowania oraz definicję i konfigurację wyzwalacza, w tym przypadku Prometheus. Przygotuj plik scaled-object.yaml z następującą zawartością:
scaled-object.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: prometheus-scaledobject
namespace: ingress-nginx
labels:
deploymentName: nginx
spec:
scaleTargetRef:
kind: Deployment
name: nginx # name of the deployment, must be in the same namespace as ScaledObject
minReplicaCount: 1
pollingInterval: 15
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-server.ingress-nginx.svc.cluster.local:9090
metricName: nginx_ingress_controller_requests
threshold: '100'
query: sum(rate(nginx_ingress_controller_requests[1m]))
Szczegółowa definicja ScaledObject znajduje się w dokumentacji Keda. W tym przykładzie pomijamy wiele ustawień domyślnych, z których najbardziej godnym uwagi jest coolDownPeriod. Ponieważ nie ma ona wyraźnie przypisanej wartości, jej domyślna wartość 300 sekund będzie obowiązywać, jednak zobacz poniżej, jak możesz zmienić tę wartość na coś innego.
Używamy tutaj metryki nginx-ingress-controller-requests do skalowania. Ta metryka pojawi się na pulpicie nawigacyjnym Prometheus dopiero wtedy, gdy żądania zaczną trafiać do naszej usługi aplikacji. Ustawiamy próg na 100 i czas na 1 minutę, więc w przypadku większej liczby żądań niż 100 na kapsułę w ciągu minuty, spowoduje to zwiększenie skali.
kubectl apply -f scaled-object.yaml -n ingress-nginx
Test z Locust
Możemy teraz przetestować, czy skalowanie działa zgodnie z oczekiwaniami. Wykorzystamy do tego Locust, który jest narzędziem do testowania obciążenia. Aby szybko wdrożyć Locust jako typ usługi LoadBalancer, wprowadź następujące polecenia:
kubectl create deployment locust --image paultur/locustproject:latest
kubectl expose deployment locust --type LoadBalancer --port 80 --target-port 8089
Po kilku minutach LoadBalancer zostaje utworzony, a Locust zostaje odsłonięty:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 28h
locust LoadBalancer 10.254.88.89 64.225.132.243 80:31287/TCP 4m19s
Wejdź do Locust UI w przeglądarce używając EXTERNAL-IP. Może to być tylko 64.225.132.243 lub 64.225.132.243.nip.io, jedna z tych wartości na pewno zadziała. Następnie naciśnij „Start Swarming”, aby zainicjować mock requesty na publicznym punkcie końcowym naszej aplikacji:
Przy domyślnych ustawieniach i nawet jednym użytkowniku, Locust natychmiast zacznie roić się od setek żądań. Dostrajanie Locusta nie wchodzi w zakres tego artykułu, ale możemy szybko zobaczyć efekt. Generowane są dodatkowe repliki podów:
$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-557bf68967-h9zf5 1/1 Running 0 27h
nginx-85b98978db-2kjx6 1/1 Running 0 30s
nginx-85b98978db-2kxzz 1/1 Running 0 61s
nginx-85b98978db-2t42c 1/1 Running 0 31s
nginx-85b98978db-2xdzw 0/1 ContainerCreating 0 16s
nginx-85b98978db-2zdjm 1/1 Running 0 30s
nginx-85b98978db-4btfm 1/1 Running 0 30s
nginx-85b98978db-4mmlz 0/1 ContainerCreating 0 16s
nginx-85b98978db-4n5bk 1/1 Running 0 46s
nginx-85b98978db-525mq 1/1 Running 0 30s
nginx-85b98978db-5czdf 1/1 Running 0 46s
nginx-85b98978db-5kkgq 0/1 ContainerCreating 0 16s
nginx-85b98978db-5rt54 1/1 Running 0 30s
nginx-85b98978db-5wmdk 1/1 Running 0 46s
nginx-85b98978db-6tc6p 1/1 Running 0 77s
nginx-85b98978db-6zcdw 1/1 Running 0 61s
...
Chłodzenie
Po naciśnięciu „Stop” w Locust, strąki będą skalowane w dół do jednej repliki, zgodnie z wartością parametru coolDownPeriod, który jest zdefiniowany w Keda ScaledObject. Jego domyślna wartość to 300 sekund. Jeśli chcesz ją zmienić, użyj polecenia
kubectl edit scaledobject prometheus-scaledobject -n ingress-nginx