yannstatic/static/2023/04/12/Podman_developper-gerer-executer_des_conteneurs.html

2484 lines
220 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Podman développer, gérer et exécuter des conteneurs - YannStatic</title>
<meta name="description" content="">
<link rel="canonical" href="https://static.rnmkcy.eu/2023/04/12/Podman_developper-gerer-executer_des_conteneurs.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
2024-11-28 11:42:23 +01:00
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/syntaxe-markdown.html">Aide</a></li></ul>
2024-10-31 20:18:37 +01:00
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Podman développer, gérer et exécuter des conteneurs</h1></header></div><meta itemprop="headline" content="Podman développer, gérer et exécuter des conteneurs"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=virtuel">virtuel</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">12&nbsp;avr.&nbsp;&nbsp;2023</span></li></ul></div><meta itemprop="datePublished" content="2023-04-12T00:00:00+02:00">
<meta itemprop="keywords" content="virtuel"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><p><img src="/images/podman-logo.png" alt="" /></p>
<p><em>Podman (« POD manager ») est un outil Open Source qui sert à développer, gérer et exécuter des conteneurs sur des systèmes Linux®. Développé par des ingénieurs Red Hat® et des membres de la communauté Open Source, Podman gère lensemble de lécosystème de conteneurs à laide de la bibliothèque libpod.<br />
Son architecture inclusive et sans démon le rend plus accessible et sécurisé pour gérer les conteneurs.Ceci permet daccéder aux différentes applications virtualisées sans droits root.<br />
Il est également possible dutiliser les principales commandes de Docker dans Podman, il suffit dutiliser lalias <code class="language-plaintext highlighter-rouge">alias docker=podman</code></em></p>
<p>Podman se distingue également par ses pods qui sont un regroupement de plusieurs conteneurs au sein dun namespace Linux commun et partageant certaines ressources.<br />
Podman permet dexécuter les différents conteneurs sur lhôte en tant quutilisateur habituel, sans droits root.
Les processus nécessitent uniquement des droits root au sein dun conteneur.</p>
<p>Le noyau dun pod est formé par des <strong>infraconteneurs</strong> responsables exclusivement de la fonctionnalité du groupe et ayant pour fonction de gérer et de garantir les différentes ressources comme les namespaces, les ports réseau, le processeur, la mémoire vive, etc. <br />
Podman utilise loutil de monitoring codé en C <strong>Conmon</strong> qui surveille les différents composants virtualisés et sécurise par exemple les journaux et il sert également dinterface avec le terminal du conteneur concerné.Podman utilise en plus le logiciel <strong>runC</strong>.<br />
<img src="/images/podman001.png" alt="" height="200" /></p>
<h2 id="podman-sur-arch-linux">Podman sur Arch Linux</h2>
<h3 id="installation">Installation</h3>
<p>Mettez à jour votre système Arch / Manjaro.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>pacman <span class="nt">-Sy</span> archlinux-keyring
<span class="nb">sudo </span>pacman-key <span class="nt">--populate</span> archlinux
<span class="nb">sudo </span>pacman <span class="nt">-Syyu</span>
</code></pre></div></div>
<p>Une fois tous les packages mis à jour, procédez à linstallation de Podman sur Arch Linux / Manjaro.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -S podman
</code></pre></div></div>
<p>version de Podman installée</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman <span class="nt">--version</span>
<span class="c"># podman version 4.4.4</span>
</code></pre></div></div>
<p>Vous pouvez également exécuter la commande <code class="language-plaintext highlighter-rouge">podman info</code> ci-dessous pour obtenir plus dinformations sur votre installation Podman.</p>
<details>
<summary><b>Etendre Réduire "podman info"</b></summary>
<figure class="highlight"><pre><code class="language-text" data-lang="text">
host:
arch: amd64
buildahVersion: 1.29.0
cgroupControllers:
- cpu
- memory
- pids
cgroupManager: systemd
cgroupVersion: v2
conmon:
package: /usr/bin/conmon appartient à conmon 1:2.1.7-1
path: /usr/bin/conmon
version: 'conmon version 2.1.7, commit: f633919178f6c8ee4fb41b848a056ec33f8d707d'
cpuUtilization:
idlePercent: 97.57
systemPercent: 1.18
userPercent: 1.25
cpus: 4
distribution:
distribution: endeavouros
version: unknown
eventLogger: journald
hostname: yano-e6230
idMappings:
gidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 100000
size: 65536
uidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 100000
size: 65536
kernel: 6.2.10-arch1-1
linkmode: dynamic
logDriver: journald
memFree: 14898380800
memTotal: 16673546240
networkBackend: netavark
ociRuntime:
name: crun
package: /usr/bin/crun appartient à crun 1.8.3-1
path: /usr/bin/crun
version: |-
crun version 1.8.3
commit: 59f2beb7efb0d35611d5818fd0311883676f6f7e
rundir: /run/user/1000/crun
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
os: linux
remoteSocket:
path: /run/user/1000/podman/podman.sock
security:
apparmorEnabled: false
capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
rootless: true
seccompEnabled: true
seccompProfilePath: /etc/containers/seccomp.json
selinuxEnabled: false
serviceIsRemote: false
slirp4netns:
executable: /usr/bin/slirp4netns
package: /usr/bin/slirp4netns appartient à slirp4netns 1.2.0-1
version: |-
slirp4netns version 1.2.0
commit: 656041d45cfca7a4176f6b7eed9e4fe6c11e8383
libslirp: 4.7.0
SLIRP_CONFIG_VERSION_MAX: 4
libseccomp: 2.5.4
swapFree: 0
swapTotal: 0
uptime: 4h 14m 7.00s (Approximately 0.17 days)
plugins:
authorization: null
log:
- k8s-file
- none
- passthrough
- journald
network:
- bridge
- macvlan
volume:
- local
registries: {}
store:
configFile: /home/yano/.config/containers/storage.conf
containerStore:
number: 0
paused: 0
running: 0
stopped: 0
graphDriverName: overlay
graphOptions: {}
graphRoot: /home/yano/.local/share/containers/storage
graphRootAllocated: 105089261568
graphRootUsed: 7493160960
graphStatus:
Backing Filesystem: extfs
Native Overlay Diff: "true"
Supports d_type: "true"
Using metacopy: "false"
imageCopyTmpDir: /var/tmp
imageStore:
number: 0
runRoot: /run/user/1000/containers
transientStore: false
volumePath: /home/yano/.local/share/containers/storage/volumes
version:
APIVersion: 4.4.4
Built: 1680009696
BuiltTime: Tue Mar 28 15:21:36 2023
GitCommit: c8223435f49a860c8ac4281a85db39232745a7cb-dirty
GoVersion: go1.20.2
Os: linux
OsArch: linux/amd64
Version: 4.4.4</code></pre></figure>
</details>
<p>Les fichiers de configuration du comportement des conteneurs se trouvent dans <code class="language-plaintext highlighter-rouge">/usr/share/containers/</code>.<br />
Vous devez copier les fichiers nécessaires dans <code class="language-plaintext highlighter-rouge">/etc/containers</code> avant de les modifier.<br />
Pour configurer linterface de pont réseau utilisée par Podman, voir <code class="language-plaintext highlighter-rouge">/etc/cni/net.d/87-podman.conflist</code></p>
<h3 id="configuration-podman-rootless">Configuration Podman “rootless”</h3>
<p class="warning">Attention : Podman sans racine repose sur lutilisation de lespace de noms de lutilisateur non privilégié (CONFIG_USER_NS_UNPRIVILEGED) qui a de sérieuses implications en matière de sécurité, voir <a href="https://wiki.archlinux.org/title/Security#Sandboxing_applications">Security#Sandboxing applications</a> pour plus de détails.</p>
<p>Par défaut, seul lutilisateur root est autorisé à exécuter des conteneurs (ou des espaces de noms en langage kernels). Lexécution de Podman sans root améliore la sécurité car un attaquant naura pas les privilèges de root sur votre système, et permet également à plusieurs utilisateurs non privilégiés dexécuter des conteneurs sur la même machine.</p>
<h4 id="dépendances-supplémentaires">Dépendances supplémentaires</h4>
<p>Le paquetage <a href="https://archlinux.org/packages/?name=slirp4netns">slirp4netns</a> est installé en tant que dépendance pour exécuter Podman dans un environnement sans racine.</p>
<p>Si Podman utilise le backend réseau <a href="https://archlinux.org/packages/?name=netavark">netavark</a>, il est alors nécessaire dinstaller <a href="https://archlinux.org/packages/?name=aardvark-dns">aardvark-dns</a> pour avoir une résolution de nom dans les conteneurs sans racine.</p>
<h4 id="activer-les-overlays-natifs-sans-racine">Activer les overlays natifs sans racine</h4>
<p>Auparavant, il était nécessaire dutiliser le paquetage <a href="https://archlinux.org/packages/?name=fuse-overlayfs">fuse-overlayfs</a> pour les montages FUSE dans un environnement sans racine. Cependant, les versions modernes de Podman et du noyau Linux prennent en charge les superpositions sans racine natives, ce qui permet dobtenir de meilleures performances. Pour migrer de fuse-overlayfs, exécutez</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman system reset
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WARNING! This will remove:
- all containers
- all pods
- all images
- all networks
- all build cache
- all machines
- all volumes
Are you sure you want to continue? [y/N] y
</code></pre></div></div>
<p>Cette commande supprimera malheureusement tous les conteneurs tirés.</p>
<p>Pour vérifier que les superpositions natives sans racine sont activées, exécutez</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman info
</code></pre></div></div>
<p>Il devrait y avoir <code class="language-plaintext highlighter-rouge">graphDriverName : overlay</code> et <code class="language-plaintext highlighter-rouge">Native Overlay Diff : "true"</code></p>
<h4 id="activer-kernel-unprivileged-userns-clone">Activer kernel unprivileged userns clone</h4>
<p>Tout dabord, vérifiez la valeur de kernel.unprivileged_userns_clone en exécutant :</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl kernel.unprivileged_userns_clone
kernel.unprivileged_userns_clone <span class="o">=</span> 1
</code></pre></div></div>
<p>Si la valeur est actuellement de 0, activez-la en mettant 1 via sysctl ou un paramètre du noyau.</p>
<blockquote>
<p>Remarque : pour linux-hardened, kernel.unprivileged_userns_clone est défini à 0 par défaut.</p>
</blockquote>
<h4 id="définir-subuid-et-subgid">Définir subuid et subgid</h4>
<p>Pour que les utilisateurs puissent utiliser Podman sans racine, une entrée de configuration subuid et subgid doit exister pour chaque utilisateur qui souhaite lutiliser.<br />
Les nouveaux utilisateurs créés à laide de useradd ont ces entrées par défaut.</p>
<p class="info">Les utilisateurs créés avant la version 4.11 de shadow nont pas dentrées dans <code class="language-plaintext highlighter-rouge">/etc/subuid </code>et <code class="language-plaintext highlighter-rouge">/etc/subgid</code> par défaut. Une entrée peut être créée pour eux en utilisant la commande <code class="language-plaintext highlighter-rouge">usermod</code> ou en modifiant manuellement les fichiers.</p>
<p>La commande suivante permet à lutilisateur et au groupe username dexécuter des conteneurs Podman (ou dautres types de conteneurs dans ce cas). Elle attribue une plage donnée dUID et de GID à lutilisateur et au groupe donnés.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
</code></pre></div></div>
<p>Lintervalle ci-dessus pour le nom dutilisateur peut déjà être utilisé par un autre utilisateur, car il définit lintervalle par défaut pour le premier utilisateur du système. En cas de doute, consultez dabord les fichiers <code class="language-plaintext highlighter-rouge">/etc/subuid</code> et <code class="language-plaintext highlighter-rouge">/etc/subgid</code> pour trouver les plages déjà réservées.</p>
<ul>
<li>De nombreuses images nécessitent 65536 uids / gids pour le mappage (notamment les images de base busybox et alpine). Il est recommandé dallouer au moins ce nombre duids / gids pour chaque utilisateur afin de maximiser la compatibilité avec docker.</li>
<li>Si vous utilisez systemd-homed, lUID et le GID minimum pour les conteneurs doivent être au moins 524288 (vérifiez la valeur “begin container users” dans la sortie de userdbctl). [1]</li>
</ul>
<h4 id="propager-les-changements-de-subuid-et-subgid">Propager les changements de subuid et subgid</h4>
<p>Podman sans racine utilise un processus de pause pour maintenir en vie les espaces de noms non privilégiés. Cela empêche toute modification des fichiers <code class="language-plaintext highlighter-rouge">/etc/subuid</code> et <code class="language-plaintext highlighter-rouge">/etc/subgid</code> dêtre propagée aux conteneurs sans racine pendant que le processus de pause est en cours dexécution.<br />
Pour que ces changements soient propagés, il est nécessaire dexécuter</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman system migrate
</code></pre></div></div>
<p>Après cela, lutilisateur/groupe spécifié dans les fichiers ci-dessus est en mesure de démarrer et dexécuter les conteneurs Podman.</p>
<h4 id="ajouter-les-capacités-sys_chroot-optionnel">Ajouter les capacités SYS_CHROOT (optionnel)</h4>
<p>À partir de la version 4.4, certaines capacités par défaut ont été supprimées, y compris SYS_CHROOT (expliqué dans un billet de blog officiel). Cela affecte les conteneurs qui utilisent chroot (comme archlinux:base) et donc les opérations de pacman échouent à lintérieur du conteneur (cest-à-dire linstallation de paquets qui exécutent des scripts de post-installation). Vous pouvez identifier ces problèmes si, lorsque vous construisez avec podman, vous obtenez des erreurs comme celles ci-dessous pendant la construction</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
could not change the root directory (Operation not permitted)
error: command failed to execute correctly
...
</code></pre></div></div>
<p>Pour résoudre ce problème, modifiez le fichier <code class="language-plaintext highlighter-rouge">/etc/containers/containers.conf</code> et ajoutez le <strong>SYS_CHROOT</strong> à la liste :</p>
<p>/etc/containers/containers.conf</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>default_capabilities = [
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
]
</code></pre></div></div>
<p>Vous pouvez également le faire temporairement depuis la ligne de commande avec <code class="language-plaintext highlighter-rouge">--cap-add sys_chroot</code> lorsque vous exécutez <code class="language-plaintext highlighter-rouge">podman-build</code></p>
<h3 id="stockage">Stockage</h3>
<p>La configuration de la manière et de lendroit où les images de conteneurs et les instances sont stockées se fait dans le fichier <code class="language-plaintext highlighter-rouge">/etc/containers/storage.conf</code></p>
<p class="info">Lors de lutilisation de <strong>Rootless Podman</strong>, des dérogations aux paramètres de stockage peuvent être ajoutées à <code class="language-plaintext highlighter-rouge">$XDG_CONFIG_HOME/containers/storage.conf</code> sur une base individuelle.
Définir le pilote en fonction du système de fichiers utilisé pour lemplacement de stockage</p>
<h3 id="architectures-étrangères">Architectures étrangères</h3>
<p>Podman est capable dexécuter des images construites pour une architecture CPU différente de celle de lhôte en utilisant le système <a href="https://en.wikipedia.org/wiki/binfmt_misc">Wikipedia:binfmt_misc</a>.</p>
<p>Pour lactiver, installez <strong>qemu-user-static</strong> et <strong>qemu-user-static-binfmt</strong></p>
<p>systemd est livré avec le service <strong>systemd-binfmt.service</strong> qui devrait activer les nouvelles règles.</p>
<p>Vérifiez que les règles binfmt ont été ajoutées</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls /proc/sys/fs/binfmt_misc
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DOSWin qemu-cris qemu-ppc qemu-sh4eb status
qemu-aarch64 qemu-m68k qemu-ppc64 qemu-sparc
qemu-alpha qemu-microblaze qemu-riscv64 qemu-sparc32plus
qemu-arm qemu-mips qemu-s390x qemu-sparc64
qemu-armeb qemu-mipsel qemu-sh4 register
</code></pre></div></div>
<p>Podman devrait maintenant être capable dexécuter des images darchitecture étrangère. La plupart des commandes utilisent larchitecture étrangère lorsque loption arch est passée.</p>
<p>Exemple :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman run --arch arm64 'docker.io/alpine:latest' arch
</code></pre></div></div>
<p>aarch64</p>
<h3 id="docker-compose">Docker Compose</h3>
<p>Podman 3.0.0 introduit le support de docker-compose. Cela nécessite lactivation dun socket Podman qui prétend être docker ; démarrez lunité podman.service.<br />
Pour les conteneurs sans racine, vous devez démarrer lunité utilisateur podman.service à la place et définir la variable DOCKER_HOST :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock"
</code></pre></div></div>
<p>Pour obtenir la résolution du nom dhôte entre les conteneurs en cours dexécution, installez <a href="https://archlinux.org/packages/?name=podman-dnsname">podman-dnsname</a></p>
<p>Note : Si vous avez activé buildkit dans docker, lintégration ne fonctionnera pas. Vous devez désactiver buildkit : <code class="language-plaintext highlighter-rouge">$ export DOCKER_BUILDKIT=0</code></p>
<h3 id="gpu-nvidia">GPU NVIDIA</h3>
<p>NVIDIA Container Toolkit fournit des conteneurs pour les GPU NVIDIA. Installez le paquet <a href="https://aur.archlinux.org/packages/nvidia-container-toolkit/">nvidia-container-toolkit</a></p>
<p>Testez linstallation :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman run --rm nvidia/cuda:12.0.0-runtime-ubuntu20.04 nvidia-smi
</code></pre></div></div>
<p>Pour pouvoir exécuter des conteneurs sans racine avec podman, le paramètre <code class="language-plaintext highlighter-rouge">no-cgroups</code> doit être mis à <code class="language-plaintext highlighter-rouge">true</code> dans <code class="language-plaintext highlighter-rouge">/etc/nvidia-container-runtime/config.toml</code></p>
<h2 id="images">Images</h2>
<p class="info">Vous pouvez omettre le préfixe de registre dans les images, car Podman cherchera automatiquement limage dans tous les registres définis dans <code class="language-plaintext highlighter-rouge">/etc/containers/registries.conf</code> à <code class="language-plaintext highlighter-rouge">unqualified-search-registries</code> dans lordre défini. Les images suivantes contiendront toujours le préfixe, pour permettre des configurations sans docker.io dans la configuration.</p>
<h3 id="arch-linux">Arch Linux</h3>
<p>La commande suivante extrait limage Arch Linux x86_64 de Docker Hub.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman pull docker.io/archlinux
</code></pre></div></div>
<p>Voir la page Docker Hub pour une liste complète des balises disponibles, y compris les versions avec et sans outils de construction.</p>
<p>Voir aussi <a href="https://gitlab.archlinux.org/archlinux/archlinux-docker/blob/master/README.md">README.md</a>.</p>
<h3 id="alpine-linux">Alpine Linux</h3>
<p>Alpine Linux est un choix populaire pour les petites images de conteneurs, en particulier pour les logiciels compilés sous forme de binaires statiques. La commande suivante extrait la dernière image Alpine Linux de Docker Hub :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman pull docker.io/alpine
</code></pre></div></div>
<p>Alpine Linux utilise limplémentation <a href="https://musl.libc.org/">musl</a> libc au lieu de limplémentation <a href="https://www.gnu.org/software/libc/">glibc</a> libc utilisée par la plupart des distributions Linux. Parce quArch Linux utilise la glibc, il y a un certain nombre de différences fonctionnelles entre un hôte Arch Linux et un conteneur Alpine Linux qui peuvent avoir un impact sur la performance et la correction des logiciels. Une liste de ces différences est documentée dans <a href="https://wiki.musl-libc.org/functional-differences-from-glibc.html">https://wiki.musl-libc.org/functional-differences-from-glibc.html</a>.</p>
<h3 id="debian">Debian</h3>
<p>La commande suivante extrait la dernière image <a href="https://hub.docker.com/_/debian">Debian</a> de <a href="https://hub.docker.com/">Docker Hub</a> :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman pull docker.io/debian
</code></pre></div></div>
<p>Voir la page Docker Hub pour une liste complète des balises disponibles, y compris les versions standard et slim pour chaque version de Debian.</p>
<h2 id="résolution-des-problèmes">Résolution des problèmes</h2>
<h3 id="ajouter-une-pause-au-processus">Ajouter une pause au processus</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WARN[0000] Failed to add pause process to systemd sandbox cgroup: Process org.freedesktop.systemd1 exited with status 1
</code></pre></div></div>
<p>Peut être résolu en utilisant : <a href="https://github.com/containers/crun/issues/704">https://github.com/containers/crun/issues/704</a></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c"># echo +cpu +cpuset +io +memory +pids &gt; /sys/fs/cgroup/cgroup.subtree_control</span>
</code></pre></div></div>
<h3 id="le-dns-de-conteneur-ne-sera-pas-activé">Le DNS de conteneur ne sera pas activé</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WARN[0000] binary not found, container DNS will not be enabled
</code></pre></div></div>
<p>Si vous utilisez <a href="https://archlinux.org/packages/?name=netavark">netavark</a> comme backend réseau de podman, vous devez installer <a href="https://archlinux.org/packages/?name=aardvark-dns">aardvark-dns</a>.</p>
<h3 id="les-conteneurs-se-terminent-lors-de-la-déconnexion-du-shell">Les conteneurs se terminent lors de la déconnexion du shell</h3>
<p>Après sêtre déconnecté de la machine, les conteneurs Podman sont arrêtés pour certains utilisateurs. Pour éviter cela, <a href="https://wiki.archlinux.org/title/Systemd/User#Automatic_start-up_of_systemd_user_instances">activez loption lingering</a> pour les utilisateurs qui utilisent des conteneurs.</p>
<p>Vous pouvez également créer une unité utilisateur systemd comme décrit dans <a href="https://man.archlinux.org/man/podman-auto-update.1#EXAMPLES">podman-auto-update(1) § EXEMPLES</a>.</p>
<h3 id="échec-du-déplacement-de-netns-sans-racine">Échec du déplacement de netns sans racine</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose up
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ERRO[0000] failed to move the rootless netns slirp4netns process to the systemd user.slice: Process org.freedesktop.systemd1 exited with status 1
</code></pre></div></div>
<p>Peut être résolu en démarrant/activant <strong>podman.service</strong></p>
<h3 id="aucune-image-trouvée">Aucune image trouvée</h3>
<p>Par défaut, la liste de registre nest pas remplie car les fichiers du paquet proviennent de lamont. Cela signifie que par défaut, essayer dextraire une image sans spécifier le registre résultera en une erreur similaire à la suivante</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Error: short-name "archlinux" did not resolve to an alias and no unqualified-search registries are defined in "/etc/containers/registries.conf"
</code></pre></div></div>
<p>Une configuration de départ pourrait être la suivante :</p>
<p>/etc/containers/registries.conf.d/00-unqualified-search-registries.conf</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unqualified-search-registries = ["docker.io"]
</code></pre></div></div>
<p>/etc/containers/registries.conf.d/01-registries.conf</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[[registry]]
location = "docker.io"```
</code></pre></div></div>
<p>Ceci est équivalent à la configuration par défaut de Docker.</p>
<p>Une alternative moins pratique, mais plus compatible avec les systèmes sans noms courts configurés, consiste à utiliser le chemin complet du registre dans le <strong>Containerfile</strong> ou le <strong>Dockerfile</strong>.</p>
<p>Containerfile</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FROM docker.io/archlinux/archlinux
</code></pre></div></div>
<h3 id="oci-permission-refusée">OCI Permission refusée</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman exec openvas_openvas_1 bash
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Error: crun: writing file `/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/user.slice/libpod-b3e8048a9b91e43c214b4d850ac7132155a684d6502e12e22ceb6f73848d117a.scope/container/cgroup.procs`: Permission denied: OCI permission denied
</code></pre></div></div>
<p>Peut être résolu : <a href="https://bbs.archlinux.org/viewtopic.php?id=253966">BBS#253966</a></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">env </span><span class="nv">DBUS_SESSION_BUS_ADDRESS</span><span class="o">=</span> podman ...
<span class="nv">$ </span><span class="nb">env </span><span class="nv">DBUS_SESSION_BUS_ADDRESS</span><span class="o">=</span> podman-compose ...
</code></pre></div></div>
<h3 id="pousser-des-images-vers-docker-hub-accès-refusé-authentification-requise">Pousser des images vers Docker Hub, accès refusé authentification requise</h3>
<p>Lors de lutilisation de podman push pour pousser des images de conteneurs vers Docker Hub, les erreurs suivantes peuvent se produire :<br />
<code class="language-plaintext highlighter-rouge">Requested access to the resource is denied</code> ou <code class="language-plaintext highlighter-rouge">Authentication required</code><br />
Les conseils suivants peuvent aider à résoudre les problèmes potentiels :</p>
<p>Marquez limage locale :</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman tag &lt;localImage&gt; docker.io/&lt;dockerHubUsername&gt;/&lt;dockerHubRepository&gt;:&lt;Tag&gt;
</code></pre></div></div>
<p>Pousser limage étiquetée :</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman push docker.io/&lt;dockerHubUsername&gt;/&lt;dockerHubRepository&gt;:&lt;Tag&gt; docker://docker.io/&lt;dockerHubUsername&gt;/&lt;dockerHubRepository&gt;:&lt;Tag&gt;
</code></pre></div></div>
<p>Connectez-vous à docker.io, au référentiel Docker Hub et au serveur Docker Hub Registry :</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman login <span class="nt">-u</span> &lt;DockerHubUsername&gt; <span class="nt">-p</span> &lt;DockerHubPassword&gt; registry-1.docker.io
podman login <span class="nt">-u</span> &lt;DockerHubUsername&gt; <span class="nt">-p</span> &lt;DockerHubPassword&gt; docker.io/&lt;dockerHubUsername&gt;/&lt;dockerHubRepository&gt;
podman login <span class="nt">-u</span> &lt;DockerHubUsername&gt; <span class="nt">-p</span> &lt;DockerHubPassword&gt; docker.io
</code></pre></div></div>
<p>Se déconnecter de tous les registres avant la connexion, par exemple,</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podman <span class="nb">logout</span> <span class="nt">--all</span>
</code></pre></div></div>
<p>Ajouter <code class="language-plaintext highlighter-rouge">&lt;dockerHubUsername&gt;</code> comme collaborateur dans longlet Docker Hub Collaborators du dépôt.</p>
<h3 id="-is-not-a-shared-mount">”/” is not a shared mount</h3>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WARN[0000] <span class="s2">"/"</span> is not a shared mount, this could cause issues or missing mounts with rootless containers
</code></pre></div></div>
<p>Buildah/Podman fonctionnant en tant que rootless sattend à ce que le montage bind soit partagé, vérifiez sil est défini sur private :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>findmnt -o PROPAGATION /
</code></pre></div></div>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PROPAGATION
private
</code></pre></div></div>
<p>Dans ce cas, voir <a href="https://man.archlinux.org/man/mount.8#Shared_subtree_operations">mount § Shared_subtree_operations</a> et définir <strong>temporairement</strong> le montage comme partagé avec :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mount --make-shared /
</code></pre></div></div>
<p>Pour le définir de manière permanente, éditez le fichier /etc/fstab et ajoutez loption shared au montage souhaité, puis redémarrez. Il en résultera une entrée du type</p>
<p>/etc/fstab</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># &lt;device&gt; &lt;dir&gt; &lt;type&gt; &lt;options&gt; &lt;dump&gt; &lt;fsck&gt;</span>
<span class="nv">UUID</span><span class="o">=</span>0a3407de-014b-458b-b5c1-848e92a327a3 / ext4 defaults,shared 0 1
</code></pre></div></div>
<h2 id="utiliser-podman">Utiliser Podman</h2>
<h3 id="activation-des-registres-oci">Activation des registres OCI</h3>
<p>Avant dutiliser Podman pour créer des conteneurs, assurez-vous que Podman peut communiquer avec les registres OCI . Podman prend en charge plusieurs registres OCI simultanément afin que vous puissiez créer des conteneurs à laide de différents référentiels.</p>
<p>Ouvrez le fichier <code class="language-plaintext highlighter-rouge">/etc/containers/registries.conf</code> avec léditeur de texte de votre choix. Ce fichier définit tous les registres avec lesquels Podman peut communiquer. Podman consulte ce fichier pour savoir à quels registres il doit se connecter.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/containers/registries.conf
</code></pre></div></div>
<p>Maintenant, remplissez le fichier registries.conf avec les lignes suivantes, enregistrez les modifications et fermez léditeur.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[registries.search]
registries = ['registry.access.redhat.com', 'quay.io', 'docker.io']
</code></pre></div></div>
<p>Ces lignes configurent Podman pour utiliser le registre public sur Docker Hub ( docker.io , register.access.redhat.com ) et le registre privé ( quay.io ), ce qui est recommandé.</p>
<h3 id="exécuter-des-conteneurs-podman-avec-des-privilèges-podman">Exécuter des conteneurs Podman avec des privilèges Podman</h3>
<p>Maintenant que vous avez installé Podman et configuré les registres, vous pouvez commencer à exécuter des conteneurs Podman avec les privilèges Podman. Le noyau Linux prend en charge un large éventail de contrôles dautorisations sur ses appels système, tels que les <a href="https://man7.org/linux/man-pages/man7/capabilities.7.html">fonctionnalités (capabilities)</a> .</p>
<p>Dans le cas des conteneurs Podman, les fonctionnalités contrôlent le comportement par défaut de root dans lespace de noms de lutilisateur. Vous pouvez utiliser lindicateur <code class="language-plaintext highlighter-rouge">--privileged</code> lors de lexécution dun conteneur pour ajouter toutes les fonctionnalités qui ne sont pas déjà présentes dans le conteneur.</p>
<ol>
<li>
<p>Exécutez la commande <code class="language-plaintext highlighter-rouge">podman run</code> ci-dessous pour créer un conteneur fedora sans fonctionnalités.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman run -d fedora sleep 100
</code></pre></div> </div>
<p><img src="/images/podman002.png" alt="" /><br />
<em>Création dun conteneur Fedora</em></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman run -d fedora sleep 100
</code></pre></div> </div>
<p><img src="/images/podman003.png" alt="" /></p>
</li>
<li>
<p>Ensuite, exécutez la commande <code class="language-plaintext highlighter-rouge">podman top</code> ci-dessous pour répertorier toutes les fonctionnalités.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman top -l capeff
</code></pre></div> </div>
<p>Comme indiqué ci-dessous, le conteneur sans racine standard a des capacités limitées.<br />
<img src="/images/podman004.png" alt="" /><br />
<em>Lister toutes les capacités</em></p>
</li>
<li>
<p>Exécutez la commande <code class="language-plaintext highlighter-rouge">podman run</code> ci-dessous pour créer un conteneur avec toutes les fonctionnalités ( privileged).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman run --privileged -d fedora sleep 100
</code></pre></div> </div>
<p><img src="/images/podman005.png" alt="" /></p>
</li>
<li>
<p>Enfin, réexécutez la commande <code class="language-plaintext highlighter-rouge">podman top</code> pour vérifier la différence de capacités.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman top -l capeff
</code></pre></div> </div>
<p>Vous remarquerez que toutes les fonctionnalités sont disponibles pour ce conteneur en raison de lindicateur <code class="language-plaintext highlighter-rouge">--privileged</code> qui permet au conteneur de sexécuter avec toutes les fonctionnalités, pas seulement celles déjà présentes dans le conteneur. Cet indicateur est important car il mappe lespace de noms dutilisateur du conteneur à lespace de noms de lhôte, lui donnant toutes les capacités des processus exécutés sur votre système.
<img src="/images/podman006.png" alt="" /><br />
<em>Vérification de la différence dautorisations</em></p>
</li>
</ol>
<p class="info">Si vous ne définissez pas lindicateur <code class="language-plaintext highlighter-rouge">--privileged</code> lors du lancement dun conteneur, le conteneur aura un ensemble restreint de fonctionnalités. Dans le cas de conteneurs qui utilisent leur propre espace de noms dutilisateur, vous devrez leur donner explicitement toutes les fonctionnalités.</p>
<h3 id="travailler-avec-des-images-et-des-conteneurs-podman">Travailler avec des images et des conteneurs Podman</h3>
<p>Maintenant que vous avez appris à ajouter des registres et des fonctionnalités OCI pour un conteneur, vous pouvez travailler avec des images et des conteneurs Podman.</p>
<p>Pour cette démo, vous utiliserez NGINX pour une image afin de créer un conteneur.</p>
<ol>
<li>
<p>Exécutez la commande <code class="language-plaintext highlighter-rouge">podman search</code> ci-dessous pour répertorier toutes les images Podman disponibles pournginx</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman search nginx
</code></pre></div> </div>
<p>Ci-dessous, vous pouvez voir que vous obtenez toutes les images étiquetées disponibles pour NGINX à partir des référentiels docker.io , quay.io et redhat.com que vous avez ajoutés précédemment<br />
<img src="/images/podman007.png" alt="" /><br />
<em>Liste des 3 images par registre Podman disponibles pour NGINX</em></p>
</li>
<li>
<p>Après avoir choisi une image NGINX à utiliser, exécutez la podmancommande ci-dessous pour télécharger ( pull) limage sur votre ordinateur local.</p>
<p>Cette démo utilise nginx:alpine car il sagit de la plus petite image et ne peut sexécuter que sur la mémoire, ce qui permet de gagner du temps sur les étapes de construction ultérieures.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman pull nginx:alpine
</code></pre></div> </div>
<p><img src="/images/podman008.png" alt="" /><br />
<em>Sélectionner une image</em><br />
À ce stade, vous disposez dune nouvelle image que vous pouvez utiliser pour créer un conteneur ou lutiliser comme image de base pour dautres conteneurs.
Téléchargement de limage NGINX Téléchargement de limage NGINX</p>
</li>
<li>
<p>Exécutez la commande <code class="language-plaintext highlighter-rouge">podman images</code> pour voir les informations de votre nouvelle image</p>
<p>podman images</p>
<p><img src="/images/podman009.png" alt="" /><br />
<em>Lister toutes les images</em></p>
</li>
<li>
<p>Maintenant, exécutez la commande <code class="language-plaintext highlighter-rouge">podman run</code> ci-dessous pour créer un conteneur à partir de limage ( nginx:alpine) et exécutez un nginxserveur sur cette image.</p>
<p>Cette commande effectue les opérations suivantes :</p>
<ul>
<li>Démarre le conteneur de manière interactive ( <code class="language-plaintext highlighter-rouge">-it</code>) et vous permet dattacher un terminal.</li>
<li>Supprime (<code class="language-plaintext highlighter-rouge">--rm</code>) le conteneur après sa sortie/arrêt.</li>
<li>Exécute le conteneur en arrière-plan ( <code class="language-plaintext highlighter-rouge">--d</code>) et publie ( <code class="language-plaintext highlighter-rouge">-p</code>) le port 80 sur toutes les interfaces à porter 8080 sur le conteneur.</li>
<li>
<p>Spécifiez le nom du conteneur ( <code class="language-plaintext highlighter-rouge">--name web</code>).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman run -it --rm -d -p 8080:80 --name web nginx:alpine
</code></pre></div> </div>
</li>
</ul>
<p>Vous obtiendrez un ID de conteneur aléatoire, comme indiqué ci-dessous, que vous pourrez utiliser pour surveiller/démarrer/arrêter/supprimer le conteneur. Notez lID du conteneur car il est utile lors de la vérification des journaux ou de larrêt dun conteneur spécifique.<br />
<img src="/images/podman010.png" alt="" /><br />
<em>Exécution du conteneur (web)</em></p>
</li>
<li>
<p>Exécutez la commande <code class="language-plaintext highlighter-rouge">podman ps</code> ci-dessous (sans arguments) pour vérifier si votre conteneur est en cours dexécution.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman ps
</code></pre></div> </div>
<p>Vous pouvez voir que le conteneur Web est Up et utilise le port 8080/TCP sur votre machine hôte pour exposer sa ressource.<br />
<img src="/images/podman011.png" alt="" /><br />
<em>Vérifier si le conteneur (web) est en cours dexécution</em></p>
</li>
<li>
<p>Pour une double vérification, ouvrez votre navigateur Web et accédez à <strong>localhost:8080</strong> ou <strong>your-server-ip:8080</strong> , où <strong>your-server-ip</strong> est ladresse IP de votre serveur.</p>
<p>Si votre conteneur fonctionne, vous verrez lécran daccueil NGINX par défaut, comme illustré ci-dessous.<br />
<img src="/images/podman012.png" alt="" /><br />
<em>Affichage de lécran daccueil NGINX par défaut</em></p>
<p>Si vous nêtes pas sûr de la configuration du conteneur ou sil contient des erreurs, exécutez la commande podman logs ci-dessous pour obtenir les fichiers journaux du conteneur. Remplacez mycontainer par votre ID de conteneur cible.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman logs mycontainer
</code></pre></div> </div>
<p><img src="/images/podman013.png" alt="" /><br />
<em>Vérification des fichiers journaux pour le conteneur (Web)</em></p>
</li>
<li>
<p>Exécutez lune des commandes <code class="language-plaintext highlighter-rouge">podman stop</code> ci-dessous pour arrêter votre conteneur. Remplacez mycontainer par votre ID de conteneur cible ou remplacez-le web par le nom réel du conteneur.</p>
<p>Puisque vous avez utilisé lindicateur rm à létape quatre, Podman supprime votre conteneur dès que vous arrêtez ce conteneur. Cette configuration permet de garder votre espace de travail sans encombrement.</p>
<p>Stops the container by Container ID</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman stop f4b19560be1ccde5e3557e44eb01e03fb8c93c193b4085dd336797f7d7d1a6da
</code></pre></div> </div>
<p>Stops the container by Container Name</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman stop web
</code></pre></div> </div>
<p><img src="/images/podman014.png" alt="" /><br />
<em>Arrêt dun conteneur</em></p>
</li>
<li>
<p>Enfin, exécutez la commande <code class="language-plaintext highlighter-rouge">podman ps</code> pour répertorier tous les conteneurs, y compris un conteneur arrêté.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> podman ps -a
</code></pre></div> </div>
<p>Votre conteneur a été supprimé lorsque vous lavez précédemment arrêté, vous nobtiendrez donc rien sur la liste, comme indiqué ci-dessous.<br />
<img src="/images/podman015.png" alt="" /><br />
<em>Vérification du conteneur arrêté</em></p>
</li>
</ol>
<h2 id="liens">Liens</h2>
<ul>
<li><a href="https://devopssec.fr/category/apprendre-docker">Apprendre docker</a></li>
<li>Podman
<ul>
<li><a href="/htmldoc/Podman Tutorial - Basics for Beginners.html">Podman Tutorial - Basics for Beginners</a></li>
<li><a href="https://adamtheautomator.com/podman/">How to Install and Use Podman (Docker Alternative)</a></li>
<li><a href="https://www.grottedubarbu.fr/podman-manage-pod/">Podman : Gérer ses Pods !</a></li>
</ul>
</li>
<li>Réseau
<ul>
<li><a href="https://devopssec.fr/article/fonctionnement-manipulation-reseau-docker">Fonctionnement et manipulation du réseau dans Docker</a></li>
<li><a href="https://www.server-world.info/en/note?os=Debian_11&amp;p=docker&amp;f=8">Docker : Docker Network</a></li>
</ul>
</li>
<li>Partage entre host et container
<ul>
<li><a href="https://linuxconfig.org/how-to-share-data-between-a-docker-container-and-host-system-using-volumes">How to share data between a Docker container and host system using volumes</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-share-data-between-the-docker-container-and-the-host">How To Share Data Between the Docker Container and the Host</a></li>
</ul>
</li>
</ul>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2023-04-12T00:00:00+02:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2023/03/29/Yunohost-PhpLdapAdmin.html">Yunohost PhpLdapAdmin</a></div><div class="next"><span>SUIVANT</span><a href="/2023/04/21/Wifi_Hotspot_YunoHost.html">Yunohost Hotspot - Point d'accès wifi</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>