Carregar métricas do servidor Prometheus

Veja no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

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.