<p>I want to understand how HPA computes CPU utilization across Pods.</p>

<p>According to this <a href="https://github.com/kubernetes/community/blob/b3349d5b1354df814b67bbdee6890477f3c250cb/contributors/design-proposals/autoscaling/horizontal-pod-autoscaler.md" rel="noreferrer">doc</a> it takes the average of CPU utilization of a pod (average across the last 1  minute) divided by the CPU requested by the pod. Then it computes the arithmetic mean of all the pods' CPU.</p>

<p>Unfortunately the doc contains some information that are outdated like for example that <code>--horizontal-pod-autoscaler-sync-period</code> is by default set to 30 seconds but in <a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#how-does-the-horizontal-pod-autoscaler-work" rel="noreferrer">the official doc</a>, the default value is 15 seconds.</p>

<p>When I tested, I noticed that HPA scales up even before that average CPU reaches the threshold I set (which is 90%),  Which made me think  that maybe it takes the maximum CPU across Pods and not the average.</p>

<p><a href="https://i.stack.imgur.com/rI7DY.png" rel="noreferrer"><img src="https://i.stack.imgur.com/rI7DY.png" alt="enter image description here"></a></p>

<p>My question is where I can find an updated documentation to understand exactly how HPA works?</p>

<p>Note that I've not a Kubernetes cluster at hand, this is a theoretical answer based on the source code of k8s.<br>
See if this actually matches your experience.  </p>

<hr>

<p>Kubernetes is opensource, here seems to be the <a href="https://github.com/kubernetes/kubernetes/tree/9b8e247839e4313a81c1b99c1bf94b591bb676b3/pkg/controller/podautoscaler" rel="noreferrer">HPA code</a>.</p>

<p>The functions <a href="https://github.com/kubernetes/kubernetes/blob/c441a1a7dcca81aa6bd7f9b0f5babe6e8a590c7b/pkg/controller/podautoscaler/replica_calculator.go#L62" rel="noreferrer"><code>GetResourceReplica</code></a> and <a href="https://github.com/kubernetes/kubernetes/blob/c441a1a7dcca81aa6bd7f9b0f5babe6e8a590c7b/pkg/controller/podautoscaler/replica_calculator.go#L176" rel="noreferrer"><code>calcPlainMetricReplicas</code></a> (for non-utilization percentage) compute the number of replicas given the current metrics.<br>
Both use the <code>usageRatio</code> returned by <a href="https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/podautoscaler/metrics/utilization.go#L26" rel="noreferrer"><code>GetMetricUtilizationRatio</code></a>, this value is multiplied by the number of <em>currently</em> ready pods in the Replica to get the new number of pods:</p>

<pre><code>New_number_of_pods = Old_numbers_of_ready_pods * usageRatio
</code></pre>

<p>There is a tolerance check (ie if the <code>usageRatio</code> falls  close enough to 1, nothing is done) and the pending and unkown-state pods are ignored (considered to use 0% of the resource) while the pods without metrics are considered to use 100% of the resource.  </p>

<p>The <code>usageRatio</code> is computed by <a href="https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/podautoscaler/metrics/utilization.go#L26" rel="noreferrer"><code>GetResourceUtilizationRatio</code></a> that is passed the metrics and the requests (of resources) of <em>all</em> the pods, it goes as follow:</p>

<pre><code>utilization = Total_sum_resource_usage_all_pods / Total_sum_resource_requests_all_pods
usageRatio = utilization * 100 / targetUtilization
</code></pre>

<p>Where <code>targetUtilization</code> comes from the HPA spec.<br>
The code is easier to read than this summary of mine, in this context the term request means "resource request" (that's an educated guess).</p>

<p>So I'd say that 90% is the resource usage <em>across all pods</em> computed as they were all a single pod requesting the sum of each pod's request and collecting the metrics as they were all running on a single dedicated node.</p>
