{"id":391,"date":"2018-10-16T18:34:45","date_gmt":"2018-10-16T18:34:45","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw93\/?p=391"},"modified":"2018-10-17T09:10:11","modified_gmt":"2018-10-17T09:10:11","slug":"kubernetes-1-8-hidden-gems-the-resource-metrics-api-the-custom-metrics-api-and-hpa-v2","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/10\/16\/kubernetes-1-8-hidden-gems-the-resource-metrics-api-the-custom-metrics-api-and-hpa-v2\/","title":{"rendered":"Kubernetes 1.8: Hidden Gems &#8211; The Resource Metrics API, the Custom Metrics API and HPA v2 \/"},"content":{"rendered":"<p>By <a target=\"\">Luke Addison<\/a><\/p>\n<p>In the coming weeks we will be releasing a series of blog posts called Kubernetes 1.8: Hidden Gems, accenting some of the less obvious but wonderful features in the latest Kubernetes release. In this week\u2019s gem, Luke looks at some of the main components in the <a href=\"https:\/\/github.com\/kubernetes\/community\/blob\/master\/contributors\/design-proposals\/instrumentation\/monitoring_architecture.md\">core metrics and monitoring pipelines<\/a> and in particular how they can be used to scale Kubernetes workloads.<\/p>\n<p>One of the features that makes Kubernetes so powerful is its extensibility. In particular, Kubernetes allows developers to easily extend the core API Server with their own API servers, which we will refer to as \u2018add-on\u2019 API servers. The <a href=\"https:\/\/github.com\/kubernetes\/community\/blob\/master\/contributors\/design-proposals\/instrumentation\/resource-metrics-api.md\">resource metrics API<\/a> (also known as the master metrics API or just the metrics API) introduced in 1.8 and the <a href=\"https:\/\/github.com\/kubernetes\/community\/blob\/master\/contributors\/design-proposals\/instrumentation\/custom-metrics-api.md\">custom metrics API<\/a>, introduced in 1.6, are implemented in exactly this way. The resource metrics API is designed to be consumed by core system components, such as the scheduler and kubectl top, whilst the custom metrics API has a wider use case.<\/p>\n<p>One Kubernetes component that makes use of both the resource metrics API and the custom metrics API is the HorizontalPodAutoscaler (HPA) controller which manages HPA resources. HPA resources are used to automatically scale the number of Pods in a ReplicationController, Deployment or ReplicaSet based on observed metrics (note that StatefulSet <a href=\"https:\/\/github.com\/kubernetes\/kubernetes\/issues\/48591#issuecomment-314905805\">is not supported<\/a>).<\/p>\n<p>The first version of HPA (v1) was only able to scale based on observed CPU utilisation. Although useful for some cases, CPU is not always the most suitable or relevant metric to autoscale an application. HPA v2, introduced in 1.6, is able to scale based on <em>custom<\/em> metrics and has been moved from alpha to beta in 1.8. This allows users to scale on any number of application-specific metrics; for example, metrics might include the length of a queue and ingress requests per second.<\/p>\n<p>The purpose of the resource metrics API is to provide a stable, versioned API that core Kubernetes components can rely on. Implementations of the API provide resource usage metrics for pods and nodes through the API Server and form part of the <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/debug-application-cluster\/core-metrics-pipeline\/\">core metrics pipeline<\/a>.<\/p>\n<p>In order to get a resource metrics add-on API server up and running we first need to <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/access-kubernetes-api\/configure-aggregation-layer\/\">configure the aggregation layer<\/a>. The <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/api-extension\/apiserver-aggregation\/\">aggregation layer<\/a> is a new feature in Kubernetes 1.7 that allows add-on API servers to register themselves with <a href=\"https:\/\/github.com\/kubernetes\/kube-aggregator\">kube-aggregator<\/a>. The aggregator will then proxy relevant requests to these add-on API servers so that they can serve custom API resources.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blog.jetstack.io\/blog\/kubernetes-1-8-hidden-gems-hpa-v2\/aggregator.png\" alt=\"kube-aggregator architecture\" \/><\/p>\n<p>Configuring the aggregation layer involves setting a number of flags on the API Server. The exact flags can be found <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/access-kubernetes-api\/configure-aggregation-layer\/\">here<\/a> and more information about these flags can be found in the <a href=\"https:\/\/kubernetes.io\/docs\/admin\/kube-apiserver\/\">kube-apiserver reference documentation<\/a>. In order to set these flags you will need to obtain a CA certificate if your cluster provider has not taken care of that already. For more details on the various CAs used by the API Server, take a look at the excellent <a href=\"https:\/\/github.com\/kubernetes-incubator\/apiserver-builder\/blob\/master\/docs\/concepts\/auth.md\">apiserver-builder documentation<\/a>.<\/p>\n<p>We now need to deploy the add-on API Server itself to serve these metrics. We can use Heapster\u2019s implementation of the resource metrics API by running it with the &#8211;api-server flag set to true, however the recommended way is to deploy <a href=\"https:\/\/github.com\/kubernetes-incubator\/metrics-server\">metrics-server<\/a>, which is a slimmed-down version of Heapster specifically designed to serve resource usage metrics. You can do this using the <a href=\"https:\/\/github.com\/kubernetes-incubator\/metrics-server\/tree\/master\/deploy\">deployment manifests<\/a> provided in the metrics-server repository. Pay special attention to the APIService resource included with the manifests. This resource claims a URL path in the Kubernetes API (\/apis\/metrics.k8s.io\/v1beta1 in this case) and tells the aggregator to proxy anything sent to that path to the registered service. For more information about metrics-server check out the <a href=\"https:\/\/github.com\/kubernetes-incubator\/metrics-server\">metrics-server repository<\/a>.<\/p>\n<p>To test our resource metrics API we can use kubectl get &#8211;raw. The following command should return a list of resource usage metrics for all the nodes in our cluster.<\/p>\n<p>$ kubectl get &#8211;raw &#8220;\/apis\/metrics.k8s.io\/v1beta1\/nodes&#8221; | jq<br \/>\n{<br \/>\n&#8220;kind&#8221;: &#8220;NodeMetricsList&#8221;,<br \/>\n&#8220;apiVersion&#8221;: &#8220;metrics.k8s.io\/v1beta1&#8221;,<br \/>\n&#8220;metadata&#8221;: {<br \/>\n&#8220;selfLink&#8221;: &#8220;\/apis\/metrics.k8s.io\/v1beta1\/nodes&#8221;<br \/>\n},<br \/>\n&#8220;items&#8221;: [<br \/>\n{<br \/>\n&#8220;metadata&#8221;: {<br \/>\n&#8220;name&#8221;: &#8220;node1.lukeaddison.co.uk&#8221;,<br \/>\n&#8220;selfLink&#8221;: &#8220;\/apis\/metrics.k8s.io\/v1beta1\/nodes\/node1.lukeaddison.co.uk&#8221;,<br \/>\n&#8220;creationTimestamp&#8221;: &#8220;2017-10-09T14:21:06Z&#8221;<br \/>\n},<br \/>\n&#8220;timestamp&#8221;: &#8220;2017-10-09T14:21:00Z&#8221;,<br \/>\n&#8220;window&#8221;: &#8220;1m0s&#8221;,<br \/>\n&#8220;usage&#8221;: {<br \/>\n&#8220;cpu&#8221;: &#8220;247m&#8221;,<br \/>\n&#8220;memory&#8221;: &#8220;1846432Ki&#8221;<br \/>\n}<br \/>\n},<br \/>\n{<br \/>\n&#8220;metadata&#8221;: {<br \/>\n&#8220;name&#8221;: &#8220;node2.lukeaddison.co.uk&#8221;,<br \/>\n&#8220;selfLink&#8221;: &#8220;\/apis\/metrics.k8s.io\/v1beta1\/nodes\/node2.lukeaddison.co.uk&#8221;,<br \/>\n&#8220;creationTimestamp&#8221;: &#8220;2017-10-09T14:21:06Z&#8221;<br \/>\n},<br \/>\n&#8220;timestamp&#8221;: &#8220;2017-10-09T14:21:00Z&#8221;,<br \/>\n&#8220;window&#8221;: &#8220;1m0s&#8221;,<br \/>\n&#8220;usage&#8221;: {<br \/>\n&#8220;cpu&#8221;: &#8220;511m&#8221;,<br \/>\n&#8220;memory&#8221;: &#8220;3589560Ki&#8221;<br \/>\n}<br \/>\n},<br \/>\n{<br \/>\n&#8220;metadata&#8221;: {<br \/>\n&#8220;name&#8221;: &#8220;node3.lukeaddison.co.uk&#8221;,<br \/>\n&#8220;selfLink&#8221;: &#8220;\/apis\/metrics.k8s.io\/v1beta1\/nodes\/node3.lukeaddison.co.uk&#8221;,<br \/>\n&#8220;creationTimestamp&#8221;: &#8220;2017-10-09T14:21:06Z&#8221;<br \/>\n},<br \/>\n&#8220;timestamp&#8221;: &#8220;2017-10-09T14:21:00Z&#8221;,<br \/>\n&#8220;window&#8221;: &#8220;1m0s&#8221;,<br \/>\n&#8220;usage&#8221;: {<br \/>\n&#8220;cpu&#8221;: &#8220;301m&#8221;,<br \/>\n&#8220;memory&#8221;: &#8220;2453620Ki&#8221;<br \/>\n}<br \/>\n}<br \/>\n]<br \/>\n}<\/p>\n<p>The resource metrics API allows HPA v2 to scale on resource metrics such as CPU and memory usage, however this API does not allow us to consume application specific metrics &#8211; we need something extra.<\/p>\n<p>The purpose of the custom metrics API is to provide a stable, versioned API that end-users and Kubernetes components can rely on. Implementations of the custom metrics API provide custom metrics to the HPA controller and form part of the monitoring pipeline.<\/p>\n<p>The steps required to configure your cluster to use a custom metrics API implementation can be found in the <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/run-application\/horizontal-pod-autoscale\/#support-for-custom-metrics\">Kubernetes HPA docs<\/a>. There are not a huge number of <a href=\"https:\/\/github.com\/kubernetes\/metrics\/blob\/master\/IMPLEMENTATIONS.md\">implementations<\/a> yet and none that are officially part of Kubernetes, but a good one to try at the moment is the <a href=\"https:\/\/github.com\/directxman12\/k8s-prometheus-adapter\">Prometheus adapter<\/a>. This adapter translates queries for custom metrics into <a href=\"https:\/\/prometheus.io\/docs\/querying\/basics\/\">PromQL<\/a>, the Prometheus query language, in order to query Prometheus itself and pass the results back to the caller.<\/p>\n<p>There is a nice <a href=\"https:\/\/github.com\/DirectXMan12\/k8s-prometheus-adapter\/blob\/master\/docs\/walkthrough.md\">walk-through<\/a> by <a href=\"https:\/\/github.com\/DirectXMan12\">DirectXMan12<\/a> that covers cluster prerequisites, how to deploy Prometheus and how to inject a Prometheus adapter container into your Prometheus deployment. This adapter can then be registered with the API Server using an APIService resource to tell the aggregator where to forward requests for custom metrics. Note that the walk-through uses the API Server path \/apis\/custom-metrics.metrics.k8s.io but for 1.8 a <a href=\"https:\/\/github.com\/kubernetes\/kubernetes\/pull\/51653#issuecomment-326654444\">decision<\/a> was made to use \/apis\/custom.metrics.k8s.io so you will need to change your APIService resource appropriately. <a href=\"https:\/\/github.com\/luxas\">luxas<\/a> has a nice example of <a href=\"https:\/\/github.com\/luxas\/kubeadm-workshop\/blob\/master\/demos\/monitoring\/custom-metrics.yaml\">everything<\/a> &#8211; thanks!<\/p>\n<p>As before, we can test our new add-on API server using kubectl get &#8211;raw. The following command should return a list of all custom metrics from the Prometheus adapter.<\/p>\n<p>$ kubectl get &#8211;raw &#8220;\/apis\/custom.metrics.k8s.io\/v1beta1&#8221; | jq<br \/>\n{<br \/>\n&#8220;kind&#8221;: &#8220;APIResourceList&#8221;,<br \/>\n&#8220;apiVersion&#8221;: &#8220;v1&#8221;,<br \/>\n&#8220;groupVersion&#8221;: &#8220;custom.metrics.k8s.io\/v1beta1&#8221;,<br \/>\n&#8220;resources&#8221;: [<br \/>\n{<br \/>\n&#8220;name&#8221;: &#8220;pods\/tasks_state&#8221;,<br \/>\n&#8220;singularName&#8221;: &#8220;&#8221;,<br \/>\n&#8220;namespaced&#8221;: true,<br \/>\n&#8220;kind&#8221;: &#8220;MetricValueList&#8221;,<br \/>\n&#8220;verbs&#8221;: [<br \/>\n&#8220;get&#8221;<br \/>\n]<br \/>\n},<br \/>\n{<br \/>\n&#8220;name&#8221;: &#8220;pods\/memory_failcnt&#8221;,<br \/>\n&#8220;singularName&#8221;: &#8220;&#8221;,<br \/>\n&#8220;namespaced&#8221;: true,<br \/>\n&#8220;kind&#8221;: &#8220;MetricValueList&#8221;,<br \/>\n&#8220;verbs&#8221;: [<br \/>\n&#8220;get&#8221;<br \/>\n]<br \/>\n},<br \/>\n&#8230;<br \/>\n{<br \/>\n&#8220;name&#8221;: &#8220;pods\/memory_swap&#8221;,<br \/>\n&#8220;singularName&#8221;: &#8220;&#8221;,<br \/>\n&#8220;namespaced&#8221;: true,<br \/>\n&#8220;kind&#8221;: &#8220;MetricValueList&#8221;,<br \/>\n&#8220;verbs&#8221;: [<br \/>\n&#8220;get&#8221;<br \/>\n]<br \/>\n}<br \/>\n]<br \/>\n}<\/p>\n<p>With the Prometheus adapter deployed, we can use the power of Prometheus to scale our workloads on custom metrics specifically tailored to our applications.<\/p>\n<p>The following example shows a HPA that scales an nginx deployment using a single resource metric (CPU) and two custom metrics (packets-per-second and requests-per-second)<\/p>\n<p>apiVersion: autoscaling\/v2beta1<br \/>\nkind: HorizontalPodAutoscaler<br \/>\nmetadata:<br \/>\nname: nginx<br \/>\nspec:<br \/>\nscaleTargetRef:<br \/>\napiVersion: apps\/v1beta1<br \/>\nkind: Deployment<br \/>\nname: nginx<br \/>\nminReplicas: 1<br \/>\nmaxReplicas: 10<br \/>\nmetrics:<br \/>\n&#8211; type: Resource<br \/>\nresource:<br \/>\nname: cpu<br \/>\ntargetAverageUtilization: 50<br \/>\n&#8211; type: Pods<br \/>\npods:<br \/>\nmetricName: packets-per-second<br \/>\ntargetAverageValue: 1k<br \/>\n&#8211; type: Object<br \/>\nobject:<br \/>\nmetricName: requests-per-second<br \/>\ntarget:<br \/>\napiVersion: extensions\/v1beta1<br \/>\nkind: Ingress<br \/>\nname: main-route<br \/>\ntargetValue: 2k<\/p>\n<ul>\n<li>To get the value for the resource metric, the HPA controller uses the resource metrics API by querying the API Server path \/apis\/metrics.k8s.io\/v1beta1\/pods.<\/li>\n<li>For custom metrics, the HPA controller uses the custom metrics API and will query the API server paths \/apis\/custom.metrics.k8s.io\/v1beta1\/namespaces\/default\/pods\/*\/packets-per-second for type Pods and \/apis\/custom.metrics.k8s.io\/v1beta1\/namespaces\/default\/ingress.extensions\/main-route\/requests-per-second for type Object.<\/li>\n<\/ul>\n<p>Note that these APIs are still in a beta status, and so may still be subject to changes. If you are using these APIs, please check the Kubernetes release notes before performing cluster upgrades to ensure your old resources are still valid.<\/p>\n<p><a href=\"https:\/\/blog.jetstack.io\/blog\/resource-and-custom-metrics-hpa-v2\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>By Luke Addison In the coming weeks we will be releasing a series of blog posts called Kubernetes 1.8: Hidden Gems, accenting some of the less obvious but wonderful features in the latest Kubernetes release. In this week\u2019s gem, Luke looks at some of the main components in the core metrics and monitoring pipelines and &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/10\/16\/kubernetes-1-8-hidden-gems-the-resource-metrics-api-the-custom-metrics-api-and-hpa-v2\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Kubernetes 1.8: Hidden Gems &#8211; The Resource Metrics API, the Custom Metrics API and HPA v2 \/&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-391","post","type-post","status-publish","format-standard","hentry","category-kubernetes"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/391","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/comments?post=391"}],"version-history":[{"count":1,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/391\/revisions"}],"predecessor-version":[{"id":537,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/391\/revisions\/537"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/media?parent=391"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/categories?post=391"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/tags?post=391"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}