Pour ce premier article dans la série sur la plateforme data, on va d’abord installer quelques outils, démarrer le cluster Kubernetes, puis lancer la partie infrastructure de la plateforme.

Prérequis

Je le rappelle, cette plateforme de donnée fonctionne mieux sous un OS de type Linux. Tous les outils peuvent fonctionner sous Windows (avec WSL) ou sur Mac, mais cela nécessite quelques configurations supplémentaires pour pouvoir accéder aux différentes interfaces web et API.

De plus Docker doit être installé, ainsi que la commande jq (avec sudo apt install jq ou sudo dnf install jq).

Présentation et installation des outils

Tout est indiqué dans le répertoire git dont on va récupérer les sources, je vais ajouter ici quelques détails supplémentaires.

Kind

Kind (initialement "Kubernetes IN Docker") est un logiciel pour déployer un cluster Kubernetes sur base de conteneurs. Chaque nœud est représenté par un conteneur, avec un réseau virtuel dédié au cluster. Kind était d’abord développé pour tester les développements du projet Kubernetes lui-même, mais peut maintenant servir à tester ses propres applications dans un environnement Kubernetes local.

Pour l’installer, il y a deux façons. A la mode de go, il suffit de lancer la commande suivante :

go install sigs.k8s.io/kind@latest

Ou bien vous pouvez télécharger le binaire et le placer dans un dossier compris dans le $PATH.

ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-${ARCH}
chmod +x ./kind
mv ./kind $HOME/.local/bin/kind

Le cluster de démo est composé d’un nœud pour le controle-plane et de deux nœuds worker, dont l’un sera utilisé pour recevoir les connexions externes, grâce au load-balancer de MetalLB.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: data-platform
networking:
  ipFamily: ipv4
nodes:
  - role: control-plane
    image: kindest/node:v1.33.1
  - role: worker
    image: kindest/node:v1.33.1
    labels:
      net: metallb-gateway
  - role: worker
    image: kindest/node:v1.33.1

Kubectl

Kubectl est l’outil de ligne de commande utilisé pour interagir avec les clusters Kubernetes. Il permet de déployer des applications, de gérer les ressources du cluster et d’obtenir des informations sur l’état des ressources.

Pour l’installer, il faut télécharger le binaire. Des repositories apt et rpm existent aussi.

ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt)
curl -LO "https://dl.k8s.io/release/${VERSION}/bin/linux/${ARCH}/kubectl"
chmod +x ./kubectl
mv ./kubectl $HOME/.local/bin/kubectl

Helm

Déployer des applications dans un cluster Kubernetes peut être laborieux. Il faut définir les différents composants nécessaires (pods, services, pv …​), le type (Deployments/DaemonSets, ClusterIP/LoadBalancer, …​), les accès réseaux (Ingress, HTTPRoute, …​). C’est là qu’intervient Helm, un gestionnaire de packages pour Kubernetes qui simplifie le déploiement et la gestion des applications. Les développeurs de l’application, ou la communauté, peuvent créer des "charts" Helm, qui sont l’équivalent des paquets APT/RPM pour Kubernetes. A ceci près que toute la configuration des applications Helm peut (doit) être définie avant l’installation, via les "values".

Un repository Helm est mis à disposition, chaque repository peut contenir des charts de plusieurs applications. Lorsqu’on installe une application dans le cluster, cela devient une "release".

Helm stocke la configuration des applications dans le cluster Kubernetes lui-même, en utilisant des objets Kubernetes tels que ConfigMaps et Secrets.

Pour l’installer, plusieurs méthodes sont disponibles. J’en reprends ici deux :

# Pour les développeurs golang
go install helm.sh/helm/v3/cmd/helm@latest

# Ou télécharger un binaire compilé
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
VERSION=$(curl -s https://api.github.com/repos/helm/helm/releases/latest | jq -r '.tag_name')
curl -L "https://get.helm.sh/helm-${VERSION}-linux-${ARCH}.tar.gz" | tar -xz --strip-components=1 linux-${ARCH}/helm
mv ./helm $HOME/.local/bin/helm

Helmfile

Une plateforme est généralement composée de plusieurs applications, et donc de plusieurs release Helm. Pour simplifier et centraliser les values et configurations, on peut utiliser Helmfile. Cet outil permet de définir l’ensemble des releases Helm dans un fichier YAML, et de les gérer de manière cohérente.

On a le choix entre un fichier helmfile.yaml par plateforme, ou de découper avec un fichier par application. En allant dans les détails de la configuration helmfile, on pourrait même gérer plusieurs environnements différents. Tout comme Helm, on peut utiliser des templates Golang, ce qui démultiplie encore les possibilités.

Pour l’installer, encore et toujours la page de documentation, et deux possibilités reprises ci-dessous :

# Pour les développeurs golang
go install github.com/helmfile/helmfile@latest

# Ou télécharger un binaire
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
VERSION=$(curl -s https://api.github.com/repos/helmfile/helmfile/releases/latest | jq -r '.tag_name')
VERSION=${VERSION#v}
curl -L "https://github.com/helmfile/helmfile/releases/download/v${VERSION}/helmfile_${VERSION}_linux_${ARCH}.tar.gz" | tar -xz -C $HOME/.local/bin helmfile
👇 Après l’installation, il faut télécharger tous les plugins helm dont helmfile a besoin.
helmfile init

Installation de la plateforme

En premier lieu, il faut cloner le repository git et se placer à l’intérieur du dossier 01-infra.

git clone https://github.com/xreveillon/data-platform-demo.git
cd data-platform-demo/01-infra

Démarrage du cluster Kind

Démarrons le cluster Kind
kind create cluster --config kind-config.yaml

On peut vérifier que le cluster est bien démarré avec la commande kubectl get nodes.

Personnalisation de la plateforme

Pendant que le cluster démarre, on va personnaliser un peu la plateforme. Dans le fichier .env, je propose de définir quelques paramètres via des variables d’environnement.

Le plus important est le nom de domaine principal, qui sera utilisé pour accéder aux différentes applications. Chaque application, avec une interface web ou avec un certificat SSL, aura son propre sous-domaine, par exemple minio.GLOBAL_DOMAIN pour Minio, ou airbyte.GLOBAL_DOMAIN pour Airbyte.

Fichier .env
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Domaine global, sous lequel chaque application prendra un sous-domaine
# Exemple, minio serait accessible sous minio.GLOBAL_DOMAIN,
# soit minio.data-platform.xreveillon.eu
GLOBAL_DOMAIN=data-platform.xreveillon.eu

MINIO_ACCESS_KEY=adminuser
MINIO_SECRET_KEY=adminpassword

AIRBYTE_S3_ACCESS_KEY=airbyte
AIRBYTE_S3_SECRET_KEY=airbytepassword

REGISTRY_USER=registry
REGISTRY_PASSWORD=registrypassword
REGISTRY_S3_ACCESS_KEY=registry
REGISTRY_S3_SECRET_KEY=registrypassword

Une fois modifiées, chargeons la configuration en mémoire.

set -a ; . .env ; set +a

Récupération d’informations réseau

Maintenant que le cluster est démarré, on va récupérer quelques informations réseau, qui serviront à configurer le réseau pour MetalLB (cf. plus bas le paragraphe sur MetalLB).

# Extraction du CIDR du réseau IPv4 du cluster kind
export KIND_IPV4_CIDR=$(docker network inspect kind | jq -r '.[0].IPAM.Config[] | select(.Subnet | test(":") | not) | .Subnet')

# Calcul de la plage d'adresses IP pour MetalLB
export METALLB_IP_RANGE=$(./last10range.sh $KIND_IPV4_CIDR)

Installation de l’infrastructure

On commence par installer les ressources de la Gateway API, et enfin on installe toute l’infra en une seule commande.

# Installer les CRD de la Gateway API depuis la branche expérimentale.
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/experimental-install.yaml

# Installer les applications
helmfile apply

Cela va durer plusieurs minutes, le temps de récupérer les images Docker et démarrer les applications. Si un timeout survient, il suffit de relancer la commande helmfile apply.

En attendant, lisons le contenu de ce que l’on déploie 👇

Contenu de l’infrastructure

MetalLB

helmfile.yaml
24
25
26
27
28
29
30
31
32
33
34
35
36
37
releases:
  - name: metallb
    namespace: metallb-system
    createNamespace: true
    chart: metallb/metallb
    wait: true
  - name: kubedeploy-metallb
    namespace: metallb-system
    chart: sysbee/kubedeploy
    disableValidationOnInstall: true
    needs:
      - metallb-system/metallb
    values:
      - values/metallb-extraobjects.yaml.gotmpl

Comme son nom l’indique, MetalLB est un load-balancer pour Kubernetes. Il existe 4 types de services pour gérer le réseau dans Kubernetes. Le service de type LoadBalancer est le seul à permettre des connections réseau depuis l’extérieur du cluster vers un port "habituel" (80, 443, 5432, …​), au moyen d’un load-balancer situé à l’extérieur. Dans un environnement cloud, le LoadBalancer externe est automatiquement approvisionné, configuré et géré par le fournisseur cloud (AWS ELB, GCP LB, Azure LB, …​). Dans un environnement on-premise ou local, il n’y a pas de load-balancer natif. MetalLB comble cette lacune en fournissant une implémentation logicielle de load-balancer, par exemple au moyen de l’allocation d’une adresse IP virtuelle sur un des noeuds.

Schéma de fonctionnement de MetalLB
Schéma de fonctionnement de MetalLB

Les adresses IP présentées sont propres à ma configuration. J’ai choisi le mode Layer 2.

Cert-manager

helmfile.yaml
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  - name: cert-manager
    namespace: cert-manager
    createNamespace: true
    chart: jetstack/cert-manager
    wait: true
    disableValidationOnInstall: true
    values:
      - crds:
          enabled: true
        prometheus:
          enabled: false
        config:
          apiVersion: controller.config.cert-manager.io/v1alpha1
          kind: ControllerConfiguration
          enableGatewayAPI: true
  - name: cert-manager-extra-objects
    namespace: cert-manager
    chart: sysbee/kubedeploy
    disableValidationOnInstall: true
    wait: true
    needs:
      - cert-manager/cert-manager
    values:
      - values/cert-manager-extraObjects.yaml.gotmpl

Cert-manager est un gestionnaire de certificats SSL pour Kubernetes. Il automatise la gestion et le renouvellement des certificats TLS, en s’intégrant avec des autorités de certification comme Let’s Encrypt ou même privées. Cert-manager surveille les ressources de certificat dans le cluster et s’assure que les certificats sont valides et à jour.

Quand je ferai évoluer la plateforme vers un mode "production-ready", Cert-manager sera très utile pour chiffrer toutes les communications internes du cluster. Là maintenant, Cert-Manager est utilisé pour sécuriser votre accès aux interfaces web.

Expliquer le pourquoi et le comment d’une PKI (public Key Infrastucture) fait partie de mes futurs articles de blog.
Si vous en avez marre de voir des avertissements de certificats dans votre navigateur en visitant les pages de la plateforme, vous pouvez installer le certificat racine de la PKI dans vos autorités de confiance. Mais je le DECONSEILLE FORTEMENT.

Trust-manager

helmfile.yaml
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  - name: trust-manager
    namespace: cert-manager
    chart: jetstack/trust-manager
    disableValidationOnInstall: true
    wait: true
    needs:
      - cert-manager/cert-manager-extra-objects
    values:
      - crds:
          enabled: true
        secretTargets:
          enabled: false
  - name: trust-manager-extra-objects
    namespace: cert-manager
    chart: sysbee/kubedeploy
    disableValidationOnInstall: true
    wait: true
    needs:
      - cert-manager/trust-manager
    values:
      - values/trust-manager-extraObjects.yaml.gotmpl

Lorsque Cert-manager gère lui-même la PKI, Trust-manager est très pratique pour distribuer le certificat public, pour que les différentes applications puissent faire confiance aux certificats émis par Cert-manager.

Traefik

helmfile.yaml
83
84
85
86
87
88
89
90
91
  - name: traefik
    namespace: traefik
    createNamespace: true
    chart: traefik/traefik
    disableValidationOnInstall: true
    values:
      - values/traefik-values.yaml.gotmpl
    needs:
      - cert-manager/cert-manager

Quand des applications web sont hébergées à l’intérieur d’un cluster Kubernetes, il faut pouvoir y accéder depuis l’extérieur. On l’a déjà vu avec MetalLb, des services de type LoadBalancer le permettent, quel que soit le protocole d’échange utilisé. Mais cela donne un accès direct aux applications, sans gestion des noms de domaines, ni des certificats SSL, ni de politiques de sécurité.

Pour le protocole HTTP(S), la meilleure méthode pour le moment est d’utiliser les Ingress avec un Ingress Controller (pour simplifier, c’est le reverse-proxy de Kubernetes). Dans ma plateforme, j’utilise Traefik comme Ingress Controller.

Traefik est aussi compatible avec la Gateway API, qui complètera les Ingress pour les applications nécessitant des configurations plus complexes.

Minio

helmfile.yaml
103
104
105
106
107
108
109
110
111
112
  - name: minio
    namespace: minio
    createNamespace: true
    chart: minio/minio
    disableValidationOnInstall: true
    wait: true
    needs:
      - minio/minio-extra-objects-pre
    values:
      - values/minio-values.yaml.gotmpl

Minio est une solution de stockage objet compatible avec l’API S3 d’Amazon. Elle est conçue pour être hautement disponible, évolutive et performante, et peut être déployée sur site ou dans le cloud. Minio est souvent utilisé pour stocker des données non structurées telles que des images, des vidéos, des sauvegardes et des fichiers journaux.

Le stockage objet est devenu prédominant dans le monde de la data, avec des solutions comme les Lakehouse.

Les lakehouse reposent sur le principe de la séparation du stockage et du calcul. Le stockage est assuré par un système de fichiers distribué ou un stockage objet, accessibles par plusieurs clients et query engines de manière concurrentielle.

Registre d’images Docker

helmfile.yaml
121
122
123
124
125
126
127
128
  - name: registry
    namespace: registry
    createNamespace: true
    chart: twuni/docker-registry
    needs:
      - minio/minio
    values:
      - values/docker-registry-values.yaml.gotmpl

Parmi les outils installés, il y a au moins Dagster qui nécessitera de créer ses propres images Docker. Et pour inclure le certificat public de l’autorité racine de la PKI privée, il faudra peut-être aussi procéder à la création d’images.

Instance PostgreSQL avec des données source

helmfile.yaml
113
114
115
116
117
118
119
120
  - name: pg-source
    namespace: postgresql
    createNamespace: true
    chart: bitnami/postgresql
    needs:
      - traefik/traefik
    values:
      - values/pg-source-values.yaml.gotmpl

Il s’agit de l’instance PostgreSQL qui fournira certaines données sources à Airbyte, Dagster ou Olake.

Structure de la database source
Structure de la base de données source
Structure de la base de données source

La base de données source contient 5 tables, dont 3 pouvant servir de dimension, et 2 de fait, nécessitant quelques transformations. Credits à drawdb.app et lilith pour le logiciel de diagramme ER

Finalisation

Vérifions déjà que tout est démarré correctement.

Commande de vérification
kubectl get daemonsets.apps,deployments.apps -A

## Résultat attendu
NAMESPACE        NAME                             DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system      daemonset.apps/kindnet           3         3         3       3            3           kubernetes.io/os=linux   6h49m
kube-system      daemonset.apps/kube-proxy        3         3         3       3            3           kubernetes.io/os=linux   6h49m
metallb-system   daemonset.apps/metallb-speaker   3         3         3       3            3           kubernetes.io/os=linux   6h46m
traefik          daemonset.apps/traefik           2         2         2       2            2           <none>                   6h45m

NAMESPACE            NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
cert-manager         deployment.apps/cert-manager               1/1     1            1           6h46m
cert-manager         deployment.apps/cert-manager-cainjector    1/1     1            1           6h46m
cert-manager         deployment.apps/cert-manager-webhook       1/1     1            1           6h46m
cert-manager         deployment.apps/trust-manager              1/1     1            1           6h45m
kube-system          deployment.apps/coredns                    2/2     2            2           6h49m
local-path-storage   deployment.apps/local-path-provisioner     1/1     1            1           6h49m
metallb-system       deployment.apps/metallb-controller         1/1     1            1           6h46m
minio                deployment.apps/minio                      1/1     1            1           6h45m
registry             deployment.apps/registry-docker-registry   1/1     1            1           6h44m

Ensuite, si l’on veut pouvoir accéder à nos services via des noms de domaine plutôt que par adresse IP, il faut ajouter une entrée dans le fichier /etc/hosts de votre machine, avec l’adresse IP du nœud du LoadBalancer créé par MetalLB.

Obtenir l’adresse IP du LoadBalancer, colonne EXTERNAL-IP
# Pour Traefik et toutes les interfaces web
kubectl get services -n traefik -o wide

# Pour PostgreSQL
kubectl get services -n postgresql -o wide pg-source-postgresql

Il faut relever l’adresse IP. En théorie, elle restera toujours la même, on peut donc la mettre dans le fichier /etc/hosts de la machine hôte.

Dans la ligne suivante, remplacez data-platform.xreveillon.eu par la valeur GLOBAL_DOMAIN que vous avez mise dans le fichier .env.

Ligne à ajouter dans /etc/hosts
<EXTERNAL-IP> traefik.data-platform.xreveillon.eu airbyte.data-platform.xreveillon.eu minio-console.data-platform.xreveillon.eu s3.data-platform.xreveillon.eu dagster.data-platform.xreveillon.eu registry.data-platform.xreveillon.eu pg-source.data-platform.xreveillon.eu

Une fois que c’est fait, on peut vérifier que tout fonctionne en navigant vers différentes URL pour voir les différentes interfaces web.

https://traefik.data-platform.xreveillon.eu/dashboard/
Dashboard de Traefik
Dashboard de Traefik

Le dashboard de Traefik permet de voir les routes configurées, les services, les middlewares, les certificats TLS, et plus encore.

https://minio-console.data-platform.xreveillon.eu/
Console de Minio
Console de Minio

La console de Minio ne permet plus que de parcourir le contenu des buckets. Auparavant on pouvait gérer aussi la configuration et la sécurité.