如何使用 Kubernetes 實現應用程式的彈性伸縮

API7_技術團隊發表於2023-02-24

本篇文章利用 KEDA 使用 Prometheus 採集 APISIX 暴露出來的指標作為伸縮器,進而實現基於流量的應用程式彈性伸縮。

作者張晉濤,API7.ai 雲原生工程師,Apache APISIX PMC。

原文連結

介紹

通常情況下,每個應用可以承載的壓力都是固定的,我們可以透過提前進行壓測來了解單應用程式副本的負載能力。如果在業務高峰,或者業務的請求壓力增加時候,對應用進行橫向擴容可以保證更好的為使用者提供服務。

Apache APISIX 是一個高效能的雲原生 API 閘道器,所有傳送到上游應用程式的流量都將透過 APISIX,所以我們可以根據 APISIX 提供的流量指標,來判斷應用程式是否需要進行彈性伸縮。

本文中將使用 KEDA 作為彈性伸縮的控制元件,用 Prometheus 採集 APISIX 提供的流量指標來進行應用的彈性伸縮。

using KEDA for autocaling

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 外掛,具體的配置方法和相關引數可以參考如下兩篇文件。

開啟後,便可以透過建立 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 努力的目標。

相關文章