Prometheus Custom Metrics Adapter
After you've enabled [cluster level monitoring]({{< baseurl >}}/rancher/v2.0-v2.4/en/monitoring-alerting/legacy/monitoring/cluster-monitoring/), You can view the metrics data from Rancher. You can also deploy the Prometheus custom metrics adapter then you can use the HPA with metrics stored in cluster monitoring.
#
Deploy Prometheus Custom Metrics AdapterWe are going to use the Prometheus custom metrics adapter, version v0.5.0. This is a great example for the custom metrics server. And you must be the cluster owner to execute following steps.
Get the service account of the cluster monitoring is using. It should be configured in the workload ID:
statefulset:cattle-prometheus:prometheus-cluster-monitoring
. And if you didn't customize anything, the service account name should becluster-monitoring
.Grant permission to that service account. You will need two kinds of permission. One role is
extension-apiserver-authentication-reader
inkube-system
, so you will need to create aRolebinding
to inkube-system
. This permission is to get api aggregation configuration from config map inkube-system
.
The other one is cluster role system:auth-delegator
, so you will need to create a ClusterRoleBinding
. This permission is to have subject access review permission.
- Create configuration for custom metrics adapter. Following is an example configuration. There will be a configuration details in next session.
- Create HTTPS TLS certs for your api server. You can use following command to create a self-signed cert.
- Then you can create the prometheus custom metrics adapter. And you will need a service for this deployment too. Creating it via Import YAML or Rancher would do. Please create those resources in
cattle-prometheus
namespaces.
Here is the prometheus custom metrics adapter deployment.
Here is the service of the deployment.
- Create API service for your custom metric server.
Then you can verify your custom metrics server by
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
. If you see the return datas from the api, it means that the metrics server has been successfully set up.You create HPA with custom metrics now. Here is an example of HPA. You will need to create a nginx deployment in your namespace first.
And then, you should see your nginx is scaling up. HPA with custom metrics works.
#
Configuration of prometheus custom metrics adapterRefer to https://github.com/DirectXMan12/k8s-prometheus-adapter/blob/master/docs/config.md
The adapter determines which metrics to expose, and how to expose them, through a set of "discovery" rules. Each rule is executed independently (so make sure that your rules are mutually exclusive), and specifies each of the steps the adapter needs to take to expose a metric in the API.
Each rule can be broken down into roughly four parts:
Discovery, which specifies how the adapter should find all Prometheus metrics for this rule.
Association, which specifies how the adapter should determine which Kubernetes resources a particular metric is associated with.
Naming, which specifies how the adapter should expose the metric in the custom metrics API.
Querying, which specifies how a request for a particular metric on one or more Kubernetes objects should be turned into a query to Prometheus.
A basic config with one rule might look like:
#
DiscoveryDiscovery governs the process of finding the metrics that you want to
expose in the custom metrics API. There are two fields that factor into
discovery: seriesQuery
and seriesFilters
.
seriesQuery
specifies Prometheus series query (as passed to the
/api/v1/series
endpoint in Prometheus) to use to find some set of
Prometheus series. The adapter will strip the label values from this
series, and then use the resulting metric-name-label-names combinations
later on.
In many cases, seriesQuery
will be sufficient to narrow down the list of
Prometheus series. However, sometimes (especially if two rules might
otherwise overlap), it's useful to do additional filtering on metric
names. In this case, seriesFilters
can be used. After the list of
series is returned from seriesQuery
, each series has its metric name
filtered through any specified filters.
Filters may be either:
is: <regex>
, which matches any series whose name matches the specified regex.isNot: <regex>
, which matches any series whose name does not match the specified regex.
For example:
#
AssociationAssociation governs the process of figuring out which Kubernetes resources
a particular metric could be attached to. The resources
field controls
this process.
There are two ways to associate resources with a particular metric. In both cases, the value of the label becomes the name of the particular object.
One way is to specify that any label name that matches some particular
pattern refers to some group-resource based on the label name. This can
be done using the template
field. The pattern is specified as a Go
template, with the Group
and Resource
fields representing group and
resource. You don't necessarily have to use the Group
field (in which
case the group is guessed by the system). For instance:
The other way is to specify that some particular label represents some
particular Kubernetes resource. This can be done using the overrides
field. Each override maps a Prometheus label to a Kubernetes
group-resource. For instance:
These two can be combined, so you can specify both a template and some individual overrides.
The resources mentioned can be any resource available in your kubernetes cluster, as long as you've got a corresponding label.
#
NamingNaming governs the process of converting a Prometheus metric name into
a metric in the custom metrics API, and vice versa. It's controlled by
the name
field.
Naming is controlled by specifying a pattern to extract an API name from a Prometheus name, and potentially a transformation on that extracted value.
The pattern is specified in the matches
field, and is just a regular
expression. If not specified, it defaults to .*
.
The transformation is specified by the as
field. You can use any
capture groups defined in the matches
field. If the matches
field
doesn't contain capture groups, the as
field defaults to $0
. If it
contains a single capture group, the as
field defautls to $1
.
Otherwise, it's an error not to specify the as field.
For example:
#
QueryingQuerying governs the process of actually fetching values for a particular
metric. It's controlled by the metricsQuery
field.
The metricsQuery
field is a Go template that gets turned into
a Prometheus query, using input from a particular call to the custom
metrics API. A given call to the custom metrics API is distilled down to
a metric name, a group-resource, and one or more objects of that
group-resource. These get turned into the following fields in the
template:
Series
: the metric nameLabelMatchers
: a comma-separated list of label matchers matching the given objects. Currently, this is the label for the particular group-resource, plus the label for namespace, if the group-resource is namespaced.GroupBy
: a comma-separated list of labels to group by. Currently, this contains the group-resource label used inLabelMatchers
.
For instance, suppose we had a series http_requests_total
(exposed as
http_requests_per_second
in the API) with labels service
, pod
,
ingress
, namespace
, and verb
. The first four correspond to
Kubernetes resources. Then, if someone requested the metric
pods/http_request_per_second
for the pods pod1
and pod2
in the
somens
namespace, we'd have:
Series: "http_requests_total"
LabelMatchers: "pod=~\"pod1|pod2",namespace="somens"
GroupBy
:pod
Additionally, there are two advanced fields that are "raw" forms of other fields:
LabelValuesByName
: a map mapping the labels and values from theLabelMatchers
field. The values are pre-joined by|
(for used with the=~
matcher in Prometheus).GroupBySlice
: the slice form ofGroupBy
.
In general, you'll probably want to use the Series
, LabelMatchers
, and
GroupBy
fields. The other two are for advanced usage.
The query is expected to return one value for each object requested. The adapter will use the labels on the returned series to associate a given series back to its corresponding object.
For example: