feat: add helm/ansible deployment files for Kubernetes
Some checks failed
Build & Deploy Smart App Web / lint (push) Failing after 1s
Build & Deploy Smart App Web / build-web (push) Has been skipped
Build & Deploy Smart App Web / docker-build (push) Has been skipped
Build & Deploy Smart App Web / deploy (push) Has been skipped

This commit is contained in:
Eric FELIXINE
2026-06-04 02:09:17 -04:00
parent 8c2251faba
commit fb62291b3e
33 changed files with 1876 additions and 0 deletions

221
helms/README.md Normal file
View File

@@ -0,0 +1,221 @@
# Smart City Martinique - Déploiement Kubernetes
## Architecture
```
┌─────────────────────────────────────────────────────────┐
│ TRAEFIK (Ingress) │
│ ports 80/443 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────┼─────────────────────────────────┐
│ │ │
┌────▼────┐ ┌──────────┐ ┌──────────▼──────────┐ ┌─────────────────┐
│ Airflow │ │ Kafka │ │ Data & Storage │ │ Monitoring │
│ │ │ Cluster │ │ │ │ │
│ web │ │ 3 brokers│ │ PostgreSQL HA │ │ Prometheus │
│ sched │ │ connect │ │ Redis Cluster │ │ Grafana │
│ worker │ │ ui │ │ MinIO │ │ Loki │
└─────────┘ └──────────┘ │ ClickHouse │ │ Promtail │
│ StarRocks │ └─────────────────┘
┌──────────┐ ┌──────────┐ │ Trino │
│ Flink │ │ IoT │ │ Delta Lake │ ┌─────────────────┐
│ │ │ │ │ DuckDB │ │ BI & Analytics │
│ jobmgr │ │ EMQX │ └─────────────────────┘ │ │
│ taskmgr │ │ Mosquitto│ │ Superset │
└──────────┘ │ Node-RED │ ┌─────────────────────┐ │ Metabase │
│ phpIPAM │ │ Git & Notebooks │ │ MindsDB │
┌──────────┐ │ ChirpStk │ │ │ └─────────────────┘
│ GIS │ └──────────┘ │ Gitea │
│ │ │ JupyterHub │ ┌─────────────────┐
│ MapStore │ ┌──────────┐ │ Zeppelin │ │ Web Apps │
│ GeoServer│ │ ODK │ └─────────────────────┘ │ │
│ FROST │ │ │ │ Smart App │
│ Stellio │ │ nginx │ ┌─────────────────────┐ │ Streamlit │
│ FIWARE │ │ service │ │ Data Collection │ │ Kepler │
└──────────┘ │ postgres │ │ │ └─────────────────┘
└──────────┘ │ Telegraf │
│ InfluxDB │
│ Simulator │
└─────────────────────┘
```
## Prérequis
### Cluster Kubernetes
- 3 nœuds minimum (1 master + 2 workers)
- Kubernetes 1.28+
- containerd
- Cilium (CNI)
### Serveur NFS
- 1 serveur NFS pour le stockage persistant
- Minimum 500Go d'espace disque
### Outils
- kubectl
- helm
- ansible 2.15+
- ansible-galaxy collection install kubernetes.core
## Installation
### 1. Cloner le repository
```bash
git clone https://gitea.digitribe.fr/eric/smart-city-digital-twin-martinique.git
cd smart-city-digital-twin-martinique/helms
```
### 2. Configurer l'inventory
Éditer `inventory/hosts.yml` avec les IPs de vos nœuds :
```yaml
k8s_masters:
hosts:
k8s-master-1:
ansible_host: "192.168.1.100"
k8s_workers:
hosts:
k8s-worker-1:
ansible_host: "192.168.1.101"
k8s-worker-2:
ansible_host: "192.168.1.102"
nfs_server:
hosts:
nfs-1:
ansible_host: "192.168.1.200"
```
### 3. Configurer les variables
Éditer `group_vars/all.yml` selon vos besoins (ressources, domaines, etc.)
### 4. Chiffrer les secrets
```bash
ansible-vault encrypt group_vars/vault.yml
```
### 5. Déployer
```bash
# Déployer toute la stack
ansible-playbook deploy.yml --ask-vault-pass
# Déployer un service spécifique
ansible-playbook deploy.yml --tags clickhouse --ask-vault-pass
ansible-playbook deploy.yml --tags trino --ask-vault-pass
ansible-playbook deploy.yml --tags streamlit --ask-vault-pass
ansible-playbook deploy.yml --tags kafka --ask-vault-pass
ansible-playbook deploy.yml --tags monitoring --ask-vault-pass
```
### 6. Vérifier
```bash
kubectl get pods --all-namespaces
kubectl get ingress --all-namespaces
```
## Services déployés
| Service | Domaine | Namespace | Helm Chart |
|---------|---------|-----------|------------|
| Airflow | airflow.digitribe.fr | airflow | apache/airflow |
| Kafka | kafka.digitribe.fr | kafka | strimzi/kafka-operator |
| Flink | flink.digitribe.fr | flink | apache/flink-kubernetes-operator |
| ClickHouse | clickhouse.digitribe.fr | clickhouse | bitnami/clickhouse |
| StarRocks | starrocks.digitribe.fr | starrocks | starrocks/starrocks-community |
| Trino | trino.digitribe.fr | trino | trinodb/trino |
| Delta Lake | deltalake.digitribe.fr | deltalake | delta-io/delta-lake |
| Streamlit | streamlit.digitribe.fr | streamlit | streamlit/streamlit |
| DuckDB | duckdb.digitribe.fr | duckdb | duckdb/duckdb |
| EMQX | emqx.digitribe.fr | iot | emqx/emqx-operator |
| Mosquitto | mqtt.digitribe.fr | iot | k8s-at-home/mosquitto |
| Node-RED | nodered.digitribe.fr | iot | k8s-at-home/node-red |
| phpIPAM | phpipam.digitribe.fr | phpipam | phpipam/phpipam |
| ChirpStack | chirpstack.digitribe.fr | iot | chirpstack/chirpstack |
| Gitea | gitea.digitribe.fr | gitea | gitea/gitea |
| JupyterHub | jupyter.digitribe.fr | jupyterhub | jupyterhub/jupyterhub |
| Zeppelin | zeppelin.digitribe.fr | default | apache/zeppelin |
| Superset | superset.digitribe.fr | superset | apache/superset |
| Metabase | metabase.digitribe.fr | metabase | bitnami/metabase |
| MindsDB | mindsdb.digitribe.fr | mindsdb | bitnami/mindsdb |
| ODK Central | odk.digitribe.fr | odk | odk/odk-central |
| MapStore | mapstore.digitribe.fr | mapstore | geosolutionsit/mapstore |
| GeoServer | geoserver.digitribe.fr | geoserver | kartoza/geoserver |
| FROST | frost.digitribe.fr | iot | fraunhoferiosb/frost-server |
| Smart App | smartapp.digitribe.fr | smartapp | custom |
| Grafana | grafana.digitribe.fr | monitoring | grafana/grafana |
| MinIO | minio.digitribe.fr | default | bitnami/minio |
## Commandes utiles
```bash
# Lister tous les pods
kubectl get pods --all-namespaces
# Voir les logs d'un pod
kubectl logs -f <pod-name> -n <namespace>
# Voir les événements
kubectl get events --all-namespaces --sort-by='.lastTimestamp'
# Voir les ingress
kubectl get ingress --all-namespaces
# Voir les PVC
kubectl get pvc --all-namespaces
# Redéployer un service
ansible-playbook deploy.yml --tags <service> --ask-vault-pass
# Supprimer un service
kubectl delete namespace <namespace>
# Supprimer toute la stack
ansible-playbook undeploy.yml
```
## Troubleshooting
### Pod en CrashLoopBackOff
```bash
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
```
### PVC en Pending
```bash
kubectl get storageclass
kubectl get pv
kubectl describe pvc <pvc-name> -n <namespace>
```
### Ingress non accessible
```bash
kubectl get ingress -n <namespace>
kubectl describe ingress <ingress-name> -n <namespace>
kubectl logs -f deployment/traefik -n traefik
```
## Maintenance
### Backup
Les sauvegardes sont configurées via Velero :
```bash
kubectl get schedules -n velero
kubectl get backups -n velero
```
### Mise à jour d'un service
```bash
ansible-playbook deploy.yml --tags <service> --ask-vault-pass
```
### Scaling
```bash
kubectl scale deployment <deployment> --replicas=<n> -n <namespace>
```

77
helms/deploy.yml Normal file
View File

@@ -0,0 +1,77 @@
---
# Playbook principal pour le déploiement Kubernetes
# Fichier: deploy.yml
- name: Déploiement Smart City Martinique sur Kubernetes
hosts: localhost
connection: local
gather_facts: false
vars_files:
- group_vars/all.yml
- group_vars/vault.yml
pre_tasks:
- name: Vérifier que kubectl est installé
command: kubectl version --client
changed_when: false
- name: Vérifier la connexion au cluster
command: kubectl cluster-info
changed_when: false
roles:
- role: prerequisites
tags: [prerequisites]
- role: namespaces
tags: [namespaces]
- role: storage
tags: [storage]
- role: traefik
tags: [traefik, ingress]
- role: cert-manager
tags: [cert-manager, tls]
- role: monitoring
tags: [monitoring]
- role: databases
tags: [databases]
- role: kafka
tags: [kafka]
- role: flink
tags: [flink]
- role: airflow
tags: [airflow]
- role: iot
tags: [iot, mqtt]
- role: gitea
tags: [gitea]
- role: jupyterhub
tags: [jupyterhub]
- role: bi
tags: [bi, superset, metabase]
- role: mindsdb
tags: [mindsdb]
- role: odk
tags: [odk]
- role: gis
tags: [gis, mapstore, geoserver, frost]
- role: clickhouse
tags: [clickhouse]
- role: starrocks
tags: [starrocks]
- role: trino
tags: [trino]
- role: deltalake
tags: [deltalake]
- role: streamlit
tags: [streamlit]
- role: duckdb
tags: [duckdb]
- role: nodered
tags: [nodered]
- role: phpipam
tags: [phpipam]
- role: smartapp
tags: [smartapp]
- role: backup
tags: [backup]

535
helms/group_vars/all.yml Normal file
View File

@@ -0,0 +1,535 @@
---
# Variables globales pour le déploiement Kubernetes
# Fichier: group_vars/all.yml
# ============================================================
# Configuration du cluster Kubernetes
# ============================================================
cluster_name: smart-city-martinique
k8s_version: "1.28.0"
container_runtime: containerd
network_plugin: cilium
# ============================================================
# Configuration réseau
# ============================================================
domain: digitribe.fr
traefik_namespace: traefik
ingress_class: traefik
# TLS
tls_enabled: true
tls_certresolver: letsencrypt
acme_email: admin@digitribe.fr
# ============================================================
# Storage
# ============================================================
storage_class: nfs-client
nfs_server: "192.168.1.200"
nfs_path: /data/k8s
# Persistent Volume sizes
storage_sizes:
postgres: 50Gi
minio: 500Gi
kafka: 100Gi
influxdb: 50Gi
loki: 100Gi
grafana: 10Gi
jupyterhub: 20Gi
gitea: 20Gi
metabase: 10Gi
superset: 10Gi
mindsdb: 20Gi
odk: 10Gi
mapstore: 10Gi
geoserver: 20Gi
airflow: 20Gi
flink: 20Gi
emqx: 10Gi
mosquitto: 5Gi
redis: 10Gi
elasticsearch: 50Gi
# ============================================================
# Helm Charts versions
# ============================================================
helm_charts:
traefik:
chart: traefik/traefik
version: "28.0.0"
ingress_nginx:
chart: ingress-nginx/ingress-nginx
version: "4.8.0"
cert_manager:
chart: jetstack/cert-manager
version: "1.13.0"
nfs_provisioner:
chart: nfs-subdir-external-provisioner/nfs-subdir-external-provisioner
version: "4.0.18"
postgresql:
chart: bitnami/postgresql
version: "13.2.0"
postgresql_ha:
chart: bitnami/postgresql-ha
version: "12.2.0"
redis:
chart: bitnami/redis
version: "18.0.0"
minio:
chart: bitnami/minio
version: "12.10.0"
kafka:
chart: strimzi/kafka-operator
version: "0.38.0"
flink:
chart: apache/flink-kubernetes-operator
version: "1.7.0"
airflow:
chart: apache/airflow
version: "1.11.0"
grafana:
chart: grafana/grafana
version: "7.0.0"
loki:
chart: grafana/loki-stack
version: "2.9.0"
prometheus:
chart: prometheus/kube-prometheus-stack
version: "51.0.0"
emqx:
chart: emqx/emqx-operator
version: "2.2.0"
mosquitto:
chart: k8s-at-home/mosquitto
version: "4.8.0"
gitea:
chart: gitea/gitea
version: "9.0.0"
jupyterhub:
chart: jupyterhub/jupyterhub
version: "3.0.0"
superset:
chart: apache/superset
version: "0.11.0"
metabase:
chart: bitnami/metabase
version: "0.13.0"
mindsdb:
chart: bitnami/mindsdb
version: "0.1.0"
odk:
chart: odk/odk-central
version: "1.0.0"
mapstore:
chart: geosolutionsit/mapstore
version: "1.0.0"
geoserver:
chart: kartoza/geoserver
version: "2.2.0"
frost:
chart: fraunhoferiosb/frost-server
version: "1.0.0"
nodered:
chart: k8s-at-home/node-red
version: "4.8.0"
phpipam:
chart: phpipam/phpipam
version: "1.0.0"
clickhouse:
chart: bitnami/clickhouse
version: "4.0.0"
starrocks:
chart: starrocks/starrocks-community
version: "1.0.0"
trino:
chart: trinodb/trino
version: "0.10.0"
deltalake:
chart: delta-io/delta-lake
version: "1.0.0"
streamlit:
chart: streamlit/streamlit
version: "1.0.0"
duckdb:
chart: duckdb/duckdb
version: "1.0.0"
elasticsearch:
chart: elastic/elasticsearch
version: "8.11.0"
kibana:
chart: elastic/kibana
version: "8.11.0"
# ============================================================
# Services configuration
# ============================================================
services:
airflow:
enabled: true
namespace: airflow
replicas: 2
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
kafka:
enabled: true
namespace: kafka
replicas: 3
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
flink:
enabled: true
namespace: flink
replicas: 2
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
emqx:
enabled: true
namespace: iot
replicas: 3
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
mosquitto:
enabled: true
namespace: iot
replicas: 2
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
postgresql:
enabled: true
namespace: default
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
redis:
enabled: true
namespace: default
replicas: 3
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
minio:
enabled: true
namespace: default
replicas: 4
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
grafana:
enabled: true
namespace: monitoring
replicas: 1
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
loki:
enabled: true
namespace: monitoring
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
prometheus:
enabled: true
namespace: monitoring
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
gitea:
enabled: true
namespace: gitea
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
jupyterhub:
enabled: true
namespace: jupyterhub
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
superset:
enabled: true
namespace: superset
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
metabase:
enabled: true
namespace: metabase
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
mindsdb:
enabled: true
namespace: mindsdb
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
odk:
enabled: true
namespace: odk
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
mapstore:
enabled: true
namespace: mapstore
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
geoserver:
enabled: true
namespace: geoserver
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
frost:
enabled: true
namespace: iot
replicas: 1
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
nodered:
enabled: true
namespace: iot
replicas: 1
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
phpipam:
enabled: true
namespace: phpipam
replicas: 1
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "1Gi"
smartapp:
enabled: true
namespace: smartapp
replicas: 2
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
clickhouse:
enabled: true
namespace: clickhouse
replicas: 1
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
starrocks:
enabled: true
namespace: starrocks
replicas: 1
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
trino:
enabled: true
namespace: trino
replicas: 1
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
deltalake:
enabled: true
namespace: deltalake
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
streamlit:
enabled: true
namespace: streamlit
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
duckdb:
enabled: true
namespace: duckdb
replicas: 1
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
# ============================================================
# Monitoring
# ============================================================
monitoring:
enabled: true
namespace: monitoring
grafana_admin_password: "{{ vault_grafana_password }}"
prometheus_retention: 30d
loki_retention: 30d
# ============================================================
# Backup
# ============================================================
backup:
enabled: true
schedule: "0 2 * * *"
retention: 30
storage_class: nfs-client
storage_size: 100Gi

View File

@@ -0,0 +1,60 @@
---
# Vault Ansible - Variables chiffrées
# Fichier: group_vars/vault.yml
# Chiffrer avec: ansible-vault encrypt group_vars/vault.yml
# PostgreSQL
vault_postgres_password: "Digitribe972"
vault_postgres_repmgr_password: "Digitribe972"
# Redis
vault_redis_password: "Digitribe972"
# MinIO
vault_minio_root_user: "minioadmin"
vault_minio_root_password: "Digitribe972"
# Grafana
vault_grafana_admin_password: "Digitribe972"
# Airflow
vault_airflow_fernet_key: "Digitribe972SecretKeyForAirflow2024"
vault_airflow_admin_password: "Digitribe972"
# Gitea
vault_gitea_admin_password: "Digitribe972"
# Superset
vault_superset_admin_password: "Digitribe972"
vault_superset_db_password: "Digitribe972"
# Metabase
vault_metabase_db_password: "Digitribe972"
# MindsDB
vault_mindsdb_password: "Digitribe972"
# ClickHouse
vault_clickhouse_password: "Digitribe972"
# Trino
vault_trino_db_password: "Digitribe972"
# MQTT
vault_mosquitto_password: "Digitribe972"
vault_emqx_admin_password: "Digitribe972"
# phpIPAM
vault_phpipam_admin_password: "Digitribe972"
# ODK
vault_odk_admin_password: "Digitribe972"
# GeoServer
vault_geoserver_admin_password: "Digitribe972"
# MapStore
vault_mapstore_admin_password: "Digitribe972"
# StarRocks
vault_starrocks_root_password: "Digitribe972"

79
helms/inventory/hosts.yml Normal file
View File

@@ -0,0 +1,79 @@
---
# Inventory pour le déploiement Kubernetes via Ansible
# Fichier: inventory/hosts.yml
all:
children:
k8s_masters:
hosts:
k8s-master-1:
ansible_host: "{{ k8s_master_ip | default('192.168.1.100') }}"
ansible_user: "{{ k8s_user | default('root') }}"
k8s_workers:
hosts:
k8s-worker-1:
ansible_host: "{{ k8s_worker1_ip | default('192.168.1.101') }}"
ansible_user: "{{ k8s_user | default('root') }}"
k8s-worker-2:
ansible_host: "{{ k8s_worker2_ip | default('192.168.1.102') }}"
ansible_user: "{{ k8s_user | default('root') }}"
nfs_server:
hosts:
nfs-1:
ansible_host: "{{ nfs_server_ip | default('192.168.1.200') }}"
ansible_user: "{{ nfs_user | default('root') }}"
vars:
# Configuration globale
cluster_name: smart-city-martinique
k8s_version: "1.28"
container_runtime: containerd
network_plugin: cilium
domain: digitribe.fr
# Namespaces Kubernetes
namespaces:
- airflow
- kafka
- flink
- monitoring
- iot
- gitea
- jupyterhub
- odk
- smartapp
- superset
- metabase
- mindsdb
- mapstore
- geoserver
- frost
- nodered
- phpipam
- traefik
- ingress-nginx
- clickhouse
- starrocks
- trino
- deltalake
- streamlit
- duckdb
# Storage
storage_class: nfs-client
nfs_path: /data/k8s
# Helm repositories
helm_repos:
- name: bitnami
url: https://charts.bitnami.com/bitnami
- name: apache
url: https://charts.apache.org
- name: grafana
url: https://grafana.github.io/helm-charts
- name: prometheus
url: https://prometheus-community.github.io/helm-charts
- name: strimzi
url: https://strimzi.io/charts/
- name: flink-operator
url: https://downloads.apache.org/flink/flink-kubernetes-operator-1.7.0/

View File

@@ -0,0 +1,34 @@
---
# Role: airflow
# Déploie Apache Airflow
- name: Installer Airflow
kubernetes.core.helm:
name: airflow
chart_ref: "{{ helm_charts.airflow.chart }}"
release_namespace: airflow
create_namespace: true
values:
executor: CeleryExecutor
fernetKey: "{{ vault_airflow_fernet_key }}"
webserver:
defaultUser:
username: admin
password: "{{ vault_airflow_admin_password }}"
dags:
persistence:
enabled: true
size: 10Gi
logs:
persistence:
enabled: true
size: "{{ storage_sizes.airflow }}"
scheduler:
resources: "{{ services.airflow.resources }}"
webserver:
resources: "{{ services.airflow.resources }}"
workers:
replicas: "{{ services.airflow.replicas }}"
resources: "{{ services.airflow.resources }}"
triggerer:
resources: "{{ services.airflow.resources }}"

View File

@@ -0,0 +1,34 @@
---
# Role: backup
# Configure les sauvegardes Velero
- name: Installer Velero
kubernetes.core.helm:
name: velero
chart_ref: vmware-tanzu/velero
release_namespace: velero
create_namespace: true
values:
configuration:
backupStorageLocation:
name: default
provider: aws
bucket: smart-city-backup
config:
region: eu-west-3
s3ForcePathStyle: true
schedules:
daily:
schedule: "{{ backup.schedule }}"
template:
includedNamespaces:
- "{{ item }}"
snapshotVolumes: true
ttl: "{{ backup.retention }}h0m0s"
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"

View File

@@ -0,0 +1,44 @@
---
# Role: bi
# Déploie Superset et Metabase
- name: Installer Superset
kubernetes.core.helm:
name: superset
chart_ref: "{{ helm_charts.superset.chart }}"
release_namespace: superset
create_namespace: true
values:
supersetNode:
connections:
redis_password: "{{ vault_redis_password }}"
db_user: superset
db_pass: "{{ vault_superset_db_password }}"
resources: "{{ services.superset.resources }}"
supersetWorker:
replicas: 2
resources: "{{ services.superset.resources }}"
bootstrapScript: |
#!/bin/bash
pip install psycopg2-binary redis
init:
adminUser:
username: admin
password: "{{ vault_superset_admin_password }}"
email: admin@digitribe.fr
- name: Installer Metabase
kubernetes.core.helm:
name: metabase
chart_ref: "{{ helm_charts.metabase.chart }}"
release_namespace: metabase
create_namespace: true
values:
database:
type: postgres
host: postgresql-ha-pgpool.default.svc.cluster.local
port: 5432
dbname: metabase
username: metabase
password: "{{ vault_metabase_db_password }}"
resources: "{{ services.metabase.resources }}"

View File

@@ -0,0 +1,39 @@
---
# Role: cert-manager
# Déploie cert-manager pour la gestion des certificats TLS
- name: Installer cert-manager
kubernetes.core.helm:
name: cert-manager
chart_ref: "{{ helm_charts.cert_manager.chart }}"
chart_version: "{{ helm_charts.cert_manager.version }}"
release_namespace: cert-manager
create_namespace: true
values:
installCRDs: true
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
- name: Créer le ClusterIssuer Let's Encrypt
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: "{{ acme_email }}"
privateKeySecretRef:
name: letsencrypt-key
solvers:
- http01:
ingress:
class: traefik

View File

@@ -0,0 +1,34 @@
---
# Role: clickhouse
# Déploie ClickHouse
- name: Installer ClickHouse
kubernetes.core.helm:
name: clickhouse
chart_ref: "{{ helm_charts.clickhouse.chart }}"
chart_version: "{{ helm_charts.clickhouse.version }}"
release_namespace: clickhouse
create_namespace: true
values:
shards: 1
replicaCount: "{{ services.clickhouse.replicas }}"
persistence:
size: "{{ storage_sizes.clickhouse | default('50Gi') }}"
storageClass: "{{ storage_class }}"
resources: "{{ services.clickhouse.resources }}"
auth:
username: default
password: "{{ vault_clickhouse_password }}"
service:
type: ClusterIP
ingress:
enabled: true
hosts:
- host: clickhouse.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: clickhouse-tls
hosts:
- clickhouse.digitribe.fr

View File

@@ -0,0 +1,54 @@
---
# Role: databases
# Déploie PostgreSQL, Redis et MinIO
- name: Installer PostgreSQL HA
kubernetes.core.helm:
name: postgresql
chart_ref: "{{ helm_charts.postgresql_ha.chart }}"
release_namespace: default
values:
postgresql:
password: "{{ vault_postgres_password }}"
repmgrPassword: "{{ vault_postgres_repmgr_password }}"
persistence:
size: "{{ storage_sizes.postgresql }}"
storageClass: "{{ storage_class }}"
resources:
requests:
cpu: "{{ services.postgresql.resources.requests.cpu }}"
memory: "{{ services.postgresql.resources.requests.memory }}"
- name: Installer Redis Cluster
kubernetes.core.helm:
name: redis
chart_ref: "{{ helm_charts.redis.chart }}"
release_namespace: default
values:
cluster:
nodes: 3
password: "{{ vault_redis_password }}"
persistence:
size: "{{ storage_sizes.redis }}"
storageClass: "{{ storage_class }}"
resources:
requests:
cpu: "100m"
memory: "256Mi"
- name: Installer MinIO
kubernetes.core.helm:
name: minio
chart_ref: "{{ helm_charts.minio.chart }}"
release_namespace: default
values:
auth:
rootUser: "{{ vault_minio_root_user }}"
rootPassword: "{{ vault_minio_root_password }}"
persistence:
size: "{{ storage_sizes.minio }}"
storageClass: "{{ storage_class }}"
resources:
requests:
cpu: "250m"
memory: "512Mi"

View File

@@ -0,0 +1,30 @@
---
# Role: deltalake
# Déploie Delta Lake
- name: Installer Delta Lake
kubernetes.core.helm:
name: deltalake
chart_ref: "{{ helm_charts.deltalake.chart }}"
chart_version: "{{ helm_charts.deltalake.version }}"
release_namespace: deltalake
create_namespace: true
values:
replicaCount: "{{ services.deltalake.replicas }}"
resources: "{{ services.deltalake.resources }}"
storage:
size: "{{ storage_sizes.deltalake | default('100Gi') }}"
storageClass: "{{ storage_class }}"
service:
type: ClusterIP
ingress:
enabled: true
hosts:
- host: deltalake.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: deltalake-tls
hosts:
- deltalake.digitribe.fr

View File

@@ -0,0 +1,30 @@
---
# Role: duckdb
# Déploie DuckDB
- name: Installer DuckDB
kubernetes.core.helm:
name: duckdb
chart_ref: "{{ helm_charts.duckdb.chart }}"
chart_version: "{{ helm_charts.duckdb.version }}"
release_namespace: duckdb
create_namespace: true
values:
replicaCount: "{{ services.duckdb.replicas }}"
resources: "{{ services.duckdb.resources }}"
storage:
size: "{{ storage_sizes.duckdb | default('50Gi') }}"
storageClass: "{{ storage_class }}"
service:
type: ClusterIP
ingress:
enabled: true
hosts:
- host: duckdb.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: duckdb-tls
hosts:
- duckdb.digitribe.fr

View File

@@ -0,0 +1,18 @@
---
# Role: flink
# Déploie Apache Flink via l'opérateur
- name: Installer l'opérateur Flink
kubernetes.core.helm:
name: flink-kubernetes-operator
chart_ref: "{{ helm_charts.flink.chart }}"
release_namespace: flink
create_namespace: true
- name: Créer le déploiement Flink
kubernetes.core.k8s:
state: present
template: flink-deployment.yml.j2
vars:
flink_namespace: flink
flink_replicas: "{{ services.flink.replicas }}"

View File

@@ -0,0 +1,37 @@
---
# Role: gis
# Déploie MapStore, GeoServer et FROST
- name: Installer MapStore
kubernetes.core.helm:
name: mapstore
chart_ref: "{{ helm_charts.mapstore.chart }}"
release_namespace: mapstore
create_namespace: true
values:
persistence:
size: "{{ storage_sizes.mapstore }}"
resources: "{{ services.mapstore.resources }}"
- name: Installer GeoServer
kubernetes.core.helm:
name: geoserver
chart_ref: "{{ helm_charts.geoserver.chart }}"
release_namespace: geoserver
create_namespace: true
values:
persistence:
geodataDir:
storageClass: "{{ storage_class }}"
size: "{{ storage_sizes.geoserver }}"
resources: "{{ services.geoserver.resources }}"
- name: Installer FROST
kubernetes.core.helm:
name: frost
chart_ref: "{{ helm_charts.frost.chart }}"
release_namespace: iot
values:
persistence:
size: 10Gi
resources: "{{ services.frost.resources }}"

View File

@@ -0,0 +1,28 @@
---
# Role: gitea
# Déploie Gitea
- name: Installer Gitea
kubernetes.core.helm:
name: gitea
chart_ref: "{{ helm_charts.gitea.chart }}"
release_namespace: gitea
create_namespace: true
values:
gitea:
admin:
username: eric
password: "{{ vault_gitea_admin_password }}"
email: admin@digitribe.fr
config:
server:
DOMAIN: gitea.digitribe.fr
ROOT_URL: https://gitea.digitribe.fr
SSH_DOMAIN: gitea.digitribe.fr
SSH_PORT: 22
persistence:
enabled: true
size: "{{ storage_sizes.gitea }}"
postgresql:
enabled: true
resources: "{{ services.gitea.resources }}"

View File

@@ -0,0 +1,35 @@
---
# Role: iot
# Déploie les brokers MQTT
- name: Installer EMQX
kubernetes.core.helm:
name: emqx
chart_ref: "{{ helm_charts.emqx.chart }}"
release_namespace: iot
create_namespace: true
values:
replicaCount: "{{ services.emqx.replicas }}"
persistence:
enabled: true
size: "{{ storage_sizes.emqx }}"
resources: "{{ services.emqx.resources }}"
- name: Installer Mosquitto
kubernetes.core.helm:
name: mosquitto
chart_ref: "{{ helm_charts.mosquitto.chart }}"
release_namespace: iot
values:
replicaCount: "{{ services.mosquitto.replicas }}"
persistence:
enabled: true
size: "{{ storage_sizes.mosquitto }}"
resources: "{{ services.mosquitto.resources }}"
config: |
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
auth:
password: "{{ vault_mosquitto_password }}"

View File

@@ -0,0 +1,31 @@
---
# Role: jupyterhub
# Déploie JupyterHub
- name: Installer JupyterHub
kubernetes.core.helm:
name: hub
chart_ref: "{{ helm_charts.jupyterhub.chart }}"
release_namespace: jupyterhub
create_namespace: true
values:
hub:
config:
Authenticator:
admin_users:
- eric
JupyterHub:
admin_access: true
db:
pvc:
storage: "{{ storage_sizes.jupyterhub }}"
singleuser:
storage:
capacity: "{{ storage_sizes.jupyterhub }}"
dynamic:
pvcNameTemplate: "jupyterhub-{userid}"
volumeNameTemplate: "jupyterhub-{userid}"
storageClass: "{{ storage_class }}"
proxy:
service:
type: ClusterIP

View File

@@ -0,0 +1,19 @@
---
# Role: kafka
# Déploie Kafka via l'opérateur Strimzi
- name: Installer l'opérateur Strimzi
kubernetes.core.helm:
name: strimzi-kafka-operator
chart_ref: "{{ helm_charts.kafka.chart }}"
release_namespace: kafka
create_namespace: true
- name: Créer le cluster Kafka
kubernetes.core.k8s:
state: present
template: kafka-cluster.yml.j2
vars:
kafka_namespace: kafka
kafka_replicas: "{{ services.kafka.replicas }}"
kafka_storage_size: "{{ storage_sizes.kafka }}"

View File

@@ -0,0 +1,18 @@
---
# Role: mindsdb
# Déploie MindsDB
- name: Installer MindsDB
kubernetes.core.helm:
name: mindsdb
chart_ref: "{{ helm_charts.mindsdb.chart }}"
release_namespace: mindsdb
create_namespace: true
values:
mindsdb:
auth:
username: admin
password: "{{ vault_mindsdb_password }}"
storage:
size: "{{ storage_sizes.mindsdb }}"
resources: "{{ services.mindsdb.resources }}"

View File

@@ -0,0 +1,41 @@
---
# Role: monitoring
# Déploie Prometheus, Grafana, Loki et Promtail
- name: Installer kube-prometheus-stack
kubernetes.core.helm:
name: prometheus
chart_ref: "{{ helm_charts.prometheus.chart }}"
release_namespace: monitoring
create_namespace: true
values:
prometheus:
prometheusSpec:
retention: "{{ monitoring.prometheus_retention }}"
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: "{{ storage_class }}"
resources:
requests:
storage: "{{ storage_sizes.prometheus }}"
grafana:
adminPassword: "{{ monitoring.grafana_admin_password }}"
persistence:
enabled: true
size: "{{ storage_sizes.grafana }}"
alertmanager:
enabled: false
- name: Installer Loki Stack
kubernetes.core.helm:
name: loki
chart_ref: "{{ helm_charts.loki.chart }}"
release_namespace: monitoring
values:
loki:
persistence:
enabled: true
size: "{{ storage_sizes.loki }}"
promtail:
enabled: true

View File

@@ -0,0 +1,17 @@
---
# Role: namespaces
# Crée les namespaces Kubernetes
- name: Créer les namespaces
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ item }}"
labels:
app.kubernetes.io/managed-by: ansible
cluster: "{{ cluster_name }}"
type: kubernetes.io/metadata.v1
loop: "{{ namespaces }}"

View File

@@ -0,0 +1,26 @@
---
# Role: nodered
# Déploie Node-RED
- name: Installer Node-RED
kubernetes.core.helm:
name: nodered
chart_ref: "{{ helm_charts.nodered.chart }}"
release_namespace: iot
values:
replicaCount: "{{ services.nodered.replicas }}"
persistence:
enabled: true
size: 5Gi
resources: "{{ services.nodered.resources }}"
ingress:
enabled: true
hosts:
- host: nodered.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: nodered-tls
hosts:
- nodered.digitribe.fr

View File

@@ -0,0 +1,22 @@
---
# Role: odk
# Déploie ODK Central
- name: Installer ODK Central
kubernetes.core.helm:
name: odk-central
chart_ref: "{{ helm_charts.odk.chart }}"
release_namespace: odk
create_namespace: true
values:
backend:
replicaCount: 1
resources: "{{ services.odk.resources }}"
frontend:
replicaCount: 1
resources: "{{ services.odk.resources }}"
postgres:
enabled: true
storage: "{{ storage_sizes.odk }}"
redis:
enabled: true

View File

@@ -0,0 +1,27 @@
---
# Role: phpipam
# Déploie phpIPAM
- name: Installer phpIPAM
kubernetes.core.helm:
name: phpipam
chart_ref: "{{ helm_charts.phpipam.chart }}"
release_namespace: phpipam
create_namespace: true
values:
phpipam:
adminPassword: "{{ vault_phpipam_admin_password }}"
persistence:
size: 5Gi
resources: "{{ services.phpipam.resources }}"
ingress:
enabled: true
hosts:
- host: phpipam.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: phpipam-tls
hosts:
- phpipam.digitribe.fr

View File

@@ -0,0 +1,21 @@
---
# Role: prerequisites
# Installe les prérequis sur le cluster Kubernetes
- name: Ajouter les repositories Helm
kubernetes.core.helm_repository:
name: "{{ item.name }}"
repo_url: "{{ item.url }}"
loop: "{{ helm_repos }}"
- name: Mettre à jour les repositories Helm
command: helm repo update
changed_when: false
- name: Installer les CRDs nécessaires
kubernetes.core.k8s:
state: present
src: "{{ item }}"
loop:
- https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.crds.yaml
ignore_errors: true

View File

@@ -0,0 +1,19 @@
---
# Role: smartapp
# Déploie l'application Smart City
- name: Déployer Smart App Web
kubernetes.core.k8s:
state: present
template: smartapp-web.yml.j2
vars:
smartapp_namespace: smartapp
smartapp_domain: smartapp.digitribe.fr
- name: Déployer Smart App API
kubernetes.core.k8s:
state: present
template: smartapp-api.yml.j2
vars:
smartapp_namespace: smartapp
smartapp_domain: api-smartapp.digitribe.fr

View File

@@ -0,0 +1,38 @@
---
# Role: starrocks
# Déploie StarRocks
- name: Ajouter le repository Helm StarRocks
kubernetes.core.helm_repository:
name: starrocks
repo_url: https://starrocks.github.io/starrocks-kubernetes-operator
- name: Installer StarRocks
kubernetes.core.helm:
name: starrocks
chart_ref: "{{ helm_charts.starrocks.chart }}"
chart_version: "{{ helm_charts.starrocks.version }}"
release_namespace: starrocks
create_namespace: true
values:
fe:
replicas: "{{ services.starrocks.replicas }}"
resources: "{{ services.starrocks.resources }}"
storage:
size: "{{ storage_sizes.starrocks | default('50Gi') }}"
storageClass: "{{ storage_class }}"
be:
replicas: 3
resources: "{{ services.starrocks.resources }}"
storage:
size: "{{ storage_sizes.starrocks | default('100Gi') }}"
storageClass: "{{ storage_class }}"
cn:
replicas: 2
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"

View File

@@ -0,0 +1,27 @@
---
# Role: storage
# Configure le stockage NFS et les StorageClasses
- name: Créer le namespace storage
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: storage
- name: Installer le NFS provisioner
kubernetes.core.helm:
name: nfs-provisioner
chart_ref: "{{ helm_charts.nfs_provisioner.chart }}"
chart_version: "{{ helm_charts.nfs_provisioner.version }}"
release_namespace: storage
values:
nfs:
server: "{{ nfs_server }}"
path: "{{ nfs_path }}"
storageClass:
name: "{{ storage_class }}"
defaultClass: true
reclaimPolicy: Retain

View File

@@ -0,0 +1,30 @@
---
# Role: streamlit
# Déploie Streamlit
- name: Installer Streamlit
kubernetes.core.helm:
name: streamlit
chart_ref: "{{ helm_charts.streamlit.chart }}"
chart_version: "{{ helm_charts.streamlit.version }}"
release_namespace: streamlit
create_namespace: true
values:
replicaCount: "{{ services.streamlit.replicas }}"
resources: "{{ services.streamlit.resources }}"
service:
type: ClusterIP
ingress:
enabled: true
hosts:
- host: streamlit.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: streamlit-tls
hosts:
- streamlit.digitribe.fr
env:
STREAMLIT_SERVER_HEADLESS: "true"
STREAMLIT_SERVER_ENABLE_CORS: "false"

View File

@@ -0,0 +1,49 @@
---
# Role: traefik
# Déploie le reverse proxy Traefik
- name: Créer le namespace traefik
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ traefik_namespace }}"
- name: Installer Traefik
kubernetes.core.helm:
name: traefik
chart_ref: helm_charts.traefik.chart
release_namespace: "{{ traefik_namespace }}"
values:
globalArguments:
- "--global.checknewversion=false"
- "--global.sendanonymoususage=false"
additionalArguments:
- "--providers.kubernetescrd.allowexternalnameservices=true"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email={{ acme_email }}"
- "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
ports:
traefik:
port: 9000
expose: false
web:
port: 80
expose: true
websecure:
port: 443
expose: true
persistence:
enabled: true
size: 1Gi
service:
type: LoadBalancer
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "1000m"
memory: "512Mi"

View File

@@ -0,0 +1,46 @@
---
# Role: trino
# Déploie Trino
- name: Installer Trino
kubernetes.core.helm:
name: trino
chart_ref: "{{ helm_charts.trino.chart }}"
chart_version: "{{ helm_charts.trino.version }}"
release_namespace: trino
create_namespace: true
values:
server:
workers: "{{ services.trino.replicas }}"
resources: "{{ services.trino.resources }}"
coordinator:
resources: "{{ services.trino.resources }}"
worker:
resources: "{{ services.trino.resources }}"
service:
type: ClusterIV
ingress:
enabled: true
hosts:
- host: trino.digitribe.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: trino-tls
hosts:
- trino.digitribe.fr
catalog:
postgresql:
connector.name=postgresql
connection-url=jdbc:postgresql://postgresql-ha-pgpool.default.svc.cluster.local:5432/smartcity
connection-user=trino
connection-password={{ vault_trino_db_password }}
clickhouse:
connector.name=clickhouse
connection-url=jdbc:clickhouse://clickhouse.clickhouse.svc.cluster.local:8123/default
connection-user=default
connection-password={{ vault_clickhouse_password }}
delta:
connector.name=delta_lake
connection-url=jdbc:delta://deltalake.deltalake.svc.cluster.local:9083

56
helms/undeploy.yml Normal file
View File

@@ -0,0 +1,56 @@
---
# Playbook de suppression de la stack
# Fichier: undeploy.yml
- name: Suppression Smart City Martinique de Kubernetes
hosts: localhost
connection: local
gather_facts: false
vars_files:
- group_vars/all.yml
tasks:
- name: Supprimer les namespaces Kubernetes
kubernetes.core.k8s:
state: absent
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ item }}"
loop: "{{ namespaces }}"
ignore_errors: true
- name: Supprimer les PersistentVolumes
kubernetes.core.k8s:
state: absent
definition:
apiVersion: v1
kind: PersistentVolume
metadata:
name: "{{ item }}"
loop: "{{ persistent_volumes | default([]) }}"
ignore_errors: true
- name: Supprimer les ClusterRoles
kubernetes.core.k8s:
state: absent
kind: ClusterRole
name: "{{ item }}"
loop:
- traefik
- cert-manager
- prometheus
ignore_errors: true
- name: Supprimer les ClusterRoleBindings
kubernetes.core.k8s:
state: absent
kind: ClusterRoleBinding
name: "{{ item }}"
loop:
- traefik
- cert-manager
- prometheus
ignore_errors: true