Từ trước đến giờ chúng ta thưởng sử dụng auto scaling on k8s bằng HPA.
hoặc bạn cài các adapter prometheus rồi tương tác custom metrics feature với HPA.
Bài toán của mình đặt ra auto scaling pods on k8s base on metrics of Cloudwatch.
1) Install Keda on kubernetes.
https://keda.sh/docs/2.8/deploy/#helm
kubectl create namespace keda
helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --namespace keda
2)Keda integrates with kafka.
Sau khi cài xong Keda, chúng ta integrate with kafka/ AWS MSK
https://keda.sh/docs/2.8/scalers/apache-kafka/
Hiện tại mình đang có MSK trên AWS.
Bạn cần tạo secret:
apiVersion: v1 kind: Secret metadata: name: kafka-akhq-secrets namespace: xxxx type: Opaque data: tls: ZW5hYmxl # enable
Bạn cần tạo TriggerAuthentication và nó link tới secret bên trên. :
apiVersion: keda.sh/v1alpha1 kind: TriggerAuthentication metadata: name: kafka-akhq-trigger-auth-credential namespace: qa-md-cloud-rest spec: secretTargetRef: - parameter: tls name: kafka-akhq-secrets key: tls
Bạn cần tạo ScaledObject
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: kafka-akhq-scaledobject namespace: qa-md-cloud-rest spec: maxReplicaCount: 5 minReplicaCount: 1 pollingInterval: 10 scaleTargetRef: name: kafka-akhq triggers: - authenticationRef: name: kafka-akhq-trigger-auth-credential metadata: activationLagThreshold: '3' bootstrapServers: b-2.xxx-msk-dev.dlweos.c12.kafka.us-west-2.amazonaws.com:9094 consumerGroup: 4dbd50d3-008c-4be2-95b4-2aab77e16bcc lagThreshold: '100' offsetResetPolicy: latest topic: results #version: 1.37.2 # Version of your Kafka brokers. See IBM/sarama version (Default: 1.0.0, Optional) type: kafka
Mà keda sử dụng package này để integrate with kafka:
https://github.com/IBM/sarama
ScaledObject sẽ tạo ra HPA cho k8s
2.1) lagThreshold
Chúng ta sẽ tìm hiểu lagThreshold
và 336/4 = 84
lagThreshold: bạn có thể hiểu là 1 consumer sẽ có khả năng consume được 100 messages.
SumOffsetLag / (number of pod) > lagThreshold ==> scale up the pods
2.2) allowIdleConsumers
Nhưng các bạn cũng đã biết nếu hoặc chưa biết
Số consumer luôn luôn <= “bé hơn hoặc bằng” số partition của 1 topic.
Nếu số consumer > partition thì số consumer dư là sẽ vào trang thái Idle (Starveling)
và Keda cũng biết điều này.
allowIdleConsumers
– When set to true
, the number of replicas can exceed the number of partitions on a topic, allowing for idle consumers. (Default: false
, Optional)
==> Nếu bạn có nhu cấu số consumer > partition thì chỉnh: allowIdleConsumers: 'true'
Bạn có thể đọc issue này để hiểu hơn
https://github.com/kedacore/keda/issues/2908#issuecomment-1133605509
2.3) pollingInterval
This is the interval to check each trigger on. By default KEDA will check each trigger source on every ScaledObject every 30 seconds.
Nếu bạn muốn cập nhật nhanh hơn chỉnh số thấp.
2.4) Keda encounters the Issue when the topic doesn’t have any message or the offset is null
Mình đang có 1 ticket là observe the resources on k8s.
Mình đang có 1 deployment sử dụng kafka và mình cũng đang apply keda và kafka trigger for scaling to deployment đó.
Hiện tại là deployment đang có 5 pods mà theo như mình đánh giá là topic đang không có message vậy tại sao pod này lại scale up như thế
khi describe HPA thì thấy topic đang có lag messages
Nhưng mà topic đang không có message vậy chuyện gì đang sảy ra.
Và mình đã tìm hiểu config này: scaleToZeroOnInvalidOffset: false
When set to true
, if a partition’s offset is invalid, the scaler reduces the number of consumers for that partition to zero. This helps avoid unnecessary resource usage when there are no valid offsets to process. If set to false
, the scaler maintains a minimum of one consumer for the partition despite the invalid offset. This configuration is crucial for optimizing consumer resources based on partition offset validity.
các offset đang null.
Giờ tôi sẽ apply scaleToZeroOnInvalidOffset: true
và kiểm tra lại HPA:
Thông số đã về report đúng
3) Keda integrates with Ram/CPU metrics.
https://keda.sh/docs/2.8/scalers/cpu/
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: cpu-scaledobject namespace: default spec: scaleTargetRef: name: my-deployment triggers: - metadata: value: '80' metricType: Utilization type: cpu - metadata: value: '80' metricType: Utilization type: memory
Parameter list:
type
– Type of metric to use. Options areUtilization
, orAverageValue
.value
– Value to trigger scaling actions for:- When using
Utilization
, the target value is the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods. - When using
AverageValue
, the target value is the target value of the average of the metric across all relevant pods (quantity).
- When using
containerName
– Name of the specific container to scale based on its CPU, rather than the entire pod. Defaults to empty if not specified.
4) Keda integrates with RabbitMQ
Ồ dê, Keda cũng có thể đọc thẳng vào queue là lấy ra lượng message chưa được sử lý.
https://keda.sh/docs/2.8/scalers/rabbitmq-queue/
Đây là config của mình:
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: workload1-nimtechnology-scaledobject spec: scaleTargetRef: name: workload1-nimtechnology minReplicaCount: 1 maxReplicaCount: 4 pollingInterval: 15 triggers: - type: rabbitmq metadata: host: amqp://guest:guest@192.168.101.27:5672 protocol: amqp queueName: publisher mode: QueueLength value: "2"
host
– Host of RabbitMQ with format<protocol>://<host>:<port>/vhost
. The resolved host should follow a format likeamqp://guest:password@localhost:5672/vhost
orhttp://guest:password@localhost:15672/vhost
. When using a username/password consider usinghostFromEnv
or a TriggerAuthentication.protocol
– Protocol to be used for communication. (Values:auto
,http
,amqp
, Default:auto
, Optional)queueName
– Name of the queue to read message from.mode
– QueueLength to trigger on number of messages in the queue. MessageRate to trigger on the publish rate into the queue. (Values:QueueLength
,MessageRate
)
Ook giờ mình sẽ giải thích một chút
Với config ….mode: QueueLength
value: "2"
Nó sẽ lấy message backlog và bạn có thể hiểu là những message được lấy bới consumers.
Bạn có thể thấy External Metric có giá trị là 2
Current Metric đang có Average Value là 1 <<<<====Tại sao nhỉ???
Nếu (Totals message in backlog) / (Numbers of Pod) lớn hơn External Metric ===> scale up pods of Deployment
Tiếp theo mình push thêm 2 message vào queue:
Bạn có thể thấy HPA current metrics đã có sự thay đổi.
và pod đã tăng lên 2
OK nhé.
Hide the authentication(user/pass) to connect RabbitMQ
Best practice là chúng ta sẽ không để passwork trên github.
Bạn tạo 1 secret chưa host: amqp://guest:password@localhost:5672
apiVersion: v1 kind: Secret metadata: name: keda-rabbitmq-secret data: host: <AMQP URI connection string> # base64 encoded value of format amqp://guest:password@localhost:5672/vhost
Tạo 1 trigger authen để map vào secret trên
apiVersion: keda.sh/v1alpha1 kind: TriggerAuthentication metadata: name: keda-trigger-auth-rabbitmq-conn namespace: default spec: secretTargetRef: - parameter: host name: keda-rabbitmq-secret key: host
Sau đó bạn thêm trigger authencation
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: rabbitmq-scaledobject namespace: default spec: scaleTargetRef: name: rabbitmq-deployment triggers: - type: rabbitmq metadata: protocol: amqp queueName: testqueue mode: QueueLength value: "20" metricName: custom-testqueue # DEPRECATED: This parameter is deprecated as of KEDA v2.10 and will be removed in version `2.12`. optional. Generated value would be `rabbitmq-custom-testqueue` authenticationRef: name: keda-trigger-auth-rabbitmq-conn ## look at
How to reduce connections from KEDA to RabbitMQ
trong 1 số trường hợp bạn được report là Keda đang tạo quá nhiều connection đến rabbitMQ. Đó là nguyên nhân dẫn đến việc RabbitMQ consume nhiều memory.
Vậy làm sao để giảm số lượng connection đến RabbitMQ từ Keda.
Chúng ta sẽ monitor rabbitMQ thông qua Http protocol.
triggers: - type: rabbitmq metadata: host: http://guest:password@localhost:15672 protocol: http mode: QueueLength value: "100.50" activationValue: "10.5" queueName: testqueue unsafeSsl: true
5) Declare the behavior of HPA in KEDA
Nếu bạn đã làm việc nhiều với HPA bạn sẽ biết trong HPA có 1 feature là Behavior
Mình cũng có 1 bài nói về Behavior trong HPA:
Vậy thì apply cho keda như thế nào?
https://github.com/kedacore/keda-docs/blob/main/content/docs/2.0/concepts/scaling-deployments.md#scaledobject-spec
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: {scaled-object-name} spec: scaleTargetRef: apiVersion: {api-version-of-target-resource} # Optional. Default: apps/v1 kind: {kind-of-target-resource} # Optional. Default: Deployment name: {name-of-target-resource} # Mandatory. Must be in the same namespace as the ScaledObject envSourceContainerName: {container-name} # Optional. Default: .spec.template.spec.containers[0] pollingInterval: 30 # Optional. Default: 30 seconds cooldownPeriod: 300 # Optional. Default: 300 seconds minReplicaCount: 0 # Optional. Default: 0 maxReplicaCount: 100 # Optional. Default: 100 advanced: # Optional. Section to specify advanced optionsapiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: {scaled-object-name} spec: scaleTargetRef: apiVersion: {api-version-of-target-resource} # Optional. Default: apps/v1 kind: {kind-of-target-resource} # Optional. Default: Deployment name: {name-of-target-resource} # Mandatory. Must be in the same namespace as the ScaledObject envSourceContainerName: {container-name} # Optional. Default: .spec.template.spec.containers[0] pollingInterval: 30 # Optional. Default: 30 seconds cooldownPeriod: 300 # Optional. Default: 300 seconds minReplicaCount: 0 # Optional. Default: 0 maxReplicaCount: 100 # Optional. Default: 100 advanced: # Optional. Section to specify advanced options restoreToOriginalReplicaCount: true/false # Optional. Default: false horizontalPodAutoscalerConfig: # Optional. Section to specify HPA related options behavior: # Optional. Use to modify HPA's scaling behavior scaleUp: stabilizationWindowSeconds: 0 selectPolicy: Max policies: - type: Pods value: 4 periodSeconds: 15 - type: Percent value: 100 periodSeconds: 15 scaleDown: stabilizationWindowSeconds: 10 selectPolicy: Max policies: - type: Pods value: 1 periodSeconds: 20 triggers: # {list of triggers to activate scaling of the target resource} restoreToOriginalReplicaCount: true/false # Optional. Default: false horizontalPodAutoscalerConfig: # Optional. Section to specify HPA related options behavior: # Optional. Use to modify HPA's scaling behavior scaleUp: stabilizationWindowSeconds: 0 selectPolicy: Max policies: - type: Pods value: 4 periodSeconds: 15 - type: Percent value: 100 periodSeconds: 15 scaleDown: stabilizationWindowSeconds: 10 selectPolicy: Max policies: - type: Pods value: 1 periodSeconds: 20 triggers: # {list of triggers to activate scaling of the target resource}
Debug on Keda
Nếu bạn muốn debug trên Keda thì bạn cần chỉnh
https://github.com/kedacore/keda/blob/main/BUILD.md#setting-log-levels
Deployment: keda-operator
deployment: keda-operator-metrics-apiserver
KEDA might break existing deployment on cluster which already has another External Metrics Adapter installed
Các bạn cần lưu ý điều này.
https://github.com/kedacore/keda/issues/470
Edit the objects belong to KEDA
Bạn muốn sửa ScaledObject:
kubectl edit scaledobject.keda.sh/<name> -n <namespace>
Enable metrics of Keda.
strong value helm bạn cần thêm như sau:
prometheus: metricServer: enabled: true
Cách thử 2 bạn sửa deployment và service
Service: keda-operator-metrics-apiserver
spec: ports: - name: https port: 443 protocol: TCP targetPort: 6443 - name: http port: 80 protocol: TCP targetPort: 8080 - name: metrics port: 9022 protocol: TCP targetPort: 9022
Deployment: keda-operator-metrics-apiserver
template: metadata: annotations: prometheus.io/path: /metrics prometheus.io/port: '9022' prometheus.io/scrape: 'true'
spec: automountServiceAccountToken: true containers: - args: - /usr/local/bin/keda-adapter - '--secure-port=6443' - '--logtostderr=true' - '--metrics-port=9022' - '--metrics-path=/metrics' - '--v=0'
name: keda-operator-metrics-apiserver ports: - containerPort: 6443 name: https protocol: TCP - containerPort: 8080 name: http protocol: TCP - containerPort: 9022 name: metrics protocol: TCP readinessProbe: httpGet: path: /readyz port: 6443 scheme: HTTPS
How to scale the component to 0 from N by Keda
Trong 1 số trường bạn sẽ cần scale down số pod xuống 0
Nhưng nếu chỉnh maxReplicaCount, minReplicaCount xuống 0 ngày thì sẽ gặp lỗi:
2024-07-19T07:36:47.256100422Z 2024-07-19T07:36:47Z ERROR Reconciler error {"controller": "scaledobject", "controllerGroup": "keda.sh", "controllerKind": "ScaledObject", "ScaledObject": {"name":"archive-ikarus-scaledobject","namespace":"mdaas-engines-dev"}, "namespace": "mdaas-engines-dev", "name": "archive-ikarus-scaledobject", "reconcileID": "e80d1f5d-6f78-430f-9baa-52f518613cf2", "error": "MinReplicaCount=1 must be less than MaxReplicaCount=0"}
Và bạn BananaSorcery đã chỉ mình như sau:
Đầu tiên bạn phải để cho ScaleObject tạo được HPA
Sau đó bạn chỉnh maxReplicaCount, minReplicaCount xuống 0 thì HPA sẽ được chỉnh xuống 0
Issues when provisioning Keda.
keda-operator error creating kafka client: kafka: client has run out of available brokers
Gần đây bên SRE có báo mình là ScaledObject bị lỗi false và trong describe:
Warning KEDAScalerFailed 85s (x3629 over 41d) keda-operator error creating kafka client: kafka: client has run out of available brokers to talk to: 3 errors occurred: │ │ * unexpected EOF │ │ * unexpected EOF │ │ * unexpected EOF │ │ Warning ScaledObjectCheckFailed 85s (x3629 over 41d) keda-operator Failed to ensure HPA is correctly created for ScaledObject
Bạn cần kiểm tra lại ScaledObject, TriggerAuthentication, Secret đã được tạo đầy đủ hay chưa?
https://github.com/kedacore/keda/discussions/2636
Scaling is not performed because triggers are not active.
Keda 2.12+
Bạn sẽ thấy ScaleObject báo lỗi này:
– status: Activating
– Scaling is not performed because triggers are not active
Lúc này queue ko có message nào cả:
Sau đó mình thử push 1 message vào
thi scaleObject đã work ok.
===> nếu keda get value = 0 thì nó sẽ hiện Scaling is not performed because triggers are not active