本篇文章利用 KEDA 使用 Prometheus 採集 APISIX 暴露出來的指標作為伸縮器,進而實現基於流量的應用程式彈性伸縮。
作者張晉濤,API7.ai 雲原生工程師,Apache APISIX PMC。
介紹
通常情況下,每個應用可以承載的壓力都是固定的,我們可以透過提前進行壓測來了解單應用程式副本的負載能力。如果在業務高峰,或者業務的請求壓力增加時候,對應用進行橫向擴容可以保證更好的為使用者提供服務。
Apache APISIX 是一個高效能的雲原生 API 閘道器,所有傳送到上游應用程式的流量都將透過 APISIX,所以我們可以根據 APISIX 提供的流量指標,來判斷應用程式是否需要進行彈性伸縮。
本文中將使用 KEDA 作為彈性伸縮的控制元件,用 Prometheus 採集 APISIX 提供的流量指標來進行應用的彈性伸縮。
KEDA 中如何使用 Prometheus 實現伸縮
KEDA 是一個 Kubernetes 中基於事件的自動伸縮元件,可以配置多種伸縮器。本文將使用 Prometheus 作為伸縮器 ,獲取 APISIX 暴露出來的 metrics(指標)並進行應用程式的擴縮容。
部署 KEDA
KEDA 的部署比較簡單,新增對應的 Helm repo 並進行安裝即可。
(MoeLove) ➜ helm repo add kedacore https://kedacore.github.io/charts
"kedacore" has been added to your repositories
(MoeLove) ➜ helm repo update kedacore
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "kedacore" chart repository
Update Complete. ⎈Happy Helming!⎈
(MoeLove) ➜ helm install keda kedacore/keda --namespace keda --create-namespace
NAME: keda
LAST DEPLOYED: Thu Jan 19 00:01:00 2023
NAMESPACE: keda
STATUS: deployed
REVISION: 1
TEST SUITE: None
在安裝完成後,Pod 處於 Running
狀態,表示已經正常安裝。
(MoeLove) ➜ kubectl -n keda get pods
NAME READY STATUS RESTARTS AGE
keda-operator-metrics-apiserver-6d4db7dcff-ck9qg 1/1 Running 0 36s
keda-operator-5dd4748dcd-k8jjz 1/1 Running 0 36s
接下來部署 Prometheus。
部署 Prometheus
此處我們使用 Prometheus Operator 來進行 Prometheus 的部署。Prometheus Operator 可以幫助我們在 Kubernetes 中快速部署 Prometheus 例項,以及透過宣告式配置的方式新增監控規則。
透過如下步驟完成 Prometheus Operator 的安裝。
(MoeLove) ➜ https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.62.0/bundle.yaml
(MoeLove) ➜ kubectl apply --server-side -f bundle.yaml
customresourcedefinition.apiextensions.k8s.io/alertmanagerconfigs.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/alertmanagers.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/podmonitors.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/probes.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/prometheuses.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/prometheusrules.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/servicemonitors.monitoring.coreos.com serverside-applied
customresourcedefinition.apiextensions.k8s.io/thanosrulers.monitoring.coreos.com serverside-applied
clusterrolebinding.rbac.authorization.k8s.io/prometheus-operator serverside-applied
clusterrole.rbac.authorization.k8s.io/prometheus-operator serverside-applied
deployment.apps/prometheus-operator serverside-applied
serviceaccount/prometheus-operator serverside-applied
service/prometheus-operator serverside-applied
然後使用如下配置作為 Prometheus 例項的配置,然後將其應用到 Kubernetes 叢集中。
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/metrics
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources:
- configmaps
verbs: ["get"]
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: default
---
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorSelector:
matchLabels:
app: apisix
serviceMonitorNamespaceSelector:
matchLabels:
team: apisix
resources:
requests:
memory: 400Mi
enableAdminAPI: false
---
apiVersion: v1
kind: Service
metadata:
name: prometheus
spec:
type: LoadBalancer
ports:
- name: web
port: 9090
protocol: TCP
targetPort: web
selector:
prometheus: prometheus
應用後,則可以看到在 default
namespace 下建立了 Prometheus 例項。由於上述配置中建立了 LoadBalancer
型別的 Service,所以可以直接透過 LoadBalancer 的公網 IP 進行 Prometheus 的訪問。
(MoeLove) ➜ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 96m
prometheus-operator ClusterIP None <none> 8080/TCP 92m
prometheus-operated ClusterIP None <none> 9090/TCP 41m
prometheus LoadBalancer 10.43.125.194 216.6.66.66 9090:30099/TCP 41m
如何部署閘道器並開啟監控
接下來部署 APISIX Ingress,並使用 Prometheus 進行 metrics 採集。
如果使用者沒有使用 APISIX Ingress,而是僅僅使用了 APISIX,操作方法也是類似的。 這裡不再分開介紹。
此處使用 Helm 進行部署,可以同時將 APISIX Ingress controller 和 APISIX 部署到叢集中。
(MoeLove) ➜ helm repo add apisix https://charts.apiseven.com
"apisix" already exists with the same configuration, skipping
(MoeLove) ➜ helm repo update apisix
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "apisix" chart repository
Update Complete. ⎈Happy Helming!⎈
(MoeLove) ➜ helm upgrade --install apisix apisix/apisix --create-namespace --namespace apisix --set gateway.type=LoadBalancer --set ingress-controller.enabled=true --set ingress-controller.config.apisix.serviceNamespace=apisix
Release "apisix" has been upgraded. Happy Helming!
NAME: apisix
LAST DEPLOYED: Thu Jan 19 02:11:23 2023
NAMESPACE: apisix
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace apisix svc -w apisix-gateway'
export SERVICE_IP=$(kubectl get svc --namespace apisix apisix-gateway --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
echo http://$SERVICE_IP:80
接下來開啟 APISIX 的 prometheus
外掛,具體的配置方法和相關引數可以參考如下兩篇文件。
- prometheus plugins | Apache APISIX®
- How to access Apache APISIX Prometheus metrics on Kubernetes | Apache APISIX®
開啟後,便可以透過建立 ServiceMonitor 資源,讓 Prometheus 抓取 APISIX 暴露出的 metrics 了。
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: example-app
labels:
app: apisix
spec:
selector:
matchLabels:
app: apisix
endpoints:
- port: web
驗證應用彈性伸縮能力
此處將建立一個示例應用。
(MoeLove) ➜ kubectl create deploy httpbin --image=kennethreitz/httpbin --port=80
deployment.apps/httpbin created
(MoeLove) ➜ kubectl expose deploy httpbin --port 80
建立如下路由規則,應用到 Kubernetes 叢集后,則可透過 APISIX 進行請求的代理。
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpserver-route
spec:
http:
- name: rule1
match:
hosts:
- local.httpbin.org
paths:
- /*
backends:
- serviceName: httpbin
servicePort: 80
接下來,建立 KEDA 的 ScaledObject,配置 Prometheus 相關引數。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: prometheus-scaledobject
namespace: default
spec:
scaleTargetRef:
name: httpbin
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.default.svc:9090
metricName: apisix_http_status
threshold: '10'
query: sum(rate(apisix_http_status{route="httpserver-route"}[1m]))
上述參數列示透過 sum(rate(apisix_http_status{route="httpserver-route"}[1m]))
作為查詢表示式,如果結果能到達 10, 則開始進行擴容(此處配置僅用於本文中的示例使用,生產環境請按照實際情況進行修改)。
然後,我們透過 curl 向 httpbin 服務發出連續請求,再次檢視示例應用的 Pod 已經變成兩個,證明 KEDA 成功自動擴容了。
(MoeLove) ➜ kubectl get pods
NAME READY STATUS RESTARTS AGE
httpbin-d46d778d7-chtdw 1/1 Running 0 12m
httpbin-d46d778d7-xanbj 1/1 Running 0 10s
待一段時間無請求後,再次檢視發現 Pod 的數量自動縮減為一個,證明自動縮容也實現了。
(MoeLove) ➜ kubectl get pods
NAME READY STATUS RESTARTS AGE
httpbin-d46d778d7-chtdw 1/1 Running 0 32m
總結
本篇文章利用 KEDA 使用 Prometheus 採集 APISIX 暴露出來的指標作為伸縮器,進而實現基於流量的應用程式彈性伸縮。由於所有流量都會先經過 APISIX ,所以在 APISIX 側進行資料統計更加簡單方便。
在業務請求量上來後,應用程式將進行自動化的擴容,當業務低谷的時候,則會自動的縮容。這可以在緩解很多生產環境下的手動擴/縮容操作,以保障使用者的服務體驗。
關於 API7.ai 與 APISIX
API7.ai 是一家提供 API 處理和分析的開源基礎軟體公司,於 2019 年開源了新一代雲原生 API 閘道器 -- APISIX 並捐贈給 Apache 軟體基金會。此後,API7.ai 一直積極投入支援 Apache APISIX 的開發、維護和社群運營。與千萬貢獻者、使用者、支持者一起做出世界級的開源專案,是 API7.ai 努力的目標。