754 lines
30 KiB
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 — Ifremer / Sismer</p>
|
|
<div class="meta">
|
|
<span>•</span> Équipe CERSAT <span>•</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 : 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> — expertise pour le développement des produits et traitements</li>
|
|
<li><strong>Sismer</strong> — mise en production et distribution des données</li>
|
|
<li>En collaboration avec : 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–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 : qu'est-ce qu'un traitement ?</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 :</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;">→</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;">→</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> : 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> — 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 • Suivi historique via Elasticsearch/Kibana • Scripts automatisés via cron</p>
|
|
</section>
|
|
|
|
<!-- ============================================================ -->
|
|
<!-- SLIDE 7 : Pourquoi la migration -->
|
|
<!-- ============================================================ -->
|
|
<section>
|
|
<h2>Pourquoi la migration ?</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 → visibilité temps réel</li>
|
|
<li>Supporte SLURM (HPC Ifremer)</li>
|
|
<li>Architecture scalable & résiliente</li>
|
|
<li>Event-driven & 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 : Python, Bash, SLURM, Kubernetes…</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é → 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 :</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> → 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> → suppression automatique</li>
|
|
<li><strong>Erreur</strong> → 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 & téléchargement (cron BDD) → 1,2 <strong>mais pas temps-réel</strong></li>
|
|
<li>🟡 UI Airflow → partiellement 4</li>
|
|
<li>❌ Pour tout le reste : <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 — 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>
|