Prometheus et localhost

#ops #prometheus #go

Prometheus a besoin d’accéder la route /handler de ce que vous voulez instrumenter.

J’ai donc une instance Prometheus qui tourne sur un serveur derrière un NAT (cad à la maison) et je veux les métriques d’un processus qui tourne sur mon serveur publique. Ce processus expose ses métriques sur http://localhost:2019/metrics.

Alors oui, je pourrais pousser les métriques sur Prometheus, mais alors j’aurais d’autres problèmes.

Alors oui, je pourrais exposer les métriques sur http://0.0.0.0:2019 mais alors ce serait open bar et même avec de l’auth, j’aime pas ça.

Alors oui, je pourrais ajouter un règle IP, mais je ne peux pas garantir que l’IP publique de mon NAT ne va pas changer.

Alors oui, je pourrais mettre en place un double passerelle, mais bon, pourquoi si compliqué.

Ma réflexion a donc été:

  • Les métriques sont exposées sur le localhost du serveur
  • J’ai un accès ssh sur ce serveur
  • Le scrapping Prometheus veut juste un handler HTTP

Donc…

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"time"
)

type Server struct {
	TargetHost string
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	cmd := exec.Command("ssh", s.TargetHost, "curl", "http://127.0.0.1:2019/metrics")
	out, err := cmd.Output()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(out)
}

func main() {
	bindAddr := os.Getenv("PROMSSHP_BIND")
	if bindAddr == "" {
		bindAddr = ":8090"
	}

	target := os.Getenv("PROMSSHP_TARGET") // i.e "myuser@myserver"

	s := &http.Server{
		Addr: bindAddr,
		Handler: &Server{
			TargetHost: target,
		},
		ReadTimeout:  60 * time.Second,
		WriteTimeout: 60 * time.Second,
	}
	log.Fatal(s.ListenAndServe())
}

Problème résolu. Prometheus peut scrap sur son propre localhost et j’ai absolument rien à maintenir.

Un petit coup de systemd, et on peut l’oublier.

[Unit]
Description=Prometheus metrics SSH proxy
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]
Restart=on-abnormal

; User and group the process will run as.
User=myuser
Group=myuser

ExecStart=/home/proullon/go/bin/promsshp

[Install]
WantedBy=multi-user.target