two/deploiement/image-qcow2.html
2026-09-09 21:14:24 +00:00

1231 lines
No EOL
62 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="fr" data-content_root="../" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Construction de l’image qcow2 &#8212; Documentation two 0.1.0</title>
<script data-cfasync="false">
document.documentElement.dataset.mode = localStorage.getItem("mode") || "";
document.documentElement.dataset.theme = localStorage.getItem("theme") || "";
</script>
<!--
this give us a css class that will be invisible only if js is disabled
-->
<noscript>
<style>
.pst-js-only { display: none !important; }
</style>
</noscript>
<!-- Loaded before other Sphinx assets -->
<link href="../_static/styles/theme.css?digest=8878045cc6db502f8baf" rel="stylesheet" />
<link href="../_static/styles/pydata-sphinx-theme.css?digest=8878045cc6db502f8baf" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=8f2a1f02" />
<link rel="stylesheet" type="text/css" href="../_static/styles/sphinx-book-theme.css?v=3c74b3bc" />
<!-- So that users can add custom icons -->
<script src="../_static/scripts/fontawesome.js?digest=8878045cc6db502f8baf"></script>
<!-- Pre-loaded scripts that we'll load fully later -->
<link rel="preload" as="script" href="../_static/scripts/bootstrap.js?digest=8878045cc6db502f8baf" />
<link rel="preload" as="script" href="../_static/scripts/pydata-sphinx-theme.js?digest=8878045cc6db502f8baf" />
<script src="../_static/documentation_options.js?v=4d0cb239"></script>
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
<script src="../_static/scripts/sphinx-book-theme.js?v=fab101a9"></script>
<script src="../_static/translations.js?v=e6b791cb"></script>
<script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js"></script>
<script type="module">import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11.12.1/dist/mermaid.esm.min.mjs";
const initStyles = () => {
const defaultStyle = document.createElement('style');
defaultStyle.textContent = `pre.mermaid {
/* Same as .mermaid-container > pre */
display: block;
width: 100%;
}
pre.mermaid > svg {
/* Same as .mermaid-container > pre > svg */
height: 500px;
width: 100%;
max-width: 100% !important;
}`;
document.head.appendChild(defaultStyle);
const fullscreenStyle = document.createElement('style');
fullscreenStyle.textContent = `.mermaid-container {
display: flex;
flex-direction: row;
width: 100%;
}
.mermaid-container > pre {
display: block;
width: 100%;
}
.mermaid-container > pre > svg {
height: 500px;
width: 100%;
max-width: 100% !important;
}
.mermaid-fullscreen-btn {
width: 28px;
height: 28px;
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
font-size: 14px;
line-height: 1;
padding: 0;
color: #333;
}
.mermaid-fullscreen-btn:hover {
opacity: 100% !important;
background: rgba(255, 255, 255, 1);
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
transform: scale(1.1);
}
.mermaid-fullscreen-btn.dark-theme {
background: rgba(50, 50, 50, 0.95);
border: 1px solid rgba(255, 255, 255, 0.3);
color: #e0e0e0;
}
.mermaid-fullscreen-btn.dark-theme:hover {
background: rgba(60, 60, 60, 1);
box-shadow: 0 3px 10px rgba(255, 255, 255, 0.2);
}
.mermaid-fullscreen-modal {
display: none;
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 95vw;
height: 100vh;
background: rgba(255, 255, 255, 0.98);
z-index: 9999;
padding: 20px;
overflow: auto;
}
.mermaid-fullscreen-modal.dark-theme {
background: rgba(0, 0, 0, 0.98);
}
.mermaid-fullscreen-modal.active {
display: flex;
align-items: center;
justify-content: center;
}
.mermaid-container-fullscreen {
position: relative;
width: 95vw;
height: 90vh;
max-width: 95vw;
max-height: 90vh;
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
overflow: auto;
display: flex;
align-items: center;
justify-content: center;
}
.mermaid-container-fullscreen.dark-theme {
background: #1a1a1a;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.8);
}
.mermaid-container-fullscreen pre.mermaid {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.mermaid-container-fullscreen .mermaid svg {
height: 100% !important;
width: 100% !important;
cursor: grab;
}
.mermaid-fullscreen-close {
position: fixed !important;
top: 20px !important;
right: 20px !important;
width: 40px;
height: 40px;
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 50%;
cursor: pointer;
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: all 0.2s;
font-size: 24px;
line-height: 1;
color: #333;
}
.mermaid-fullscreen-close:hover {
background: white;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
transform: scale(1.1);
}
.mermaid-fullscreen-close.dark-theme {
background: rgba(50, 50, 50, 0.95);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #e0e0e0;
}
.mermaid-fullscreen-close.dark-theme:hover {
background: rgba(60, 60, 60, 1);
box-shadow: 0 6px 16px rgba(255, 255, 255, 0.2);
}
.mermaid-fullscreen-modal .mermaid-fullscreen-btn {
display: none !important;
}`;
document.head.appendChild(fullscreenStyle);
}
// Detect if page has dark background
const isDarkTheme = () => {
// We use a set of heuristics:
// 1. Check for common dark mode classes or attributes
// 2. Check computed background color brightness
if (document.documentElement.classList.contains('dark') ||
document.documentElement.getAttribute('data-theme') === 'dark' ||
document.body.classList.contains('dark') ||
document.body.getAttribute('data-theme') === 'dark') {
// console.log("Dark theme detected via class/attribute");
return true;
}
if (document.documentElement.classList.contains('light') ||
document.documentElement.getAttribute('data-theme') === 'light' ||
document.body.classList.contains('light') ||
document.body.getAttribute('data-theme') === 'light') {
// console.log("Light theme detected via class/attribute");
return false;
}
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
// console.log("Dark theme detected via prefers-color-scheme");
return true;
}
const bgColor = window.getComputedStyle(document.body).backgroundColor;
const match = bgColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)/);
if (match) {
const r = parseInt(match[1]);
const g = parseInt(match[2]);
const b = parseInt(match[3]);
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
// console.log("Background color brightness:", brightness);
return brightness < 128;
}
// console.log("No dark or light theme detected, defaulting to light theme");
return false;
};
let darkTheme = isDarkTheme();
let modal = null;
let modalContent = null;
let previousScrollOffset = [window.scrollX, window.scrollY];
const runMermaid = async (rerun) => {
console.log("Running mermaid diagrams, rerun =", rerun);
// clear all existing mermaid charts
let all_mermaids = document.querySelectorAll(".mermaid");
if (rerun) {
all_mermaids.forEach((el) => {
if(!el.hasAttribute("data-original-code")) {
// store original code
// console.log(`Storing original code for first run: `, el.innerHTML);
el.setAttribute('data-original-code', el.innerHTML);
}
if(el.getAttribute("data-processed") === "true") {
// remove and restore original
el.removeAttribute("data-processed");
// console.log(`Restoring original code for re-run: `, el.getAttribute('data-original-code'));
el.innerHTML = el.getAttribute('data-original-code');
} else {
// store original code
// console.log(`Storing original code for re-run: `, el.innerHTML);
el.setAttribute('data-original-code', el.innerHTML);
}
});
await mermaid.run();
}
all_mermaids = document.querySelectorAll(".mermaid");
const mermaids_processed = document.querySelectorAll(".mermaid[data-processed='true']");
if ("False" === "True") {
const mermaids_to_add_zoom = -1 === -1 ? all_mermaids.length : -1;
if(mermaids_to_add_zoom > 0) {
var svgs = d3.selectAll("");
if(all_mermaids.length !== mermaids_processed.length) {
setTimeout(() => runMermaid(false), 200);
return;
} else if(svgs.size() !== mermaids_to_add_zoom) {
setTimeout(() => runMermaid(false), 200);
return;
} else {
svgs.each(function() {
var svg = d3.select(this);
svg.html("<g class='wrapper'>" + svg.html() + "</g>");
var inner = svg.select("g");
var zoom = d3.zoom().on("zoom", function(event) {
inner.attr("transform", event.transform);
});
svg.call(zoom);
});
}
}
} else if(all_mermaids.length !== mermaids_processed.length) {
// Wait for mermaid to process all diagrams
setTimeout(() => runMermaid(false), 200);
return;
}
// Stop here if not adding fullscreen capability
if ("True" !== "True") return;
if (modal !== null ) {
// Destroy existing modal
modal.remove();
modal = null;
modalContent = null;
}
modal = document.createElement('div');
modal.className = 'mermaid-fullscreen-modal' + (darkTheme ? ' dark-theme' : '');
modal.setAttribute('role', 'dialog');
modal.setAttribute('aria-modal', 'true');
modal.setAttribute('aria-label', 'Fullscreen diagram viewer');
modal.innerHTML = `
<button class="mermaid-fullscreen-close${darkTheme ? ' dark-theme' : ''}" aria-label="Close fullscreen">✕</button>
<div class="mermaid-container-fullscreen${darkTheme ? ' dark-theme' : ''}"></div>
`;
document.body.appendChild(modal);
modalContent = modal.querySelector('.mermaid-container-fullscreen');
const closeBtn = modal.querySelector('.mermaid-fullscreen-close');
const closeModal = () => {
modal.classList.remove('active');
modalContent.innerHTML = '';
document.body.style.overflow = ''
window.scrollTo({left: previousScrollOffset[0], top: previousScrollOffset[1], behavior: 'instant'});
};
closeBtn.addEventListener('click', closeModal);
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('active')) {
closeModal();
}
});
document.querySelectorAll('.mermaid').forEach((mermaidDiv) => {
if (mermaidDiv.parentNode.classList.contains('mermaid-container') ||
mermaidDiv.closest('.mermaid-fullscreen-modal')) {
// Already processed, adjust button class if needed
const existingBtn = mermaidDiv.parentNode.querySelector('.mermaid-fullscreen-btn');
if (existingBtn) {
existingBtn.className = 'mermaid-fullscreen-btn' + (darkTheme ? ' dark-theme' : '');
}
return;
}
const container = document.createElement('div');
container.className = 'mermaid-container';
mermaidDiv.parentNode.insertBefore(container, mermaidDiv);
container.appendChild(mermaidDiv);
const fullscreenBtn = document.createElement('button');
fullscreenBtn.className = 'mermaid-fullscreen-btn' + (darkTheme ? ' dark-theme' : '');
fullscreenBtn.setAttribute('aria-label', 'View diagram in fullscreen');
fullscreenBtn.textContent = '⛶';
fullscreenBtn.style.opacity = '50%';
// Calculate dynamic position based on diagram's margin and padding
const diagramStyle = window.getComputedStyle(mermaidDiv);
const marginTop = parseFloat(diagramStyle.marginTop) || 0;
const marginRight = parseFloat(diagramStyle.marginRight) || 0;
const paddingTop = parseFloat(diagramStyle.paddingTop) || 0;
const paddingRight = parseFloat(diagramStyle.paddingRight) || 0;
fullscreenBtn.style.top = `${marginTop + paddingTop + 4}px`;
fullscreenBtn.style.right = `${marginRight + paddingRight + 4}px`;
fullscreenBtn.addEventListener('click', () => {
previousScrollOffset = [window.scroll, window.scrollY];
const clone = mermaidDiv.cloneNode(true);
modalContent.innerHTML = '';
modalContent.appendChild(clone);
const svg = clone.querySelector('svg');
if (svg) {
svg.removeAttribute('width');
svg.removeAttribute('height');
svg.style.width = '100%';
svg.style.height = 'auto';
svg.style.maxWidth = '100%';
svg.style.sdisplay = 'block';
if ("False" === "True") {
setTimeout(() => {
const g = svg.querySelector('g');
if (g) {
var svgD3 = d3.select(svg);
svgD3.html("<g class='wrapper'>" + svgD3.html() + "</g>");
var inner = svgD3.select("g");
var zoom = d3.zoom().on("zoom", function(event) {
inner.attr("transform", event.transform);
});
svgD3.call(zoom);
}
}, 100);
}
}
modal.classList.add('active');
document.body.style.overflow = 'hidden';
});
container.appendChild(fullscreenBtn);
});
};
const load = async () => {
initStyles();
await runMermaid(true);
const reRunIfThemeChanges = async () => {
const newDarkTheme = isDarkTheme();
if (newDarkTheme !== darkTheme) {
darkTheme = newDarkTheme;
console.log("Theme change detected, re-running mermaid with", darkTheme ? "dark" : "default", "theme");
await mermaid.initialize(
{...JSON.parse(
`{"startOnLoad": false}`
),
...{ darkMode: darkTheme, theme: darkTheme ? 'dark' : 'default' },
}
);
await runMermaid(true);
}
};
// Update theme classes when theme changes
const themeObserver = new MutationObserver(reRunIfThemeChanges);
themeObserver.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class', 'style', 'data-theme']
});
themeObserver.observe(document.body, {
attributes: true,
attributeFilter: ['class', 'style', 'data-theme']
});
};
console.log("Initializing mermaid with", darkTheme ? "dark" : "default", "theme");
mermaid.initialize(
{...JSON.parse(
`{"startOnLoad": false}`
),
...{ darkMode: darkTheme, theme: darkTheme ? 'dark' : 'default' },
}
);
window.addEventListener("load", load);
window.runMermaid = runMermaid;</script>
<script>DOCUMENTATION_OPTIONS.pagename = 'deploiement/image-qcow2';</script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Recherche" href="../search.html" />
<link rel="next" title="Routeurs" href="routeurs.html" />
<link rel="prev" title="Architecture du cluster" href="architecture-cluster.html" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="docsearch:language" content="fr"/>
<meta name="docsearch:version" content="0.1" />
</head>
<body data-bs-spy="scroll" data-bs-target=".bd-toc-nav" data-offset="180" data-bs-root-margin="0px 0px -60%" data-default-mode="">
<div id="pst-skip-link" class="skip-link d-print-none"><a href="#main-content">Passer au contenu principal</a></div>
<div id="pst-scroll-pixel-helper"></div>
<button type="button" class="btn rounded-pill" id="pst-back-to-top">
<i class="fa-solid fa-arrow-up"></i>Haut de page</button>
<dialog id="pst-search-dialog">
<form class="bd-search d-flex align-items-center"
action="../search.html"
method="get">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="search"
class="form-control"
name="q"
placeholder="Search..."
aria-label="Search..."
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"/>
<span class="search-button__kbd-shortcut"><kbd class="kbd-shortcut__modifier">Ctrl</kbd>+<kbd>K</kbd></span>
</form>
</dialog>
<div class="pst-async-banner-revealer d-none">
<aside id="bd-header-version-warning" class="d-none d-print-none" aria-label="Alerte de version"></aside>
</div>
<header class="bd-header navbar navbar-expand-lg bd-navbar d-print-none">
</header>
<div class="bd-container">
<div class="bd-container__inner bd-page-width">
<dialog id="pst-primary-sidebar-modal"></dialog>
<div id="pst-primary-sidebar" class="bd-sidebar-primary bd-sidebar">
<div class="sidebar-header-items sidebar-primary__section">
</div>
<div class="sidebar-primary-items__start sidebar-primary__section">
<div class="sidebar-primary-item">
<a class="navbar-brand logo" href="../index.html">
<p class="title logo__title">Documentation two 0.1.0</p>
</a></div>
<div class="sidebar-primary-item">
<button class="btn search-button-field search-button__button pst-js-only" title="Recherche" aria-label="Recherche" data-bs-placement="bottom" data-bs-toggle="tooltip">
<i class="fa-solid fa-magnifying-glass"></i>
<span class="search-button__default-text">Recherche</span>
<span class="search-button__kbd-shortcut"><kbd class="kbd-shortcut__modifier">Ctrl</kbd>+<kbd class="kbd-shortcut__modifier">K</kbd></span>
</button></div>
<div class="sidebar-primary-item"><nav class="bd-links bd-docs-nav" aria-label="Main">
<div class="bd-toc-item navbar-nav active">
<ul class="nav bd-sidenav bd-sidenav__home-link">
<li class="toctree-l1">
<a class="reference internal" href="../index.html">
two
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading"><span class="caption-text">Mise en œuvre</span></p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1 has-children"><a class="reference internal" href="../demarrage/index.html">Démarrage</a><details><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul>
<li class="toctree-l2"><a class="reference internal" href="../demarrage/installation.html">Installation d’un hyperviseur</a></li>
<li class="toctree-l2"><a class="reference internal" href="../demarrage/premier-vpc.html">Premier VPC, premier subnet, première VM</a></li>
</ul>
</details></li>
<li class="toctree-l1 current active has-children"><a class="reference internal" href="index.html">Déploiement d’un cluster</a><details open="open"><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="architecture-cluster.html">Architecture du cluster</a></li>
<li class="toctree-l2 current active"><a class="current reference internal" href="#">Construction de l’image qcow2</a></li>
<li class="toctree-l2"><a class="reference internal" href="routeurs.html">Routeurs</a></li>
<li class="toctree-l2"><a class="reference internal" href="premier-hyperviseur.html">Premier hyperviseur</a></li>
<li class="toctree-l2"><a class="reference internal" href="route-reflector.html">VM route reflector</a></li>
</ul>
</details></li>
</ul>
<p aria-level="2" class="caption" role="heading"><span class="caption-text">Exploitation</span></p>
<ul class="nav bd-sidenav">
<li class="toctree-l1 has-children"><a class="reference internal" href="../exploitation/index.html">Exploitation</a><details><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul>
<li class="toctree-l2"><a class="reference internal" href="../exploitation/configuration.html">Configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="../exploitation/services.html">Services systemd</a></li>
<li class="toctree-l2 has-children"><a class="reference internal" href="../exploitation/api-agent/index.html">API de l’agent</a><details><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul>
<li class="toctree-l3"><a class="reference internal" href="../exploitation/api-agent/asynchronisme.html">Modèle asynchrone et codes de retour</a></li>
<li class="toctree-l3"><a class="reference internal" href="../exploitation/api-agent/reference.html">Référence</a></li>
</ul>
</details></li>
<li class="toctree-l2"><a class="reference internal" href="../exploitation/observabilite.html">Observabilité</a></li>
<li class="toctree-l2"><a class="reference internal" href="../exploitation/diagnostic.html">Diagnostic</a></li>
</ul>
</details></li>
</ul>
<p aria-level="2" class="caption" role="heading"><span class="caption-text">Interne</span></p>
<ul class="nav bd-sidenav">
<li class="toctree-l1 has-children"><a class="reference internal" href="../concepts/index.html">Concepts</a><details><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul>
<li class="toctree-l2"><a class="reference internal" href="../concepts/vpc-subnet-vm.html">VPC, subnet et VM</a></li>
<li class="toctree-l2"><a class="reference internal" href="../concepts/modes-reseau.html">Modes réseau</a></li>
<li class="toctree-l2"><a class="reference internal" href="../concepts/cycle-de-vie.html">Cycle de vie des ressources</a></li>
<li class="toctree-l2"><a class="reference internal" href="../concepts/metadata-cloud-init.html">Metadata et cloud-init</a></li>
</ul>
</details></li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../architecture/index.html">Architecture</a><details><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul>
<li class="toctree-l2"><a class="reference internal" href="../architecture/vue-densemble.html">Vue d’ensemble</a></li>
<li class="toctree-l2"><a class="reference internal" href="../architecture/stockage.html">Schéma des clés</a></li>
<li class="toctree-l2"><a class="reference internal" href="../architecture/contraintes.html">Invariants et pièges</a></li>
</ul>
</details></li>
<li class="toctree-l1 has-children"><a class="reference internal" href="../versions/index.html">Versions</a><details><summary><span class="toctree-toggle" role="presentation"><i class="fa-solid fa-chevron-down"></i></span></summary><ul>
<li class="toctree-l2"><a class="reference internal" href="../versions/0.2.0.html">Bael</a></li>
<li class="toctree-l2"><a class="reference internal" href="../versions/0.1.0.html">Michael</a></li>
</ul>
</details></li>
</ul>
</div>
</nav></div>
</div>
<div class="sidebar-primary-items__end sidebar-primary__section">
<div class="sidebar-primary-item">
<div id="ethical-ad-placement"
class="flat"
data-ea-publisher="readthedocs"
data-ea-type="readthedocs-sidebar"
data-ea-manual="true">
</div></div>
</div>
</div>
<main id="main-content" class="bd-main" role="main">
<div class="sbt-scroll-pixel-helper"></div>
<div class="bd-content">
<div class="bd-article-container">
<div class="bd-header-article d-print-none">
<div class="header-article-items header-article__inner">
<div class="header-article-items__start">
<div class="header-article-item"><button class="sidebar-toggle primary-toggle btn btn-sm" title="Toggle primary sidebar" data-bs-placement="bottom" data-bs-toggle="tooltip">
<span class="fa-solid fa-bars"></span>
</button></div>
</div>
<div class="header-article-items__end">
<div class="header-article-item">
<div class="article-header-buttons">
<div class="dropdown dropdown-download-buttons">
<button class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Téléchargez cette page">
<i class="fas fa-download"></i>
</button>
<ul class="dropdown-menu">
<li><a href="../_sources/deploiement/image-qcow2.rst" target="_blank"
class="btn btn-sm btn-download-source-button dropdown-item"
title="Télécharger le fichier source"
data-bs-placement="left" data-bs-toggle="tooltip"
>
<span class="btn__icon-container">
<i class="fas fa-file"></i>
</span>
<span class="btn__text-container">.rst</span>
</a>
</li>
<li>
<button onclick="window.print()"
class="btn btn-sm btn-download-pdf-button dropdown-item"
title="Imprimer au format PDF"
data-bs-placement="left" data-bs-toggle="tooltip"
>
<span class="btn__icon-container">
<i class="fas fa-file-pdf"></i>
</span>
<span class="btn__text-container">.pdf</span>
</button>
</li>
</ul>
</div>
<button onclick="toggleFullScreen()"
class="btn btn-sm btn-fullscreen-button pst-navbar-icon"
title="Mode plein écran"
data-bs-placement="bottom" data-bs-toggle="tooltip"
>
<span class="btn__icon-container">
<i class="fas fa-expand"></i>
</span>
</button>
<button class="btn btn-sm nav-link pst-navbar-icon theme-switch-button pst-js-only" aria-label="Thème" data-bs-title="Thème" data-bs-placement="bottom" data-bs-toggle="tooltip">
<i class="theme-switch fa-solid fa-sun fa-lg" data-mode="light" title="Clair"></i>
<i class="theme-switch fa-solid fa-moon fa-lg" data-mode="dark" title="Sombre"></i>
<i class="theme-switch fa-solid fa-circle-half-stroke fa-lg" data-mode="auto" title="Paramètres système"></i>
</button>
<button class="btn btn-sm pst-navbar-icon search-button search-button__button pst-js-only" title="Recherche" aria-label="Recherche" data-bs-placement="bottom" data-bs-toggle="tooltip">
<i class="fa-solid fa-magnifying-glass fa-lg"></i>
</button>
<button class="sidebar-toggle secondary-toggle btn btn-sm pst-navbar-icon" title="Toggle secondary sidebar" data-bs-placement="bottom" data-bs-toggle="tooltip">
<span class="fa-solid fa-list"></span>
</button>
</div></div>
</div>
</div>
</div>
<div id="jb-print-docs-body" class="onlyprint">
<h1>Construction de l’image qcow2</h1>
<!-- Table of contents -->
<div id="print-main-content">
<div id="jb-print-toc">
<div>
<h2> Contenu </h2>
</div>
<nav aria-label="Page">
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#principe">Principe</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#variables">Variables</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-1-le-seed-cloud-init-de-la-vm-de-construction">Étape 1 — Le seed cloud-init de la VM de construction</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-2-les-disques">Étape 2 — Les disques</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-3-lancer-la-vm-de-construction">Étape 3 — Lancer la VM de construction</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-4-ecrire-l-image-du-fournisseur-sur-le-disque-cible">Étape 4 — Écrire l’image du fournisseur sur le disque cible</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-5-personnaliser-l-image">Étape 5 — Personnaliser l’image</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-6-nettoyer-puis-eteindre">Étape 6 — Nettoyer, puis éteindre</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#points-de-vigilance">Points de vigilance</a></li>
</ul>
</nav>
</div>
</div>
</div>
<div id="searchbox"></div>
<article class="bd-article">
<section id="construction-de-l-image-qcow2">
<h1>Construction de l’image qcow2<a class="headerlink" href="#construction-de-l-image-qcow2" title="Lien vers cette rubrique">#</a></h1>
<p>Toutes les VM du cluster — <code class="docutils literal notranslate"><span class="pre">intel</span></code>, PostgreSQL, route reflector et les suivantes — partent
d’une même image qcow2 « golden », construite une fois puis réutilisée. Cette page décrit la
procédure en service.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Cette image est un <strong>artefact redistribuable</strong> : tout ce qui s’y trouve se retrouve dans
chaque VM qui en dérive. Les étapes de nettoyage de la fin ne sont pas une commodité, ce sont
des exigences.</p>
</div>
<section id="principe">
<h2>Principe<a class="headerlink" href="#principe" title="Lien vers cette rubrique">#</a></h2>
<p>La construction se fait dans une <strong>VM jetable</strong>, et non par montage de l’image sur l’host : le
chroot a besoin d’un noyau et d’un espace utilisateur cohérents avec la distribution cible, ce
que l’host ne fournit pas nécessairement.</p>
<p>Cette VM de construction démarre sur un overlay de l’image du fournisseur et voit deux disques
supplémentaires : le futur disque « golden », et un espace de travail.</p>
<pre class="mermaid">
graph LR
ISO[&quot;seed.iso&lt;br/&gt;cloud-init NoCloud&quot;] --&gt; BVM
OVL[&quot;&amp;lt;os&amp;gt;-tmp.qcow2&lt;br/&gt;&lt;i&gt;overlay, jetable&lt;/i&gt;&quot;] --&gt; BVM[&quot;VM de construction&quot;]
BVM --&gt; ROOT[&quot;&amp;lt;os&amp;gt;-root.qcow2&lt;br/&gt;&lt;b&gt;image golden&lt;/b&gt;&quot;]
BVM --&gt; WORK[&quot;tmp.qcow2&lt;br/&gt;&lt;i&gt;espace de travail&lt;/i&gt;&quot;]
BASE[&quot;image du fournisseur&lt;br/&gt;(qcow2)&quot;] -.backing file.-&gt; OVL
</pre><div class="pst-scrollable-table-container"><table class="table">
<colgroup>
<col style="width: 26.0%" />
<col style="width: 20.0%" />
<col style="width: 54.0%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Disque</p></th>
<th class="head"><p>Vu dans la VM</p></th>
<th class="head"><p>Rôle</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">&lt;os&gt;-tmp.qcow2</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">vda</span></code> (virtio-blk)</p></td>
<td><p>système de la VM de construction ; overlay de l’image du fournisseur, jeté à la fin</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">&lt;os&gt;-root.qcow2</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">sda</span></code> (SCSI)</p></td>
<td><p><strong>le résultat</strong> : l’image golden, écrite en brut depuis la VM</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">tmp.qcow2</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">sdb</span></code> (SCSI)</p></td>
<td><p>espace de travail : téléchargement et conversion</p></td>
</tr>
</tbody>
</table>
</div>
</section>
<section id="variables">
<h2>Variables<a class="headerlink" href="#variables" title="Lien vers cette rubrique">#</a></h2>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nb">export</span><span class="w"> </span><span class="nv">os</span><span class="o">=</span>&lt;nom_os&gt;
<span class="nb">export</span><span class="w"> </span><span class="nv">os_link</span><span class="o">=</span>&lt;url_du_qcow2_fournisseur&gt;
<span class="nb">export</span><span class="w"> </span><span class="nv">os_file</span><span class="o">=</span>&lt;nom_du_fichier_qcow2&gt;
<span class="nb">export</span><span class="w"> </span><span class="nv">os_dir</span><span class="o">=</span>&lt;repertoire_de_telechargement&gt;
<span class="nb">export</span><span class="w"> </span><span class="nv">disk_dir</span><span class="o">=</span>&lt;repertoire_des_disques&gt;
</pre></div>
</div>
</section>
<section id="etape-1-le-seed-cloud-init-de-la-vm-de-construction">
<h2>Étape 1 — Le seed cloud-init de la VM de construction<a class="headerlink" href="#etape-1-le-seed-cloud-init-de-la-vm-de-construction" title="Lien vers cette rubrique">#</a></h2>
<p>Ce seed ne concerne <strong>que la VM de construction</strong>. Il n’a aucun rapport avec la configuration
cloud-init de l’image produite, qui est posée plus loin en chroot. Son seul rôle est de donner
un accès à la VM le temps du build.</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>mkdir<span class="w"> </span>-p<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_dir</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nb">cd</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_dir</span><span class="si">}</span><span class="s2">"</span>
mkdir<span class="w"> </span>-p<span class="w"> </span>/opt/seed/<span class="si">${</span><span class="nv">os</span><span class="si">}</span>
cat<span class="w"> </span><span class="s">&lt;&lt; 'ENDFILE' &gt; /opt/seed/${os}/meta-data</span>
<span class="s">instance-id: iid-local01</span>
<span class="s">local-hostname: my-vm-01</span>
<span class="s">ENDFILE</span>
cat<span class="w"> </span><span class="s">&lt;&lt; 'ENDFILE' &gt; /opt/seed/${os}/network-config</span>
<span class="s">version: 2</span>
<span class="s">renderer: networkd</span>
<span class="s">ethernets:</span>
<span class="s"> eth0:</span>
<span class="s"> dhcp4: true</span>
<span class="s">ENDFILE</span>
cat<span class="w"> </span><span class="s">&lt;&lt; 'ENDFILE' &gt; /opt/seed/${os}/user-data</span>
<span class="s">#cloud-config</span>
<span class="s">users:</span>
<span class="s"> - name: &lt;utilisateur&gt;</span>
<span class="s"> lock_passwd: false</span>
<span class="s"> passwd: "&lt;hash du mot de passe&gt;"</span>
<span class="s"> sudo: ALL=(ALL) NOPASSWD:ALL</span>
<span class="s"> ssh_authorized_keys:</span>
<span class="s"> - &lt;clé publique ssh&gt;</span>
<span class="s">ENDFILE</span>
mkisofs<span class="w"> </span>-o<span class="w"> </span>/opt/seed/<span class="si">${</span><span class="nv">os</span><span class="si">}</span>_seed.iso<span class="w"> </span>-V<span class="w"> </span>cidata<span class="w"> </span>-J<span class="w"> </span>-r<span class="w"> </span>/opt/seed/<span class="si">${</span><span class="nv">os</span><span class="si">}</span>/
</pre></div>
</div>
<p>Le label de volume <code class="docutils literal notranslate"><span class="pre">cidata</span></code> n’est pas décoratif : c’est ce qui fait reconnaître l’ISO comme une
source NoCloud par cloud-init.</p>
<div class="admonition warning">
<p class="admonition-title">Avertissement</p>
<p><code class="docutils literal notranslate"><span class="pre">passwd</span></code> attend un <strong>hash</strong>, et <code class="docutils literal notranslate"><span class="pre">ssh_authorized_keys</span></code> une clé publique personnelle : ces
deux valeurs sont des données à ne pas recopier hors de l’host de construction. Elles ne
figurent volontairement pas dans cette documentation.</p>
<p><code class="docutils literal notranslate"><span class="pre">openssl</span> <span class="pre">passwd</span> <span class="pre">-5</span></code> pour generer un hash</p>
</div>
</section>
<section id="etape-2-les-disques">
<h2>Étape 2 — Les disques<a class="headerlink" href="#etape-2-les-disques" title="Lien vers cette rubrique">#</a></h2>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>curl<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_link</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>-O
qemu-img<span class="w"> </span>create<span class="w"> </span>-f<span class="w"> </span>qcow2<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">disk_dir</span><span class="si">}</span><span class="s2">/</span><span class="si">${</span><span class="nv">os</span><span class="si">}</span><span class="s2">-root.qcow2"</span><span class="w"> </span>10G
qemu-img<span class="w"> </span>create<span class="w"> </span>-f<span class="w"> </span>qcow2<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">disk_dir</span><span class="si">}</span><span class="s2">/tmp.qcow2"</span><span class="w"> </span>50G
qemu-img<span class="w"> </span>create<span class="w"> </span>-f<span class="w"> </span>qcow2<span class="w"> </span>-b<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_dir</span><span class="si">}</span><span class="s2">/</span><span class="si">${</span><span class="nv">os_file</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>-F<span class="w"> </span>qcow2<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">disk_dir</span><span class="si">}</span><span class="s2">/</span><span class="si">${</span><span class="nv">os</span><span class="si">}</span><span class="s2">-tmp.qcow2"</span><span class="w"> </span>10G
</pre></div>
</div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p><code class="docutils literal notranslate"><span class="pre">-F</span> <span class="pre">qcow2</span></code> est <strong>obligatoire</strong> sur qemu récent : sans lui, le format du backing file n’est
pas figé dans l’en-tête de l’overlay.</p>
</div>
<p>La taille de <code class="docutils literal notranslate"><span class="pre">&lt;os&gt;-root.qcow2</span></code> (10 Gio ici) borne l’image produite : elle doit être au moins
égale à la taille <strong>virtuelle</strong> de l’image du fournisseur, pas à la taille de son fichier.</p>
</section>
<section id="etape-3-lancer-la-vm-de-construction">
<h2>Étape 3 — Lancer la VM de construction<a class="headerlink" href="#etape-3-lancer-la-vm-de-construction" title="Lien vers cette rubrique">#</a></h2>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>qemu-system-x86_64<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-enable-kvm<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-cpu<span class="w"> </span>host<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-m<span class="w"> </span><span class="m">2048</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-smp<span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-nographic<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-serial<span class="w"> </span>mon:stdio<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-monitor<span class="w"> </span>unix:/tmp/vm-build.mon-sock,server,nowait<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-drive<span class="w"> </span><span class="nv">file</span><span class="o">=</span>/opt/seed/<span class="si">${</span><span class="nv">os</span><span class="si">}</span>_seed.iso,media<span class="o">=</span>cdrom,if<span class="o">=</span>ide<span class="w"> </span><span class="se">\</span>
<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-drive<span class="w"> </span><span class="nv">file</span><span class="o">=</span><span class="si">${</span><span class="nv">disk_dir</span><span class="si">}</span>/<span class="si">${</span><span class="nv">os</span><span class="si">}</span>-tmp.qcow2,format<span class="o">=</span>qcow2,if<span class="o">=</span>none,id<span class="o">=</span>vda<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-device<span class="w"> </span>virtio-blk-pci,drive<span class="o">=</span>vda,bootindex<span class="o">=</span><span class="m">0</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-device<span class="w"> </span>virtio-scsi-pci,id<span class="o">=</span>scsi0<span class="w"> </span><span class="se">\</span>
<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-drive<span class="w"> </span><span class="nv">file</span><span class="o">=</span><span class="si">${</span><span class="nv">disk_dir</span><span class="si">}</span>/<span class="si">${</span><span class="nv">os</span><span class="si">}</span>-root.qcow2,if<span class="o">=</span>none,id<span class="o">=</span>hd0<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-device<span class="w"> </span>scsi-hd,drive<span class="o">=</span>hd0,bus<span class="o">=</span>scsi0.0<span class="w"> </span><span class="se">\</span>
<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-drive<span class="w"> </span><span class="nv">file</span><span class="o">=</span><span class="si">${</span><span class="nv">disk_dir</span><span class="si">}</span>/tmp.qcow2,if<span class="o">=</span>none,id<span class="o">=</span>hd1<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-device<span class="w"> </span>scsi-hd,drive<span class="o">=</span>hd1,bus<span class="o">=</span>scsi0.0<span class="w"> </span><span class="se">\</span>
<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-netdev<span class="w"> </span>tap,id<span class="o">=</span>net0,ifname<span class="o">=</span>tap0,script<span class="o">=</span>no,downscript<span class="o">=</span>no<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>-device<span class="w"> </span>virtio-net-pci,netdev<span class="o">=</span>net0,mac<span class="o">=</span><span class="m">00</span>:22:33:00:00:01
</pre></div>
</div>
<p>La répartition virtio-blk pour le système / SCSI pour les disques supplémentaires est la même que
celle qu’impose l’agent — voir <a class="reference internal" href="../architecture/contraintes.html"><span class="doc">Invariants et pièges</span></a>. Le tap <code class="docutils literal notranslate"><span class="pre">tap0</span></code> doit exister et
être raccordé à un réseau qui donne un accès sortant : la suite télécharge l’image du
fournisseur depuis la VM.</p>
</section>
<section id="etape-4-ecrire-l-image-du-fournisseur-sur-le-disque-cible">
<h2>Étape 4 — Écrire l’image du fournisseur sur le disque cible<a class="headerlink" href="#etape-4-ecrire-l-image-du-fournisseur-sur-le-disque-cible" title="Lien vers cette rubrique">#</a></h2>
<p>Les commandes suivantes s’exécutent <strong>dans la VM de construction</strong>. Identifier d’abord les
disques : le disque de travail et le disque cible ne doivent pas être confondus.</p>
<div class="admonition danger">
<p class="admonition-title">Danger</p>
<p><code class="docutils literal notranslate"><span class="pre">qemu-img</span> <span class="pre">convert</span></code> écrase intégralement le disque cible. Vérifier les noms avant, avec
<code class="docutils literal notranslate"><span class="pre">lsblk</span></code>, plutôt que de supposer l’ordre d’énumération.</p>
</div>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nv">work_disk</span><span class="o">=</span>/dev/sdb
<span class="nv">os_disk</span><span class="o">=</span>/dev/sda
mkdir<span class="w"> </span>/work
mkfs.xfs<span class="w"> </span><span class="si">${</span><span class="nv">work_disk</span><span class="si">}</span>
mount<span class="w"> </span><span class="si">${</span><span class="nv">work_disk</span><span class="si">}</span><span class="w"> </span>/work
<span class="nb">cd</span><span class="w"> </span>/work
curl<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_link</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>-O
qemu-img<span class="w"> </span>convert<span class="w"> </span>./*.qcow2<span class="w"> </span>-O<span class="w"> </span>raw<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_disk</span><span class="si">}</span><span class="s2">"</span>
</pre></div>
</div>
<p>L’image du fournisseur est écrite <strong>en brut</strong> directement sur le disque cible : le qcow2 obtenu
côté host contient donc une image disque complète et amorçable, sans backing file.</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>partprobe
<span class="nb">echo</span><span class="w"> </span><span class="m">1</span><span class="w"> </span>&gt;<span class="w"> </span>/sys/block/sda/device/rescan
sleep<span class="w"> </span><span class="m">2</span>
<span class="c1"># La partition racine est la plus grande du disque</span>
<span class="nv">root_partition</span><span class="o">=</span><span class="k">$(</span>fdisk<span class="w"> </span>-lo<span class="w"> </span>device,size<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">os_disk</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-E<span class="w"> </span><span class="s1">'^/dev/'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tr<span class="w"> </span>-s<span class="w"> </span><span class="s1">' '</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span><span class="p">|</span><span class="w"> </span>sort<span class="w"> </span>-rhk2<span class="w"> </span><span class="p">|</span><span class="w"> </span>head<span class="w"> </span>-n1<span class="w"> </span><span class="p">|</span><span class="w"> </span>cut<span class="w"> </span>-d<span class="w"> </span><span class="s1">' '</span><span class="w"> </span>-f1<span class="k">)</span>
mount<span class="w"> </span>-o<span class="w"> </span>nouuid<span class="w"> </span><span class="nv">$root_partition</span><span class="w"> </span>/mnt
mount<span class="w"> </span>-o<span class="w"> </span><span class="nb">bind</span><span class="w"> </span>/dev<span class="w"> </span>/mnt/dev
mount<span class="w"> </span>-o<span class="w"> </span><span class="nb">bind</span><span class="w"> </span>/proc<span class="w"> </span>/mnt/proc
mount<span class="w"> </span>-o<span class="w"> </span><span class="nb">bind</span><span class="w"> </span>/sys<span class="w"> </span>/mnt/sys
cp<span class="w"> </span>/etc/resolv.conf<span class="w"> </span>/mnt/etc/resolv.conf
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">-o</span> <span class="pre">nouuid</span></code> est nécessaire parce que le système de fichiers qui vient d’être écrit porte le
même UUID que celui déjà monté par la VM de construction. Le <code class="docutils literal notranslate"><span class="pre">resolv.conf</span></code> est copié pour que
les commandes en chroot aient la résolution DNS ; il est supprimé au nettoyage.</p>
</section>
<section id="etape-5-personnaliser-l-image">
<h2>Étape 5 — Personnaliser l’image<a class="headerlink" href="#etape-5-personnaliser-l-image" title="Lien vers cette rubrique">#</a></h2>
<p><strong>Accès SSH</strong></p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>yum<span class="w"> </span>install<span class="w"> </span>-y<span class="w"> </span>augeas
<span class="nb">echo</span><span class="w"> </span><span class="s2">"The default user for Syonad VMs is 'syonad'."</span><span class="w"> </span>&gt;<span class="w"> </span>/mnt/etc/banner
augtool<span class="w"> </span>-r<span class="w"> </span>/mnt<span class="w"> </span>-s<span class="w"> </span><span class="s">&lt;&lt;'EOF'</span>
<span class="s">set /files/etc/ssh/sshd_config/X11Forwarding no</span>
<span class="s">set /files/etc/ssh/sshd_config/PermitTunnel no</span>
<span class="s">set /files/etc/ssh/sshd_config/PermitRootLogin no</span>
<span class="s">set /files/etc/ssh/sshd_config/RSAAuthentication yes</span>
<span class="s">set /files/etc/ssh/sshd_config/PubkeyAuthentication yes</span>
<span class="s">set /files/etc/ssh/sshd_config/PasswordAuthentication no</span>
<span class="s">set /files/etc/ssh/sshd_config/UseDNS no</span>
<span class="s">set /files/etc/ssh/sshd_config/ChallengeResponseAuthentication no</span>
<span class="s">set /files/etc/ssh/sshd_config/GSSAPIAuthentication no</span>
<span class="s">set /files/etc/ssh/sshd_config/Match[1]/Condition/User "root,centos,ubuntu,debian,ec2-user"</span>
<span class="s">set /files/etc/ssh/sshd_config/Match[1]/Settings/Banner "/etc/banner"</span>
<span class="s">EOF</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">PasswordAuthentication</span> <span class="pre">no</span></code> vaut pour toutes les VM dérivées : l’accès se fait par clé, et le
champ <code class="docutils literal notranslate"><span class="pre">password</span></code> de l’API de l’agent ne sert donc <strong>pas</strong> à ouvrir une session SSH.</p>
<p><strong>Utilisateur par défaut et source de metadata</strong></p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>cat<span class="w"> </span><span class="s">&lt;&lt; 'ENDFILE' &gt; /mnt/etc/cloud/cloud.cfg.d/20_user.cfg</span>
<span class="s">system_info:</span>
<span class="s"> default_user:</span>
<span class="s"> name: syonad</span>
<span class="s">ENDFILE</span>
cat<span class="w"> </span><span class="s">&lt;&lt; 'ENDFILE' &gt; /mnt/etc/cloud/cloud.cfg.d/99_metadata.cfg</span>
<span class="s">datasource_list: [ NoCloud ]</span>
<span class="s">datasource:</span>
<span class="s"> NoCloud:</span>
<span class="s"> seedfrom: 'http://169.254.169.254:80'</span>
<span class="s"> timeout: 5</span>
<span class="s"> max_wait: 10</span>
<span class="s">ENDFILE</span>
</pre></div>
</div>
<p>C’est ce second fichier qui raccorde l’image au serveur de metadata de l’agent : <code class="docutils literal notranslate"><span class="pre">NoCloud</span></code> est
la seule source retenue, et elle pointe sur <code class="docutils literal notranslate"><span class="pre">169.254.169.254</span></code>. La route <code class="docutils literal notranslate"><span class="pre">/32</span></code> vers cette
adresse est indispensable côté agent — voir <a class="reference internal" href="../concepts/modes-reseau.html"><span class="doc">Modes réseau</span></a>.</p>
<p><strong>Services et durcissement</strong></p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>chroot<span class="w"> </span>/mnt/<span class="w"> </span>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>fstrim.timer
chroot<span class="w"> </span>/mnt/<span class="w"> </span>systemctl<span class="w"> </span>disable<span class="w"> </span>rpcbind.service
chroot<span class="w"> </span>/mnt/<span class="w"> </span>systemctl<span class="w"> </span>disable<span class="w"> </span>rpcbind.socket
augtool<span class="w"> </span>-r<span class="w"> </span>/mnt<span class="w"> </span>-s<span class="w"> </span><span class="nb">set</span><span class="w"> </span>/files/etc/selinux/config/SELINUX<span class="w"> </span>disabled
chroot<span class="w"> </span>/mnt/<span class="w"> </span>dnf<span class="w"> </span>remove<span class="w"> </span>-y<span class="w"> </span><span class="s1">'cockpit*'</span>
chroot<span class="w"> </span>/mnt/<span class="w"> </span>rm<span class="w"> </span>-rf<span class="w"> </span>/run/cockpit
</pre></div>
</div>
</section>
<section id="etape-6-nettoyer-puis-eteindre">
<h2>Étape 6 — Nettoyer, puis éteindre<a class="headerlink" href="#etape-6-nettoyer-puis-eteindre" title="Lien vers cette rubrique">#</a></h2>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span>rm<span class="w"> </span>-f<span class="w"> </span>/mnt/etc/resolv.conf
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/var/cache/yum
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/root/.ssh
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/root/.bash_history
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/tmp/*
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/var/lib/dhcp/*
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/var/tmp/*
find<span class="w"> </span>/mnt/var/log<span class="w"> </span>!<span class="w"> </span>-type<span class="w"> </span>d<span class="w"> </span>-exec<span class="w"> </span>rm<span class="w"> </span><span class="s1">'{}'</span><span class="w"> </span><span class="se">\;</span>
rm<span class="w"> </span>-rf<span class="w"> </span>/mnt/var/lib/cloud/*
poweroff
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">/mnt/var/lib/cloud/*</span></code> est le nettoyage le plus important : c’est lui qui fait que cloud-init
considère chaque VM dérivée comme une instance neuve. Sans lui, l’image embarque l’identité de
l’instance de construction et le user-data n’est pas appliqué — même mécanisme que la
recréation d’une VM sous un nom déjà utilisé, cf. <a class="reference internal" href="../concepts/metadata-cloud-init.html"><span class="doc">Metadata et cloud-init</span></a>.</p>
<p>Une fois la VM éteinte, <code class="docutils literal notranslate"><span class="pre">${disk_dir}/${os}-root.qcow2</span></code> est l’image golden.
<code class="docutils literal notranslate"><span class="pre">${os}-tmp.qcow2</span></code> et <code class="docutils literal notranslate"><span class="pre">tmp.qcow2</span></code> sont jetables.</p>
</section>
<section id="points-de-vigilance">
<h2>Points de vigilance<a class="headerlink" href="#points-de-vigilance" title="Lien vers cette rubrique">#</a></h2>
<div class="admonition warning">
<p class="admonition-title">Avertissement</p>
<p><strong>SELinux est désactivé</strong> dans l’image. C’est une couche de protection en moins sur toutes les
VM qui en dérivent, y compris celles qui portent des fonctions sensibles comme le route
reflector ou la base de données. Décision à assumer explicitement, et à réévaluer : le mode
<code class="docutils literal notranslate"><span class="pre">permissive</span></code> permettrait au minimum de savoir ce qui serait bloqué.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><code class="docutils literal notranslate"><span class="pre">fstrim.timer</span></code> est activé dans l’image, mais l’agent lance QEMU <strong>sans</strong> <code class="docutils literal notranslate"><span class="pre">discard=unmap</span></code>
ni <code class="docutils literal notranslate"><span class="pre">detect-zeroes=unmap</span></code> sur les disques. Le <code class="docutils literal notranslate"><span class="pre">fstrim</span></code> du guest ne rend donc aujourd’hui
aucun espace à l’host : les qcow2 ne se rétractent pas. L’activation reste utile pour le jour
où l’option sera ajoutée côté agent, mais ne pas compter dessus pour la place disque.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><strong>À vérifier</strong> — <code class="docutils literal notranslate"><span class="pre">seedfrom</span></code> sans barre oblique finale. cloud-init construit l’URL des
documents en concaténant <code class="docutils literal notranslate"><span class="pre">seedfrom</span></code> avec <code class="docutils literal notranslate"><span class="pre">meta-data</span></code> et <code class="docutils literal notranslate"><span class="pre">user-data</span></code>. Confirmer sur une
VM réelle que les deux documents sont bien récupérés, et corriger en
<code class="docutils literal notranslate"><span class="pre">http://169.254.169.254:80/</span></code> si ce n’est pas le cas.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><strong>Provenance de l’image du fournisseur</strong> — tout ce qui est construit en hérite. Vérifier la
somme de contrôle, et la signature quand elle existe, avant de construire dessus. La
procédure actuelle télécharge l’image deux fois, une fois sur l’host et une fois dans la VM,
sans vérification.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><strong>À rédiger</strong> — la procédure ne dit pas encore comment l’image produite est nommée, versionnée
et distribuée aux hyperviseurs, ni quelles variantes existent par rôle (<code class="docutils literal notranslate"><span class="pre">intel</span></code>, PostgreSQL,
route reflector) : image unique personnalisée au démarrage par cloud-init, ou images
dérivées ?</p>
</div>
</section>
</section>
</article>
<footer class="prev-next-footer d-print-none">
<div class="prev-next-area">
<a class="left-prev"
href="architecture-cluster.html"
title="page précédente">
<i class="fa-solid fa-angle-left"></i>
<div class="prev-next-info">
<p class="prev-next-subtitle">précédent</p>
<p class="prev-next-title">Architecture du cluster</p>
</div>
</a>
<a class="right-next"
href="routeurs.html"
title="page suivante">
<div class="prev-next-info">
<p class="prev-next-subtitle">suivant</p>
<p class="prev-next-title">Routeurs</p>
</div>
<i class="fa-solid fa-angle-right"></i>
</a>
</div>
</footer>
</div>
<dialog id="pst-secondary-sidebar-modal"></dialog>
<div id="pst-secondary-sidebar" class="bd-sidebar-secondary bd-toc"><div class="sidebar-secondary-items sidebar-secondary__inner">
<div class="sidebar-secondary-item"><div
id="pst-page-navigation-heading-2"
class="page-toc tocsection onthispage">
<i class="fa-solid fa-list"></i> Contenu
</div>
<nav id="pst-page-toc-nav" class="page-toc" aria-labelledby="pst-page-navigation-heading-2">
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#principe">Principe</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#variables">Variables</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-1-le-seed-cloud-init-de-la-vm-de-construction">Étape 1 — Le seed cloud-init de la VM de construction</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-2-les-disques">Étape 2 — Les disques</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-3-lancer-la-vm-de-construction">Étape 3 — Lancer la VM de construction</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-4-ecrire-l-image-du-fournisseur-sur-le-disque-cible">Étape 4 — Écrire l’image du fournisseur sur le disque cible</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-5-personnaliser-l-image">Étape 5 — Personnaliser l’image</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#etape-6-nettoyer-puis-eteindre">Étape 6 — Nettoyer, puis éteindre</a></li>
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#points-de-vigilance">Points de vigilance</a></li>
</ul>
</nav></div>
</div></div>
</div>
<footer class="bd-footer-content">
<div class="bd-footer-content__inner container">
<div class="footer-item">
<p class="component-author">
Par Nicolas Boufidjeline
</p>
</div>
<div class="footer-item">
<p class="copyright">
© Copyright 2026, Nicolas Boufidjeline.
<br/>
</p>
</div>
<div class="footer-item">
</div>
<div class="footer-item">
</div>
</div>
</footer>
</main>
</div>
</div>
<!-- Scripts loaded after <body> so the DOM is not blocked -->
<script defer src="../_static/scripts/bootstrap.js?digest=8878045cc6db502f8baf"></script>
<script defer src="../_static/scripts/pydata-sphinx-theme.js?digest=8878045cc6db502f8baf"></script>
<footer class="bd-footer">
</footer>
</body>
</html>