Projet visant à récupérer les prix annoncés des stations esssences sur différents carburants dans une zone géographique. Associé à une application streamlit (dashboard) facilitant la prise de décision journalière et affichant l'historique des fluctuations.
- MonEssence.fr : https://mon-essence.fr/ville/29383-mauregny-en-haye?q=02820
-> draw.io A FAIRE
-> Tables (nom colonne, description, type, valeurs)
| Nom colonne | Description |
|---|---|
id |
Identifiant unique de l'insertion |
date |
Date du reccueil des données |
code_postale |
Code postal de la requête |
carburant |
Type de carburant récupéré |
station |
Nom de la station d'essence |
ville |
Nom de la ville dans laquelle la station est localisée |
distance |
Distancedepuis la position géolocalisée du site |
prix |
Prix affiché en euros (€) du carburant |
verif |
Vérification du prix le jour-même |
lien |
Lien du site web de la station |
├── 📁 .venv/ 🚫 (auto-hidden)
├── 📁 dags/
│ └── 🐍 dag_essence.py
├── 📁 data/
├── 📁 gitops/
│ ├── 📁 apps/
│ │ ├── ⚙️ airflow.yaml
│ │ ├── ⚙️ postgresql.yaml
│ │ └── ⚙️ selenium-standalone-chrome.yaml
│ ├── 📁 components/
│ │ └── 📁 postgresql/
│ │ └── ⚙️ values.yaml
│ ├── 📁 helm/
│ │ └── 📁 airflow/
│ │ ├── 📁 templates/
│ │ │ └── 📄 _noop.tpl
│ │ ├── 📄 .helmignore
│ │ ├── ⚙️ Chart.yaml
│ │ └── ⚙️ values.yaml
│ └── 📁 projects/
│ └── ⚙️ platform-project.yaml
├── 📁 scripts/
│ ├── 📁 __pycache__/ 🚫 (auto-hidden)
│ ├── 🐍 MonEssence.py
│ ├── 🐍 MonEssence_local.py
│ └── 🐍 utils.py
├── 📄 .DS_Store 🚫 (auto-hidden)
├── 📄 .python-version 🚫 (auto-hidden)
├── 📖 README.md
├── 🐍 main.py
├── ⚙️ pipeline.conf
├── ⚙️ pyproject.toml
├── 📄 requirements.txt
├── ⚙️ root-app.yaml
└── 🔒 uv.lock
- Installer k8s:
sudo apt-get update
sudo apt-get install -y ca-certificates curl apt-transport-https gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update && sudo apt-get install -y kubectl
kubectl version --client
- Installer helm:
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version
- Installer un driver Docker:
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
# Repository Docker officiel
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# démarrer et activer
sudo systemctl enable --now docker
# Activer le sudo mode
sudo usermod -aG docker $USER
newgrp docker
docker info
- Cluster local minikube (sans GKE)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Lancer minikube avec le driver docker
minikube start --driver=docker
# Vérifier les noeuds et pods
kubectl get nodes
kubectl -n kube-system get pods
- Créer le namespace & installer le manifest
kubectl create namespace argocd
kubectl -n argocd apply -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
-
Accéder à l'UI par port-forward (sur la VM):
kubectl -n argocd port-forward svc/argocd-server 8080:443 -
Créer un tunnel pour accéder à l'UI sur votre ordinateur (sur le terminal du PC):
gcloud auth login # s'authentifier
gcloud config set project gazolina # setup le projet
# Ouvrir le tunnel
gcloud compute ssh vm-gazolina \
--project gazolina \
--zone europe-west1-b \
-- -N -L 8443:127.0.0.1:8080
- S'authentifier avec l'utilisateur "admin" et le password créé:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d; echo
-
Création des fichiers
gitops/apps/postgresql.yaml&gitops/components/postgresql/values.yaml -
Mettre à jour le fichier
gitops/apps/projects/platform-project.yamlavec le nouveau chart destiné à la base de données PostgreSQL
- Mettre en place l'architecture:
- gitops/
- apps/ # ← le root va pointer ici
- airflow.yaml # Application Argo CD pour Airflow
- postgresql.yaml # Application pour la DB PostgreSQL
- (autres-apps…).yaml
- projects/ platform-project.yaml # AppProject (bonnes pratiques)
- values/
- airflow/values.yaml # tes values Helm Airflow
- apps/ # ← le root va pointer ici
- root-app.yaml
-
Créer les fichiers
platform-project.yaml&root-app.yaml -
Accorder l'accès en SSH à ArgoCD:
- Préparer une deploy key:
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519_argocd -C "argocd-repo" - Récupérer la clé:
cat ~/.ssh/id_ed25519_argocd.pub - Générer le secreta avec known_hosts:
ssh-keyscan github.com > /tmp/known_hosts - Créer le Secret repository dans argocd:
kubectl -n argocd create secret generic repo-gazolina \
--from-literal=url='git@github.com:2FromField/Gazolina.git' \
--from-file=sshPrivateKey="$HOME/.ssh/id_ed25519_argocd" \
--from-file=sshKnownHosts=/tmp/known_hosts
kubectl -n argocd label secret repo-gazolina \
argocd.argoproj.io/secret-type=repository --overwrite
- Vérification:
# Présence de la clé privée:
kubectl -n argocd get secret repo-gazolina -o jsonpath='{.data.sshPrivateKey}' | base64 -d | head -n3
-
Créer le projet "platform":
kubectl apply -n argocd -f https://raw.githubusercontent.com/2FromField/Gazolina/main/uv_gazolina/gitops/projects/platform-project.yaml -
Créer le service "root":
kubectl apply -n argocd -f https://raw.githubusercontent.com/2FromField/Gazolina/main/uv_gazolina/root-app.yaml& rafraichir:kubectl -n argocd patch application root --type merge -p '{"metadata":{"annotations":{"argocd.argoproj.io/refresh":"hard"}}}' -
Vérifier que le projet "platform" a été créé:
kubectl -n argocd get appproject
- Préparer l'accès Git pour la git-sync (via SSH):
# Génère une clé SANS passphrase (ou réutilise ta deploy-key GitHub)
ssh-keygen -t ed25519 -N "" -f ./id_ed25519 -C "airflow@cluster"
cat ./id_ed25519.pub
# known_hosts GitHub (ed25519) :
ssh-keyscan github.com > ./known_hosts
-
Créer le namespace pour Airflow:
kubectl create namespace airflow -
Créer les secrets nécessaires:
# Clé SSH du repo GitHub
kubectl -n airflow create secret generic airflow-ssh-secret \
--from-file=gitSshKey=./id_ed25519 \
--from-file=known_hosts=./known_hosts
# Clé Fernet
FERNET_KEY=$(head -c 32 /dev/urandom | base64 | tr '+/' '-_' | tr -d '\n')
kubectl -n airflow create secret generic airflow-fernet-key \
--from-literal=airflow-fernet-key="$FERNET_KEY"
# Clé secret Flask du webserver
kubectl -n airflow create secret generic airflow-webserver-secret-key \
--from-literal=webserver-secret-key='Yx3tYqQZfHn9v2S5pL7T1dK0wR8uM6cN4bA2fG1hJ0qZ' \
--dry-run=client -o yaml | kubectl apply -f -
# Relancer les pods
kubectl -n airflow rollout restart deploy/airflow-webserver
kubectl -n airflow rollout restart statefulset/airflow-scheduler
- Supprimer le service et le relancer:
kubectl -n argocd delete application airflow
-
Générer le fichier de dépendances 'requirements.txt':
uv pip compile uv_gazolina/pyproject.toml -o uv_gazolina/requirements.txt -
(Spécificité à MongoDB) Ajouter l'adresse IP de la VM pour dans le 'Network Access':
kubectl -n airflow run curlip --rm -it --image=curlimages/curl --restart=Never -- \
curl -s https://ifconfig.me
Vérifications:
- Image PostgreSQL (devant être: "docker.io/bitnami/postgresql:16"):
kubectl -n airflow get statefulset airflow-postgresql \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
- Vérifier la Job migration:
kubectl -n airflow get jobs,pods | grep -i migrate || true
MIGPOD=$(kubectl -n airflow get pod -l job-name=airflow-migrate-database-job -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) || true
[ -n "$MIGPOD" ] && kubectl -n airflow logs "$MIGPOD" --tail=200 || echo "Pas de pod de migration trouvé"
Si la sortie retourne "Pas de pod de migration trouvé", alors il faut créer une Job 'one-shot' faisant un airflow db upgrade:
cat <<'YAML' | kubectl -n airflow apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: airflow-db-migrate
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: apache/airflow:2.9.3
command: ["bash","-lc","airflow db migrate"]
env:
- name: AIRFLOW__DATABASE__SQL_ALCHEMY_CONN
value: "postgresql+psycopg2://airflow:airflow@postgresql.database.svc.cluster.local:5432/airflow"
YAML
# Suivre la migration
kubectl -n airflow logs -f job/airflow-db-migrate
-
Créer un fichier
uv_gazolina/pipeline.confcontenant les credentials -
Installer Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -
Installer age & SOPS sur MacOS:
brew update
brew install age sops
# Confirmer l'installation en affichant les versions
age --version
sops --version
- Générer une clé de chiffrage SOPS (+ age):
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
PUB=$(age-keygen -y ~/.config/sops/age/keys.txt)
echo "$PUB"
- Chiffrer le fichier 'pipeline.conf' en 'pipeline.conf.enc' avec SOPS et la clé de chiffrement:
sops --encrypt --age "$PUB" uv_gazolina/pipeline.conf > uv_gazolina/pipeline.conf.enc
- Créer le manifest de Secret afin de créer un Secret k8s pour ArgoCD:
cat > uv_gazolina/gitops/secrets/mongo-pipeline.yaml <<'YAML'
apiVersion: v1
kind: Secret
metadata:
name: mongo-pipeline
namespace: airflow
type: Opaque
stringData:
MONGO_URI: mongodb+srv://user:pass@host/db
MONGO_USER: user
MONGO_PASS: pass
YAML
-
Chiffrer localement avec SOPS:
sops --encrypt --age "$PUB" -i uv_gazolina/gitops/secrets/mongo-pipeline.yaml -
Copier la clé privée age du local vers la VM:
mkdir -p ~/.config/sops/age
cat > ~/.config/sops/age/keys.txt <<'EOF'
# colle ici TOUT le contenu affiché sur ton Mac,
# y compris les lignes "# public key: ..." et la ligne AGE-SECRET-KEY-1...
EOF
- Créer le secret dans 'argocd':
kubectl -n argocd create secret generic sops-age \
--from-file=age.agekey=$HOME/.config/sops/age/keys.txt \
--dry-run=client -o yaml | kubectl apply -f -
- Créer le ConfigMap du plugin CMP:
cat <<'YAML' | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cmp-cm
namespace: argocd
data:
sops-plugin.yaml: |
apiVersion: argoproj.io/v1alpha1
kind: ConfigManagementPlugin
metadata:
name: sops
spec:
version: v1.0
# Autorise explicitement ton repo (sinon: "plugin ... not supporting the given repository")
allow:
repos:
- https://github.com/2FromField/Gazolina.git
generate:
command: [bash, -lc]
args:
- |
set -euo pipefail
# Déchiffre chaque YAML s'il est chiffré SOPS, sinon le laisse tel quel, puis agrège
files=$(find . -type f \( -name "*.yaml" -o -name "*.yml" \));
for f in $files; do
if sops -d "$f" >/dev/null 2>&1; then sops -d "$f"; else cat "$f"; fi
done | yq -s cat
YAML
- Monter le secret dans 'argocd-repo-sercer' et redémarrer:
kubectl -n argocd create secret generic sops-age \
--from-file=age.agekey=$HOME/.config/sops/age/keys.txt \
--dry-run=client -o yaml | kubectl apply -f -
kubectl -n argocd patch deploy argocd-repo-server --type merge -p '{
"spec":{"template":{"spec":{
"volumes":[{"name":"sops-age","secret":{"secretName":"sops-age"}}],
"containers":[{"name":"argocd-repo-server",
"volumeMounts":[{"name":"sops-age","mountPath":"/sops"}],
"env":[{"name":"SOPS_AGE_KEY_FILE","value":"/sops/age.agekey"}]
}]
}}}}'
kubectl -n argocd rollout restart deploy/argocd-repo-server
- Ajouter un Config Management Plugin permettant à ArgoCD de déchirer les fichier .yaml SOPS
kubectl -n argocd patch configmap argocd-cm --type merge -p '{
"data": {
"configManagementPlugins": "- name: sops\n generate:\n command: [\"bash\",\"-lc\"]\n args: [\"set -euo pipefail; files=$(find . -type f \\( -name \\\"*.yaml\\\" -o -name \\\"*.yml\\\" \\)); for f in $files; do if sops -d $f >/dev/null 2>&1; then sops -d $f; else cat $f; fi; done | yq -s cat\"]\n"
}
}'
kubectl -n argocd rollout restart deploy/argocd-repo-server
| Commade | Description |
|---|---|
kubectl get svc --all-namespaces |
Afficher tous les services installés |
kubectl get pods -n airflow |
Afficher les pods d'un namespace précis |
- Installation des UV pour Linux :
curl -LsSf https://astral.sh/uv/install.sh | sudo sh - Ajouter UV dans le $PATH :
source $HOME/.local/bin/env - Vérifier l'installation :
uv --version
- Créer et nommer le projet :
uv init $UV_PROJECT_NAME - Naviguer dans le projet :
cd $UV_PROJECT_NAME - Utiliser UV :
uv add $PACKAGE
| Commade | Description |
|---|---|
uv add $PACKAGE |
Ajouter une ou plusieurs dépendances |
uv add $PACKAGE=2.0.2 |
Ajouter une dépendance sous une certaine version |
uv remove $PACKAGE |
Supprimer une dépendance |
uv python list --only-installed |
Afficher la liste des dépendances et leurs versions |
uv run $PYTHON_FILENAME.py |
Exécuter des scripts python avec UV |
uv export -o requirements.txt |
Générer le fichier requirements.txt |
- Région: europe-west1 (Belgique)
- Zone: europe-west1-b
- Type: e2-medium (2 vCPU, 1 coeur(s), 4 Go de mémoire)
OU
gcloud compute instances create vm-gazolina \
--project gazolina \
--zone europe-west1-b \
--machine-type=e2-medium \
--image-family=debian-12 \
--image-project=debian-cloud
Supprimer l'instance et son disque boot, puis recréer une VM neuve:
gcloud compute instances delete vm-gazolina \
--project gazolina \
--zone europe-west1-b \
--delete-disks=all
- Vérifier l'identifiant du compte GCP:
gcloud auth list
- Si l'adresse mail n'est pas celle du compte, l'ajouter:
gcloud auth loginet suivre les indication de la page web
- Vérifier que l'on cible le bon projet contenant notre VM:
gcloud config get-value project(l'identifiant se trouve sur GCP lors du choix du projet)
- Si ce n'est pas le bon projet, redéfinir la target:
gcloud config set project gazolina
- Vérifier que la vm est bien présente dans le projet:
gcloud compute instances list --project gazolina \
--filter='name=("vm_gazolina")' \
--format='table(project, name, zone, status, networkInterfaces[].accessConfigs[].natIP)'
-
Installation des composants GCP cloud:
gcloud components update -
S'y connecter:
gcloud compute ssh vm-gazolina \
--project gazolina \
--zone europe-west1-b
- Augmenter la taille du disque boot:
gcloud compute disks resize vm-gazolina \
--project gazolina \
--zone europe-west1-b \
--size 60GB
- Modifier l'espace de stockage du
sda1:
- Repérer la partition14:
sudo parted -m /dev/sda unit s print - Redimensionner le disque au maximum:
sudo parted /dev/sda ---pretend-input-tty <<'EOF'
unit s
print
resizepart 1 100%
Yes
quit
EOF
- Etendre le système de fichiers:
sudo resize2fs /dev/sda1 - Afficher les espaces de stockages:
df -h
# 1. Tuer le cluster minikube
minikube delete --all --purge || true
docker rm -f minikube 2>/dev/null || true
# 2. Nettoyage réseau/cache
docker network prune -f
sudo systemctl restart docker
# 3. Configurer le nouveau cluster
minikube config set driver docker
minikube config set cpus 4
minikube config set memory 8192
minikube config set disk-size 20g
minikube start --kubernetes-version=v1.30.0 --delete-on-failure -v=1