Carregar métricas do servidor Prometheus

Visão geral

Isso carrega CoreDNS tutorial métricas de uma Prometheus servidor em um tf.data.Dataset , em seguida, utiliza tf.keras de formação e inferência.

CoreDNS é um servidor DNS com foco na descoberta de serviços, e é amplamente implantado como parte do Kubernetes cluster. Por esse motivo, muitas vezes é monitorado de perto pelas operações de devops.

Este tutorial é um exemplo que pode ser usado por devops que buscam automação em suas operações por meio de aprendizado de máquina.

Configuração e uso

Instale o pacote tensorflow-io necessário e reinicie o tempo de execução

import os
try:
 
%tensorflow_version 2.x
except Exception:
 
pass
TensorFlow 2.x selected.
pip install tensorflow-io
from datetime import datetime

import tensorflow as tf
import tensorflow_io as tfio

Instalar e configurar CoreDNS e Prometheus

Para demonstração fins, um servidor CoreDNS localmente com a porta 9053 aberta para receber consultas DNS e porta 9153 (defult) aberta para expor métricas para raspagem. O seguinte é uma configuração básica corefile para CoreDNS e está disponível para baixar :

.:9053 {
  prometheus
  whoami
}

Mais detalhes sobre a instalação poderia ser encontrado na das CoreDNS documentação .

curl -s -OL https://github.com/coredns/coredns/releases/download/v1.6.7/coredns_1.6.7_linux_amd64.tgz
tar -xzf coredns_1.6.7_linux_amd64.tgz

curl -s -OL https://raw.githubusercontent.com/tensorflow/io/master/docs/tutorials/prometheus/Corefile

cat Corefile
.:9053 {
  prometheus
  whoami
}
# Run `./coredns` as a background process.
# IPython doesn't recognize `&` in inline bash cells.
get_ipython
().system_raw('./coredns &')

O próximo passo é para o servidor Prometeu configuração e usar Prometeu para CoreDNS scrape métricas que estão expostas na porta 9153 de cima. O prometheus.yml arquivo de configuração também está disponível para o download :

curl -s -OL https://github.com/prometheus/prometheus/releases/download/v2.15.2/prometheus-2.15.2.linux-amd64.tar.gz
tar -xzf prometheus-2.15.2.linux-amd64.tar.gz --strip-components=1

curl -s -OL https://raw.githubusercontent.com/tensorflow/io/master/docs/tutorials/prometheus/prometheus.yml

cat prometheus.yml
global:
  scrape_interval:     1s
  evaluation_interval: 1s
alerting:
  alertmanagers:

  - static_configs:
    - targets:
rule_files:
scrape_configs:
- job_name: 'prometheus'
  static_configs:
  - targets: ['localhost:9090']
- job_name: "coredns"
  static_configs:
  - targets: ['localhost:9153']
# Run `./prometheus` as a background process.
# IPython doesn't recognize `&` in inline bash cells.
get_ipython
().system_raw('./prometheus &')

A fim de mostrar alguma atividade, dig comando pode ser usado para gerar algumas consultas DNS contra o servidor CoreDNS que foi configurado:

sudo apt-get install -y -qq dnsutils
dig @127.0.0.1 -p 9053 demo1.example.org
; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @127.0.0.1 -p 9053 demo1.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53868
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 855234f1adcb7a28 (echoed)
;; QUESTION SECTION:
;demo1.example.org.     IN  A

;; ADDITIONAL SECTION:
demo1.example.org.  0   IN  A   127.0.0.1
_udp.demo1.example.org. 0   IN  SRV 0 0 45361 .

;; Query time: 0 msec
;; SERVER: 127.0.0.1#9053(127.0.0.1)
;; WHEN: Tue Mar 03 22:35:20 UTC 2020
;; MSG SIZE  rcvd: 132
dig @127.0.0.1 -p 9053 demo2.example.org
; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @127.0.0.1 -p 9053 demo2.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53163
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: f18b2ba23e13446d (echoed)
;; QUESTION SECTION:
;demo2.example.org.     IN  A

;; ADDITIONAL SECTION:
demo2.example.org.  0   IN  A   127.0.0.1
_udp.demo2.example.org. 0   IN  SRV 0 0 42194 .

;; Query time: 0 msec
;; SERVER: 127.0.0.1#9053(127.0.0.1)
;; WHEN: Tue Mar 03 22:35:21 UTC 2020
;; MSG SIZE  rcvd: 132

Agora, um servidor CoreDNS cujas métricas são extraídas por um servidor Prometheus e prontas para serem consumidas pelo TensorFlow.

Criar conjunto de dados para métricas do CoreDNS e usá-lo no TensorFlow

Criar um conjunto de dados para CoreDNS métricas que é acessível através de um servidor PostgreSQL, poderia ser feito com tfio.experimental.IODataset.from_prometheus . No mínimo dois argumentos são necessários. query é passada para o servidor Prometheus para selecionar as métricas e length é o período que você deseja carregar em Dataset.

Você pode começar com "coredns_dns_request_count_total" e "5" (segundos) para criar o conjunto de dados abaixo. Desde anteriormente no tutorial duas consultas DNS foram enviados, espera-se que as métricas para "coredns_dns_request_count_total" será "2.0" no final da série temporal:

dataset = tfio.experimental.IODataset.from_prometheus(
     
"coredns_dns_request_count_total", 5, endpoint="http://localhost:9090")


print("Dataset Spec:\n{}\n".format(dataset.element_spec))

print("CoreDNS Time Series:")
for (time, value) in dataset:
 
# time is milli second, convert to data time:
  time
= datetime.fromtimestamp(time // 1000)
 
print("{}: {}".format(time, value['coredns']['localhost:9153']['coredns_dns_request_count_total']))
Dataset Spec:
(TensorSpec(shape=(), dtype=tf.int64, name=None), {'coredns': {'localhost:9153': {'coredns_dns_request_count_total': TensorSpec(shape=(), dtype=tf.float64, name=None)} } })

CoreDNS Time Series:
2020-03-03 22:35:17: 2.0
2020-03-03 22:35:18: 2.0
2020-03-03 22:35:19: 2.0
2020-03-03 22:35:20: 2.0
2020-03-03 22:35:21: 2.0

Analisando ainda mais as especificações do conjunto de dados:

(
 
TensorSpec(shape=(), dtype=tf.int64, name=None),
 
{
   
'coredns': {
     
'localhost:9153': {
       
'coredns_dns_request_count_total': TensorSpec(shape=(), dtype=tf.float64, name=None)
     
}
   
}
 
}
)

É óbvio que o conjunto de dados consiste de um (time, values) tuple onde a values de campo é um dict python expandiu-se em:

"job_name": {
 
"instance_name": {
   
"metric_name": value,
 
},
}

No exemplo acima, 'coredns' é o nome do trabalho, 'localhost:9153' é o nome da instância e 'coredns_dns_request_count_total' é o nome da métrica. Observe que, dependendo da consulta do Prometheus usada, é possível que vários jobs/instâncias/métricas possam ser retornados. Esta é também a razão pela qual o python dict foi usado na estrutura do Dataset.

Tome outra consulta "go_memstats_gc_sys_bytes" como um exemplo. Uma vez que ambos CoreDNS e Prometheus são escritos em golang, "go_memstats_gc_sys_bytes" métrica está disponível para "coredns" trabalho e "prometheus" trabalho:

dataset = tfio.experimental.IODataset.from_prometheus(
   
"go_memstats_gc_sys_bytes", 5, endpoint="http://localhost:9090")

print("Time Series CoreDNS/Prometheus Comparision:")
for (time, value) in dataset:
 
# time is milli second, convert to data time:
  time
= datetime.fromtimestamp(time // 1000)
 
print("{}: {}/{}".format(
      time
,
      value
['coredns']['localhost:9153']['go_memstats_gc_sys_bytes'],
      value
['prometheus']['localhost:9090']['go_memstats_gc_sys_bytes']))
Time Series CoreDNS/Prometheus Comparision:
2020-03-03 22:35:17: 2385920.0/2775040.0
2020-03-03 22:35:18: 2385920.0/2775040.0
2020-03-03 22:35:19: 2385920.0/2775040.0
2020-03-03 22:35:20: 2385920.0/2775040.0
2020-03-03 22:35:21: 2385920.0/2775040.0

O criado Dataset está pronto para ser passado para tf.keras diretamente para uma formação ou inferência fins agora.

Usar conjunto de dados para treinamento de modelo

Com métricas Dataset criados, é possível passar diretamente o conjunto de dados para tf.keras de formação ou inferência modelo.

Para fins de demonstração, este tutorial usará apenas um modelo LSTM muito simples com 1 recurso e 2 etapas como entrada:

n_steps, n_features = 2, 1
simple_lstm_model
= tf.keras.models.Sequential([
    tf
.keras.layers.LSTM(8, input_shape=(n_steps, n_features)),
    tf
.keras.layers.Dense(1)
])

simple_lstm_model
.compile(optimizer='adam', loss='mae')

O conjunto de dados a ser usado é o valor de 'go_memstats_sys_bytes' para CoreDNS com 10 amostras. No entanto, uma vez que uma janela deslizante de window=n_steps e shift=1 são formados, amostras adicionais são necessários (por quaisquer dois elementos consecute, o primeiro é tomado como x e o segundo é tomado como y para formação). O total é de 10 + n_steps - 1 + 1 = 12 segundos.

O valor de dados também é dimensionado para [0, 1] .

n_samples = 10

dataset
= tfio.experimental.IODataset.from_prometheus(
   
"go_memstats_sys_bytes", n_samples + n_steps - 1 + 1, endpoint="http://localhost:9090")

# take go_memstats_gc_sys_bytes from coredns job
dataset
= dataset.map(lambda _, v: v['coredns']['localhost:9153']['go_memstats_sys_bytes'])

# find the max value and scale the value to [0, 1]
v_max
= dataset.reduce(tf.constant(0.0, tf.float64), tf.math.maximum)
dataset
= dataset.map(lambda v: (v / v_max))

# expand the dimension by 1 to fit n_features=1
dataset
= dataset.map(lambda v: tf.expand_dims(v, -1))

# take a sliding window
dataset
= dataset.window(n_steps, shift=1, drop_remainder=True)
dataset
= dataset.flat_map(lambda d: d.batch(n_steps))


# the first value is x and the next value is y, only take 10 samples
x
= dataset.take(n_samples)
y
= dataset.skip(1).take(n_samples)

dataset
= tf.data.Dataset.zip((x, y))

# pass the final dataset to model.fit for training
simple_lstm_model
.fit(dataset.batch(1).repeat(10),  epochs=5, steps_per_epoch=10)
Train for 10 steps
Epoch 1/5
10/10 [==============================] - 2s 150ms/step - loss: 0.8484
Epoch 2/5
10/10 [==============================] - 0s 10ms/step - loss: 0.7808
Epoch 3/5
10/10 [==============================] - 0s 10ms/step - loss: 0.7102
Epoch 4/5
10/10 [==============================] - 0s 11ms/step - loss: 0.6359
Epoch 5/5
10/10 [==============================] - 0s 11ms/step - loss: 0.5572
<tensorflow.python.keras.callbacks.History at 0x7f1758f3da90>

O modelo treinado acima não é muito útil na realidade, pois o servidor CoreDNS que foi configurado neste tutorial não possui carga de trabalho. No entanto, este é um pipeline de trabalho que pode ser usado para carregar métricas de servidores de produção reais. O modelo poderia então ser melhorado para resolver o problema do mundo real da automação de devops.