Cet article est le second d’une série de 3 sur le monitoring avec un focus sur Thanos.
- Partie 1 : “Thanos : stockage des métriques Prometheus sur le long terme”
- Partie 2 : “Déployer Thanos et Prometheus sur un cluster K8s”
- Partie 3 : “Thanos : agrégation de plusieurs Prometheus”
Dans deux précédents articles, nous avons vu comment superviser Kubernetes avec Prometheus et le fonctionnement de Thanos pour stocker ses métriques sur le long terme.
Aujourd’hui, place à l’action : on fait chauffer notre cluster Kubernetes et on se penche sur comment déployer Thanos.
Note : on se concentre ici sur un Prometheus et un Thanos sur Kubernetes mais on peut aussi utiliser et déployer Thanos en dehors de Kubernetes.
Déployer Thanos sur K8s
Il nous faut un stockage objet pour que Thanos y conserve les métriques. Dans cet article, on utilise un stockage de type S3 avec une instance MinIO dans le cluster K8s.
Dans la vraie vie, il est tout aussi pertinent d’utiliser du stockage objet fourni par notre cloud provider.
# On installe le MinIO
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install minio bitnami/minio --set persistence.enabled=false
# On récupère les credentials
export ROOT_USER=$(kubectl get secret --namespace monitoring minio -o jsonpath="{.data.root-user}" | base64 -d)
export ROOT_PASSWORD=$(kubectl get secret --namespace monitoring minio -o jsonpath="{.data.root-password}" | base64 -d)
# On créé un bucket 'thanos'
kubectl run --namespace monitoring minio-client --rm --tty -i --restart='Never' --env MINIO_SERVER_ROOT_USER=$ROOT_USER --env MINIO_SERVER_ROOT_PASSWORD=$ROOT_PASSWORD --env MINIO_SERVER_HOST=minio --image docker.io/bitnami/minio-client -- mb -p minio/thanos
Pour cette démo, par simplicité je n’utilise pas de stockage persistant. À ne pas reproduire en production bien évidemment, sous peine de voir ses données disparaître en un claquement de doigts 🙂
De façon similaire, j’agis en tant qu'admin par simplicité, mais il faut normalement un utilisateur dédié avec les bonnes permissions (par exemple pour du S3)
Configuration de l’accès de Thanos au stockage objet
Thanos a besoin de savoir comment se connecter au stockage objet. On crée le Secret pour utiliser le stockage que l’on vient de créer :
export ENDPOINT="minio:9000" BUCKET=thanos
cat > objstore.yml << EOF
type: S3
config:
endpoint: "${ENDPOINT}"
bucket: "${BUCKET}"
access_key: "${ROOT_USER}"
secret_key: "${ROOT_PASSWORD}"
insecure: true
EOF
kubectl create secret generic thanos-objstore --from-file=objstore.yml -o yaml --dry-run=client | kubectl apply -f -
Configuration du Thanos sidecar
Je vous présente ici deux options qui fonctionnent bien :
- via prometheus-operator
- via le Helm chart officiel Prometheus
Avec le prometheus-operator
Custom Resource Prometheus
Le prometheus-operator ajoute automatiquement le sidecar lors du remplissage de la section thanos
de la Custom Resource Prometheus.
Il suffit donc de fournir la configuration pour le stockage objet, avec le secret créé précédemment :
spec:
thanos:
objectStorageConfig:
name: thanos-objstore
key: objstore.yml
Si besoin, il est possible de configurer d’autres éléments du sidecar, comme l’image exacte à utiliser (voir la documentation).
Helm chart kube-prometheus-stack
Le chart kube-prometheus-stack permet aussi de configurer la Custom Resource Prometheus, mais également d’y ajouter un ServiceMonitor pour récupérer les métriques du sidecar, avec les values suivantes :
prometheus:
prometheusSpec:
thanos:
objectStorageConfig:
name: thanos-objstore
key: objstore.yml
thanosService:
enabled: true
thanosServiceMonitor:
enabled: true
Via le Helm chart Prometheus officiel
Dans le cas hautement improbable où prometheus-operator n’est pas utilisé dans le cluster (pour pallier à ce problème 😉), mais plutôt le chart Prometheus, il est également possible de configurer le sidecar. Cela demande des values un poil plus longues :
server:
extraFlags:
- web.enable-lifecycle
- storage.tsdb.min-block-duration=2h
- storage.tsdb.max-block-duration=2h
global:
external_labels:
prometheus_from: myprom
service:
gRPC:
enabled: true
sidecarContainers:
thanos-sidecar:
image: quay.io/thanos/thanos:v0.31.0
imagePullPolicy: IfNotPresent
args:
- sidecar
- --prometheus.url=http://localhost:9090/
- --tsdb.path=/prometheus
- --grpc-address=[$(POD_IP)]:10901
- --http-address=[$(POD_IP)]:10902
- --objstore.config=$(OBJSTORE_CONFIG)
volumeMounts:
- mountPath: /prometheus
name: storage-volume
env:
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: OBJSTORE_CONFIG
valueFrom:
secretKeyRef:
name: thanos-objstore
key: objstore.yml
ports:
- name: http
containerPort: 10902
protocol: TCP
- name: grpc
containerPort: 10901
protocol: TCP
Il y a plusieurs choses à configurer pour Prometheus:
- Activer l’api pour que le sidecar puisse reload en cas de changement de configuration
- S’assurer que les blocs générés par Prometheus ne sont pas compactés (min == max duration)
- Avoir au moins un external label pour identifier l’instance Prometheus
Puis on configure le Thanos sidecar et le service pour l’exposer.
Déployer les autres composants Thanos
On va utiliser le chart bitnami/thanos qui est assez complet. On utilise les values suivantes :
existingObjstoreSecret: thanos-objstore
query:
dnsDiscovery:
sidecarsService: "prometheus-operated"
sidecarsNamespace: "monitoring"
compactor:
enabled: true
storegateway:
enabled: true
metrics:
enabled: true
serviceMonitor:
enabled: true
Puis on déploie avec :
helm upgrade --install thanos bitnami/thanos --values thanos.values.yaml
On a alors 4 composants Thanos qui sont installés:
- query, qui va utiliser le DNS service discovery pour joindre la StoreAPI du sidecar et de la storegateway
- query-frontend, configuré pour cibler le query
- storegateway, qui expose le contenu du stockage objet
- compactor, qui s’occupera de la compaction et de la rétention dans le stockage objet
Par défaut, le compactor et la storegateway ont besoin d’un volume persistent. Dans la réalité, ils peuvent cependant s’en passer, le démarrage sera juste plus long pour la storegateway (le temps de synchroniser les metadata depuis le stockage objet) et le compactor travaillera sur de l'ephemeral-storage (attention à mettre des resources limits dans ce cas). Pour la simplicité de la démo je vais le désactiver :
compactor:
enabled: true
persistence:
enabled: false
storegateway:
enabled: true
persistence:
enabled: false
Le chart est suffisamment flexible pour configurer les différents paramètres de Thanos (cache, durée de rétention, …) et des manifests Kubernetes (ingress, resources, affinity/taint, …).
Un exemple de configuration :
query:
replicaCount: 3
replicaLabel: prometheus_replica
podAntiAffinityPreset: hard
pdb:
create: true
existingSDConfigmap: thanos-storeapi-file-sd
extraFlags:
- --query.promql-engine=thanos
queryFrontend:
replicaCount: 2
podAntiAffinityPreset: hard
pdb:
create: true
extraFlags:
- '--query-frontend.downstream-tripper-config="max_idle_conns_per_host": 100'
config: |-
type: REDIS
config:
addr: 'redis:6379'
compactor:
enabled: true
retentionResolutionRaw: 90d
retentionResolution5m: 180d
retentionResolution1h: 2y
storegateway:
enabled: true
replicaCount: 2
podAntiAffinityPreset: hard
pdb:
create: true
config: |-
type: REDIS
config:
addr: 'redis:6379'
cache_size: '1G'
Avec ces values, on a:
- Le query, query-frontend et la storegateway avec plusieurs réplicas, une anti-affinity (
requiredDuringScheduling
) entre eux et des PodDisruptionBudgets - Le choix du label qui différencie les replicas Prometheus HA sur le query (
replicaLabel
) - L’utilisation d’une ConfigMap avec la liste des StoreAPI pour le service discovery du query
- Des arguments supplémentaires pour le query et query-frontend pour configurer certaines options
- La configuration de Redis comme cache pour le query-frontend et la storegateway
- Les durées de rétention des différentes métriques appliquées par le compactor
Utiliser Thanos à la place de Prometheus
Pour les requêtes PromQL via la WebUI
Le Thanos query fournit une interface similaire à celle de Prometheus. On peut y accéder via un port-forwarding ou bien configurer un ingress. Si le query-frontend est utilisé, c’est dans ses values qu’il faut configurer l'ingress :
queryFrontend:
ingress:
enabled: true
hostname: thanos.example.com
ingressClassName: public
On retrouve de quoi faire des requêtes PromQL, comme avec Prometheus :
Les alertes, targets et rules des différents Prometheus sont également accessibles :
Et l’on peut lister les différentes StoreAPI configurées sur le query :
Thanos en datasource pour Grafana
L’utilisation la plus commune de Thanos reste derrière un Grafana. Thanos query expose la même API que Prometheus, il suffit donc de rajouter une datasource de type Prometheus dans Grafana et de cibler le Thanos query (ou query-frontend si déployé) :
Il est possible d’indiquer à Grafana le type de datasource Prometheus et fournir des paramètres pour les requêtes. Par exemple pour indiquer que l’on veut récupérer les version downsamplées des métriques automatiquement en fonction de la résolution :
Il ne reste qu’à l’utiliser comme datasource d’un panel ou lors de l’import d’un dashboard :
Ou encore mieux, configurer la nouvelle datasource comme celle par défaut, puisque Thanos query permet d’avoir plusieurs instances Prometheus requêtables derrière.
Le dernier article de cette série sur Thanos aborde justement comment et dans quels cas il est pertinent d'exposer plusieurs Prometheus derrière Thanos… A bientôt !
Ne ratez pas nos prochains articles DevOps et Cloud Native! Suivez Enix sur Twitter!