2741 lines
236 KiB
HTML
2741 lines
236 KiB
HTML
|
<!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>Docker + Docker Compose sur Debian, installation et utilisation - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2020/03/10/Docker-Debian-Buster.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} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a></li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
|
|||
|
<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="/aide-jekyll-text-theme.html">Aide</a></li></ul>
|
|||
|
</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;">Docker + Docker Compose sur Debian, installation et utilisation</h1></header></div><meta itemprop="headline" content="Docker + Docker Compose sur Debian, installation et utilisation"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=debian">debian</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">10 mars 2020</span>
|
|||
|
|
|||
|
<span title="Modification" style="color:#00FF7F">31 oct. 2023</span></li></ul></div><meta itemprop="datePublished" content="2023-10-31T00:00:00+01:00">
|
|||
|
<meta itemprop="keywords" content="debian"><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">⇧</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/docker-logo.png" alt="image" width="300px" /></p>
|
|||
|
|
|||
|
<h2 id="i---docker">I - Docker</h2>
|
|||
|
|
|||
|
<p><a href="https://www.howtoforge.com/how-to-install-docker-engine-on-debian-12/">How to Install and Use Docker on Debian 12</a></p>
|
|||
|
|
|||
|
<p><em>Docker a pour objectif de faciliter le déploiement d’applications, d’avoir plusieurs versions d’une même application sur un son serveur (phase de développement, tests), mais aussi d’automatiser le packaging d’applications. Avec Docker, on s’oriente vers de l’intégration et du déploiement en continu grâce au système de container.</em></p>
|
|||
|
|
|||
|
<p><em>De plus, Docker permet de garder son système de base propre, tout en installant de nouvelles fonctionnalités au sein de containers. En quelque sorte, on part d’une base qui est le système d’exploitation et on ajoute différentes briques conteneurisées qui sont les applications.</em></p>
|
|||
|
|
|||
|
<h3 id="conditions-préalables">Conditions préalables</h3>
|
|||
|
|
|||
|
<p>Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Un serveur debian 10 et 11 configuré en suivant le guide de configuration initiale du serveur debian 10 et 11, y compris un utilisateur sudo non root et un pare-feu.</li>
|
|||
|
<li>Un compte sur Docker Hub si vous souhaitez créer vos propres images et les pousser vers Docker Hub, comme indiqué aux étapes 7 et 8.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="1---installation-du-docker">1 - Installation du docker</h3>
|
|||
|
|
|||
|
<p>Le paquet d’installation de Docker disponible dans le référentiel Debian officiel peut ne pas être la dernière version. Pour nous assurer d’obtenir la dernière version, nous installerons Docker à partir du dépôt officiel de Docker. Pour ce faire, nous ajouterons une nouvelle source de paquet, ajouterons la clé GPG de Docker pour nous assurer que les téléchargements sont valides, puis installerons le paquet.</p>
|
|||
|
|
|||
|
<p>Tout d’abord, mettez à jour votre liste existante de paquets :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, installez quelques paquets prérequis qui permettent à apt d’utiliser des paquets sur HTTPS :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ajoutez ensuite la clé GPG du référentiel officiel du Docker à votre système :</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>curl <span class="nt">-fsSL</span> https://download.docker.com/linux/debian/gpg | <span class="nb">sudo </span>gpg <span class="nt">--dearmor</span> <span class="nt">-o</span> /usr/share/keyrings/docker-archive-keyring.gpg
|
|||
|
|
|||
|
<span class="nb">echo</span> <span class="se">\</span>
|
|||
|
<span class="s2">"deb [arch="</span><span class="si">$(</span>dpkg <span class="nt">--print-architecture</span><span class="si">)</span><span class="s2">" signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian </span><span class="se">\</span><span class="s2">
|
|||
|
"</span><span class="si">$(</span><span class="nb">.</span> /etc/os-release <span class="o">&&</span> <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$VERSION_CODENAME</span><span class="s2">"</span><span class="si">)</span><span class="s2">" stable"</span> | <span class="se">\</span>
|
|||
|
<span class="nb">sudo tee</span> /etc/apt/sources.list.d/docker.list <span class="o">></span> /dev/null
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, mettez à jour la base de données des paquets avec les paquets Docker du repo nouvellement ajouté :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installez Docker :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Version <code class="language-plaintext highlighter-rouge">sudo docker version</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Client: Docker Engine - Community
|
|||
|
Version: 24.0.7
|
|||
|
API version: 1.43
|
|||
|
Go version: go1.20.10
|
|||
|
Git commit: afdd53b
|
|||
|
Built: Thu Oct 26 09:08:02 2023
|
|||
|
OS/Arch: linux/amd64
|
|||
|
Context: default
|
|||
|
|
|||
|
Server: Docker Engine - Community
|
|||
|
Engine:
|
|||
|
Version: 24.0.7
|
|||
|
API version: 1.43 (minimum version 1.12)
|
|||
|
Go version: go1.20.10
|
|||
|
Git commit: 311b9ff
|
|||
|
Built: Thu Oct 26 09:08:02 2023
|
|||
|
OS/Arch: linux/amd64
|
|||
|
Experimental: false
|
|||
|
containerd:
|
|||
|
Version: 1.6.24
|
|||
|
GitCommit: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870523
|
|||
|
runc:
|
|||
|
Version: 1.1.9
|
|||
|
GitCommit: v1.1.9-0-gccaecfc
|
|||
|
docker-init:
|
|||
|
Version: 0.19.0
|
|||
|
GitCommit: de40ad0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier que les services sont actifs , réponse “enabled”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl is-enabled docker
|
|||
|
sudo systemctl is-enabled containerd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les status</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl status docker
|
|||
|
sudo systemctl status containerd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour afficher que les services sont actifs et en cours d’exécution :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● docker.service - Docker Application Container Engine
|
|||
|
Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
|
|||
|
Active: active (running) since Tue 2023-10-31 09:01:14 CET; 7min ago
|
|||
|
TriggeredBy: ● docker.socket
|
|||
|
Docs: https://docs.docker.com
|
|||
|
Main PID: 1465140 (dockerd)
|
|||
|
Tasks: 10
|
|||
|
Memory: 43.6M
|
|||
|
CPU: 479ms
|
|||
|
CGroup: /system.slice/docker.service
|
|||
|
└─1465140 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
|
|||
|
|
|||
|
● containerd.service - containerd container runtime
|
|||
|
Loaded: loaded (/lib/systemd/system/containerd.service; enabled; preset: enabled)
|
|||
|
Active: active (running) since Tue 2023-10-31 09:01:09 CET; 12min ago
|
|||
|
Docs: https://containerd.io
|
|||
|
Main PID: 1465057 (containerd)
|
|||
|
Tasks: 9
|
|||
|
Memory: 23.5M
|
|||
|
CPU: 2.744s
|
|||
|
CGroup: /system.slice/containerd.service
|
|||
|
└─1465057 /usr/bin/containerd
|
|||
|
[...]
|
|||
|
oct. 31 09:01:09 rnmkcy.eu systemd[1]: Started containerd.service - containerd container runtime.
|
|||
|
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>L’installation de Docker vous donne maintenant non seulement le service Docker (démon) mais aussi l’utilitaire de ligne de commande du docker, ou le client Docker. Nous verrons comment utiliser la commande docker plus loin dans ce tutoriel.</p>
|
|||
|
|
|||
|
<p>Version docker</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker -v
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Docker version 24.0.7, build afdd53b
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="2---exécution-de-la-commande-docker-sans-sudo-optionnel">2 - Exécution de la commande Docker sans sudo (optionnel)</h3>
|
|||
|
|
|||
|
<p>Par défaut, la commande du docker ne peut être exécutée que par l’utilisateur root ou par un utilisateur du groupe de dockers, qui est automatiquement créé pendant le processus d’installation du docker. Si vous essayez d’exécuter la commande du docker sans la préfixer avec sudo ou sans être dans le groupe docker, vous obtiendrez un résultat comme ceci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?.
|
|||
|
See 'docker run --help'.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si vous voulez éviter de taper sudo à chaque fois que vous exécutez la commande docker, ajoutez votre nom d’utilisateur au groupe docker :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -aG docker ${USER}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour appliquer la nouvelle appartenance au groupe, déconnectez-vous du serveur et reconnectez ou tapez ce qui suit :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>su - ${USER}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous serez invité à entrer le mot de passe de votre utilisateur pour continuer.</p>
|
|||
|
|
|||
|
<p>Confirmez que votre utilisateur est maintenant ajouté au groupe de dockers en tapant :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id -nG
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>admbust adm cdrom floppy audio dip video plugdev systemd-journal netdev vboxusers docker www-default partage
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si vous avez besoin d’ajouter un utilisateur au groupe de dockers sous lequel vous n’êtes pas connecté, déclarez ce nom d’utilisateur explicitement en utilisant :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -aG docker username
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le reste de cet article suppose que vous exécutez la commande docker en tant qu’utilisateur dans le groupe docker. Si vous choisissez de ne pas le faire, préparez les commandes avec sudo.</p>
|
|||
|
|
|||
|
<p>Examinons maintenant la commande docker.</p>
|
|||
|
|
|||
|
<p>Étape 3 - Utilisation de la commande Docker</p>
|
|||
|
|
|||
|
<p>L’utilisation du docker consiste à lui passer une chaîne d’options et de commandes suivie d’arguments. La syntaxe prend cette forme :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker [option] [command] [arguments]
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour afficher toutes les sous-commandes disponibles, tapez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>À partir du docker 18, la liste complète des sous-commandes disponibles comprend :</p>
|
|||
|
|
|||
|
<table>
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th>Option</th>
|
|||
|
<th>Comment EN</th>
|
|||
|
<th>Comment FR</th>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<tr>
|
|||
|
<td>attach</td>
|
|||
|
<td>Attach local standard input, output, and error streams to a running container</td>
|
|||
|
<td>Attacher les flux d’entrée, de sortie et d’erreurs standard locaux à un conteneur en cours d’exécution</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>build</td>
|
|||
|
<td>Build an image from a Dockerfile</td>
|
|||
|
<td>Construire une image à partir d’un Dockerfile</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>commit</td>
|
|||
|
<td>Create a new image from a container’s changes</td>
|
|||
|
<td>Créer une nouvelle image à partir des modifications d’un conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>cp</td>
|
|||
|
<td>Copy files/folders between a container and the local filesystem</td>
|
|||
|
<td>Copier des fichiers/dossiers entre un conteneur et le système de fichiers local</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>create</td>
|
|||
|
<td>Create a new container</td>
|
|||
|
<td>Créer un nouveau conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>diff</td>
|
|||
|
<td>Inspect changes to files or directories on a container’s filesystem</td>
|
|||
|
<td>Inspecter les modifications apportées aux fichiers ou répertoires du système de fichiers d’un conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>events</td>
|
|||
|
<td>Get real time events from the server</td>
|
|||
|
<td>Obtenir les événements en temps réel à partir du serveur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>exec</td>
|
|||
|
<td>Run a command in a running container</td>
|
|||
|
<td>Exécuter une commande dans un conteneur en cours d’exécution</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>export</td>
|
|||
|
<td>Export a container’s filesystem as a tar archive</td>
|
|||
|
<td>Exporter le système de fichiers d’un conteneur sous forme d’archive tar</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>history</td>
|
|||
|
<td>Show the history of an image</td>
|
|||
|
<td>Afficher l’historique d’une image</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>images</td>
|
|||
|
<td>List images</td>
|
|||
|
<td>Liste des images</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>import</td>
|
|||
|
<td>Import the contents from a tarball to create a filesystem image</td>
|
|||
|
<td>Importer le contenu d’une archive pour créer une image de système de fichiers</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>info</td>
|
|||
|
<td>Display system-wide information</td>
|
|||
|
<td>Afficher les informations sur l’ensemble du système</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>inspect</td>
|
|||
|
<td>Return low-level information on Docker objects</td>
|
|||
|
<td>Retourner les informations de bas niveau sur les objets Docker</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>kill</td>
|
|||
|
<td>Kill one or more running containers</td>
|
|||
|
<td>Tuer un ou plusieurs conteneurs en cours d’exécution</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>load</td>
|
|||
|
<td>Load an image from a tar archive or STDIN</td>
|
|||
|
<td>Charger une image depuis une archive tar ou STDIN</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>login</td>
|
|||
|
<td>Log in to a Docker registry</td>
|
|||
|
<td>Se connecter à un registre Docker</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>logout</td>
|
|||
|
<td>Log out from a Docker registry</td>
|
|||
|
<td>Déconnexion d’un registre Docker</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>logs</td>
|
|||
|
<td>Fetch the logs of a container</td>
|
|||
|
<td>Récupérer les “logs” d’un conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>pause</td>
|
|||
|
<td>Pause all processes within one or more containers</td>
|
|||
|
<td>Pause Tous les processus dans un ou plusieurs conteneurs</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>port</td>
|
|||
|
<td>List port mappings or a specific mapping for the container</td>
|
|||
|
<td>Liste des mappages de port ou un mappage spécifique pour le conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>ps</td>
|
|||
|
<td>List containers</td>
|
|||
|
<td>Liste des conteneurs</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>pull</td>
|
|||
|
<td>Pull an image or a repository from a registry</td>
|
|||
|
<td>Sortir une image ou un référentiel d’un registre</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>push</td>
|
|||
|
<td>Push an image or a repository to a registry</td>
|
|||
|
<td>Pousse une image ou un référentiel vers un registre</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>rename</td>
|
|||
|
<td>Rename a container</td>
|
|||
|
<td>Renommer un conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>restart</td>
|
|||
|
<td>Restart one or more containers</td>
|
|||
|
<td>Redémarrer un ou plusieurs conteneurs</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>rm</td>
|
|||
|
<td>Remove one or more containers</td>
|
|||
|
<td>Retirer un ou plusieurs récipients</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>rmi</td>
|
|||
|
<td>Remove one or more images</td>
|
|||
|
<td>Supprimer une ou plusieurs images</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>run</td>
|
|||
|
<td>Run a command in a new container</td>
|
|||
|
<td>Exécuter une commande dans un nouveau conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>save</td>
|
|||
|
<td>Save one or more images to a tar archive (streamed to STDOUT by default)</td>
|
|||
|
<td>Enregistrer une ou plusieurs images dans une archive tar (diffusée en continu vers STDOUT par défaut)</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>search</td>
|
|||
|
<td>Search the Docker Hub for images</td>
|
|||
|
<td>Rechercher des images dans le Docker Hub</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>start</td>
|
|||
|
<td>Start one or more stopped containers</td>
|
|||
|
<td>Démarrer un ou plusieurs conteneurs arrêtés</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>stats</td>
|
|||
|
<td>Display a live stream of container(s) resource usage statistics</td>
|
|||
|
<td>Afficher un flux en direct des statistiques d’utilisation des ressources du ou des conteneurs</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>stop</td>
|
|||
|
<td>Stop one or more running containers</td>
|
|||
|
<td>Arrêter un ou plusieurs conteneurs en mouvement</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>tag</td>
|
|||
|
<td>Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE</td>
|
|||
|
<td>Créer une balise TARGET_IMAGE qui se réfère à SOURCE_IMAGE</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>top</td>
|
|||
|
<td>Display the running processes of a container</td>
|
|||
|
<td>Afficher les processus en cours d’un conteneur</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>unpause</td>
|
|||
|
<td>Unpause all processes within one or more containers</td>
|
|||
|
<td>Unpause tous les processus dans un ou plusieurs conteneurs</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>update</td>
|
|||
|
<td>Update configuration of one or more containers</td>
|
|||
|
<td>Mettre à jour la configuration d’un ou plusieurs conteneurs</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>version</td>
|
|||
|
<td>Show the Docker version information</td>
|
|||
|
<td>Afficher les informations de version du Docker</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>wait</td>
|
|||
|
<td>Block until one or more containers stop, then print their exit codes</td>
|
|||
|
<td>attendre qu’un ou plusieurs conteneurs s’arrêtent, puis imprimer leur code de sortie</td>
|
|||
|
</tr>
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
|
|||
|
<p>Pour afficher les options disponibles pour une commande spécifique, tapez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker docker-subcommand --help
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour afficher des informations sur Docker à l’échelle du système, utilisez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker info
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Examinons quelques-unes de ces commandes. Nous allons commencer par travailler avec des images.</p>
|
|||
|
|
|||
|
<h3 id="4---travailler-avec-les-images-du-docker">4 - Travailler avec les images du docker</h3>
|
|||
|
|
|||
|
<p>Les conteneurs Docker sont construits à partir d’images Docker. Par défaut, Docker extrait ces images de Docker Hub, un registre de Docker géré par Docker, la société derrière le projet Docker. N’importe qui peut héberger ses images Docker sur Docker Hub, donc la plupart des applications et distributions Linux dont vous aurez besoin auront des images hébergées là.</p>
|
|||
|
|
|||
|
<p>Pour vérifier si vous pouvez accéder et télécharger des images depuis Docker Hub, tapez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run hello-world
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>La sortie indiquera que le Docker fonctionne correctement :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Unable to find image 'hello-world:latest' locally
|
|||
|
latest: Pulling from library/hello-world
|
|||
|
9db2ca6ccae0: Pull complete
|
|||
|
Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc
|
|||
|
Status: Downloaded newer image for hello-world:latest
|
|||
|
|
|||
|
Hello from Docker!
|
|||
|
This message shows that your installation appears to be working correctly.
|
|||
|
...
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Docker n’a d’abord pas pu trouver l’image hello-world localement, alors il a téléchargé l’image depuis Docker Hub, qui est le référentiel par défaut. Une fois l’image téléchargée, Docker crée un conteneur à partir de l’image et l’application à l’intérieur du conteneur est exécutée, affichant le message.</p>
|
|||
|
|
|||
|
<p>Vous pouvez rechercher des images disponibles sur Docker Hub en utilisant la commande docker avec la sous-commande de recherche. Par exemple, pour rechercher l’image Ubuntu, tapez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker search ubuntu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le script parcourra le Docker Hub et retournera une liste de toutes les images dont le nom correspond à la chaîne de recherche. Dans ce cas, la sortie sera similaire à celle-ci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NAME DESCRIPTION STARS OFFICIAL AUTOMATED
|
|||
|
ubuntu Ubuntu is a Debian-based Linux operating sys… 8320 [OK]
|
|||
|
dorowu/ubuntu-desktop-lxde-vnc Ubuntu with openssh-server and NoVNC 214 [OK]
|
|||
|
rastasheep/ubuntu-sshd Dockerized SSH service, built on top of offi… 170 [OK]
|
|||
|
consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC session… 128 [OK]
|
|||
|
ansible/ubuntu14.04-ansible Ubuntu 14.04 LTS with ansible 95 [OK]
|
|||
|
ubuntu-upstart Upstart is an event-based replacement for th… 88 [OK]
|
|||
|
neurodebian NeuroDebian provides neuroscience research s… 53 [OK]
|
|||
|
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5 ubuntu-16-nginx-php-phpmyadmin-mysql-5 43 [OK]
|
|||
|
ubuntu-debootstrap debootstrap --variant=minbase --components=m… 39 [OK]
|
|||
|
nuagebec/ubuntu Simple always updated Ubuntu docker images w… 23 [OK]
|
|||
|
tutum/ubuntu Simple Ubuntu docker images with SSH access 18
|
|||
|
i386/ubuntu Ubuntu is a Debian-based Linux operating sys… 13
|
|||
|
1and1internet/ubuntu-16-apache-php-7.0 ubuntu-16-apache-php-7.0 12 [OK]
|
|||
|
ppc64le/ubuntu Ubuntu is a Debian-based Linux operating sys… 12
|
|||
|
eclipse/ubuntu_jdk8 Ubuntu, JDK8, Maven 3, git, curl, nmap, mc, … 6 [OK]
|
|||
|
darksheer/ubuntu Base Ubuntu Image -- Updated hourly 4 [OK]
|
|||
|
codenvy/ubuntu_jdk8 Ubuntu, JDK8, Maven 3, git, curl, nmap, mc, … 4 [OK]
|
|||
|
1and1internet/ubuntu-16-nginx-php-5.6-wordpress-4 ubuntu-16-nginx-php-5.6-wordpress-4 3 [OK]
|
|||
|
pivotaldata/ubuntu A quick freshening-up of the base Ubuntu doc… 2
|
|||
|
1and1internet/ubuntu-16-sshd ubuntu-16-sshd 1 [OK]
|
|||
|
ossobv/ubuntu Custom ubuntu image from scratch (based on o… 0
|
|||
|
smartentry/ubuntu ubuntu with smartentry 0 [OK]
|
|||
|
1and1internet/ubuntu-16-healthcheck ubuntu-16-healthcheck 0 [OK]
|
|||
|
pivotaldata/ubuntu-gpdb-dev Ubuntu images for GPDB development 0
|
|||
|
paasmule/bosh-tools-ubuntu Ubuntu based bosh-cli 0 [OK]
|
|||
|
...
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans la colonne OFFICIAL, OK indique une image construite et soutenue par l’entreprise derrière le projet. Une fois que vous avez identifié l’image que vous souhaitez utiliser, vous pouvez la télécharger sur votre ordinateur en utilisant la sous-commande pull.</p>
|
|||
|
|
|||
|
<p>Exécutez la commande suivante pour télécharger l’image ubuntu officielle sur votre ordinateur :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker pull ubuntu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Using default tag: latest
|
|||
|
latest: Pulling from library/ubuntu
|
|||
|
6b98dfc16071: Pull complete
|
|||
|
4001a1209541: Pull complete
|
|||
|
6319fc68c576: Pull complete
|
|||
|
b24603670dc3: Pull complete
|
|||
|
97f170c87c6f: Pull complete
|
|||
|
Digest: sha256:5f4bdc3467537cbbe563e80db2c3ec95d548a9145d64453b06939c4592d67b6d
|
|||
|
Status: Downloaded newer image for ubuntu:latest
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Après le téléchargement d’une image, vous pouvez ensuite exécuter un conteneur à l’aide de l’image téléchargée avec la sous-commande Exécuter. Comme vous l’avez vu avec l’exemple hello-world, si une image n’a pas été téléchargée lorsque le docker est exécuté avec la sous-commande run, le client Docker téléchargera d’abord l’image, puis exécutera un conteneur en l’utilisant.</p>
|
|||
|
|
|||
|
<p>Pour voir les images qui ont été téléchargées sur votre ordinateur, tapez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker images
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>La sortie doit ressembler à ce qui suit :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>REPOSITORY TAG IMAGE ID CREATED SIZE
|
|||
|
ubuntu latest 16508e5c265d 13 days ago 84.1MB
|
|||
|
hello-world latest 2cb0d9787c4d 7 weeks ago 1.85kB
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Comme vous le verrez plus loin dans ce tutoriel, les images que vous utilisez pour exécuter des conteneurs peuvent être modifiées et utilisées pour générer de nouvelles images, qui peuvent ensuite être téléchargées (poussées est le terme technique) vers Docker Hub ou d’autres registres Docker.</p>
|
|||
|
|
|||
|
<p>Examinons plus en détail la façon d’utiliser les conteneurs.</p>
|
|||
|
|
|||
|
<h3 id="5---utilisation-dun-conteneur-de-docker">5 - Utilisation d’un conteneur de docker</h3>
|
|||
|
|
|||
|
<p>Le conteneur hello-world que vous avez utilisé à l’étape précédente est un exemple de conteneur qui fonctionne et sort après avoir émis un message de test. Les conteneurs peuvent être beaucoup plus utiles que cela, et ils peuvent être interactifs. Après tout, elles sont similaires aux machines virtuelles, mais plus respectueuses des ressources.</p>
|
|||
|
|
|||
|
<p>Par exemple, exécutons un conteneur en utilisant la dernière image d’Ubuntu. La combinaison des commutateurs -i et -t vous donne un accès interactif à l’interpréteur de commandes dans le conteneur :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run -it ubuntu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Votre invite de commande devrait changer pour refléter le fait que vous travaillez maintenant à l’intérieur du conteneur et devrait prendre cette forme :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@d9b100f2f636:/#
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Notez l’ID du conteneur dans l’invite de commande. Dans cet exemple, il s’agit de d9b100f2f2f636. Vous aurez besoin de cet ID de conteneur plus tard pour identifier le conteneur lorsque vous voudrez l’enlever.</p>
|
|||
|
|
|||
|
<p>Vous pouvez maintenant exécuter n’importe quelle commande à l’intérieur du conteneur. Par exemple, mettons à jour la base de données des paquets à l’intérieur du conteneur. Vous n’avez pas besoin de préfixer une commande avec sudo, car vous opérez dans le conteneur en tant qu’utilisateur root :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, installez n’importe quelle application. Installons Node.js :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install nodejs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ceci installe Node.js dans le conteneur à partir du dépôt officiel d’Ubuntu. Une fois l’installation terminée, vérifiez que Node.js est installé :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node -v
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous verrez le numéro de version affiché dans votre terminal :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>v8.10.0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Toute modification apportée à l’intérieur du conteneur ne s’applique qu’à ce conteneur.<br />
|
|||
|
Pour quitter le conteneur, tapez exit à l’invite.<br />
|
|||
|
Regardons maintenant la gestion des conteneurs sur notre système.</p>
|
|||
|
|
|||
|
<h3 id="6---gestion-des-conteneurs-de-dockers">6 - Gestion des conteneurs de dockers</h3>
|
|||
|
|
|||
|
<p>Après avoir utilisé Docker pendant un certain temps, vous aurez de nombreux conteneurs actifs (en cours d’exécution) et inactifs sur votre ordinateur. Pour visualiser les actifs, utilisez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker ps
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous verrez une sortie similaire à la suivante :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONTAINER ID IMAGE COMMAND CREATED
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans ce tutoriel, vous avez démarré deux conteneurs ; l’un de l’image hello-world et l’autre de l’image ubuntu. Les deux conteneurs ne fonctionnent plus, mais ils existent toujours sur votre système.</p>
|
|||
|
|
|||
|
<p>Pour afficher tous les conteneurs - actifs et inactifs, lancez le docker ps avec l’interrupteur -a :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker ps -a
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous verrez une sortie similaire à celle-ci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>d9b100f2f636 ubuntu "/bin/bash" About an hour ago Exited (0) 8 minutes ago sharp_volhard
|
|||
|
01c950718166 hello-world "/hello" About an hour ago Exited (0) About an hour ago festive_williams
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour afficher le dernier conteneur que vous avez créé, passez-lui l’option -l :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker ps -l
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|||
|
d9b100f2f636 ubuntu "/bin/bash" About an hour ago Exited (0) 10 minutes ago sharp_volhard
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour démarrer un conteneur à l’arrêt, utilisez la fonction de démarrage du docker, suivie de l’ID du conteneur ou du nom du conteneur. Démarrons le conteneur basé sur Ubuntu avec l’ID d9b100f2f636 :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker start d9b100f2f636
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le conteneur démarre et vous pouvez utiliser docker ps pour voir son état :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|||
|
d9b100f2f636 ubuntu "/bin/bash" About an hour ago Up 8 seconds sharp_volhard
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour arrêter un conteneur en cours de fonctionnement, utilisez la fonction docker stop, suivie de l’ID ou du nom du conteneur. Cette fois, nous utiliserons le nom que Docker a attribué au conteneur, qui est sharp_volhard :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker stop sharp_volhard
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Une fois que vous avez décidé que vous n’avez plus besoin d’un conteneur, supprimez-le à l’aide de la commande docker rm, en utilisant à nouveau l’ID ou le nom du conteneur. Utilisez la commande docker ps -a pour trouver l’ID ou le nom du conteneur associé à l’image hello-world et le supprimer.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker rm festive_williams
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous pouvez démarrer un nouveau conteneur et lui donner un nom en utilisant le commutateur –name. Vous pouvez également utiliser le commutateur –rm pour créer un conteneur qui se retire tout seul lorsqu’il est arrêté. Reportez-vous à la commande d’aide de l’exécution du docker pour plus d’informations sur ces options et d’autres.</p>
|
|||
|
|
|||
|
<p>Les conteneurs peuvent être transformés en images que vous pouvez utiliser pour construire de nouveaux conteneurs. Voyons comment cela fonctionne.</p>
|
|||
|
|
|||
|
<h3 id="7---transformation-dun-conteneur-en-une-image-docker">7 - Transformation d’un conteneur en une image docker</h3>
|
|||
|
|
|||
|
<p>Lorsque vous démarrez une image Docker, vous pouvez créer, modifier et supprimer des fichiers comme vous le pouvez avec une machine virtuelle. Les modifications que vous apportez ne s’appliqueront qu’à ce contenant. Vous pouvez le démarrer et l’arrêter, mais une fois que vous l’aurez détruit avec la commande rm du docker, les changements seront perdus pour de bon.</p>
|
|||
|
|
|||
|
<p>Cette section vous montre comment enregistrer l’état d’un conteneur en tant que nouvelle image du Docker.</p>
|
|||
|
|
|||
|
<p>Après avoir installé Node.js dans le conteneur Ubuntu, vous avez maintenant un conteneur qui fonctionne à partir d’une image, mais le conteneur est différent de l’image que vous avez utilisée pour le créer. Mais vous voudrez peut-être réutiliser ce conteneur Node.js comme base pour de nouvelles images plus tard.</p>
|
|||
|
|
|||
|
<p>Ensuite, validez les modifications sur une nouvelle instance d’image du Docker à l’aide de la commande suivante.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker commit -m "What you did to the image" -a "Author Name" container_id repository/new_image_name
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le commutateur -m est pour le message de livraison qui vous aide, vous et les autres, à savoir quels changements vous avez faits, tandis que -a est utilisé pour spécifier l’auteur. Le container_id est celui que vous avez noté plus tôt dans le tutoriel lorsque vous avez démarré la session interactive du Docker. A moins que vous n’ayez créé des dépôts supplémentaires sur Docker Hub, le dépôt (repository) est généralement votre nom d’utilisateur Docker Hub.</p>
|
|||
|
|
|||
|
<p>Par exemple, pour l’utilisateur sammy, avec l’ID de conteneur d9b100f2f636, la commande serait :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker commit -m "added Node.js" -a "sammy" d9b100f2f636 sammy/ubuntu-nodejs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lorsque vous validez une image, la nouvelle image est enregistrée localement sur votre ordinateur. Plus loin dans ce tutoriel, vous apprendrez comment pousser une image vers un registre Docker comme Docker Hub pour que d’autres puissent y accéder.</p>
|
|||
|
|
|||
|
<p>Le fait de lister à nouveau les images du Docker affichera la nouvelle image, ainsi que l’ancienne dont elle est dérivée :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker images
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous verrez une sortie comme celle-ci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>REPOSITORY TAG IMAGE ID CREATED SIZE
|
|||
|
sammy/ubuntu-nodejs latest 7c1f35226ca6 7 seconds ago 179MB
|
|||
|
ubuntu latest 113a43faa138 4 weeks ago 81.2MB
|
|||
|
hello-world latest e38bc07ac18e 2 months ago 1.85kB
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans cet exemple, ubuntu-nodejs est la nouvelle image, qui a été dérivée de l’image ubuntu existante de Docker Hub. La différence de taille reflète les changements qui ont été apportés. Et dans cet exemple, le changement a été l’installation de NodeJS. Ainsi, la prochaine fois que vous aurez besoin d’exécuter un conteneur en utilisant Ubuntu avec NodeJS préinstallé, vous pourrez simplement utiliser la nouvelle image.</p>
|
|||
|
|
|||
|
<p>Vous pouvez également construire des images à partir d’un fichier docker (Dockerfile), ce qui vous permet d’automatiser l’installation du logiciel dans une nouvelle image. Cependant, cela n’entre pas dans le cadre de ce tutoriel.</p>
|
|||
|
|
|||
|
<p>Partageons maintenant la nouvelle image avec d’autres personnes pour qu’elles puissent créer des conteneurs à partir de celle-ci.</p>
|
|||
|
|
|||
|
<h3 id="8---pousser-les-docker-images-vers-un-docker-repository">8 - Pousser les Docker Images vers un Docker Repository</h3>
|
|||
|
|
|||
|
<p>La prochaine étape logique après la création d’une nouvelle image à partir d’une image existante est de la partager avec quelques-uns de vos amis, le monde entier sur Docker Hub, ou tout autre registre Docker auquel vous avez accès. Pour pousser une image vers Docker Hub ou tout autre registre Docker, vous devez y avoir un compte.</p>
|
|||
|
|
|||
|
<p>Cette section vous montre comment pousser une image du Docker vers le Hub du Docker. Pour savoir comment créer votre propre registre de dockers privé, consultez la section Comment créer un registre de dockers privé sur Ubuntu 14.04.</p>
|
|||
|
|
|||
|
<p>Pour pousser votre image, connectez-vous d’abord à Docker Hub.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker login -u docker-registry-username
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous serez invité à vous authentifier à l’aide de votre mot de passe Docker Hub. Si vous avez spécifié le mot de passe correct, l’authentification devrait réussir.</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Remarque : Si votre nom d’utilisateur du registre Docker est différent du nom d’utilisateur local que vous avez utilisé pour créer l’image, vous devrez marquer votre image avec votre nom d’utilisateur du registre. Pour l’exemple donné à la dernière étape, vous devez taper :<br />
|
|||
|
<code class="language-plaintext highlighter-rouge">docker tag sammy/ubuntu-nodejs docker-registry-username/ubuntu-nodejs</code></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Ensuite, vous pouvez pousser votre propre image en utilisant :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker push docker-registry-username/docker-image-name
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour pousser l’image ubuntu-nodejs vers le dépôt sammy, la commande serait :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker push sammy/ubuntu-nodejs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le processus peut prendre un certain temps pour se terminer lorsqu’il télécharge les images, mais une fois terminé, le résultat ressemblera à ceci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The push refers to a repository [docker.io/sammy/ubuntu-nodejs]
|
|||
|
e3fbbfb44187: Pushed
|
|||
|
5f70bf18a086: Pushed
|
|||
|
a3b5c80a4eba: Pushed
|
|||
|
7f18b442972b: Pushed
|
|||
|
3ce512daaf78: Pushed
|
|||
|
7aae4540b42d: Pushed
|
|||
|
|
|||
|
...
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Après avoir poussé une image vers un registre, elle devrait être listée dans le tableau de bord de votre compte, comme cela apparaît dans l’image ci-dessous.</p>
|
|||
|
|
|||
|
<p><img src="/images/ec2vX3Z.png" alt="" width="600" /></p>
|
|||
|
|
|||
|
<p>Nouvelle liste d’images de Docker sur Docker Hub</p>
|
|||
|
|
|||
|
<p>Si une tentative de poussée entraîne une erreur de ce type, il est probable que vous ne vous soyez pas connecté :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The push refers to a repository [docker.io/sammy/ubuntu-nodejs]
|
|||
|
e3fbbfb44187: Preparing
|
|||
|
5f70bf18a086: Preparing
|
|||
|
a3b5c80a4eba: Preparing
|
|||
|
7f18b442972b: Preparing
|
|||
|
3ce512daaf78: Preparing
|
|||
|
7aae4540b42d: Waiting
|
|||
|
unauthorized: authentication required
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Connectez-vous avec le login du docker docker login et répétez la tentative de poussée. Vérifiez ensuite qu’il existe sur votre page de dépôt Docker Hub.</p>
|
|||
|
|
|||
|
<p>Vous pouvez maintenant utiliser docker pull sammy/ubuntu-nodejs pour tirer l’image vers une nouvelle machine et l’utiliser pour exécuter un nouveau conteneur.</p>
|
|||
|
|
|||
|
<h3 id="9---comment-supprimer-des-images-des-conteneurs-et-des-volumes-docker">9 - <a href="https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes-fr">Comment supprimer des images, des conteneurs et des volumes Docker</a></h3>
|
|||
|
|
|||
|
<h3 id="conclusion">Conclusion</h3>
|
|||
|
|
|||
|
<p>Dans ce tutoriel, vous avez installé Docker, travaillé avec des images et des conteneurs, et déplacé une image modifiée vers Docker Hub. Maintenant que vous connaissez les bases, explorez les <a href="https://www.digitalocean.com/community/tags/docker?type=tutorials">autres tutoriels de Docker</a> dans la communauté DigitalOcean.</p>
|
|||
|
|
|||
|
<h2 id="ii---docker-compose">II - Docker Compose</h2>
|
|||
|
|
|||
|
<h3 id="introduction">Introduction</h3>
|
|||
|
|
|||
|
<p><em>Docker est un excellent outil pour automatiser le déploiement d’applications Linux à l’intérieur de conteneurs logiciels, mais pour tirer pleinement parti de son potentiel, chaque composant d’une application doit fonctionner dans son propre conteneur individuel. Pour des applications complexes avec beaucoup de composants, orchestrer tous les conteneurs pour démarrer, communiquer et s’arrêter ensemble peut rapidement devenir compliqué.<br />
|
|||
|
La communauté Docker a mis au point une solution populaire appelée Fig, qui vous permet d’utiliser un seul fichier YAML pour orchestrer tous vos conteneurs et configurations Docker. Cela est devenu si populaire que l’équipe Docker a décidé de créer <strong>Docker Compose</strong> à partir de la source Fig, qui est maintenant obsolète. Docker Compose permet aux utilisateurs d’orchestrer plus facilement les processus des conteneurs Docker, y compris le démarrage, l’arrêt et la mise en place de liens et de volumes intra-container.</em></p>
|
|||
|
|
|||
|
<p>Dans ce tutoriel, nous allons vous montrer comment installer la dernière version de Docker Compose pour vous aider à gérer les applications multi-containers sur un serveur debian 10 et 11.</p>
|
|||
|
|
|||
|
<h3 id="conditions-préalables-1">Conditions préalables</h3>
|
|||
|
|
|||
|
<p>Pour suivre cet article, vous aurez besoin de :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Un serveur debian 10 et 11 et un utilisateur non root avec des privilèges sudo. Cette configuration initiale du serveur avec le tutoriel debian 10 et 11 explique comment configurer cela.</li>
|
|||
|
<li>Docker installé avec les instructions des étapes 1 et 2 de Comment installer et utiliser le docker sur debian 10 et 11</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Remarque : Bien que les conditions préalables donnent des instructions pour installer Docker sur debian 10 et 11, les commandes de docker dans cet article devraient fonctionner sur d’autres systèmes d’exploitation tant que Docker est installé.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="1---installation-de-docker-compose">1 - Installation de Docker Compose</h3>
|
|||
|
|
|||
|
<p>Bien que nous puissions installer Docker Compose à partir des dépôts Debian officiels, il y a plusieurs versions mineures derrière la dernière version, donc nous allons l’installer à partir du dépôt GitHub de Docker. La commande ci-dessous est légèrement différente de celle que vous trouverez sur la page Communiqués. En utilisant l’option -o pour spécifier d’abord le fichier de sortie plutôt que de rediriger la sortie, cette syntaxe évite de se heurter à une erreur de refus de permission causée par l’utilisation de sudo.</p>
|
|||
|
|
|||
|
<p>Nous allons vérifier la version actuelle et, si nécessaire, la mettre à jour dans la commande ci-dessous :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo curl -L https://github.com/docker/compose/releases/download/1.25.3/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, nous allons définir les permissions :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chmod +x /usr/local/bin/docker-compose
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, nous vérifierons que l’installation a réussi en vérifiant la version :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose --version
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ceci imprimera la version que nous avons installée :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-compose version 1.25.3, build d4d1b42b
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Maintenant que Docker Compose est installé, nous sommes prêts à lancer un exemple “Hello World”.</p>
|
|||
|
|
|||
|
<h3 id="2---utilisation-dun-conteneur-avec-docker-compose">2 - Utilisation d’un conteneur avec Docker Compose</h3>
|
|||
|
|
|||
|
<p>Le registre public des dockers, Docker Hub, comprend une image Hello World pour démonstration et test. Il illustre la configuration minimale requise pour exécuter un conteneur en utilisant Docker Compose : un fichier YAML qui appelle une seule image. Nous allons créer cette configuration minimale pour faire fonctionner notre conteneur hello-world.</p>
|
|||
|
|
|||
|
<p>Tout d’abord, nous allons créer un répertoire pour le fichier YAML et y accéder :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir hello-world
|
|||
|
cd hello-world
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, nous allons créer le fichier YAML :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano docker-compose.yml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Placez le contenu suivant dans le fichier, enregistrez le fichier et quittez l’éditeur de texte :
|
|||
|
docker-compose.yml</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>my-test:
|
|||
|
image: hello-world
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>La première ligne du fichier YAML est utilisée comme partie du nom du conteneur. La deuxième ligne spécifie l’image à utiliser pour créer le conteneur. Lorsque nous lançons la commande <strong>docker-composer up</strong>, elle cherchera une image locale par le nom que nous avons spécifié, <strong>hello-world</strong>. Une fois cela en place, nous sauvegarderons et quitterons le fichier.</p>
|
|||
|
|
|||
|
<p>Nous pouvons regarder manuellement les images sur notre système avec la commande docker images :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker images
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lorsqu’il n’y a pas d’images locales du tout, seuls les titres des colonnes s’affichent :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>REPOSITORY TAG IMAGE ID CREATED SIZE
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Maintenant, alors que nous sommes encore dans le répertoire <strong>~/hello-world</strong>, nous allons exécuter la commande suivante :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-composer up
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>La première fois que nous exécutons la commande, s’il n’y a pas d’image locale nommée hello-world, Docker Compose la sortira du dépôt public de Docker Hub :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Pulling my-test (hello-world:)...
|
|||
|
latest: Pulling from library/hello-world
|
|||
|
9db2ca6ccae0: Pull complete
|
|||
|
Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc
|
|||
|
Status: Downloaded newer image for hello-world:latest
|
|||
|
. . .
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Après avoir tiré l’image, <strong>docker-compose</strong> crée un conteneur, attache et exécute le programme hello, qui à son tour confirme que l’installation semble fonctionner :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>. . .
|
|||
|
Creating helloworld_my-test_1...
|
|||
|
Attaching to helloworld_my-test_1
|
|||
|
my-test_1 |
|
|||
|
my-test_1 | Hello from Docker.
|
|||
|
my-test_1 | This message shows that your installation appears to be working correctly.
|
|||
|
my-test_1 |
|
|||
|
. . .
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, il imprime une explication de ce qu’il a fait :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> To generate this message, Docker took the following steps:
|
|||
|
my-test_1 | 1. The Docker client contacted the Docker daemon.
|
|||
|
my-test_1 | 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
|||
|
my-test_1 | (amd64)
|
|||
|
my-test_1 | 3. The Docker daemon created a new container from that image which runs the
|
|||
|
my-test_1 | executable that produces the output you are currently reading.
|
|||
|
my-test_1 | 4. The Docker daemon streamed that output to the Docker client, which sent it
|
|||
|
my-test_1 | to your terminal.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les conteneurs des dockers fonctionnent tant que la commande est active, donc une fois que hello a fini de fonctionner, le conteneur s’est arrêté. Par conséquent, lorsque nous regardons les processus actifs, les en-têtes de colonnes apparaîtront, mais le conteneur hello-world ne sera pas listé parce qu’il ne fonctionne pas :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker ps
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Nous pouvons voir les informations sur le conteneur, dont nous aurons besoin à l’étape suivante, en utilisant le drapeau -a. Ceci montre tous les conteneurs, pas seulement ceux qui sont actifs :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker ps -a
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|||
|
06069fd5ca23 hello-world "/hello" 35 minutes ago Exited (0) 35 minutes ago hello-world_my-test_1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ceci affiche les informations dont nous aurons besoin pour retirer le conteneur lorsque nous en aurons fini avec lui.</p>
|
|||
|
|
|||
|
<h3 id="3---retrait-de-limage-facultatif">3 - Retrait de l’image (facultatif)</h3>
|
|||
|
|
|||
|
<p>Pour éviter d’utiliser inutilement de l’espace disque, nous allons supprimer l’image locale. Pour ce faire, nous devrons supprimer tous les conteneurs qui font référence à l’image à l’aide de la commande <strong>docker rm</strong>, suivie soit de l’ID CONTAINER, soit du NOM. Ci-dessous, nous utilisons l’ID CONTAINER du <strong>docker ps -a</strong> commande que nous venons d’exécuter. Assurez-vous de remplacer l’ID de votre conteneur :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker rm 06069fd5ca23
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Une fois que tous les conteneurs qui font référence à l’image ont été supprimés, nous pouvons supprimer l’image :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker rmi hello-world
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="conclusion-1">Conclusion</h3>
|
|||
|
|
|||
|
<p>Nous avons maintenant installé <strong>Docker Compose</strong>, testé notre installation en exécutant un exemple Hello World, et supprimé l’image de test et le conteneur.</p>
|
|||
|
|
|||
|
<p>Bien que l’exemple de Hello World ait confirmé notre installation, la configuration simple ne montre pas l’un des principaux avantages de Docker Compose - être capable de faire monter et descendre un groupe de conteneurs Docker tous en même temps. Pour voir la puissance de Docker Compose en action, vous pouvez consulter cet exemple pratique, <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-a-continuous-integration-testing-environment-with-docker-and-docker-compose-on-ubuntu-16-04">Comment configurer un environnement de test d’intégration continue avec Docker et Docker Compose sur Ubuntu 16.04 (en)</a>.</p>
|
|||
|
|
|||
|
<h2 id="conteneur-docker-systemd-service">Conteneur Docker systemd service</h2>
|
|||
|
|
|||
|
<h3 id="introduction-1">Introduction</h3>
|
|||
|
|
|||
|
<p>Il existe de nombreuses façons d’orchestrer la gestion, l’initialisation, le déploiement des conteneurs de docker, etc. Même Docker apporte son propre outil et son mode vanille. Il existe également de nombreux autres outils tiers d’orchestration de conteneurs tels que Kubernetes, Rancher, Apache Mesos, etc.</p>
|
|||
|
|
|||
|
<p>Le démon Docker offre des moyens simples pour démarrer, arrêter, gérer et interroger le statut des conteneurs déployés. Dans cet article, nous allons voir comment utiliser une approche docker + systemd uniquement pour déployer des conteneurs en tant que services Linux sans avoir besoin d’outils tiers ou de descripteurs de déploiement complexes.</p>
|
|||
|
|
|||
|
<p>Dans ce tutoriel, nous montrerons comment déployer Portainer en tant que service systemd de Linux.</p>
|
|||
|
|
|||
|
<h3 id="conteneur-existant">Conteneur existant</h3>
|
|||
|
|
|||
|
<p>La méthode la plus simple pour déployer un conteneur en tant que service consiste à créer un conteneur de docker avec un nom donné et ensuite de mapper chacune des opérations de docker (démarrage et arrêt) aux commandes de service du système.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run -d --name portainer --privileged -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v /opt/docker/data/portainer:/data portainer/portainer
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Une fois que nous avons créé ce conteneur, nous pouvons le démarrer, l’arrêter et le redémarrer en utilisant les commandes habituelles du docker en indiquant le nom du conteneur (docker stop portainer, docker start portainer, docker restart portainer).</p>
|
|||
|
|
|||
|
<p>Nous pouvons créer un nouveau fichier d’unité systemd avec la description du service en créant un nouveau fichier dans /etc/systemd/system/. Pour les besoins de cet exemple, nous allons créer un nouveau fichier portainer.service avec le contenu suivant</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
|
|||
|
Description=Portainer container
|
|||
|
After=docker.service
|
|||
|
Wants=network-online.target docker.socket
|
|||
|
Requires=docker.socket
|
|||
|
|
|||
|
[Service]
|
|||
|
Restart=always
|
|||
|
ExecStart=/usr/bin/docker start -a portainer
|
|||
|
ExecStop=/usr/bin/docker stop -t 10 portainer
|
|||
|
|
|||
|
[Install]
|
|||
|
WantedBy=multi-user.target
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le fichier d’unité crée un nouveau service et associe les commandes de démarrage et d’arrêt du docker aux séquences de démarrage et d’arrêt du service.</p>
|
|||
|
|
|||
|
<p>Le fichier unit décrit comme des dépendances la cible réseau en ligne et la prise docker, si la prise docker ne démarre pas ce service ne le fera pas non plus. Il ajoute également une dépendance à docker.service, de sorte que ce service ne fonctionnera pas tant que docker.service n’aura pas démarré.</p>
|
|||
|
|
|||
|
<p>Nous pouvons maintenant démarrer/arrêter le service en émettant la commande correspondante :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl start portainer
|
|||
|
systemctl stop portainer
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Nous pouvons également installer le service pour qu’il fonctionne au démarrage en courant :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl enable portainer.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="créer-un-conteneur-au-démarrage">Créer un conteneur au démarrage</h3>
|
|||
|
|
|||
|
<p>Nous pouvons améliorer le fichier d’unité précédent pour créer le conteneur s’il n’existe pas, cela nous permettra de sauter la première étape de création manuelle du conteneur (docker run…) et peut être utilisé pour déployer les conteneurs en créant simplement le fichier d’unité de descripteur de service.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Unit]
|
|||
|
Description=Portainer container
|
|||
|
After=docker.service
|
|||
|
Wants=network-online.target docker.socket
|
|||
|
Requires=docker.socket
|
|||
|
|
|||
|
[Service]
|
|||
|
Restart=always
|
|||
|
ExecStartPre=/bin/bash -c "/usr/bin/docker container inspect portainer 2> /dev/null || /usr/bin/docker run -d --name portainer --privileged -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v /opt/docker/data/portainer:/data portainer/portainer"
|
|||
|
ExecStart=/usr/bin/docker start -a portainer
|
|||
|
ExecStop=/usr/bin/docker stop -t 10 portainer
|
|||
|
|
|||
|
[Install]
|
|||
|
WantedBy=multi-user.target
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Nous avons simplement ajouté une ligne supplémentaire avec une instruction <strong>ExecStartPre</strong>. Les fichiers d’unité Systemd présentent certaines limitations lors de l’exécution de commandes dans les définitions <strong>ExecStart</strong>, <strong>ExtecStop</strong>, <strong>ExecStartPre</strong>….. Afin de surmonter ces limitations, nous avons encapsulé la commande dans une commande <strong>“/bin/bash -c”</strong> qui nous permet un peu plus de flexibilité.</p>
|
|||
|
|
|||
|
<p>La première commande (docker container inspect) vérifiera si un conteneur de ce nom existe déjà dans la machine hôte du docker. Si cette commande provoque une erreur (c’est-à-dire si le conteneur n’existe pas), l’instruction suivante sera exécutée. Cette commande est la même que celle que nous avons utilisée précédemment pour créer le conteneur manuellement.</p>
|
|||
|
|
|||
|
<p>Il est vraiment important d’exécuter la commande d’exécution du Docker avec le drapeau <strong>-d (détaché)</strong>, sinon la commande ne reviendra pas et l’étape suivante (ExecStart) ne pourra pas être exécutée, de sorte que le systemd ne sera jamais actif.</p>
|
|||
|
|
|||
|
<p>En fonction de l’existence antérieure du conteneur, la séquence de démarrage du service se comportera d’une manière ou d’une autre :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Un conteneur nommé portainer existe déjà :
|
|||
|
<ul>
|
|||
|
<li><strong>ExecStartPre</strong> reviendra sans erreur sur la première commande (docker container inspect…) donc n’exécutera pas la seconde (docker run…).</li>
|
|||
|
<li><strong>ExecStart</strong> s’exécutera normalement et le processus s’attachera au conteneur.</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li>Un conteneur nommé portainer n’existe pas :
|
|||
|
<ul>
|
|||
|
<li><strong>ExecStartPre</strong> reviendra avec une erreur sur la première commande (docker container inspect…), la deuxième commande créera et démarrera le conteneur en mode détaché en renvoyant le contrôle à systemctl.</li>
|
|||
|
<li><strong>ExecStart</strong> s’exécutera (docker start) ce qui n’aura aucun effet mais s’attachera au conteneur en cours d’exécution.</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="conclusion-2">Conclusion</h3>
|
|||
|
|
|||
|
<p>Dans ce tutoriel, nous avons montré une façon simple de déployer des conteneurs dockers en tant que services systemd Linux. Il s’agit d’un “chea</p>
|
|||
|
|
|||
|
<h2 id="désinstaller">Désinstaller</h2>
|
|||
|
|
|||
|
<p>Pour une désinstallation complète</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt purge -y docker-ce docker-buildx-plugin docker-compose docker-compose-plugin python3-docker python3-dockerpty docker.io
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-03-10T00:00:00+01: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>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/03/07/WireGuard-on-Linux-terminal(advanced).html">Wireguard (Mullvad) sur terminal Linux (avancé)</a></div><div class="next"><span>SUIVANT</span><a href="/2020/03/10/GRUB-files-and-scripts-for-create-usb-pendrive-capable-of-booting-different-ISO-files(multiboot).html">MULTIBOOT USB 32Go (EFI+GPT et BIOS+GPT/MBR)</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} {title}</a> (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>
|
|||
|
|