CérénIT

Le blog tech de Nicolas Steinmetz (Time Series, IoT, Web, Ops, Data)

Web, Ops & Data - Décembre 2020

podmandockerruncrootlessswarmcgroupskubernetescridockershimvectorawstimestreamwarp10dashboardptsmtimescalecentosrhelpodmaninfluxdbtimeseries

Containers et orchestration

  • Electro Monkeys #37 – Podman, l’alternative de Redhat à Docker avec Benjamin Vouillaume : je me demandais si podman permettait un management de containers à distance et l'étendue de son écosystème. Le podcast permet de compléter le tour du propriétaire et de se faire une bonne idée de son positionnement.
  • How to deploy on remote Docker hosts with docker-compose : dans la même quête, je me demandais s'il était possible de piloter un noeud docker à distance quand je me suis rappelé qu'il était possible de le faire au travers d'une connexion ssh. En creusant un peu plus, j'ai découvert la notion de contexte qui permet ainsi de cibler un noeud docker, docker swarm ou kubernetes.
  • Don't Panic: Kubernetes and Docker et Dockershim Deprecation FAQ : A partir de kubernetes 1.20 (fin 2020) et définitivement à partir de la version 1.23 (fin 2021), le retrait du binaire docker comme CRI de Kubernetes est annoncé. Cela ne devrait pas changer grand chose et c'est essentiellement de la plomberie interne. Plutôt que de passer par Dockershim qui implémentait l'interface CRI et qui discutait ensuite avec Docker pour lancer les conteneurs via containerd, l'appel sera directement fait à containerd. Il n'y a que ceux qui montent la socket docker dans les pods qui vont avoir un souci. Si c'est pour builder des images, il y a des alternatives comme img, kaniko, etc. Pour les autres cas, il faudra peut être passer par l'API kubernetes ou trouver les alternatives qui vont bien.
  • What developers need to know about Docker, Docker Engine, and Kubernetes v1.20 et Mirantis to take over support of Kubernetes dockershim : Mirantis et Docker Inc vont assurer le support de cette interface dockershim pour permettre à ceux qui ont en besoin de pouvoir continuer à l'utliiser. La limite étant que si vous êtes sur du service managé et que votre provider ne le fournit pas, vous ne pourrez pas l'utiliser...
  • Kubernetes 1.20: The Raddest Release : voilà, la version 1.20 est sortie et apporte son lot de nouveautés et de stabilisation.
  • Announcing General Availability of HashiCorp Nomad 1.0 : Nomad 1.0 est également disponible.
  • Introducing Docker Engine 20.10 - Docker Blog : Docker 20.10 arrive avec des profondes nouveautés comme le support des cgroupsv2 et un mode rootless, docker logs fonctionne avec tous les drivers de log et non unqiement json & journald et plein d'autres améliorations/harmonisations au niveau de la CLI. Pour ceux sous Fedora qui avaient bidouillé avec firewalld précédemment pour faire fonctionner docker et qui ont un problème lié à l'interface docker0 au démarrage du service docker, allez voir par ici.
  • Docker Engine Release Notes - Version 20.10 : En plus des points précédents, il y a l'arrivée des jobs dans swarm - depuis le temps que je l'attendais 🤩 (même si on peut se toujours se poser la question de la pérénnité de swarm depuis qu'il a été racheté par Mirantis)
  • New features in Docker 20.10 (Yes, it’s alive) : un billet décrivant plus en détail certaines feautres de docker 20.10 comme support Fedora/CentOS, le rootless mode, l'option -mount, les jpbs swarm et une synthèse de l'actualité de l'écosystème docker.
  • Podman Release 2.2.0 : ajout des commandes network (dis)connect, support des alias avec des noms courts, amélioration des commandes play|generate kube et capacité de monter une image OCI dans un container.

Observabilité

  • Vector - Collect, transform, & route all observability data with one simple tool. (via) : vector est un outil en rust qui permet de collecter et manipuler des métriques/logs/événements et de les envoyer vers différentes destinations. De quoi remplacer filebeat/journalbeat voire même telegraf ? ;-)
  • Our new partnership with AWS gives Grafana users more options : AWS vient d'annoncer un service managé pour Prometheus basé sur Cortex et pour Grafana (version Entrepsise). Grafana et Cortex étant des projets édités par Grafana Labs sous licence OSS (et des déclinaisons Cloud et Entreprise). AWS changerait-il sa façon de travailler avec les projets OSS lorsqu'il souhaite en faire des services managés et prendre ainsi une attitude plus positive vis à vis de la communauté OSS ?

OSS

  • Death of an Open Source Business Model : Analyse du passage de Mapbox GL JS v2 sous licence propriétaire, le modèle de l'open core et les menaces des top cloud providers sur le reste de l'économie du logiciel. On peut étendre cela aussi "VC funded OSS company".

Système

  • CentOS Project shifts focus to CentOS Stream, CentOS Stream: Building an innovative future for enterprise Linux et la FAQ associée : Historiquement CentOS Linux était batie sur les sources de Red Hat Entreprise Linux un fois celle-ci disponible. CentOS Stream renverse un peu la tendance avec un cycle d'intégration plutôt Fedora -> CentOS Stream -> RHEL. L'initiative CentOS Stream avait été annoncée en septembre 2019 et ce changement permet donc aux équipes CentOS de se focoaliser sur une seule version (CentOS Stream) et non plus deux versions (CentOS Stream et CentOS Linux). CentOS Linux 7 sera maintenue jusqu'à la fin du support de RHEL 7 et et CentOS 8 jusqu'à fin 2021 (et non pas 2029 comme prévu). Il n'y aura pas de version 9 de CentOS Linux. A tester pour voir si CentOS Stream est plus stable que Fedora mais moins conservateur que RHEL et pourrait alors s'avérer être un bon compromis.
  • Before You Get Mad About The CentOS Stream Change, Think About… : un billet assez long d'un employé de Red Hat qui exprime son opinion et cherche à remettre les choses en perspective en dépassionnant le débat.

Time Series

  • PTSM Edition #8 - Amazon TimeStream 101 : Edition du Paris time Series Meetup sur AWS Timestream
  • TimescaleDB vs. Amazon Timestream: 6000x higher inserts, 5-175x faster queries, 150x-220x cheaper : avec toutes les réserves habitudelles sur les benchmarks, Timescale a comparé son produit avec AWS Timestream et la conclusion semble clairement en faveur de Timescaledb. A noter que l'update des données est arrivé dans AWS Timestream entre temps.
  • Truly Dynamic Dashboards as Code : les équipes de SenX ont implémenté leur vision du "Dashboards as Code" sous le nom Discovery. Discovery veut aller plus loin que la simple description d'un dashboard comme on peut le voir dans Grafana ou InfluxDB 2.0 en apportant une touche de dynamisme et de génération dynamique des dashboards en fonction des élements obtenus (ex si valeur X > Y alors afficher la procédure AAA de résolution d'incident). J'ai commencé à jouer avec, un billet de blog sur ce sujet devrait bientôt arriver.
  • NeuralProphet : un modèle neuronal orienté série temporelles, inspiré de Facebook Prophet et développé avce PyTorch.
  • Release Notes InfluxDB 2.0.3 et Release Announcement: InfluxDB OSS 2.0.3 : build arm64 en preview, un petit conflit de packaging entre influxdb et influxdb2 à passer pour ceux qui étaient déjà en 2.0 et ceci afin d'éviter que des gens en 1.x passent involontairement en 2.x, le "delete with predicate" a été réactivé, améliorations sur le process d'upgrade, des commandes autour des actions en mode V1, mise à jour de flux, et plein d'autres corrections/améliorations.

Web

  • Web Almanac 2020 - Rapport annuel de HTTP Archive sur l’état du Web : une synthèse de l'état du web d'après HTTP Archive sur une base de 7.5 millions de sites testés, soit 31.3 To de données traitées. De quoi relativisez un peu les biais de notre bulle technologique : non tout le monde ne fait pas du React/Angular/Vue.js par ex mais plutôt du JQuery ! Suivant vos usages, plein d'enseignements et de choses intéressantes à tirer de cette synthèse.

Il ne me reste plus qu'à vous souhaiter de bonnes fêtes de fin d'année et on se retrouve l'année prochaine !

Web, Ops & Data - Novembre 2020

kubernetesvitessmysqlkuberneteshelmmesosinfluxdbrustarrowparquetscpsftpgkegcpobservabilitymonitoringdigdnsdogrustovhcloudgit

Ce soir, il y a la 8ème édition du Paris Time Series Meetup sur AWS TimeStream.

Cloud

Code

Container et orchestration

SQL

  • Announcing Vitess 8 : Vitess, la base distribuée prévue pour un déploiement sur kubernetes et avec une compatibilité MySQL arrive en version 8 et améliore son support de MySQL et des principales librairies et frameworks dans différents langages.

Système

  • Deprecating scp : qui n'a pas fait un scp file destination:/path/to/file ? La commande scp est victime de nombreuses failles. Du coup, elle va être dépréciée. Néanmoins une initiative vise à maintenir uen commande scp mais se fondant sur sftp et son modèle de sécurité.
  • ogham/dog : dog est une réécriture de dig en rust avec coloration syntaxique et différentes fonctionnalités comme le support de DoH, DoT, etc.
  • k6 : k6 est un outil de test de performance avec lequel on peut définir des scénarios plus ou moins élaborés suivant ses besoins ; je l'avais recommandé à un client pour faire des tests de performance d'API; la version 0.29 vient de sortir.

Timeseries

Astuce du mois

Pour ceux sous Fedora et utilisant podman en alternative au binaire docker, pour se connecter à la registry google (via):

gcloud auth print-access-token | podman login -u oauth2accesstoken --password-stdin gcr.io

InfluxDB 2.0 OSS - Notes de mise à jour

timeseriesinfluxdbfluxgrafanatelegraf

InfluxDB 0SS 2.0 étant sortie, j'ai testé la mise à jour d'une instance 1.8.3 vers 2.0.1 sur une VM Debian 10 à jour.

Mise à jour

La documentation pour une mise à jour 1.x vers 2.x est disponible. La vidéo "Path to InfluxDB 2.0: Seamlessly Migrate 1.x Data" reprend cela et va plus loin en présentant bien tous les points à prendre en compte (y compris pour Telegraf, Chronograf et Kapacitor). Je ne rajouterai donc que mes remarques.

Concernant la commande influxd upgrade :

  • Il est fort probable qu'il faille rajouter la commande sudo pour ne pas avoir de problèmes de permisisons.
  • Par défaut, les données migrées vont être mises dans ~/.influxdbV2. Or je doute que vous vouliez que vos données soient à cet endroit. Je vous invite donc à regarder la documentation de influxd upgrade pour définir les propriétés --engine-path et --bolt-path

Exemple:

mkdir -p /srv/influxdb/influxdb2
influxd upgrade --engine-path /srv/influxdb/influxdb2/engine --bolt-path /srv/influxdb/influxdb2/influxd.bolt
  • A l'issue de la migration, un fichier config.toml est généré dans /etc/influxdb/. Il contient quelques valeurs issues de la migration et des valeurs par défaut. Je l'ai personnalisé de la façon suivante pour tenir compte de mes valeurs :
bolt-path = "/srv/influx/influxdb2/influxd.bolt"
engine-path = "/srv/influx/influxdb2/engine"
http-bind-address = "127.0.0.1:8086"
storage-series-id-set-cache-size = 100
  • Post-migration, le service influxd cherchait à initialiser ses fichiers dans /var/lib/influxdb/.influxdbv2. Ayant noté que le service InfluxDB prennait /etc/default/influxdb comme fichier d'environnement, j'ai ajouté dans ce fichier :
# /etc/default/influxdb
INFLUXD_CONFIG_PATH=/etc/influxdb/config.toml

Dès lors, /etc/influxdb/config.toml était bien pris en compte et InfluxDB démarrait bien avec mes données.

Une fois InfluxDB 2 démarré, j'ai pu noter avec plaisir :

  • que l'ingestion via telegraf continuait à se faire sans interruption,
  • que mes dashboards Grafana continuaient à fonctionner.

Je n'ai donc pas d'urgence à migrer la configuration et le paramétrage de ces derniers. Je vais pouvoir le faire progressivement ces prochains jours.

N'utilisant pas Chronograf et Kapacitor, je n'ai pas eu de données à migrer ou d'ajustements à faire à ce niveau là. La vidéo reprend bien les points d'attention et les éventuelles limitations à prendre en compte dans le cadre de la migration.

Finalement, c'est pas mal qu'ils aient réintégrer les endpoints 1.x dans la version 2.0 à ce niveau là ;-)

La 2.0.2 étant sortie pendant ma mise à jour, j'ai poursuivi la mise à jour. Je suis tombé sur ce bug rendant l'écriture de données impossibles. Cela a mis en évidence un bug sur la migration des "retention policies" et sur le fait que j'avais aussi des très vieilles bases InfluxDB. Je n'aurai a priori pas eu ce bug en faisant la migration 1.8.3 vers 2.0.2. En tous cas, une 2.0.3 devrait donc arriver prochainement avec une amélioration du processus de migration faisant suite à ma séance de troubleshooting.

Migration des configurations

Elle peut se faire très progressivement - si par ex vous utilisez telegraf pour envoyer vos données et Grafana pour la partie dashboarding :

  • Vous pouvez mettre à jour votre configuration telegraf en passant de l'outputs influxdb à l'output influxdb_v2 sans impacter grafana qui continuera à accéder à vos données en InfluxQL
  • Vous pouvez ensuite mettre à jour votre datasource InfluxDB ou plutôt en créer une nouvelle et migrer vos dashboards progressivement sans interruption de service

Créer un accès en InfluxQL à un nouveau bucket

Si vous devez rétablir un accès à vos données via les API 1.x à un bucket nouvellement créé (j'ai profité de la migration pour mettre des buckets clients dans des organisations représentant les clients en question).

# Créer le bucket
influx bucket create --name <BUCKET_NAME> --retention 0  --org <ORGANISATION>
# Récupérer l'ID de bucket via la liste des buckets
influx bucket list
# Créer une DBRP (DataBase Retention Policies) pour le bucket en question - les accès en 1.x se font en mode  SELECT * FROM <db_name>.<retention_policies> ...
influx v1 dbrp create --bucket-id=<BUCKET_ID> --db=<BUCKET_NAME> --rp=autogen --default=true
# Créer un utilsateur sans mot de passe pour le moment
influx v1 auth create --username <USER> --read-bucket <BUCKET_ID> --write-bucket <BUCKET_ID> --org <ORGANISATION> --no-password
# Créer un mot de passe au format V1
influx v1 auth set-password --username <USER>

Les utilisateurs migrés depuis la version 1.x sont visibles via influx v1 auth list.

Intégration InfluxDB 2.0 / Flux et Grafana

Le support de Flux dans Grafan existe depuis la version 7.1 mais il n'est pas aussi aisé que celui dans InfluxDB 2.0 OSS. Il y a certes de la complétion au niveau du code ou le support des variables mais pas de capacité d'introspection sur la partie données.

Pour le moment, je procède donc de la façon suivante :

  • Création de la Requête via le Query Builder dans InfluxDB 0SS
  • Passage en mode "Script editor" pour dynamiser les variables ou ajuster certains comportements
  • Copier/coller dans l'éditeur de Grafana
  • Ajustement des variables pour les mettre au format attendu par Grafana.

Ex coté InfluxDB 2.0 OSS / Flux :

from(bucket: v.bucket)
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "net")
  |> filter(fn: (r) => r["_field"] == "bytes_recv" or r["_field"] == "bytes_sent")
  |> filter(fn: (r) => r["host"] == v.host)
  |> derivative(unit: v.windowPeriod, nonNegative: false)
  |> yield(name: "derivative")

La version dans Grafana :

from(bucket: "${bucket}")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "net")
|> filter(fn: (r) => r["_field"] == "bytes_recv" or r["_field"] == "bytes_sent")
|> filter(fn: (r) => r["host"] == "${host}")
|> derivative(unit: v.windowPeriod, nonNegative: false)
|> yield(name: "derivative")

La différence portant sur la gestion des variables v.host vs "${host}" et v.bucket vs "${bucket}".

Autre bonne nouvelle, les variables sont supportées dans Grafana ; vous pouvez donc définir les variables comme celles vu juste au-dessus :

Variable bucket de type "Query" en prenant InfluxDB/Flux comme datasource :

buckets()
  |> filter(fn: (r) => r.name !~ /^_/)
  |> rename(columns: {name: "_value"})
  |> keep(columns: ["_value"])

Variable host de type "Query" en prenant InfluxDB/Flux comme datasource :

# Provide list of hosts
import "influxdata/influxdb/schema"
schema.tagValues(bucket: v.bucket, tag: "host")

Si votre requête fonctionne dans un dashboard InfluxDB ou en mode explore mais qu'elle est tronquée dans Grafana, il vous faudra ajuster le "Max Data Points" pour récupérer plus de points pour cette requête (cf grafana/grafana#26484).

InfluxDB 2.0 OSS - Grafana - Max Data Points

Calcul de la durée d'un état avec des timeseries

timeseriesinfluxdbfluxwarp10warpscriptduration

Un client m'a demandé la chose suivante : "Nicolas, je voudrais savoir la durée pendant laquelle mes équipements sont au delà d'un certain seuil ; je n'arrive pas à le faire simplement".

Souvent, quand on manipule des séries temporelles, la requête est de la forme "Sur la période X, donne moi les valeurs de tel indicateur". On a moins l'habitude de travailler dans le sens inverse, à savoir : "Donne moi les périodes de temps pour laquelle la valeur est comprise entre X et Y".

C'est ce que nous allons chercher à trouver.

Influx 1.8 et InfluxQL

Avec l'arrivée imminente d'Influx 2.0, j'avoue ne pas avoir cherché la solution mais je ne pense pas que cela soit faisable purement en InfluxQL.

Influx 1.8 / 2.0 et Flux

Avec Flux, j'ai rapidement trouvé des fonctions comme duration et surtout stateDuration

L'exemple ci-dessous se fait avec une base InfluxDB 1.8.3 pour laquelle Flux a été activé. Le requêtage se fait depuis une instance Chronograf en version 1.8.5.

Pour approcher l'exemple de mon client, j'ai considéré le pourcentage d'inactivité des CPU d'un serveur que l'on obtient de la façon suivante:

from(bucket: "crntbackup/autogen")
  |> range(start: dashboardTime)
  |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_idle" and r.cpu == "cpu-total")
  |> window(every: autoInterval)
  |> group(columns: ["_time", "_start", "_stop", "_value"], mode: "except")

Cela donne:

flux - duration 1

Ensuite, j'ai besoin d'une fonction qui va me rajouter une colonne avec mon état. Cet état est calculé en fonction de seuils - par souci de lisibilité, je vais extraire cette fonction de la façon suivante et appliquer la fonction à ma requête :

set_level = (tables=<-) =>
  tables
    |> map(fn: (r) => ({
      r with
      level:
        if r._value >= 95 then "fully_idle"
        else if r._value >= 90 and r._value <95 then "something_is_moving"
        else if r._value >= 85 and r._value <90 then "oh_oh"
        else if r._value >= 80 and r._value <85 then "hmm"
        else if r._value < 80 then "i_have_to_work"
        else "overloaded"
      })
    )

from(bucket: "crntbackup/autogen")
  |> range(start: dashboardTime)
  |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_idle" and r.cpu == "cpu-total")
  |> window(every: autoInterval)
  |> group(columns: ["_time", "_start", "_stop", "_value"], mode: "except")
  |> set_level()

La colonne "level" n'est à ce stade pas persistée en base contrairement aux autres données issue de la base de données.

Cela donne ceci en mode "raw data" - tout à fait à droite

flux - duration 2

Maintenant que j'ai mon état, je peux application la fonction stateDuration() ; elle va calculer la périodes de temps où le seuil est "something_is_moving" par tranche de 1 seconde. Le résulat sera stocké dans une colonne "stateDuration". Pour les autres états, la valeur est de -1. La valeur se remet à 0 à chaque fois que l'état est atteint puis la durée est comptée :

set_level = (tables=<-) =>
  tables
    |> map(fn: (r) => ({
      r with
      level:
        if r._value >= 95 then "fully_idle"
        else if r._value >= 90 and r._value <95 then "something_is_moving"
        else if r._value >= 85 and r._value <90 then "oh_oh"
        else if r._value >= 80 and r._value <85 then "hmm"
        else if r._value < 80 then "i_have_to_work"
        else "overloaded"
      })
    )

from(bucket: "crntbackup/autogen")
  |> range(start: dashboardTime)
  |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_idle" and r.cpu == "cpu-total")
  |> window(every: autoInterval)
  |> group(columns: ["_time", "_start", "_stop", "_value"], mode: "except")
  |> set_level()
  |> stateDuration(fn: (r) => r.level == "something_is_moving", column: "stateDuration", unit: 1s)

On voit le rajout de la colonne stateDuration en mode "raw data" ; elle n'ont plus n'est pas persistée dans la base à ce stade :

flux - duration 4

et coté visualisation :

flux - duration 3

Maintenant que j'ai ces périodes, je vais vouloir savoir quelle est la durée totale de ces différentes périodes que nous avons identifée. On peut en effet imaginer un cas où on sait que l'équipement est à remplacer lorsqu'il a atteint un seuil donné pendant plus de X heures.

Pour cela, je vais:

  • filtrer sur un état voulu,
  • calculer le différentiel entre chaque valeur de stateDuration pour n'avoir que les écarts non plus la somme des durées en supprimant les valeurs négatives pour gérer les retours à la valeur 0
  • et faire la somme de l'ensemble.
set_level = (tables=<-) =>
  tables
    |> map(fn: (r) => ({
      r with
      level:
        if r._value >= 95 then "fully_idle"
        else if r._value >= 90 and r._value <95 then "something_is_moving"
        else if r._value >= 85 and r._value <90 then "oh_oh"
        else if r._value >= 80 and r._value <85 then "hmm"
        else if r._value < 80 then "i_have_to_work"
        else "overloaded"
      })
    )

from(bucket: "crntbackup/autogen")
  |> range(start: dashboardTime)
  |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_idle" and r.cpu == "cpu-total")
  |> window(every: autoInterval)
  |> group(columns: ["_time", "_start", "_stop", "_value"], mode: "except")
  |> set_level()
  |> stateDuration(fn: (r) => r.level == "something_is_moving", column: "stateDuration", unit: 1s)
  |> filter(fn: (r) => r.level == "something_is_moving")
  |> derivative(unit: 10s, nonNegative: true, columns: ["stateDuration"], timeColumn: "_time")
  |> sum(column: "stateDuration")

Ce qui me donne un total de 2230 secondes pour l'heure (3600s) qui vient de s'écouler.

flux - duration 5

C'est un POC rapide pour démontrer la faisabilité de la chose. Le code est surement améliorable/perfectible.

Dans un contexte InfluxDB 2.0, il y a aussi la fonction events.duration qui semble intéressante. Ce billet "TL;DR InfluxDB Tech Tips – How to Monitor States with InfluxDB" montre aussi l'usage de la fonction monitor.stateChanges() qui peut compléter l'approche.

Influx 1.8 / Flux - variante pour les séries irrégulières

La fonction derivative impose d'avoir des durées régulières pour calculer le delta. Dans le cas d'une série irrégulière, cela peut coincer rapidement et fausser les calculs. On peut donc remplacer les deux dernières lignes par la fonction increase. Elle prend la différence entre deux valeurs consécutives (quelque soit leur timestamp) et réalise une somme cumulative. Les différences négatives sont ignorées de la même façon que nous le faisions précédemment.

set_level = (tables=<-) =>
  tables
    |> map(fn: (r) => ({
      r with
      level:
        if r._value >= 95 then "fully_idle"
        else if r._value >= 90 and r._value <95 then "something_is_moving"
        else if r._value >= 85 and r._value <90 then "oh_oh"
        else if r._value >= 80 and r._value <85 then "hmm"
        else if r._value < 80 then "i_have_to_work"
        else "overloaded"
      })
    )

from(bucket: "crntbackup/autogen")
  |> range(start: dashboardTime)
  |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_idle" and r.cpu == "cpu-total")
  |> window(every: autoInterval)
  |> group(columns: ["_time", "_start", "_stop", "_value"], mode: "except")
  |> set_level()
  |> stateDuration(fn: (r) => r.level == "something_is_moving", column: "stateDuration", unit: 1s)
  |> filter(fn: (r) => r.level == "something_is_moving")
  |> increase(columns: ["stateDuration"])

La sortie change un peu car au lieu d'un nombre unique, on a l'ensemble des points filtrés et leur somme au fur et à mesure (colonne de droite):

flux - duration increase dataviz

Cela donne des possiblités différentes au niveau dataviz :

flux - duration increase dataviz

Warp 10 / WarpScript

En la même chose en WarpScript avec Warp 10, cela donne quoi ? Regardons cela :

'<readToken>' 'readToken' STORE

// Récupération des données de cpu de type "usage_idle" en ne prenant que le label "cpu-total"
[ $readToken '~crntd10monitoring.cpu.usage_idle' { 'cpu' 'cpu-total' } NOW 1 h ] FETCH
0 GET         // Fetch retourne une liste de GTS, on prend donc la première (et unique) GTS
'cpu' STORE   // Stockage dans une variable cpu

// Utilisation de BUCKETIZE pour créer une série régulière de données séparées par 1 seconde
// Mes données étant espacées d'environ 10s, cela va donc créer 10 entrées de 1 seconde au final
// Pour chaque espace, on utliise la dernière valeur connue de l'espace en question pour garder les valeurs de la GTS de départ
[
  $cpu
  bucketizer.last
  0
  1 s
  0
]
BUCKETIZE
// Les espaces insérés n'ont pas encore de valeurs associées
// On remplit les entrées sans valeurs avec les valeurs ci-dessus
// On utilise FILLPREVIOUS et FILLNEXT pour gérer aussi les premières et dernières valeurs
FILLPREVIOUS
FILLNEXT
// A ce stade, on a donc une GTS avec un point toute les secondes et la valeur associée. Cette valeur était la valeur que l'on avait toutes les 10s précédemment.

// On fait une copie de la GTS pour pouvoir comparer avec la version filtrée par ex
DUP

// On filtre sur les valeurs qui nous intéressent, ici on veut les valeurs >= 90 et < 95
[ SWAP 90.0 mapper.ge 0 0 0 ] MAP
[ SWAP 95.0 mapper.lt 0 0 0 ] MAP
// On renomme la liste (pratique si on affiche par ex l'ancienne et la nouvelle liste dans la partie dataviz - cf capture ci-dessous)
'+:above90below95' RENAME

// On compte le nombre d'élément de la GTS qui est sous la forme d'une liste de GTS à l'issu du MAP
0 GET SIZE

// On multiplie le nombre d'entrées par 1 s
1 s *

// on garde une copie de la valeur en secondes
DUP
// On applique le filtre HUMANDURATION qui transforme ce volume de secondes en une durée compréhensible
HUMANDURATION

warp10 - duration 1

On voit ci-dessous l'usage de DUP avec la valeur humainement lisible, la valeur brute en seconde (puis le reste de la pile):

warp10 - duration 1

Si on ne veut pas de dataviz / ne pas conserver les valeurs intermédiaires et n'avoir que la valeur finale, on peut supprimer les lignes avec DUP et RENAME.

'<readToken>' 'readToken' STORE
[ $readToken '~crntd10monitoring.cpu.usage_idle' { 'cpu' 'cpu-total' } NOW 1 h ] FETCH
0 GET
'cpu' STORE

[
  $cpu
  bucketizer.last
  0
  1 s
  0
]
BUCKETIZE
FILLPREVIOUS
FILLNEXT

[ SWAP 90.0 mapper.ge 0 0 0 ] MAP
[ SWAP 95.0 mapper.lt 0 0 0 ] MAP
0 GET SIZE
1 s *
HUMANDURATION

Et on obtient:

20m20.000000s

Un grand merci à Mathias Herberts pour sa disponiblité, sa patience et son aide face à toutes mes questions pour arriver à produire ce code.

Warp 10 / WarpScript - version agrégée

On peut aussi vouloir avoir une version agrégée de la donnée plutôt que de filter sur un état particulier. Ainsi, on peut avoir la répartition des valeurs que prend un équipement sur un indicateur donnée.

'<readToken>' 'readToken' STORE
// Récupération des métriques comme précédemment
[ $readToken '~crntd10monitoring.cpu.usage_idle' { 'cpu' 'cpu-total' } NOW 1 h ] FETCH
0 GET
'cpu' STORE

// Reformatage des données comme précédemment
[
  $cpu
  bucketizer.last
  0
  1 s
  0
]
BUCKETIZE
FILLPREVIOUS
FILLNEXT

// Utilisation de QUANTIZE
// QUANTIZE a besoin que l'on définisse des sous-ensembles dans un ensemble
// Notre indicateur CPU étant un pourcentage, on prend par ex 10 sous ensemble compris entre 0 et 100
// QUANTIZE gère aussi les cas où l'on est plus petit que la première valeur et plus grand que la derinère valeur de l'ensemble
0 100 10 LBOUNDS
// On a donc 10+2 = 12 sous-ensembles : ]-infini,0],[1, 10],[11, 20],...,[90, 100],[101, inf+[
// Pour chaque valeur que nous allons passer à QUANTIZE, elle va retourer une valeur associée au sous ensemble dans laquelle la valeur va "tomber".
// Ainsi, un valeur de 95% va aller dans gt90.
// Liste des valeurs pour les 12 sous-ensembles :
[ 'neg' 'gt0' 'gt10' 'gt20' 'gt30' 'gt40' 'gt50' 'gt60' 'gt70' 'gt80' 'gt90' 'gt100' ]
QUANTIZE
// A ce stade, notre GTS de départ ne contient plus les valeurs de cpu mais les valeurs associées au tableau de QUANTIZE
// on passe donc de [<timestamp>, 95.45] à [<timestamp>, 'gt90']

// Utilisation de VALUEHISTOGRAM qui va compter le nombre d'occurences de chaque valeur d'une liste de GTS
VALUEHISTOGRAM

On obtient alors :

[{"gt90":3491,"gt80":40,"gt70":40,"gt60":10}]

Et voilà !

Web, Ops & Data - Octobre 2020

kubernetesingressyamlpipelinegitlabtraefikrootlessmeshyqjqdevopsdatamaturitémariadbs3flowswarp10timeseriesinfluxdbpulsaramqpmqttkafkapythongitvscodearmnvidia

Des nouvelles du Paris Time Series Meetup : l'éditions 6 sur TimescaleDB et l'édition 7 sur QuestDB

CI/CD

  • 3 YAML tips for better pipelines : la troisième est certainement la plus intéressante - il est possible d'avoir des mécanismes de "composabilité" / "héritage" avec YAML et Gitlab. Si les include et extends sont déjà sympathiques, les anchors ont l'air de faire des choses intéressantes aussi !

Code

  • What’s New In Python 3.9 et un thread twitter qui donne des exemples des principales nouveautés : au programme nouvelle syntaxe pour la fuston des dictionnaires, des méthides pour supprimer des suffixes/préfixes sur les strings, du typage et plein d'autres améliorations et corrections.
  • Fortunately, I don't squash my commits : s'il peut être tentant sur une MR/PR de faire un squash des commits, l'article vous confortera dans l'idée que ce n'est pas une bonne idée. En écrasant l'historique des commits, on y perd sur nos capacités de debug. Par ailleurs, il est conseillé de faire des petits commits pour capturer un ensemble de changements traduisant un moment précis du développement.

Container et orchestration

  • Kubernetes Ingress Goes GA : l'apparition de IngressClassName dans k8s 1.19 va plus loin qu'un simple renommage de champ comme je l'avais compris initialement. C'est une vraie ressource et cela ouvre aussi des possibilités. Avant de l'utiliser, vérifiez aussi que vos ingress controller le supporte (en plus d'attendre d'être en 1.19)
  • Houston, we have Plugins! Traefik 2.3 Announcement : la version 2.3 dont on a déjà parlé ici, est arrivé en version stable avec son support des plugins, son intégration avec Traefik Pilot, le support d'Amazone ECS et le support de la ressource IngressClassName. Au passage, Containous, la société éditrice de Traefik s'appelle maintenant Traefik Labs.
  • Introducing Traefik Pilot 1.0: the Traefik Control Center : Version 1.0 de ce nouveau "Control Plane" de Traefik qui permet d'avoir une vision globale sur ses instances traefik, d'utiliser les plugins et d'avoir un monitoring et des alertes autour de la disponibilité, des performances et de la sécurité.
  • Rootless mode : A voir si cela pourra être inclus dans la version 1.20 mais le rootless mode est clairement une tendance de fond dans kubernetes et les conteneurs en général. Si vous ne vous y êtes pas déjà mis, ne tardez pas !
  • Announcing Traefik Mesh 1.4 - New Name, New Features : nouvelle version du service mesh par Traefik Labs et qui s'appelle maintenant Traefik Mesh (et non uniquement Maesh). Le reste des améliorations semble porter sur le filtrage des headers et des paths.
  • yq : A command line tool that will help you handle your YAML resources better : vous voulez faire des opératoins sur des fichiers YAML sans faire un chart helm ou sortir kustomize, vous pouvez faire des choses minimalistes avec yq (le pendant yaml de jq).
  • Bridge to Kubernetes GA, "bridge to kubernetes" est une extension pour vscode permettant de connecter une application tournant en local avec d'autres applications situées dans un ckuster kubernetes et faciliter ainsi l'expérience des développeurs.

Culture DevOps

Data

Hardware

IaC

  • Announcing HashiCorp Terraform 0.14 Beta: la capacité à marquer des variables comme sensibles pour éviter que leur valeur soit visible dans les logs/diff/..., un diff plus concis, un lock sur les providers et des binaires disponibles pour arm64.

Monitoring

Pratique

  • endoflife.date : recense les dates de fin de support de vos langages et technologies préférées. Tout n'est pas complètement à jour mais cela permet de récupérer rapidement les informations.

SQL

  • Exciting and New Features in MariaDB 10.5 : évoqué au mois d'aout, le support de S3 dans MariaDB est disponible en version GA dans la version 10.5. D'autres améliorations existent comme le support du type INET6, des améliorations sur ColumnStore, la gestion des privilèges, le cluster Galera supporte complètement le GTID, du refactoring au niveau d'InnoDB et enfin les binaires mariadb vont enfin s'appeler mariadb et non plus mysql (avec une couche de compatibilité via des liens symboliques)

Time Series

Sur la base des informations disponibles pour le moment :

  • vous définissez une période de rétention en mémoire (entre 1h et 1 an) et une période de rétention sur stockage magnétique (1 jour à 200 ans),
  • le requêtage des données se fait en SQL (via Presto ?),
  • les données à requêter communément sont à mettre dans la même table,
  • le join est limité à la même table,
  • des mesures simples (pas de multi mesures pour un même enregistrement),
  • une intégration avec l'écosystème comme telegraf, grafana, etc en plus de l'intégration avec différents composants AWS

Pour les moins bons côtés :

  • pas d'UPDATE/DELETE sur vos données ; en cas de doublons, c'est le premier arrivé qui gagne
  • pas de bulk import de vos données, donc pas de reprise de vos données existantes. En effet, il n'est pas possible d'ingérer des données plus vieille que la période en mémoire,
  • dans la même veine, si un incident de production dépasse votre période de rétention, vous ne pourrez pas réinjecter vos données
  • il ne semble pas possible de mettre à jour ses durées de rétention - donc pas de ménage possible ou d'ajustements en cours de route

Une solution a priori très orienté pour du monitoring et qui semble souffir des mêmes travers qu'InfluxDB avec InfluxQL et pourtant en passe d'être résolus avec Flux.

On devrait en parler plus en détail dans une prochaine édition du Paris Time Series Meetup avec des personnes de chez AWS ;-)

Work

Warp 10 - Interactions avec une instance InfluxDB - FLoWS edition

warp10timeseriesinfluxdbwarpscriptwarpfleetflows

Maintenant que FLoWS est officiellement disponible, je vous propose de revisiter l'article de la semaine dernière Warp 10 - Interactions avec une instance InfluxDB en utliisant FLoWS à la place de WarpScript pour se faire une idée.

Pré-requis: warpfleet

Installons déjà warpfleet, le gestionnaire de package conçu pour Warp 10.

# Installation de npm
sudo dnf install -y npm

# installation de warpfleet
sudo npm install -g @senx/warpfleet

# Vérification de la bonne installation de warpfleet
wf version
      ___       __                     _______________         _____
      __ |     / /_____ __________________  ____/__  /___________  /_
      __ | /| / /_  __ `/_  ___/__  __ \_  /_   __  /_  _ \  _ \  __/
      __ |/ |/ / / /_/ /_  /   __  /_/ /  __/   _  / /  __/  __/ /_
      ____/|__/  \__,_/ /_/    _  .___//_/      /_/  \___/\___/\__/
                               /_/version: 1.0.31
1.0.31

Installation de l'extension warp10-ext-influxdb

Sans trop rentrer dans les détails de warpfleet, il utilise un système de namespace appelés "Groups" pour ces packages et qui permettent de définir ses propres dépots. Pour l'extension warp10-ext-influxdb, le "group" est io.warp10.

Ce qui pour l"installation donne la commande suivante :

# Si votre utilisateur n'a pas accès à /path/to/warp10, il vous faudra utiliser sudo
(sudo) wf g -w /path/to/warp10 io.warp10 warp10-ext-influxdb

warpfleet va vous demander quelle version de l'extension vous souhaitez puis va procéder à son téléchargement et son installation.

Cela donne :

sudo wf g -w /opt/warp10 io.warp10 warp10-ext-influxdb
       ___       __                     _______________         _____
       __ |     / /_____ __________________  ____/__  /___________  /_
       __ | /| / /_  __ `/_  ___/__  __ \_  /_   __  /_  _ \  _ \  __/
       __ |/ |/ / / /_/ /_  /   __  /_/ /  __/   _  / /  __/  __/ /_
       ____/|__/  \__,_/ /_/    _  .___//_/      /_/  \___/\___/\__/
                                /_/                                        ™
 version: 1.0.31
? Which revision do you want to retrieve? latest
✔ ext io.warp10:warp10-ext-influxdb#1.0.1-uberjar retrieved
✔ Download successful: gradle-wrapper.jar
✔ Download successful: gradle-wrapper.properties
✔ Download successful: gradlew
✔ Download successful: gradlew.bat
✔ Dependency warp10-ext-influxdb-1.0.1-uberjar.jar successfully deployed
✔ Done

Note: Pour éviter un bug dans la fonction INFLUXDB.UPDATE identifié lors de la rédaction de ce billet, assurez-vous d'avoir une version >= 1.0.1

Ensuite, il faut créer le fichier /path/to/warp10/etc/conf.d/90--influxdb-extension.conf et y ajouter la ligne suivante:

warpscript.extension.influxdb = io.warp10.script.ext.influxdb.InfluxDBWarpScriptExtension

Je préfère créer un fichier plutôt que d'éditer un fichier existant pour le suivi des mises à jour et j'ai utilisé le prefix 90 car il n'est pas utilisé par les fichiers de Warp10.

Relancer ensuite Warp 10 pour que le plugin soit chargé au démarrage de l'instance :

(sudo) /path/to/warp10/bin/warp10-standalone.init restart

Dans /path/to/warp10/logs/warp10.log, vous devriez voir apparaitre :

2020-09-17T10:59:23,742 main INFO  script.WarpScriptLib - LOADED extension 'io.warp10.script.ext.influxdb.InfluxDBWarpScriptExtension'

Installation de FLoWS

Assurez-vous d'avoir préalablement une version >= 2.7.1 de Warp 10

sudo wf g -w /opt/warp10 io.warp10 warp10-ext-flows
       ___       __                     _______________         _____
       __ |     / /_____ __________________  ____/__  /___________  /_
       __ | /| / /_  __ `/_  ___/__  __ \_  /_   __  /_  _ \  _ \  __/
       __ |/ |/ / / /_/ /_  /   __  /_/ /  __/   _  / /  __/  __/ /_
       ____/|__/  \__,_/ /_/    _  .___//_/      /_/  \___/\___/\__/
                                /_/                                        ™
 version: 1.0.31
? Which revision do you want to retrieve? latest
✔ ext io.warp10:warp10-ext-flows#0.1.0-uberjar retrieved
✔ Download successful: gradle-wrapper.jar
✔ Download successful: gradle-wrapper.properties
✔ Download successful: gradlew
✔ Download successful: gradlew.bat
✔ Dependency warp10-ext-flows-0.1.0-uberjar.jar successfully deployed
warpscript.extension.flows = io.warp10.ext.flows.FLoWSWarpScriptExtension
? Choose what you want to add (Press <space> to select, <a> to toggle all, <i> to invert selection)warpscript.extension.flows = io.warp10.ext.flows.FLoWSWarpScriptExtension
✔ warpscript.extension.flows = io.warp10.ext.flows.FLoWSWarpScriptExtension added to /opt/warp10/etc/conf.d/io.warp10-warp10-ext-flows.conf
✔ Done

Relancer ensuite Warp 10 pour que le plugin soit chargé au démarrage de l'instance :

(sudo) /path/to/warp10/bin/warp10-standalone.init restart

Dans /path/to/warp10/logs/warp10.log, vous devriez voir apparaitre :

2020-10-08T10:59:51,288 main INFO  script.WarpScriptLib - LOADED extension 'io.warp10.ext.flows.FLoWSWarpScriptExtension'

Préalable sur FLoWS

FLoWS ne dispose pas encore d'un endpoint /flows ; nous continuons donc à utiliser les "endpoints historiques warpscript compatibles".

Ce qui nous amène à réaliser une seule action en RPN/NPI (Notation Polonaise Inversée) lorsque l'on soumet du code FLoWS à Warp 10 :

# Multiligne WarpScript qui permet de mettre son code FLoWS
<'
... Code FLoWS ...
'>
# Applique la fonction FLOWS au code ci-dessus
FLOWS

Pour les types, les notations, etc - je voue renvoie au billet de blog introduisant FLoWS.

Requêtage d'une instance InfluxDB 1.x

La semaine dernière nous écrivions en WarpScript :

# Requête INFLUXQL et informations de connection à InfluxDB 1.X
{ 'influxql' "select * from cpu where host=%27myHost%27 and time > now() - 1h" 'db' "myDatabase" 'password' "myPassword" 'user' "myUser" 'url' "http://url.to.influxdb:8086" }
INFLUXDB.FETCH
# On récupère une liste de liste de séries GTS. Il n'y a qu'un seul élément dans cette liste. Nous le prenons pour n'avoir plus qu'une liste de séries GTS.
0 GET
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE
# Affichage de la liste de GTS
$cpu

Cette semaine, nous écrivons en FLoWS :

<'
# Récupération de la liste de GTS
cpu_fetch = INFLUXDB.FETCH({'influxql':'select * from cpu where host=%27myHost%27 and time > now() - 1h', 'db':'myDatabase', 'password':'myPassword', 'user':'myUser', 'url':'http://url.to.influxdb:8086'})

# Récupération de la GTS en prenant l'index 0 de la liste
cpu = GET(cpu_fetch, 0)

# Affichage de la liste de GTS
return cpu
'>
FLOWS

On peut déjà noter :

  • la lecture du code correspond plus à nos habitudes dans les autres lanagage
  • les fonctions ont les mêmes noms, leur signature ne change pas non plus
  • le mot clé return est nouveau ici et permet d'afficher la GTS dans le studio par ex.
  • les tableaux (MAP) sont plus lisibles (arguments séparés par des virugules, la clé et la valeur sont séparés par deux points) et moins sources d'erreurs (gestion des espaces plus sensibles en WarpScript)

Le résultat est identique :

warp10 - influxdb 1

Pour illustrer cette liste de liste de GTS, si on veut récupérer la GTS du cpu idle, on voit dans le graphique que c'est la 5ème courbe, donc un indice 4.

En WarpScript :

{ 'influxql' "select * from cpu where host=%27myHost%27 and time > now() - 1h" 'db' "myDatabase" 'password' "myPassword" 'user' "myUser" 'url' "http://url.to.influxdb:8086" }
INFLUXDB.FETCH
0 GET
'cpu' STORE
# Récupération de la 5ème liste (indice 4)
$cpu 4 GET

En FLoWS :

<'
cpu_fetch = INFLUXDB.FETCH({'influxql':'select * from cpu where host=%27myHost%27 and time > now() - 1h', 'db':'myDatabase', 'password':'myPassword', 'user':'myUser', 'url':'http://url.to.influxdb:8086'})
cpu = GET(cpu_fetch, 0)
# Récupération de la 5ème liste (indice 4)
# on pourrait écrire : return GET(cpu, 4) mais on peut aussi écrire de façon plus concise :
return cpu[4]
'>
FLOWS

warp10 - influxdb 2

Requêtage d'une instance InfluxDB 2.x

La semaine dernière, nous écrivions en WarpScript :

# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
<'
from(bucket: "crntbackup")
  |> range(start: -1h, stop: now())
  |> filter(fn: (r) => r["_measurement"] == "cpu")
  |> filter(fn: (r) => r["cpu"] == "cpu-total")
  |> aggregateWindow(every: 1s, fn: mean, createEmpty: false)
  |> yield(name: "mean")
'>
'fluxquery' STORE

# Paramètres de la fonction INFLUX.FLUX avec la requête flux (la variable fluxquery) et les informations de connection à InfluxDB 2.x
{ 'flux' $fluxquery 'org' "myOrganisation" 'token' "myToken" 'url' "http://url.to.influxdb2:9999" }
INFLUXDB.FLUX
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE
# Affichage de la liste de GTS
$cpu

En FLoWS :

# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
<'
# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
fluxquery = 'from(bucket: "crntbackup")
  |> range(start: -1h, stop: now())
  |> filter(fn: (r) => r["_measurement"] == "cpu")
  |> filter(fn: (r) => r["cpu"] == "cpu-total")
  |> aggregateWindow(every: 1s, fn: mean, createEmpty: false)
  |> yield(name: "mean")'

# Paramètres de la fonction INFLUX.FLUX avec la requête flux (la variable fluxquery) et les informations de connection à InfluxDB 2.x
params = {'flux':fluxquery, 'org':'myOrganisation', 'token':'myToken', 'url':'http://url.to.influxdb2:9999' }
# Sauvegarde de la liste dans une variable cpu
cpu = INFLUXDB.FLUX(params)
# Affichage de la liste de GTS
return cpu
'>
FLOWS

On obtient :

warp10 - influxdb 3

Si on veut comme précédemment avec InfluxQL afficher la courbe du CPU idle.

En WarpScript :

# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
<'
from(bucket: "crntbackup")
  |> range(start: -1h, stop: now())
  |> filter(fn: (r) => r["_measurement"] == "cpu")
  |> filter(fn: (r) => r["cpu"] == "cpu-total")
  |> aggregateWindow(every: 1s, fn: mean, createEmpty: false)
  |> yield(name: "mean")
'>
'fluxquery' STORE

# Paramètres de la fonction INFLUX.FLUX avec la requête flux (la variable fluxquery) et les informations de connection à InfluxDB 2.x
{ 'flux' $fluxquery 'org' "myOrganisation" 'token' "myToken" 'url' "http://url.to.influxdb2:9999" }
INFLUXDB.FLUX
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE

# Affiche la 7eme liste (incide 6)
$cpu 6 GET

En FLoWS :

# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
<'
# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
fluxquery = 'from(bucket: "crntbackup")
  |> range(start: -1h, stop: now())
  |> filter(fn: (r) => r["_measurement"] == "cpu")
  |> filter(fn: (r) => r["cpu"] == "cpu-total")
  |> aggregateWindow(every: 1s, fn: mean, createEmpty: false)
  |> yield(name: "mean")'

# Paramètres de la fonction INFLUX.FLUX avec la requête flux (la variable fluxquery) et les informations de connection à InfluxDB 2.x
params = {'flux':fluxquery, 'org':'myOrganisation', 'token':'myToken', 'url':'http://url.to.influxdb2:9999' }
# Sauvegarde de la liste dans une variable cpu
cpu = INFLUXDB.FLUX(params)
# Affiche la 7eme liste (incide 6)
return cpu[6]
'>
FLOWS

warp10 - influxdb 4

Sauvegarder des données dans InfluxDB

La semaine dernière, nous écrivions en WarpScript :

'<read_token>' 'readToken' STORE
'<write_token>' 'writeToken' STORE

# Récupération des dépenses sous la forme d'une série  (GTS)
[ $readToken 'expense' { 'company' '=cerenit' } '2016-12-01T00:00:00Z' '2020-06-01T00:00:00Z' ] FETCH
0 GET
'exp' STORE

# Récupération du chiffre d'affaires mensuel sous la forme d'une série  (GTS)
[ $readToken 'revenue' { 'company' '=cerenit' } '2016-12-01T00:00:00Z' '2020-06-01T00:00:00Z' ] FETCH
0 GET
'revenue' STORE

# Calcul du résulat mensuel
$revenue $exp -
# Stockage de la série obtenue dans une série appelée "result"
"result" RENAME
{ "company" "cerenit" } RELABEL
$writeToken UPDATE

# Récupération du résultat mensuel sous la forme d'une série (GTS)
[ $readToken 'result' { 'company' '=cerenit' } '2016-12-01T00:00:00Z' '2020-06-01T00:00:00Z' ] FETCH
0 GET
'result' STORE

# Version 1.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' true 'url' "http://url.to.influxdb:8086" 'measurement' "result" 'db' "crntcompta" 'password' "myPassword" 'user' "myUser" }
'params' STORE
# Utilisatoin de la fonction INFLUXDB.UPDATE qui prend la variable 'params' pour les paramètres de connection et une GTS ou liste de GTS pour les données à sauvegarder
$result $params INFLUXDB.UPDATE

# Version 2.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' false 'url' "http://url.to.influxdb:9999" 'measurement' "result" 'bucket' "crntcompta" 'token' "myToken" 'org' "myOrganisation" }
'params' STORE
$result $params  INFLUXDB.UPDATE

En FLoWS, cela donne :

<'
# Gestion des tokens de lecture et écriture
readToken = '<read_token>'
writeToken = '<write_token>'

# Récupération de la liste de GTS dans Warp 10
expense_fetch = FETCH([readToken, 'expense', {'company':'cerenit'}, '2016-12-01T00:00:00Z', '2020-06-01T00:00:00Z'])
# On n'a toujours qu'une liste à 1 élement, on récupère donc la GTS en prenant l'index 0 de la liste
expense = expense_fetch[0]

# Même logique pour le chiffre d'affaires
revenue_fetch = FETCH([readToken, 'revenue', {'company':'cerenit'}, '2016-12-01T00:00:00Z', '2020-06-01T00:00:00Z'])
revenue = revenue_fetch[0]

# On calcule la résultat en faisant la différence entre les 2 GTS revenue et expense
r = revenue - expense
# la GTS obtenue n'ayant pas de nom, on lui en fournit un
RENAME(r, 'result')
# On ajoute les labels manquants
RELABEL(r, {"company":"cerenit"})
# On persiste la GTS dans Warp 10
UPDATE(r, writeToken)

# On récupère la contenu de la GTS result sur le même modèle que revenue et expense précédemment
result_fetch = FETCH([readToken, 'result', {'company':'cerenit'}, '2016-12-01T00:00:00Z', '2020-06-01T00:00:00Z'])
result = result_fetch[0]

# InfluxDB 1.X
# Définition des paramètres de connection
params = {'v1':true, 'url':"http://url.to.influxdb:8086", 'measurement':"result", 'db':"crntcompta", 'password':"myPassword", 'user':"myUser"}
# Persistance des données dans InfluxDB 1.x
INFLUXDB.UPDATE(result, params)

# InfluxDB 2.X
# Définition des paramètres de connection
params = {'v1':false, 'url':"http://url.to.influxdb:9999", 'measurement':"result", 'bucket':"crntcompta", 'token':"myToken", 'org':"myOrganisation" }
# Persistance des données dans InfluxDB 2.x
INFLUXDB.UPDATE(result, params)
'>
# Fin du code FLoWS
# Application de la fonction FLOWS à notre ensemble de code
FLOWS

Coté InfluxDB, on retrouve bien nos données :

warp10 - influxdb 5

Si au contraire, je veux regrouper plusieurs valeurs dans un même measurement InfluxDB, il faut passer une liste de GTS à INFLUXDB.UPDATE.

La semaine dernière, nous écrivions en WarpScript :

# Version 1.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' true 'url' "http://url.to.influxdb:8086" 'measurement' "accountancy" 'db' "crntcompta" 'password' "myPassword" 'user' "myUser" }
'params' STORE
# Passage d'une liste de GTS plutôt qu'une seule série de l'expemple précédent
[ $result $revenue $exp ] $params INFLUXDB.UPDATE

# Version 2.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' false 'url' "http://url.to.influxdb:9999" 'measurement' "accountancy" 'bucket' "crntcompta" 'token' "myToken" 'org' "myOrganisation" }
'params' STORE
# Passage d'une liste de GTS plutôt qu'une seule série de l'expemple précédent
[ $result $revenue $exp ] $params INFLUXDB.UPDATE

Cette semaine en FLoWS :

# InfluxDB 1.X
# Définition des paramètres de connection
params = {'v1':true, 'url':'http://url.to.influxdb:8086', 'measurement':'result', 'db':'crntcompta', 'password':'myPassword', 'user':'myUser'}
# Persistance des données dans InfluxDB 1.x en passant une liste de GTS
INFLUXDB.UPDATE([result, revenue, expense], params)

# InfluxDB 2.X
# Définition des paramètres de connection
params = {'v1':false, 'url':'http://url.to.influxdb:9999', 'measurement':'result', 'bucket':'crntcompta', 'token':'myToken', 'org':'myOrganisation' }
# Persistance des données dans InfluxDB 2.x en passant une liste de GTS
INFLUXDB.UPDATE([result, revenue, expense], params)
'>
FLOWS

Coté InfluxDB, on retrouve bien nos données :

warp10 - influxdb 6

Conclusion

Personnellement, au travers de cette exercice, je trouve FLoWS plutôt agréable à utiliser et il remplit bien son objectif de faciliter la prise en main de Warp 10 :

  • Même si je commençais à m'habituer à la NPI/RPN, avoir une approche plus traditionnelle évite de devoir se concentrer sur l'ordre,
  • La séparation par des virgules et/ou par des deux points (:) dans les listes et tableaux (MAP) facilitent leur lisiblité
  • La migration d'un code en Warpscript vers FLoWS peut se faire de façon très progressive puisque les deux peuvent cohabiter ; c'est d'ailleurs comme ça que j'ai procédé pour ce billet et valider ainsi que je ne perdais rien au fur et à mesure. Il suffit à la fin d'enlever tous les blocs intermédiaires pour n'avoir plus qu'un seul bloc de code en FLoWS. C'est plutôt malin ! Et si une extension ou un code ne serait pas encore disponible en FLoWS, il est possible de débrancher sur du Warpscript.
  • Il manque la complétion FLOWS dans le studio (et VSCode je présume) mais c'est pour bientôt !
  • Le code gagne en lisiblité car on identifie les blocs qui vont ensemble.

Pour illustrer ce dernier point : quand je repense au code du tutoriel sur les cyclone "Number per year", nous avons ce code à un moment :

$fetch_wind $end $end $start - TIMECLIP NONEMPTY SIZE

La fonction TIMECLIP prend trois arguments sauf que là, j'en vois potentiellement cinq. Il faut alors comprendre que le troisième argument est en fait le résulat de l'opération $end $start -.

En FLoWS, on aura alors :

TIMECLIP(fetch_wind, end, end - start)

et au global (non testé) :

SIZE(NONEMPTY(TIMECLIP(fetch_wind, end, end - start)))

Ce qui me semble nettement plus clair/lisible.

Le pari de FLoWS était de rendre Warp 10 plus accessible et de rendre les développeurs productifs plus rapidement, il semblerait bien que les objectifs soient remplis.

Warp 10 - Interactions avec une instance InfluxDB

warp10timeseriesinfluxdbwarpscriptwarpfleet

Après les premiers pas avec Warp10 et en attendant que l'extension FLoWS soit disponible pour la version 2.7.0, j'ai mis à jour mon instance Warp 10 en 2.7.0 et j'ai voulu jouer avec l'extension warp10-ext-influxdb. Cette extension permet de requêter une instance InfluxDB 1.x ou 2.x avec du WarpScript.

Attention à ne pas confondre le plugin natif InfluxDB qui permet d'envoyer des métriques au format Line Protocol d'InfluxDB dans Warp10 et l'extension InfluxDB qui permet d'interagir avce une base InfluxDB en WarpScript.

Pré-requis: warpfleet

Installons déjà warpfleet, le gestionnaire de package conçu pour Warp 10.

# Installation de npm
sudo dnf install -y npm

# installation de warpfleet
sudo npm install -g @senx/warpfleet

# Vérification de la bonne installation de warpfleet
wf version
      ___       __                     _______________         _____
      __ |     / /_____ __________________  ____/__  /___________  /_
      __ | /| / /_  __ `/_  ___/__  __ \_  /_   __  /_  _ \  _ \  __/
      __ |/ |/ / / /_/ /_  /   __  /_/ /  __/   _  / /  __/  __/ /_
      ____/|__/  \__,_/ /_/    _  .___//_/      /_/  \___/\___/\__/
                               /_/version: 1.0.31
1.0.31

Installation de l'extension warp10-ext-influxdb

Sans trop rentrer dans les détails de warpfleet, il utilise un système de namespace appelés "Groups" pour ces packages et qui permettent de définir ses propres dépots. Pour l'extension warp10-ext-influxdb, le "group" est io.warp10.

Ce qui pour l"installation donne la commande suivante :

# Si votre utilisateur n'a pas accès à /path/to/warp10, il vous faudra utiliser sudo
(sudo) wf g -w /path/to/warp10 io.warp10 warp10-ext-influxdb

warpfleet va vous demander quelle version de l'extension vous souhaitez puis va procéder à son téléchargement et son installation.

Cela donne :

sudo wf g -w /opt/warp10 io.warp10 warp10-ext-influxdb
       ___       __                     _______________         _____
       __ |     / /_____ __________________  ____/__  /___________  /_
       __ | /| / /_  __ `/_  ___/__  __ \_  /_   __  /_  _ \  _ \  __/
       __ |/ |/ / / /_/ /_  /   __  /_/ /  __/   _  / /  __/  __/ /_
       ____/|__/  \__,_/ /_/    _  .___//_/      /_/  \___/\___/\__/
                                /_/                                        ™
 version: 1.0.31
? Which revision do you want to retrieve? latest
✔ ext io.warp10:warp10-ext-influxdb#1.0.1-uberjar retrieved
✔ Download successful: gradle-wrapper.jar
✔ Download successful: gradle-wrapper.properties
✔ Download successful: gradlew
✔ Download successful: gradlew.bat
✔ Dependency warp10-ext-influxdb-1.0.1-uberjar.jar successfully deployed
✔ Done

Note: Pour éviter un bug dans la fonction INFLUXDB.UPDATE identifié lors de la rédaction de ce billet, assurez-vous d'avoir une version >= 1.0.1

Ensuite, il faut créer le fichier /path/to/warp10/etc/conf.d/90--influxdb-extension.conf et y ajouter la ligne suivante:

warpscript.extension.influxdb = io.warp10.script.ext.influxdb.InfluxDBWarpScriptExtension

Je préfère créer un fichier plutôt que d'éditer un fichier existant pour le suivi des mises à jour et j'ai utilisé le prefix 90 car il n'est pas utilisé par les fichiers de Warp10.

Relancer ensuite Warp 10 pour que le plugin soit chargé au démarrage de l'instance :

(sudo) /path/to/warp10/bin/warp10-standalone.init restart

Dans /path/to/warp10/logs/warp10.log, vous devriez voir apparaitre :

2020-09-17T10:59:23,742 main INFO  script.WarpScriptLib - LOADED extension 'io.warp10.script.ext.influxdb.InfluxDBWarpScriptExtension'

Requêtage d'une instance InfluxDB 1.x

Note: La librairie influxdb-java ne semble pas supporter un reverse proxy http/2 devant l'instance InfluxDB. Il faut donc accéder à InfluxDB en direct via le port 8086.

# Requête INFLUXQL et informations de connection à InfluxDB 1.X
{ 'influxql' "select * from cpu where host=%27myHost%27 and time > now() - 1h" 'db' "myDatabase" 'password' "myPassword" 'user' "myUser" 'url' "http://url.to.influxdb:8086" }
INFLUXDB.FETCH
# On récupère une liste de liste de séries GTS. Il n'y a qu'un seul élément dans cette liste. Nous le prenons pour n'avoir plus qu'une liste de séries GTS.
0 GET
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE
# Affichage de la liste de GTS
$cpu

Dans ce qu'il faut noter ici:

  • INFLUXDB.FETCH prend ses paramètres dans une MAP ayant pour paramètres: influxql, db, password, user et url.
  • Pour la directive where, il faut encoder les apostrophes via %27 : en InfluxQL, on écrirait ... where host='myHost' ; là, il faut écrire where host=%27myHost%27
  • Si dans InfluxDB, on a un measurements (cpu) avec n items (usage_guest, usage_idle, etc), on a une conversion en une liste de n GTS avec une valeur chacune.
  • influxql prend une ou plusieurs requêtes séparées par des points virgules. Cela donnera en sortie plusieurs listes de listes de GTS (vu que comme dit au dessus, pour une requête influxql sur un measurement on a 1 à n GTS ; donc pour y requêtes, on aura y listes de n listes de GTS)

warp10 - influxdb 1

Pour illustrer cette liste de liste de GTS, si on veut récupérer la GTS du cpu idle, on voit dans le graphique que c'est la 5ème courbe, donc un indice 4.

{ 'influxql' "select * from cpu where host=%27myHost%27 and time > now() - 1h" 'db' "myDatabase" 'password' "myPassword" 'user' "myUser" 'url' "http://url.to.influxdb:8086" }
INFLUXDB.FETCH
0 GET
'cpu' STORE
# Récupération de la 5ème liste (indice 4)
$cpu 4 GET

warp10 - influxdb 2

Requêtage d'une instance InfluxDB 2.x

Note: La librairie influxdb-client-java ne semble pas plus supporter un reverse proxy http/2 devant l'instance InfluxDB. Il faut donc accéder à InfluxDB en direct via le port 9999.

Si on fait une requête similaire en flux :

# Requête FLUX et informations de connection à InfluxDB 2.x
{ 'flux' "from(bucket: %22myBucket%22) |> range(start: -1h, stop: now()) |> filter(fn: (r) => r[%22_measurement%22] == %22cpu%22) |> filter(fn: (r) => r[%22cpu%22] == %22cpu-total%22) |> aggregateWindow(every: 1s, fn: mean, createEmpty: false) |> yield(name: %22mean%22)" 'org' "myOrganisation" 'token' "myToken" 'url' "http://url.to.influxdb2:9999" }
INFLUXDB.FLUX
# On récupère une liste de séries GTS
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE
# Affichage de la liste de GTS
$cpu

warp10 - influxdb 2

On note que la requête flux n'est pas très lisible de par l'encodage des guillemets et de son coté monoligne. On peut améliorer ça avec une variable STRING en multi-ligne :

# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
<'
from(bucket: "crntbackup")
  |> range(start: -1h, stop: now())
  |> filter(fn: (r) => r["_measurement"] == "cpu")
  |> filter(fn: (r) => r["cpu"] == "cpu-total")
  |> aggregateWindow(every: 1s, fn: mean, createEmpty: false)
  |> yield(name: "mean")
'>
'fluxquery' STORE

# Paramètres de la fonction INFLUX.FLUX avec la requête flux (la variable fluxquery) et les informations de connection à InfluxDB 2.x
{ 'flux' $fluxquery 'org' "myOrganisation" 'token' "myToken" 'url' "http://url.to.influxdb2:9999" }
INFLUXDB.FLUX
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE
# Affichage de la liste de GTS
$cpu

On y gagne en lisibilité et pas besoin d'encoder les guillements !

Dans les deux cas, on obtient :

warp10 - influxdb 3

On note d'ailleurs que les méta-données (nom du measurement, nom du champ et les tags sont repris sous la forme de labels)

Contraiement à la requête en InfluxQL, on ne peut passer qu'une requête à la fois mais ce qui permet d'avoir directment une liste de GTS puis la GTS. On n'a plus une liste de liste de GTS.

Si on veut comme précédemment avec InfluxQL afficher la courbe du CPU idle:

# Utilisation du string multi-ligne pour améliorer la lisibilité de la requête FLUX et sauvegarde dans une variable fluxquery.
<'
from(bucket: "crntbackup")
  |> range(start: -1h, stop: now())
  |> filter(fn: (r) => r["_measurement"] == "cpu")
  |> filter(fn: (r) => r["cpu"] == "cpu-total")
  |> aggregateWindow(every: 1s, fn: mean, createEmpty: false)
  |> yield(name: "mean")
'>
'fluxquery' STORE

# Paramètres de la fonction INFLUX.FLUX avec la requête flux (la variable fluxquery) et les informations de connection à InfluxDB 2.x
{ 'flux' $fluxquery 'org' "myOrganisation" 'token' "myToken" 'url' "http://url.to.influxdb2:9999" }
INFLUXDB.FLUX
# Sauvegarde de la liste dans une variable cpu
'cpu' STORE

# Affiche la 7eme liste (incide 6)
$cpu 6 GET

warp10 - influxdb 4

Je ne vais pas pousser l'exemple plus loin, il ne tient qu'à vous de poursuivre la manipulation de vos données en WarpScript. On pourrait se demander où mettre la limite entre la requête en Flux/InfluxQL et les manipulations à faire en WarpScript ensuite. Tout dépendra de votre cas d'usage.

Sauvegarder des données dans InfluxDB

Pour le moment, nous avons requêté des données stockées dans InfluxDB 1.x ou 2.x ; mais nous pouvons très bien imaginer un cas où les données sont issues d'une autre source de données ou bien ont été générées avec WarpScript mais qu'on veuille les persister dans InfluxDB 1.x ou 2.x

Reprenons mon exercice de compatbilité et de prédictions et sauvegardons tout ça dans InfluxDB.

Pour rappel, nous avons fait ceci :

'<read_token>' 'readToken' STORE
'<wrtie_token>' 'writeToken' STORE

# Récupération des dépenses sous la forme d'une série  (GTS)
[ $readToken 'expense' { 'company' '=cerenit' } '2016-12-01T00:00:00Z' '2020-06-01T00:00:00Z' ] FETCH
0 GET
'exp' STORE

# Récupération du chiffre d'affaires mensuel sous la forme d'une série  (GTS)
[ $readToken 'revenue' { 'company' '=cerenit' } '2016-12-01T00:00:00Z' '2020-06-01T00:00:00Z' ] FETCH
0 GET
'revenue' STORE

# Calcul du résulat mensuel
$revenue $exp -
# Stockage de la série obtenue dans une série appelée "result"
"result" RENAME
{ "company" "cerenit" } RELABEL
$writeToken UPDATE

# Récupération du résultat mensuel sous la forme d'une série (GTS)
[ $readToken 'result' { 'company' '=cerenit' } '2016-12-01T00:00:00Z' '2020-06-01T00:00:00Z' ] FETCH
0 GET
'result' STORE

Si je veux sauvegarder une série dans un measurement influxdb :

# Version 1.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' true 'url' "http://url.to.influxdb:8086" 'measurement' "result" 'db' "crntcompta" 'password' "myPassword" 'user' "myUser" }
'params' STORE
# Utilisatoin de la fonction INFLUXDB.UPDATE qui prend la variable 'params' pour les paramètres de connection et une GTS ou liste de GTS pour les données à sauvegarder
$result $params INFLUXDB.UPDATE

# Version 2.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' false 'url' "http://url.to.influxdb:9999" 'measurement' "result" 'bucket' "crntcompta" 'token' "myToken" 'org' "myOrganisation" }
'params' STORE
$result $params  INFLUXDB.UPDATE

Coté InfluxDB, on retrouve bien nos données :

warp10 - influxdb 5

Si au contraire, je veux regrouper plusieurs valeurs dans un même measurement InfluxDB, il faut passer une liste de GTS à INFLUXDB.UPDATE.

# Version 1.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' true 'url' "http://url.to.influxdb:8086" 'measurement' "accountancy" 'db' "crntcompta" 'password' "myPassword" 'user' "myUser" }
'params' STORE
# Passage d'une liste de GTS plutôt qu'une seule série de l'expemple précédent
[ $result $revenue $exp ] $params INFLUXDB.UPDATE

# Version 2.x
# Création d'une MAP 'params' avec les informations de connection à l'instance InfluxDB
{ 'v1' false 'url' "http://url.to.influxdb:9999" 'measurement' "accountancy" 'bucket' "crntcompta" 'token' "myToken" 'org' "myOrganisation" }
'params' STORE
# Passage d'une liste de GTS plutôt qu'une seule série de l'expemple précédent
[ $result $revenue $exp ] $params INFLUXDB.UPDATE

Coté InfluxDB, on retrouve bien nos données :

warp10 - influxdb 6

On arrive au bout de ce billet, nous avons vu que nous pouvons :

  • En WarpScript, requêter des données stockées dans InfluxDB 1.x et 2.x
  • En WarpScript, manipuler des données issues de Warp 10 puis les stocker dans InfluxDB 1.x et 2.x

Nous pourrions aller plus loin avec :

  • des scénarios d'enrichissement de données en s'interfaçant par ex avec des données de sources SQL (référentiels, etc)
  • des scénarios d'analytics en croisant des données issues de Warp10, InfluxDB ou d'autres sources de données (bases SQL, etc)
  • des scénarios de projection en appliquant par exemple les algorythmes de machine learning sur des données issues d'InfluxDB
  • ...

WarpScript semble ainsi permettre d'avoir un langage de manipulation de séries temporelles multi-sources et d'offrir une expérience unifiée de manipulatoin de ces données. Dans les prochains billets, nous explorerons d'avantage la partie visualisation et alerting.

Web, Ops & Data - Septembre 2020

podmantimezonegrafanadashboardterraformsécuritéterrascanterracostnvidiaarmcnicsinetworkstorageciliumcalicolonghornportworxopenebsrancherpythongkewarp10influxdbdata-engineerdate-scientistsql

Cloud

  • terrascan : terrascan va scanner vos fichiers terraform et les valider contre 500+ règles de sécurité (au format Open Policy Agent) afin d'identifier les éventuels problèmes de sécurité. L'outil supporte AWS, GCP et Azure.
  • infracost : estimez le coût de vos projets terraform à l'heure ou au mois. Il est même possible de faire apparaitre les évolutions de vos coûts d'infra lors d'une MR/PR. A défaut d'être forcément précis, cela pourra au moins donner une idée et permettra peut être de sensibiliser les développeurs et/ou les clients aux évolutions de couts de leurs projets.

Code

  • All Python versions before 3.6 are now totally unsupported : Python 2 n'est plus supporté depuis le début de l'année - c'est au tour de Python 3.5 de ne plus l'être depuis le 13 sept. Pour Python 3.6, ce sera décembre 2021.
  • nackjicholson/aiosql : juste milieu (?) entre du SQL brut et un ORM, aiosql semble permettre d'associer une requête SQL à une fonction pour une manipulation assez simple ensuite dans le code par la suite.

Container et orchestration

(Big) data

  • #19. Lucien Fregosi - Hugo Larcher - Erika Gelinard - Dessine moi un data engineer : Pour cette saison 2 de DataBuzzWord, des réflexions intéressantes autour du Data Engineer / Data Scientists, le Data Engineer qui fait du Build/Run, les pipelines & job as a service et de l'importance de simplifier / déporter le run pour que le Data Engineer et a fortiori le Data Scientist se concentrent sur leurs pipelines ou leur exploitation et gérer moins d'infrastructure.

Hardware

Time Series

  • InfluxDB OSS 2.0 General Availability Roadmap : un bon résumé sur les avancées d'Influx 2.0 OSS et la transition 1.x vers 2.x ; Début septembre, j'étais sceptique quand même avec le retour du stockage et du requêtage da la V1 dans la branche v2 (cf la PR "Port TSM1 storage engine") et ce à un mois de la date de release prévue annoncés aux Influxdays de Londres (ie fin septembre). Au final, la version 2.0 OSS et Entreprise auront les feautres "frontend" de la V2 (Tasks, Dashobards, etc) mais uniquement le moteur de stockage de la V1. Si je comprends le besoin pour ne pas perdre leurs clients dans la migration, c'est un écart de plus entre les version OSS/Entreprise et la version Cloud. Les couches hautes (API, UI, fonctionnalités type Task/Dashboards/...) seront commmunes mais sous le capot (stockage, ingestion), cela diffère. On peut raisonnablement se demander si c'est une phase intermédiaire avant une migration ultérieure sur le moteur de stockage de la 2.0 quand InfluxData aura plus de recul sur le sujet ou bien si les projets Cloud et OSS/Entreprise ne vont pas diverger significativement à moyen terme. Ceux qui ont commencé à alimenter leur base InfluxDB 2.0 sur la base des versions beta devront repartir de zéro du fait de cette incompatibilité de version de moteur de stockage.
  • Popular community plugins that can improve your Grafana dashboards : une collection de plugins Grafana pour améliorer vos dashboards.
  • September 2020: Warp 10 release 2.7.0, ready for FLoWS : la version 2.7 de Warp 10 est disponible et est la première version qui va supporter FLoWS, la syntaxe fonctionnelle alternative à WarpScript. Pour en savoir plus sur FLoWS, je vous renvoie à l'édition 5 du Paris Time Series Meetup avec la présentation de FLoWS. D'autres améliorations font partie de cette release, tant d'un point de vue fonctionnalités que performances.

Web, Ops & Data - Juillet 2020

terraformacmeletsencryptinfluxdbinfluxdaysquestdbtimeseriesranchersusestashkubedbmaeshwarp10warpscriptflowsptsmrgpdsafe-harbordonnées personnellesgrafanaflux

Cloud

Container et orchestration

  • Announcing Maesh 1.3 : Maesh continue son chemin et ajoute la capacité de surveiller des namespace particuliées (en plus de pouvoir en ignorer), le support du lookup des ports (http -> 80), le support de CoreDNS chez AKS et d'autres améliorations encore.
  • Electro Mpnkeys #9 – Traefik et Maesh : de l’ingress au service mesh avec Michael Matur : si vous voulez en savoir plus sur Traefik et Maesh, je vous conseille cet épisode (et les autres) du podcast Electro Monkeys.
  • Introducing Traefik Pilot: a First Look at Our New SaaS Control Platform for Traefik : Containous, la société derrière Traefik, Maesh et Yaegi sort son offre SaaS pour piloter et monitorer ses instances traefik. Un système de plugins pour les middleware fait également son apparaition. Il faut une version 2.3+ (actuellement en RC) de Traefik pour bénéficier de cette intégration.
  • Relicensing Stash & KubeDB : KubeDB, l'operateur de bases de données et Stash, l'outil de sauvegarde se cherchent un modèle économique et changent de licence. La version gratuite, avec code source disponible, reste disponible pour des usages non commerciaux (voir les détails de la licence pour une slite exacte). Pour un usage commercial, il faudra passer par la version Entreprise qui apporte aussi des fonctionnalités supplémentaires.
  • Suse to acquire Rancher : Suse était sorti de mon radar; c'est donc pour moi l'entrée (ou le retour ?) de Suse dans le monde de kubernetes et de son orchestration. Est-ce une volonté d'aller prendre des parts de marchés à Redhat/Openshift ou de faire face à des rumeurs telles que Google en discussion pour acquérir D2IQ (ex Mesoshphère) ? A voir si cette acquisition va être un tremplin pour Rancher et ses différents projets (rke, rio, k3s, longhorn, etc) comme l'indique son CTO ou pas.

Time Series

Vie privée & données personnelles

Le Privacy Shield, l'accord entre l'Europe et les USA sur le transfert des données des Européens vers les USA (ou les sociétés américaines) vient d'être invalidé par la cour de justice européene. Les flux "absolument nécessaires" peuvent continuer à se faire pour le moment et la cour a validé "les clauses contractuelles types" définies par la Commission Européenne pourront être utilisées par les entreprises. Néanmoins, pour s'y référer, il semble qu'il faut vérifier que l'entreprise protège effectivement les données. Je vous invite à contacter votre juriste ou avocat pour mieux appréhender les impacts de cette invalidation si vous utilisez les plateformes cloud et des services dont les entreprises sont basées aux USA. En tant qu'individu, il peut être intéressant de se poser des questions également. N'étant pas juriste, je vais donc limiter mon interprétation ici et vous laisse lire les liens ci-dessous.

Web, Ops & Data - Juin 2020

terraformtelegrafkubernetesoperatorrancherlonghornraspberrypiprometheusvictoria-metricsmonitoringinfluxdbwarp10forecast

Je ne peux résister à mentionner la sortie de l'épisode 100 du BigDataHebdo, podcast où j'ai le plaisir de contribuer. Pour ce numéro spécial (épisode 100 et 6 ans du podcast), nous avons fait appel aux membres de la communauté pour partager avec nous leur base de données favorite, la technologie qui les a le plus impressionée durant ces 6 dernières années et celle qu'ils voient comme majeure pour les 6 prochaines années. Allez l'écouter !

Cloud

Container et orchestration

IoT

  • 8GB Raspberry Pi 4 on sale now at $75 : Le Raspberry Pi 4 arrive en version 8Go de RAM, Raspberry PI OS arrive en 64 bits, le support du boot sur usb arrive aussi (adieu la SDCard) et plein d'autres choses. Le tout au prix de 75$.

Ops

  • Sismology: Iguana Solutions’ Monitoring System : retour d'expérience sur une plateforme de monitoring initiée sur Prometheus et qui évolue vers VictoriaMetrics en prenant les aspects de stockage à long terme, le multi-tenant et la haute disponibilité de la plateforme.

Time Series

← Précédent 2 / 4 Suivant →