Prometheus chapter

This commit is contained in:
Jerome Petazzoni
2018-09-08 07:16:28 -05:00
parent f74addd0ca
commit 57166f33aa
2 changed files with 487 additions and 5 deletions

486
slides/k8s/prometheus.md Normal file
View File

@@ -0,0 +1,486 @@
# Collecting metrics with Prometheus
- Prometheus is an open-source monitoring system including:
- multiple *service discovery* backends to figure out which metrics to collect
- a *scraper* to collect these metrics
- an efficient *time series database* to store these metrics
- a specific query language (PromQL) to query these time series
- an *alert manager* to notify us according to metrics values or trends
- We are going to deploy it on our Kubernetes cluster and see how to query it
---
## Why Prometheus?
- We don't endorse Prometheus more or less than any other system
- It's relatively well integrated within the Cloud Native ecosystem
- It can be self-hosted (this is useful for tutorials like this)
- It can be used for deployments of varying complexity:
- one binary and 10 lines of configuration to get started
- all the way to thousands of nodes and millions of metrics
---
## Exposing metrics to Prometheus
- Prometheus obtains metrics and their values by querying *exporters*
- An exporter serves metrics over HTTP, in plain text
- This is was the *node exporter* looks like:
http://demo.robustperception.io:9100/metrics
- Prometheus itself exposes its own internal metrics, too:
http://demo.robustperception.io:9090/metrics
- If you want to expose custom metrics to Prometheus:
- serve a text page like these, and you're good to go
- libraries are available in various languages to help with quantiles etc.
---
## How Prometheus gets these metrics
- The *Prometheus server* will *scrape* URLs like these at regular intervals
(by default: every minute; can be more/less frequent)
- If you're worried about parsing overhead: exporters can also use protobuf
- The list of URLs to scrape (the *scrape targets*) is defined in configuration
---
## Defining scrape targets
This is maybe the simplest configuration file for Prometheus:
```yaml
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
```
- In this configuration, Prometheus collects its own internal metrics
- A typical configuration file will have multiple `scrape_configs`
- In this configuration, the list of targets is fixed
- A typical configuration file will use dynamic service discovery
---
## Service discovery
This configuration file will leverage existing DNS `A` records:
```yaml
scrape_configs:
- ...
- job_name: 'node'
dns_sd_configs:
- names: ['api-backends.dc-paris-2.enix.io']
type: 'A'
port: 9100
```
- In this configuration, Prometheus resolves the provided name(s)
(here, `api-backends.dc-paris-2.enix.io`)
- Each resulting IP address is added as a target on port 9100
---
## Dynamic service discovery
- In the DNS example, the names are re-resolved at regular intervals
- As DNS records are created/updated/removed, scrape targets change as well
- Existing data (previously collected metrics) is not deleted
- Other service discovery backends work in a similar fashion
---
## Other service discovery mechanisms
- Prometheus can connect to e.g. a cloud API to list instances
- Or to the Kubernetes API to list nodes, pods, services ...
- Or a service like Consul, Zookeeper, etcd, to list applications
- The resulting configurations files are *way more complex*
(but don't worry, we won't need to write them ourselves)
---
## Time series database
- We could wonder, "why do we need a specialized database?"
- One metrics data point = metrics ID + timestamp + value
- With a classic SQL or noSQL data store, that's at least 160 bits of data + indexes
- Prometheus is way more efficient, without sacrificing performance
(it will even be gentler on the I/O subsystem since it needs to write less)
FIXME link to Goutham's talk
---
## Running Prometheus on our cluster
We need to:
- Run the Prometheus server in a pod
(using e.g. a Deployment to ensure that it keeps running)
- Expose the Prometheus server web UI (e.g. with a NodePort)
- Run the *node exporter* on each node (with a Daemon Set)
- Setup a Service Account so that Prometheus can query the Kubernetes API
- Configure the Prometheus server
(storing the configuration in a Config Map for easy updates)
---
## Helm Charts to the rescue
- To make our lives easier, we are going to use a Helm Chart
- The Helm Chart will take care of all the steps explained above
(including some extra features that we don't need, but won't hurt)
---
## Step 1: install Helm
- If we already installed Helm earlier, these commands won't break anything
.exercice[
- Install Tiller (Helm's server-side component) on our cluster:
```bash
helm init
```
- Give Tiller permission to deploy things on our cluster:
```bash
kubectl create clusterrolebinding add-on-cluster-admin \
--clusterrole=cluster-admin --serviceaccount=kube-system:default
```
]
---
## Step 2: install Prometheus
- Skip this if we already installed Prometheus earlier
(in doubt, check with `helm list`)
.exercice[
- Install Prometheus on our cluster:
```bash
helm install stable/prometheus \
--set server.service.type=NodePort \
--set server.persistentVolume.enabled=false
```
]
The provided flags:
- expose the server web UI (and API) on a NodePort
- use an ephemeral volume for metrics storage
<br/>
(instead of requesting a Persistent Volume through a Persistent Volume Claim)
---
## Connecting to the Prometheus web UI
- Let's connect to the web UI and see what we can do
.exercise[
- Figure out the NodePort that was allocated to the Prometheus server:
```bash
kubectl get svc prometheus-server
```
- With your browser, connect to that port
]
---
## Querying some metrics
- This is easy ... if you are familiar with PromQL
.exercise[
- Click on "Graph", and in "expression", paste the following:
```
sum by (instance) (
irate(
container_cpu_usage_seconds_total{
pod_name=~"worker.*"
}[5m]
)
)
```
]
- Click on the blue "Execute" button and on the "Graph" tab just below
- We see the cumulated CPU usage of worker pods for each node
<br/>
(if we just deployed Prometheus, there won't be much data to see, though)
---
## Getting started with PromQL
- We can't learn PromQL in just 5 minutes
- But we can cover the basics to get an idea of what is possible
(and have some keywords and pointers)
- We are going to break down the query above
(building it one step at a time)
---
## Graphing one metric across all tags
This query will show us CPU usage across all containers:
```
container_cpu_usage_seconds_total
```
- The suffix of the metrics name tells us:
- the unit (seconds of CPU)
- that it's the total used since the container creation
- Since it's a "total", it is an increasing quantity
(we need to compute the derivative if we want e.g. CPU % over time)
- We see that the metrics retrieved have *tags* attached to them
---
## Selecting metrics with tags
This query will show us only metrics for worker containers:
```
container_cpu_usage_seconds_total{pod_name=~"worker.*"}
```
- The `=~` operator allows regex matching
- We select all the pods with a name starting with `worker`
(it would be better to use labels to select pods; more on that later)
- The result is a smaller set of containers
---
## Transforming counters in rates
This query will show us CPU usage % instead of total seconds used:
```
100*irate(container_cpu_usage_seconds_total{pod_name=~"worker.*"}[5m])
```
- The [`irate`](https://prometheus.io/docs/prometheus/latest/querying/functions/#irate) operator computes the "per-second instant rate of increase"
- `rate` is similar but allows decreasing counters and negative values
- with `irate`, if a counter goes back to zero, we don't get a negative spike
- The `[5m]` tells how far to look back if there is a gap in the data
- And we multiply with `100*` to get CPU % usage
---
## Aggregation operators
This query sums the CPU usage per node:
```
sum by (instance) (
irate(container_cpu_usage_seconds_total{pod_name=~"worker.*"}[5m])
)
```
- `instance` corresponds to the node on which the container is running
- `sum by (instance) (...)` computes the sum for each instance
- Note: all the other tags are collapsed
(in other words, the resulting graph only shows the `instance` tag)
- PromQL supports many more [aggregation operators](https://prometheus.io/docs/prometheus/latest/querying/operators/#aggregation-operators)
---
## What kind of metrics can we collect?
- Node metrics (related to physical or virtual machines)
- Container metrics (resource usage per container)
- Databases, message queues, load balancers, ...
(check out this [list of exporters](https://prometheus.io/docs/instrumenting/exporters/)!)
- Instrumentation (=deluxe `printf` for our code)
- Business metrics (customers served, revenue, ...)
---
class: extra-details
## Node metrics
- CPU, RAM, disk usage on the whole node
- Total number of processes running, and their states
- Number of open files, sockets, and their states
- I/O activity (disk, network), per operation or volume
- Physical/hardware (when applicable): temperature, fan speed ...
- ... and much more!
---
class: extra-details
## Container metrics
- Similar to node metrics, but not totally identical
- RAM breakdown will be different
- active vs inactive memory
- some memory is *shared* between containers, and accounted specially
- I/O activity is also harder to track
- async writes can cause deferred "charges"
- some page-ins are also shared between containers
For details about container metrics, see:
<br/>
http://jpetazzo.github.io/2013/10/08/docker-containers-metrics/
---
class: extra-details
## Application metrics
- Arbitrary metrics related to your application and business
- System performance: request latency, error rate ...
- Volume information: number of rows in database, message queue size ...
- Business data: inventory, items sold, revenue ...
---
class: extra-details
## Detecting scrape targets
- Prometheus can leverage Kubernetes service discovery
(with proper configuration)
- Services or pods can be annotated with:
- `prometheus.io/scrape: true` to enable scraping
- `prometheus.io/port: 9090` to indicate the port number
- `prometheus.io/path: /metrics` to indicate the URI (`/metrics` by default)
- Prometheus will detect and scrape these (without needing a restart or reload)
---
## Querying labels
- What if we want to get metrics for containers belong to pod tagged `worker`?
- The cAdvisor exporter does not give us Kubernetes labels
- Kubernetes labels are exposed through another exporter
- We can see Kubernetes labels through metrics `kube_pod_labels`
(each container appears as a time series with constant value of `1`)
- Prometheus *kind of* supports "joins" between time series
- But only if the names of the tags match exactly
---
## Unfortunately ...
- The cAdvisor exporter uses tag `pod_name` for the name of a pod
- The Kubernetes service endpoints exporter uses tag `pod` instead
- And this is why we can't have nice things
- See [Prometheus issue #2204](https://github.com/prometheus/prometheus/issues/2204) for the rationale
([this comment](https://github.com/prometheus/prometheus/issues/2204#issuecomment-261515520) in particular if you want a workaround involving relabeling)
- Then see [this blog post](https://www.robustperception.io/exposing-the-software-version-to-prometheus) or [this other one](https://www.weave.works/blog/aggregating-pod-resource-cpu-memory-usage-arbitrary-labels-prometheus/) to see how to perform "joins"
- There is a good chance that the situation will improve in the future

View File

@@ -18,10 +18,6 @@ chapters:
- - k8s/authn-authz.md
- k8s/ingress.md
- k8s/gitworkflows.md
- |
# metrics
prometheus
- k8s/prometheus.md
- - k8s/healthchecks.md