ifremer_presentation/presentation_airflow.html

754 lines
30 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Migration des chaînes du CERSAT vers Airflow</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/dist/reveal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/dist/theme/white.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/plugin/highlight/monokai.css">
<style>
:root {
--deep-blue: #003D7A;
--text: #1A1A2E;
--muted: #5A5A7A;
--light-bg: #F5F7FA;
--border: #E0E4EA;
--accent-light: #E8F0FE;
}
* { box-sizing: border-box; }
/* Ifremer logo fixed top-right on every slide */
.ifremer-corner {
position: fixed;
top: 16px;
right: 24px;
z-index: 999;
opacity: 0.85;
transition: opacity 0.2s;
}
.ifremer-corner:hover { opacity: 1; }
.ifremer-corner img { height: 28px; width: auto; }
.reveal {
font-family: 'Inter', 'Segoe UI', -apple-system, sans-serif;
color: var(--text);
}
.reveal h1, .reveal h2, .reveal h3, .reveal h4 {
font-weight: 700;
letter-spacing: -0.02em;
color: var(--deep-blue);
}
.reveal h1 { font-size: 2.6em; margin-bottom: 0.3em; }
.reveal h2 { font-size: 1.8em; margin-bottom: 0.4em; }
.reveal h3 { font-size: 1.3em; margin-bottom: 0.3em; color: var(--text); }
.reveal h4 { font-size: 1.1em; color: var(--deep-blue); }
.reveal p, .reveal li {
font-size: 0.85em;
line-height: 1.6;
color: var(--text);
}
.reveal ul, .reveal ol {
display: inline-block;
text-align: left;
}
.reveal li { margin-bottom: 0.3em; }
.reveal .highlight { color: var(--deep-blue); font-weight: 600; }
.reveal .subtitle {
font-size: 0.55em;
color: var(--muted);
margin-top: -0.5em;
font-weight: 400;
}
.reveal section img.logo-grid {
margin: 0 10px;
height: 48px;
vertical-align: middle;
}
.reveal section img.logo-grid-cn { height: 32px; }
.reveal section img.logo-grid-es { height: 40px; }
.reveal .logo-row {
display: flex;
justify-content: center;
align-items: center;
gap: 32px;
flex-wrap: wrap;
margin: 28px 0;
}
.reveal .logo-row img { height: 44px; width: auto; }
.reveal .col-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 28px;
text-align: left;
margin-top: 16px;
}
.reveal .col-2 .box {
background: var(--light-bg);
border-radius: 12px;
padding: 20px 24px;
border: 1px solid var(--border);
}
.reveal .col-2 .box h4 {
margin-top: 0;
margin-bottom: 8px;
font-size: 1em;
}
.reveal .col-2 .box ul { margin: 0; padding-left: 1.2em; }
.reveal .col-2 .box li { font-size: 0.8em; }
.reveal .badge {
display: inline-block;
background: var(--deep-blue);
color: #fff;
padding: 2px 12px;
border-radius: 20px;
font-size: 0.65em;
font-weight: 600;
margin-right: 6px;
}
.reveal code {
font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
font-size: 0.78em;
}
.reveal pre {
width: 100%;
box-shadow: none;
border-radius: 8px;
border: 1px solid var(--border);
}
.reveal pre code {
max-height: 480px;
padding: 18px 20px;
font-size: 0.62em;
line-height: 1.55;
}
.reveal .mermaid {
text-align: center;
margin: 20px 0;
}
/* Title slide */
.title-slide h1 {
font-size: 2.8em;
margin-bottom: 0.15em;
}
.title-slide .meta {
font-size: 0.5em;
color: var(--muted);
margin-top: 1.5em;
}
/* Section divider */
.section-slide h2 {
font-size: 2.2em;
}
.section-slide p {
color: var(--muted);
font-size: 0.7em;
}
/* Inline icon pills */
.pill-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin: 16px 0;
}
.pill-list .pill {
background: var(--accent-light);
color: var(--deep-blue);
padding: 6px 18px;
border-radius: 24px;
font-size: 0.72em;
font-weight: 500;
border: 1px solid rgba(0,61,122,0.15);
}
/* Small text */
.reveal .small { font-size: 0.68em; color: var(--muted); }
/* Vertical spacing for Mermaid on architecture slides */
.arch-slide .mermaid { margin: 12px 0; font-size: 0.85em; }
/* Mermaid overrides */
.mermaid svg { max-width: 100%; height: auto; }
/* Data metrics */
.metrics {
display: flex;
justify-content: center;
gap: 36px;
margin: 20px 0;
}
.metrics .metric {
text-align: center;
}
.metrics .metric .num {
font-size: 1.6em;
font-weight: 700;
color: var(--deep-blue);
}
.metrics .metric .label {
font-size: 0.6em;
color: var(--muted);
}
@media print {
.ifremer-corner { position: absolute; }
}
</style>
</head>
<body>
<div class="ifremer-corner">
<img src="https://upload.wikimedia.org/wikipedia/en/c/c8/Institut_fran%C3%A7ais_de_recherche_pour_l%27exploitation_de_la_mer_%28logo%29.svg" alt="Ifremer">
</div>
<div class="reveal">
<div class="slides">
<!-- ============================================================ -->
<!-- SLIDE 1 : Titre -->
<!-- ============================================================ -->
<section class="title-slide">
<h1>Migration des chaînes<br>du CERSAT vers Airflow</h1>
<p class="subtitle">Modernisation de l'infrastructure de production &mdash; Ifremer / Sismer</p>
<div class="meta">
<span>&#x2022;</span> Équipe CERSAT <span>&#x2022;</span>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 2 : Contexte -->
<!-- ============================================================ -->
<section>
<h2>Contexte</h2>
<div style="text-align:left; margin: 0 auto; max-width: 90%;">
<p><strong>CERSAT</strong> est le centre de distribution et de traitement des données satellitaires d'Ifremer. Objectif&nbsp;: fournir des données et outils pour l'étude de l'état des océans et des interactions air-océan.</p>
<ul>
<li><strong>LOPS</strong> &mdash; expertise pour le développement des produits et traitements</li>
<li><strong>Sismer</strong> &mdash; mise en production et distribution des données</li>
<li>En collaboration avec&nbsp;: Copernicus, ESA, CNES, Eumetsat, membre d'ODATIS</li>
</ul>
</div>
<!-- Logos row -->
<div class="logo-row">
<img src="https://upload.wikimedia.org/wikipedia/en/c/c8/Institut_fran%C3%A7ais_de_recherche_pour_l%27exploitation_de_la_mer_%28logo%29.svg" alt="Ifremer" style="height:36px;">
<img src="https://upload.wikimedia.org/wikipedia/commons/6/6e/ESA_logo_simple.svg" alt="ESA" style="height:36px;">
<img src="https://upload.wikimedia.org/wikipedia/fr/e/e3/CNES_2005-2017_Logo.svg" alt="CNES" style="height:36px;">
<img src="https://www.copernicus.eu/sites/default/files/styles/image_img_fluid/public/images/media/low/295955-Copernicus_logo_node_full_image_2.jpg" alt="Copernicus" style="height:40px;">
</div>
<p class="small" style="margin-top:8px;">L'équipe CERSAT du Sismer assure déploiement, suivi de production et distribution</p>
<div style="display:flex; justify-content:center; gap:24px; margin-top:16px;">
<div style="background:var(--light-bg); border-radius:8px; padding:10px 18px; border:1px solid var(--border); text-align:center;">
<p style="margin:0; font-size:0.75em;"><strong>1&ndash;2</strong><br><span style="color:var(--muted);">opérateurs</span></p>
</div>
<div style="background:var(--light-bg); border-radius:8px; padding:10px 18px; border:1px solid var(--border); text-align:center;">
<p style="margin:0; font-size:0.75em;"><strong>2</strong><br><span style="color:var(--muted);">ingénieurs</span></p>
</div>
<div style="background:var(--light-bg); border-radius:8px; padding:10px 18px; border:1px solid var(--border); text-align:center;">
<p style="margin:0; font-size:0.75em;"><strong>1</strong><br><span style="color:var(--muted);">manager</span></p>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 3 : Métier -->
<!-- ============================================================ -->
<section>
<h2>Métier&nbsp;: qu'est-ce qu'un traitement&nbsp;?</h2>
<div style="text-align:left; margin: 0 auto; max-width: 88%;">
<p>Un <strong>traitement</strong> est un enchaînement d'étapes qui transforme des données brutes en produits exploitables&nbsp;:</p>
</div>
<div style="display:flex; justify-content:center; gap:16px; margin:20px 0; flex-wrap:wrap;">
<div style="background:var(--light-bg); border-radius:10px; padding:14px 22px; border:1px solid var(--border); min-width:140px; text-align:center;">
<p style="margin:0; font-size:0.8em;">📡 <strong>Récupération</strong><br><span style="color:var(--muted); font-size:0.85em;">Données bas niveau</span></p>
</div>
<div style="display:flex; align-items:center; color:var(--muted); font-size:1.4em;">&rarr;</div>
<div style="background:var(--accent-light); border-radius:10px; padding:14px 22px; border:1px solid var(--deep-blue); min-width:160px; text-align:center;">
<p style="margin:0; font-size:0.8em;">⚙️ <strong>Enrichissement</strong><br><span style="color:var(--muted); font-size:0.85em;">Fusion, correction, format</span></p>
</div>
<div style="display:flex; align-items:center; color:var(--muted); font-size:1.4em;">&rarr;</div>
<div style="background:var(--light-bg); border-radius:10px; padding:14px 22px; border:1px solid var(--border); min-width:140px; text-align:center;">
<p style="margin:0; font-size:0.8em;">📤 <strong>Distribution</strong><br><span style="color:var(--muted); font-size:0.85em;">FTP, catalogue</span></p>
</div>
</div>
<div style="text-align:left; margin: 0 auto; max-width: 80%;">
<p class="small" style="margin-top:8px;">Distribution directe (FTP, catalogue) ou indirecte (vers des organismes pour leurs propres produits)</p>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 4 : Enjeux -->
<!-- ============================================================ -->
<section>
<h2>Enjeux</h2>
<div style="text-align:left; margin: 0 auto; max-width: 88%;">
<p><strong>Service de production contractuel (SLA)</strong></p>
<ul>
<li>Exemple <strong>SMOS Wind</strong>&nbsp;: production des données en moins de <span class="highlight">4H</span> (30 min de traitement chez Ifremer)</li>
<li>Des besoins de service pour l'infrastructure qui impactent chercheurs et utilisateurs</li>
</ul>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:20px; text-align:left; margin:20px auto; max-width:80%;">
<div style="background:var(--light-bg); border-radius:10px; padding:16px 20px; border:1px solid var(--border);">
<h4 style="margin:0 0 6px 0; font-size:0.85em;">🔁 Besoins SLA</h4>
<ul style="font-size:0.75em;">
<li>Haute disponibilité</li>
<li>Temps de traitement garanti</li>
<li>Redondance des services</li>
</ul>
</div>
<div style="background:var(--accent-light); border-radius:10px; padding:16px 20px; border:1px solid var(--deep-blue);">
<h4 style="margin:0 0 6px 0; font-size:0.85em; color:var(--deep-blue);">🎯 Impact</h4>
<ul style="font-size:0.75em;">
<li>Qualité de service pour les chercheurs</li>
<li>Respect des engagements contractuels</li>
<li>Visibilité sur la production</li>
</ul>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 5 : Données -->
<!-- ============================================================ -->
<section>
<h2>Données</h2>
<div style="text-align:left; margin: 0 auto; max-width: 80%;">
<p><span class="badge">Format</span> <strong>NetCDF4</strong> &mdash; format standard pour données scientifiques et satellitaires</p>
</div>
<div class="metrics">
<div class="metric">
<div class="num">XX TB</div>
<div class="label">Archives</div>
</div>
<div class="metric">
<div class="num">YY TB</div>
<div class="label">Workspace</div>
</div>
<div class="metric">
<div class="num">ZZ Go/j</div>
<div class="label">Volume quotidien</div>
</div>
</div>
<p class="small">(à compléter avec les chiffres réels de l'infrastructure CERSAT)</p>
</section>
<!-- ============================================================ -->
<!-- SLIDE 6 : Architecture Avant -->
<!-- ============================================================ -->
<section class="arch-slide">
<h2>Architecture de production</h2>
<h3 style="font-size:0.9em; color:var(--muted); margin-bottom:10px;">Avant la migration</h3>
<div class="mermaid">
flowchart LR
T["📥 Downloader"] --> CS["⚙️ ChainScheduler"]
CS --> PBS["📋 PBS"]
CS --> SP["📊 suivi_production"]
SP --> ES[("🗄️ Elasticsearch")]
ES --> K["📈 Kibana"]
</div>
<div class="mermaid" style="margin-top:8px;">
flowchart LR
cron["⏰ cron"] --> scripts["📜 scripts shell"]
</div>
<p class="small" style="margin-top:8px;">Ordonnancement via ChainScheduler + PBS &bull; Suivi historique via Elasticsearch/Kibana &bull; Scripts automatisés via cron</p>
</section>
<!-- ============================================================ -->
<!-- SLIDE 7 : Pourquoi la migration -->
<!-- ============================================================ -->
<section>
<h2>Pourquoi la migration&nbsp;?</h2>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:20px; text-align:left; margin:0 auto; max-width:88%;">
<div class="box" style="background:#FFF0F0; border-color:#E8B4B4;">
<h4 style="color:#B71C1C;">❌ ChainScheduler</h4>
<ul>
<li>Non maintenu</li>
<li>Visualisation des états uniquement via logs</li>
<li>Tourne sur machines indépendantes (ISI) <strong>sans SLA</strong></li>
<li>Hors conditions de production</li>
<li>Utilise <strong>PBS</strong> (décommissionné à la rentrée)</li>
</ul>
</div>
<div class="box" style="background:#E8F5E9; border-color:#A5D6A7;">
<h4 style="color:#1B5E20;">✅ Airflow</h4>
<ul>
<li>Orchestrateur moderne et maintenu</li>
<li>UI intégrée &rarr; visibilité temps réel</li>
<li>Supporte SLURM (HPC Ifremer)</li>
<li>Architecture scalable &amp; résiliente</li>
<li>Event-driven &amp; DAGs chaînables</li>
</ul>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 8 : Architecture Après -->
<!-- ============================================================ -->
<section class="arch-slide">
<h2>Architecture de production</h2>
<h3 style="font-size:0.9em; color:var(--muted); margin-bottom:10px;">Après la migration</h3>
<div class="mermaid">
flowchart LR
T["📥 Downloader"] --> AF["☁️ Airflow"]
AF --> SLURM["📋 SLURM<br/>(HPC Ifremer)"]
AF --> MSP["📊 Meilleur suivi<br/>de production"]
MSP --> DASH["📈 Dashboard<br/>+ Alertes"]
</div>
<div style="display:flex; justify-content:center; gap:12px; margin-top:16px; flex-wrap:wrap;">
<span class="pill">📉 Moins de silos</span>
<span class="pill">🔄 Automatisation complète</span>
<span class="pill">🔔 Alertes proactives</span>
<span class="pill">📋 SLA traçable</span>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 9 : Section titre - Airflow -->
<!-- ============================================================ -->
<section class="section-slide">
<h2>Passer les traitements<br>sur Airflow</h2>
<p>De la chaîne legacy au DAG moderne</p>
</section>
<!-- ============================================================ -->
<!-- SLIDE 10 : Anatomie d'une chaîne -->
<!-- ============================================================ -->
<section>
<h2>Anatomie d'une chaîne</h2>
<div class="mermaid">
flowchart LR
A["🚀 Exécution"] --> B["📡 Récupération<br/>de la donnée"]
B --> C["⚙️ Traitement"]
C --> D["📦 Déplacement<br/>de la donnée"]
D --> E["✅ Vérifications"]
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:20px; text-align:left; margin:20px auto; max-width:85%;">
<div class="box">
<h4>📋 En terme Airflow</h4>
<p style="font-size:0.75em;"><strong>DAG</strong> = chaîne<br>
<strong>Task</strong> = étape élémentaire</p>
<p style="font-size:0.7em; color:var(--muted);">Les tasks peuvent être n'importe quoi&nbsp;: Python, Bash, SLURM, Kubernetes&hellip;</p>
</div>
<div class="box" style="background:var(--accent-light); border-color:var(--deep-blue);">
<h4 style="color:var(--deep-blue);">✨ Ce que permet Airflow</h4>
<ul style="font-size:0.7em;">
<li>Arborescence de tasks libre</li>
<li>Event-driven (sensors)</li>
<li>Chaînage de DAGs</li>
<li>Retry automatique</li>
</ul>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 11 : Ce que nous permet Airflow (détail) -->
<!-- ============================================================ -->
<section>
<h2>Fonctionnalités clés d'Airflow</h2>
<div style="display:grid; grid-template-columns:1fr 1fr 1fr; gap:16px; text-align:left; margin:0 auto; max-width:92%;">
<div class="box">
<h4 style="font-size:0.85em;">🧩 Arborescence</h4>
<p style="font-size:0.68em;">Construisez des graphes de tâches complexes avec des dépendances paramétrables.</p>
</div>
<div class="box">
<h4 style="font-size:0.85em;">🔔 Event-Driven</h4>
<p style="font-size:0.68em;">Les sensors déclenchent des tâches à l'arrivée de fichiers, à une heure donnée, ou sur condition.</p>
</div>
<div class="box">
<h4 style="font-size:0.85em;">🔗 Chaînage de DAGs</h4>
<p style="font-size:0.68em;">Un DAG peut déclencher un autre via <code>TriggerDagRunOperator</code>.</p>
</div>
</div>
<div class="pill-list" style="margin-top:20px;">
<span class="pill">🔄 Retry automatique</span>
<span class="pill">📧 Alertes email/Slack</span>
<span class="pill">📊 Logs centralisés</span>
<span class="pill">⏱ Planning cron natif</span>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 12 : Exemple de DAG -->
<!-- ============================================================ -->
<section>
<h2>Exemple de DAG</h2>
<pre><code class="language-python" data-trim data-noescape>
from airflow import DAG
from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator
from datetime import datetime
default_args = {
'owner': 'cersat',
'start_date': datetime(2025, 1, 1),
}
with DAG(
'exemple_chaine_cersat',
default_args=default_args,
schedule=None,
catchup=False,
) as dag:
def initialiser(**context):
params = context['params']
return f"Traitement de {params['fichier']}"
init = PythonOperator(
task_id='initialisation',
python_callable=initialiser,
params={'fichier': 'S3A_OL_1_*.nc'},
)
traitement = BashOperator(
task_id='traitement_slurm',
bash_command='sbatch /opt/scripts/traiter.sh',
)
transfert = BashOperator(
task_id='transfert_fichiers',
bash_command='cp /data/workspace/{{ dag_run.id }} /data/archive/',
)
verification = BashOperator(
task_id='verification',
bash_command='python /opt/scripts/verifier_produit.py',
)
init >> traitement >> transfert >> verification
</code></pre>
</section>
<!-- ============================================================ -->
<!-- SLIDE 13 : Slurm Operator -->
<!-- ============================================================ -->
<section>
<h2>Nos outils Airflow</h2>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:20px; text-align:left; margin:0 auto; max-width:88%;">
<div class="box" style="grid-column:1 / -1;">
<h4>📋 Slurm Operator</h4>
<p style="font-size:0.75em;">Lance les jobs via <strong>SLURM</strong> sur <code>hpc.ifremer.fr</code></p>
<div style="display:flex; gap:16px; margin-top:8px;">
<div style="background:#FFF3E0; border-radius:8px; padding:10px 14px; flex:1;">
<p style="margin:0; font-size:0.7em;"><strong>Besoins</strong></p>
<ul style="font-size:0.65em; margin:4px 0 0 0;">
<li>Jeton d'utilisation</li>
<li>Utilisateur airflow autorisé sur le cluster</li>
</ul>
</div>
<div style="background:#E3F2FD; border-radius:8px; padding:10px 14px; flex:1;">
<p style="margin:0; font-size:0.7em;"><strong>Avantages</strong></p>
<ul style="font-size:0.65em; margin:4px 0 0 0;">
<li>Calcul distribué haute performance</li>
<li>Ressources mutualisées Ifremer</li>
</ul>
</div>
</div>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 14 : Convertible Path -->
<!-- ============================================================ -->
<section>
<h2>Convertible Path</h2>
<p style="font-size:0.75em; color:var(--muted); margin-bottom:10px;">La problématique des accès disques</p>
<div class="col-2">
<div class="box">
<h4>⚙️ Problème</h4>
<p style="font-size:0.72em;">Airflow est containerisé &rarr; l'accès aux disques doit être géré dans le DAG</p>
<ul style="font-size:0.68em;">
<li><strong>KubernetesOperator</strong> : container créé pour la tâche, montages de volumes à spécifier</li>
<li><strong>CeleryExecutor</strong> : container toujours en exécution, réduit le délai pour tâches rapides</li>
</ul>
</div>
<div class="box" style="background:var(--accent-light); border-color:var(--deep-blue);">
<h4 style="color:var(--deep-blue);">🔀 Solution</h4>
<p style="font-size:0.72em;">Les chemins de montage diffèrent selon la machine&nbsp;:</p>
<div class="pill-list" style="margin:8px 0;">
<span class="pill">Datarmor</span>
<span class="pill">CeleryExecutor</span>
<span class="pill">HPC (SLURM)</span>
</div>
<p style="font-size:0.72em; margin-top:4px;"><strong>ConvertiblePath</strong> &rarr; classe utilitaire pour convertir les chemins facilement</p>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 15 : WorkdirManager -->
<!-- ============================================================ -->
<section>
<h2>WorkdirManager</h2>
<p style="font-size:0.75em; color:var(--muted); margin-bottom:6px;">Gestion des dossiers temporaires des chaînes de traitement</p>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:20px; text-align:left; margin:0 auto; max-width:85%;">
<div class="box" style="background:var(--accent-light); border-color:var(--deep-blue);">
<h4 style="color:var(--deep-blue);">✅ Fonctionnalités</h4>
<ul style="font-size:0.72em;">
<li>Création automatique de dossiers pour chaque task</li>
<li>Génération de dossiers pour les tasks dynamiques</li>
<li>Partage des chemins d'une tâche à l'autre</li>
<li>Nettoyage à la fin du DAG</li>
</ul>
</div>
<div class="box">
<h4>🧹 Politique de nettoyage</h4>
<ul style="font-size:0.72em;">
<li><strong>Succès</strong> &rarr; suppression automatique</li>
<li><strong>Erreur</strong> &rarr; conservation pour débogage</li>
</ul>
</div>
</div>
<pre style="margin-top:14px; width:auto; display:inline-block;"><code class="language-python" data-trim>
# Exemple de configuration
with WorkdirManager(root="/data/workspace") as wm:
input_dir = wm.make_dirs("input")
output_dir = wm.make_dirs("output")
# Les dossiers seront nettoyés
# automatiquement en cas de succès
</code></pre>
</section>
<!-- ============================================================ -->
<!-- SLIDE 16 : Suivi de la production -->
<!-- ============================================================ -->
<section>
<h2>Suivi de la production</h2>
<div style="text-align:left; margin: 0 auto; max-width: 88%;">
<p><strong>Besoins</strong></p>
<ol style="font-size:0.75em;">
<li>Vision temps-réel + historique de ce qui a été produit/téléchargé</li>
<li>Vision des fichiers <strong>non</strong> produits/téléchargés</li>
<li>Vision des sources utilisées pour quels produits</li>
<li>Vision des états (actif/inactif) des services, infra, DAGs</li>
<li>Alertes pour les points 2 et 4</li>
</ol>
</div>
<div class="col-2" style="margin-top:16px;">
<div class="box" style="border-color:#E8B4B4;">
<h4 style="color:#B71C1C;">Aujourd'hui</h4>
<ul style="font-size:0.68em;">
<li>✅ Elasticsearch pour production &amp; téléchargement (cron BDD) &rarr; 1,2 <strong>mais pas temps-réel</strong></li>
<li>🟡 UI Airflow &rarr; partiellement 4</li>
<li>❌ Pour tout le reste&nbsp;: <strong>fouiller les logs</strong></li>
</ul>
</div>
<div class="box" style="background:#E8F5E9; border-color:#A5D6A7;">
<h4 style="color:#1B5E20;">Objectif</h4>
<ul style="font-size:0.68em;">
<li>📊 Dashboard temps réel</li>
<li>🔔 Alerting automatisé</li>
<li>📈 Métriques de production</li>
<li>🔄 Traçabilité de bout en bout</li>
</ul>
</div>
</div>
</section>
<!-- ============================================================ -->
<!-- SLIDE 17 : Merci -->
<!-- ============================================================ -->
<section class="title-slide">
<h2 style="font-size:2.4em;">Merci</h2>
<p class="subtitle">Questions / Discussion</p>
<div class="meta" style="margin-top:1.5em;">
<span>Équipe CERSAT &mdash; Sismer / Ifremer</span>
</div>
</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/dist/reveal.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/plugin/highlight/highlight.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/plugin/notes/notes.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/plugin/zoom/zoom.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@4.3.1/plugin/search/search.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: false,
theme: 'base',
themeVariables: {
primaryColor: '#003D7A',
primaryTextColor: '#1A1A2E',
primaryBorderColor: '#003D7A',
lineColor: '#003D7A',
secondaryColor: '#E8F0FE',
tertiaryColor: '#F5F7FA',
fontSize: '16px',
fontFamily: 'Inter, sans-serif',
},
flowchart: {
useMaxWidth: true,
htmlLabels: true,
curve: 'basis',
}
});
Reveal.initialize({
controls: true,
controlsTutorial: false,
controlsLayout: 'bottom-right',
controlsBackArrows: 'visible',
progress: true,
slideNumber: true,
hash: true,
center: true,
transition: 'convex',
transitionSpeed: 'default',
backgroundTransition: 'fade',
pdfSeparateFragments: false,
viewDistance: 3,
hideInactiveCursor: true,
hideCursorTime: 3000,
keyboard: true,
plugins: [ RevealHighlight, RevealNotes, RevealZoom, RevealSearch ],
});
// Render Mermaid after Reveal is ready
Reveal.addEventListener('ready', function() {
mermaid.run({ nodes: document.querySelectorAll('.mermaid') });
});
// Re-render Mermaid on slide change (for diagrams that aren't visible yet)
Reveal.addEventListener('slidechanged', function() {
setTimeout(function() {
const visibleSlide = Reveal.getCurrentSlide();
const mermaids = visibleSlide.querySelectorAll('.mermaid:not([data-processed])');
if (mermaids.length > 0) {
mermaid.run({ nodes: mermaids });
}
}, 200);
});
</script>
</body>
</html>