Horizontal Pod Autoscaling for Docker Compose

Horizontal Pod Autoscaling requires metrics-server installed in the cluster.

HPA feature is supported for Application, Service and Database component kinds.

HPA is allowed only for resulting K8s Deployment and StatefulSet. It's not supported for DaemonSets or Pods, this is a Kube restriction.

HPA is allowed only if you didn't set dockerCompose.deploy.replicas on the component. Theoretically Kube allows this, but the behaviour will be hard to guess, when the HPA will be allowed to work, when the static replicas number will be enforced, so Bunnyshell forces you to choose one.

The HPA config needs to specify the min and max replicas to scale between, optionally the metrics used to trigger the scaling, and optionally the scaleUp and scaleDown behaviours, basically the scaling rate, how many Pods per unit of time, to spawn or to destroy.

components:
    - kind: Service
      name: nginx
      dockerCompose:
          image: nginx
          deploy:
              resources:
                  reservations:
                      cpus: 100m
                      memory: 100MiB
      hpa:
          minReplicas: 1
          maxReplicas: 3
          metrics:
              - cpu: 70%
              
              - memory: 80%
          scaleUp:
              policies:
                  - value: 100%
                    periodSeconds: 30
                  - value: 25%
                    periodSeconds: 300
          scaleDown:
              stabilizationWindowSeconds: 300
              selectPolicy: Min
              policies:
                  - value: 25%
                    periodSeconds: 30
                  - value: 1
                    periodSeconds: 60

Metrics

Kubernetes supports 5 metric types:

  • Resource
  • ContainerResource
  • Pods
  • Object
  • External

Resource and ContainerResource are implemented by default in the metrics-server. For the custom metrics Pods and Object you may need extra tools and configs in cluster, also for the External one.

type Resource

This metric refers to Pod resources, CPU or Memory. It is the default type in Bunnyshell, and it has an oversimplified syntax for it. Just specify the cpu or the memory property with either a percent value or an absolute one.

hpa:
    minReplicas: 1
    maxReplicas: 3
    metrics:
        - cpu: 60%
        - cpu: 200m
        - memory: 80%
        - memory: 300Mi

You can have more cpu (or memory) metrics, although it may not make sense, but Kube will evaluate the current consumption and compare it with each declared metric and decide if it needs to trigger the scaling.

The way how HPA works in kubernetes, it requires the Pod to have set the resources.requests, because the HPA algorithm computes the used percentage relative to these requests values.

type ContainerResource

This is very similar with the Resource, just that it refers to a container resources and not the whole Pod. It's useful when you have a larger Pod, with a main container and many sidecars, and you want to control the scaling based on specific containers only.

This also has a very simple syntax in Bunnyshell, just add the type property. Optionally you can set also the container, if not set by default it means the main container.

Same as for the Resource one, at least the required container should have set the resources.requests.

hpa:
    minReplicas: 1
    maxReplicas: 3
    metrics:
        - type: ContainerResource
          cpu: 60%
        - type: ContainerResource
          cpu: 200m
          container: nginx
        - type: ContainerResource
          memory: 80%
          container: nginx
        - type: ContainerResource
          memory: 300Mi

You can combine Resource type metrics with ContainerResource type, as said above, Kube will compute all the required metrics, compare them with specified values, and trigger the scaling or not.

type Pods

This is a custom metric, you may need extra tools and configuration in the cluster.

The Bunnyshell syntax is similar with the K8s one. matchLabels are optional.

hpa:
    minReplicas: 1
    maxReplicas: 3
    metrics:
        - type: Pods
          metricName: pod_metric_name
          matchLabels:
              optional: value
          averageValue: '100'
        - type: Pods
          metricName: phpfpm_active_processes_utilization
          averageValue: 700m

type Object

This is a custom metric, you may need extra tools and configuration in the cluster.

The Bunnyshell syntax is similar with the K8s one. matchLabels are optional and it can use either value or averageValue.

hpa:
    minReplicas: 1
    maxReplicas: 3
    metrics:
        - type: Object
          describedObject:
              apiVersion: /v1
              kind: Service
              name: my-srv
          metricName: obj_metric_name
          matchLabels:
              optional: value
          value: '100'
        - type: Object
          describedObject:
              apiVersion: /v1
              kind: Service
              name: rabbitmq
          metricName: rabbitmq_queue_messages_ready
          matchLabels:
              queue: rabbit_queue_name
          averageValue: "3"

type External

You may need extra tools and configuration in the cluster for this, but it allows to autoscale based on metrics that don't have an obvious relationship to any object in the Kubernetes cluster, such as metrics describing a hosted service with no direct correlation to Kubernetes namespaces.

The Bunnyshell syntax is similar with the K8s one. matchLabels are optional and it can use either value or averageValue.

hpa:
    minReplicas: 1
    maxReplicas: 3
    metrics:
        - type: External
          metricName: ext_metric_name
          matchLabels:
              optional: value
          value: '100'
        - type: External
          metricName: ext2_metric_name
          averageValue: "3"