3865 lines
290 KiB
HTML
3865 lines
290 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>Virtualisation KVM/QEMU - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="-">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2020/09/12/KVM-QEMU-virtualisation-linux.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;">Virtualisation KVM/QEMU</h1></header></div><meta itemprop="headline" content="Virtualisation KVM/QEMU"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=virtuel">virtuel</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">12 sept. 2020</span></li></ul></div><meta itemprop="datePublished" content="2020-09-12T00:00:00+02:00">
|
|||
|
<meta itemprop="keywords" content="virtuel"><div class="js-article-content">
|
|||
|
<div class="layout--article"><!-- start custom article top snippet -->
|
|||
|
<style>
|
|||
|
#myBtn {
|
|||
|
display: none;
|
|||
|
position: fixed;
|
|||
|
bottom: 10px;
|
|||
|
right: 10px;
|
|||
|
z-index: 99;
|
|||
|
font-size: 12px;
|
|||
|
font-weight: bold;
|
|||
|
border: none;
|
|||
|
outline: none;
|
|||
|
background-color: white;
|
|||
|
color: black;
|
|||
|
cursor: pointer;
|
|||
|
padding: 5px;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
#myBtn:hover {
|
|||
|
background-color: #555;
|
|||
|
}
|
|||
|
</style>
|
|||
|
|
|||
|
<button onclick="topFunction()" id="myBtn" title="Haut de page">⇧</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/kvm-logo.png" alt="KVM" /> - <img src="/images/qemulogo.png" alt="Qemu" /></p>
|
|||
|
|
|||
|
<p><strong>KVM</strong> est une bifurcation de <strong>QEMU</strong>. Le code KVM est modifié pour prendre en charge l’accélération matérielle lorsqu’elle est disponible (même architecture pour la VM hôte et la VM invitée).</p>
|
|||
|
|
|||
|
<p>La plupart du temps, la <strong>QEMU</strong> est utilisée pour émuler une autre architecture (par exemple, émuler ARM/Power arch. en utilisant un processeur x86. Exemple : faire tourner une image RaspberryPI qui fonctionne sur ARM dans un ordinateur équipé d’un processeur Intel)</p>
|
|||
|
|
|||
|
<p>Une différence entre les deux est que la <strong>QEMU</strong> fonctionne sur un processeur sans avoir besoin d’une extension de virtualisation matérielle (Intel VT/VT-d, AMD-V) alors que la <strong>KVM</strong> l’utilise. Les extensions de virtualisation matérielle vous permettent d’accéder directement au matériel sur la machine physique. L’inconvénient est que la base de code <strong>KVM</strong> ne peut pas émuler une autre architecture.</p>
|
|||
|
|
|||
|
<h1 id="kvmqemu">KVM/Qemu</h1>
|
|||
|
|
|||
|
<p><em>Kernel-based Virtual Machine (KVM) est un module de virtualisation pour le noyau Linux qui le transforme en hyperviseur</em></p>
|
|||
|
|
|||
|
<p><u>Simuler une machine complète pour avoir son propre environnement d’exécution.</u><br />
|
|||
|
<em>Les avantages sont nombreux, isolations des processus, plusieurs environnements différents, etc…</em></p>
|
|||
|
|
|||
|
<p>La virtualisation matérielle est possible au moyen de ce que l’on appelle des hyperviseurs.<br />
|
|||
|
<strong>Il existe plusieurs types d’hyperviseurs, classés en 2 niveaux.</strong></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Le niveau 1 est dit “natif”.
|
|||
|
<ul>
|
|||
|
<li><strong>Natif</strong> car les instructions processeurs du système virtuelle sont directement transmis aux hardware. Il faut donc vérifier la compatibilité entre les systèmes virtualisés et les composants matérielles.</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li>Le niveau 2 est dit “hosted”.
|
|||
|
<ul>
|
|||
|
<li><strong>Hosted</strong> car la virtualisation s’effectue grâce à un logiciel installé sur un système d’exploitation. Donc la machine virtualisée n’interagit pas directement avec le Hardware.</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong><u>KVM est un hyperviseur de type 1</u></strong>, il est intégré de manière native à beaucoup de distribution basées sur le noyau Linux. KVM pour Kernel-based Virtual Machine car il transforme le noyau linux sur lequel il est exécuté en hyperviseur, proxmox est basé dessus.
|
|||
|
Il en existe d’autres.</p>
|
|||
|
|
|||
|
<p>On utilise <strong>QEMU</strong> (QuickEmulator) pour interagir avec <strong>KVM</strong>.</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><u>**Qemu** est de type 1 et 2</u>.
|
|||
|
<ul>
|
|||
|
<li>Il peut simuler un environnement pour une machine totalement différente de la votre, par exemple une py sur un PC. Dans ce cas la il transforme les exécutions de processeurs pour les rendre compatibles avec le hardware, donc la il est de <strong>type 2</strong>.</li>
|
|||
|
<li>Mais quand il est utilise avec <strong>KVM</strong> dans ce cas la il fonctionne en <strong>type 1</strong> avec des performances bien meilleures.</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>En clair <strong>Qemu sert à manager les machines virtuels, c’est un client</strong>.<br />
|
|||
|
Et la liaison entre Qemu et KVM est faite via l’API libvirt ( management du réseau, stockages, clavier, souris, etc )</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p><a href="http://libvirt.org/">libvirt</a> est une bibliothèque permettant d’interagir avec différentes solutions de virtualisation (cet article s’intéressera uniquement à KVM/QEMU, mais Xen, VirtualBox et d’autres sont aussi possibles)<br />
|
|||
|
<a href="http://virt-manager.org/">Virtual Machine Manager</a> est un ensemble d’applications permettant de gérer les machines virtuelles</p>
|
|||
|
|
|||
|
<p>En mode graphique :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>virt-viewer</strong> est une interface graphique permettant de se connecter sur une machine virtuelle</li>
|
|||
|
<li><strong>virt-manager</strong> est une interface graphique permettant de gérer les machines virtuelles</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>En ligne de commande :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>virt-clone</strong> permet de dupliquer une machine existante</li>
|
|||
|
<li><strong>virt-convert</strong> permet de convertir l’image d’une machine</li>
|
|||
|
<li><strong>virt-image</strong> permet de créer un nouvelle machine à partir d’une image</li>
|
|||
|
<li><strong>virt-install</strong> permet de créer une nouvelle machine ou d’importer une machine déjà créé ultérieurement avec qemu ou qemu-kvm</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><a href="http://www.nongnu.org/qemu/">QEMU</a> est une <u>solution d'émulation et de virtualisation</u> (avec kqemu un pilote permettant d’optimiser l’émulation lorsque qu’elle concerne la même architecture).QEMU peut utiliser KVM lors de l’exécution d’une architecture cible identique à l’architecture hôte. Par exemple, lorsque vous exécutez qemu-system-x86 sur un processeur compatible x86, vous pouvez profiter de l’accélération KVM - ce qui vous donne un avantage pour votre hôte et votre système invité.</p>
|
|||
|
|
|||
|
<p><a href="http://www.linux-kvm.org/page/Main_Page">KVM</a> (<em>Kernel-based Virtual Machine</em>) est une <u>solution de virtualisation</u>, pour les processeurs disposant des capacités nécessaires, et intégré au noyau linux.Il supporte les processeurs Intel et AMD récents (x86 et x86_64), PPC 440, PPC 970, S/390, ARM (Cortex A15, AArch64), et les processeurs MIPS32.</p>
|
|||
|
|
|||
|
<font color="red"><b>Vous ne pouvez pas utiliser KVM en même temps que VirtualBox. Il faudra en effet fermer KVM pour utiliser VirtualBox et vice versa. Ou désactiver le support de la virtualisation processeur dans VirtualBox</b></font>
|
|||
|
|
|||
|
<h3 id="debian">Debian</h3>
|
|||
|
|
|||
|
<p>Vous pouvez utiliser KVM pour exécuter plusieurs systèmes d’exploitation tels que Windows, *BSD, distribution Linux en utilisant des machines virtuelles. Chaque machine virtuelle a son disque privé, sa carte graphique, une carte réseau et plus encore.</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Le serveur hôte situé dans le centre de données distant et c’est un serveur sans affichage.</li>
|
|||
|
<li>Toutes les commandes de ce tutoriel ont été tapées via une session <strong>ssh</strong>.</li>
|
|||
|
<li>Vous avez besoin d’un client vnc pour installer le système d’exploitation invité.</li>
|
|||
|
<li>Dans ce tutoriel, vous apprendrez comment installer le logiciel KVM sur le serveur Debian Linux 9.x et utiliser KVM pour configurer votre première VM invitée.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h4 id="installation-sur-serveur-debian">Installation sur serveur debian</h4>
|
|||
|
|
|||
|
<p>On utilise ssh pour se connecter au serveur<br />
|
|||
|
Installation, exécuter la commande suivante</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils libguestfs-tools genisoimage virtinst libosinfo-bin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Chargez et activez le module vhost_net</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo modprobe vhost_net
|
|||
|
lsmod | grep vhost
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vhost_net 24576 0
|
|||
|
tun 49152 1 vhost_net
|
|||
|
vhost 49152 1 vhost_net
|
|||
|
tap 28672 1 vhost_net
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour que le module soit rechargé au prochain démarrage</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo "vhost_net" | sudo tee -a /etc/modules
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="ajout-utilisateur-au-groupe-libvirt">Ajout utilisateur au groupe libvirt</h4>
|
|||
|
|
|||
|
<p>Si vous voulez que l’utilisateur normal/régulier puisse gérer les machines virtuelles. Ajouter l’utilisateur $USER à libvirt et libvirt-qemu en utilisant la commande <em>usermod</em></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo adduser $USER libvirt
|
|||
|
sudo adduser $USER libvirt-qemu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Recharger l’adhésion à un groupe avec l’aide de la commande <em>newgrp</em></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>newgrp libvirt
|
|||
|
newgrp libvirt-qemu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifiez votre appartenance à un groupe à l’aide de la commande <em>id</em></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Veuillez noter que vous devez utiliser la commande suivante pour vous connecter au serveur KVM</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh --connect qemu:///system
|
|||
|
virsh --connect qemu:///system command
|
|||
|
virsh --connect qemu:///system list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="kvm-supporté-par-le-cpu-">kvm supporté par le CPU ?</h4>
|
|||
|
|
|||
|
<p>Exécutez la commande <em>egrep</em> suivante pour vérifier que <strong>Intel VMX</strong> ou <strong>AMD SVM</strong> est supporté sur votre CPU</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>egrep --color 'vmx|svm' /proc/cpuinfo
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>vmx (Intel) ou svm (Amd) doit apparaître d’une autre couleur dans le résultat</p>
|
|||
|
|
|||
|
<h4 id="service-libvirtd">Service libvirtd</h4>
|
|||
|
|
|||
|
<p>On vérifie qu’il est démarré et actif</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl status libvirtd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>● libvirtd.service - Virtualization daemon
|
|||
|
Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
|
|||
|
Active: active (running) since Sat 2019-11-30 09:11:26 CET; 13min ago
|
|||
|
Docs: man:libvirtd(8)
|
|||
|
https://libvirt.org
|
|||
|
Main PID: 31894 (libvirtd)
|
|||
|
Tasks: 17 (limit: 32768)
|
|||
|
Memory: 17.0M
|
|||
|
CGroup: /system.slice/libvirtd.service
|
|||
|
└─31894 /usr/sbin/libvirtd
|
|||
|
|
|||
|
nov. 30 09:11:26 xoyize.xyz systemd[1]: Starting Virtualization daemon...
|
|||
|
nov. 30 09:11:26 xoyize.xyz systemd[1]: Started Virtualization daemon.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans le cas contraire</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable libvirtd
|
|||
|
sudo systemctl start libvirtd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="créer-des-machines-virtuelles">Créer des machines virtuelles</h4>
|
|||
|
|
|||
|
<p>Tous les fichiers de la machine virtuelle et les autres fichiers associés seront stockés sous <strong>/var/lib/libvirt/</strong>.<br />
|
|||
|
Le chemin par défaut des images ISO est <strong>/var/lib/libvirt/boot/</strong>.<br />
|
|||
|
On va créer un autre répertoire et lui donner des droits</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir /srv/data/virtuel
|
|||
|
sudo chown $USER. /srv/data/virtuel
|
|||
|
mkdir -p /srv/data/virtuel/{boot,images}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="le-réseau">Le réseau</h4>
|
|||
|
|
|||
|
<p>Avant toute chose, il faut activer le réseau <br />
|
|||
|
On liste</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Name State Autostart Persistent
|
|||
|
----------------------------------------------
|
|||
|
default inactive no yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>On active</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-start default
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Network default started</p>
|
|||
|
|
|||
|
<p>On vérifie</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Name State Autostart Persistent
|
|||
|
--------------------------------------------
|
|||
|
default active no yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>créer et démarre automatiquement virbr0 au démarrage de l’hôte:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-autostart default
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>pour personnaliser sa configuration réseau :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-edit default
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Lors de l’utilisation du réseau par défaut de libvirt, libvirt va connecter l’interface de la machine virtuelle à un pont appelé virbr0. Il existe un processus dnsmasq géré par libvirt qui distribuera une adresse IP sur le sous-réseau 192.168.122.0/24, et libvirt a des règles iptables pour faire NAT pour les adresses IP sur ce sous-réseau.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h4 id="machine-virtuelle">Machine virtuelle</h4>
|
|||
|
|
|||
|
<p>Voyons d’abord s’il existe des machines virtuelles. Pour afficher la liste des machines virtuelles disponibles, exécutez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Id Name State
|
|||
|
--------------------
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Il n’y a pas de machine virtuelle disponible en ce moment.<br />
|
|||
|
Créer une machine virtuelle <strong>manjaro-xfce</strong> avec 2000 Mo de RAM (2Go), 1 CPU core, 10 Go Hdd.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-install --name manjaro-xfce-18 \
|
|||
|
--ram=2000 \
|
|||
|
--vcpus=1 \
|
|||
|
--cpu host \
|
|||
|
--network network=default \
|
|||
|
--disk path=/srv/data/virtuel/images/manjaro-xfce-18-vm1,size=10 \
|
|||
|
--cdrom /srv/data/virtuel/boot/manjaro-xfce-18.0.4-stable-x86_64.iso \
|
|||
|
--graphics vnc
|
|||
|
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Veuillez vous assurer d’avoir manjaro-xfce-18 ISO image dans le chemin <strong>/var/lib/libvirt/boot/</strong> ou tout autre chemin que vous avez donné dans la commande ci-dessus.</p>
|
|||
|
|
|||
|
<p>Décomposons la commande ci-dessus et voyons ce que chaque option fait.</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>-name</strong> : Cette option définit le nom du nom virtuel. Dans notre cas, le nom de VM est Ubuntu-16.04.</li>
|
|||
|
<li><strong>-ram=512</strong> : Affecte 512 Mo de RAM à la VM.</li>
|
|||
|
<li><strong>-vcpus=1</strong> : Indique le nombre de cœurs CPU dans la VM.</li>
|
|||
|
<li><strong>-cpu host</strong> : Optimise les propriétés du CPU pour la VM en exposant la configuration du CPU de l’hôte à l’invité.</li>
|
|||
|
<li><strong>-hvm</strong> : Demande la virtualisation complète du matériel.(Non Utilisé)</li>
|
|||
|
<li><strong>–network</strong> : Réseau par défaut</li>
|
|||
|
<li><strong>-disk path</strong> : L’emplacement pour sauvegarder le hdd et la taille de la machine virtuelle. Dans notre exemple, j’ai alloué une taille de hdd de 8 Go.</li>
|
|||
|
<li><strong>-cdrom</strong> : L’emplacement de l’image ISO de l’installateur. Veuillez noter que vous devez avoir l’image ISO actuelle à cet endroit.</li>
|
|||
|
<li><strong>-graphics vnc</strong> : Permet à la VNC d’accéder à la VM depuis un client distant.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Le déroulement</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>WARNING No operating system detected, VM performance may suffer. Specify an OS with --os-variant for optimal results.
|
|||
|
WARNING Unable to connect to graphical console: virt-viewer not installed. Please install the 'virt-viewer' package.
|
|||
|
WARNING No console to launch for the guest, defaulting to --wait -1
|
|||
|
|
|||
|
Starting install...
|
|||
|
Allocating 'manjaro-xfce-18-vm1' | 10 GB 00:00:00
|
|||
|
Domain installation still in progress. Waiting for installation to complete.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>ATTENTION!!!</strong><br />
|
|||
|
<em>Rien n’est apparu parce que vous avez lancé virt-install sur un terminal qui n’avait pas d’information d’affichage X disponible, donc il ne pouvait pas démarrer virt-viewer pour afficher la console de la machine virtuelle.<br />
|
|||
|
Éventuellement, l’installation de la VM sera terminée et la VM s’éteindra. A ce stade, virt-install redémarrera la VM et quittera elle-même. Vous pouvez également appuyer sur Ctrl+C pour arrêter l’attente de l’installation virt-install. Comme la VM est toujours en cours d’exécution, l’installation se poursuivra, mais la VM restera éteinte à la fin, plutôt que de redémarrer dans le système nouvellement installé.<br />
|
|||
|
Vous pouvez également utiliser virt-manager sur votre système local pour visualiser la console de la VM pendant l’installation, si virt-manager a la permission de gérer l’hyperviseur distant.</em></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h4 id="accès-aux-machines-virtuelles-via-virtual-manager--ssh">Accès aux machines virtuelles via Virtual Manager + ssh</h4>
|
|||
|
|
|||
|
<p>Client test</p>
|
|||
|
|
|||
|
<p>La boîte de dialogue de l’interface graphique du gestionnaire de virt n’a pas la possibilité de spécifier un port ssh autre que par défaut ou la clé privée à utiliser lors de la connexion au serveur distant, mais cela se fait facilement en démarrant virt-manager avec le paramètre ‘-c’.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-manager -c 'qemu+ssh://myuser@192.168.1.139:2222/system?keyfile=id_rsa'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans l’exemple ci-dessus, nous nous connectons en tant que’myuser’ au port d’écoute ssh non par défaut de 2222, et utilisons la clé privée trouvée dans le répertoire courant du fichier’id_rsa’.</p>
|
|||
|
|
|||
|
<p>virt-manager devrait vous demander immédiatement la phrase de chiffrement protégeant la clé privée (ce n’est pas le mot de passe de l’utilisateur !), et une fois que vous l’aurez entré, vous verrez virt-manager comme si vous étiez assis sur l’hôte KVM localement.</p>
|
|||
|
|
|||
|
<p>Notre configuration</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-manager -c 'qemu+ssh://admbust@xoyize.xyz:55035/system?keyfile=/home/yannick/.ssh/vbox-srvbust-ed25519'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/qemu-ssh-xoyize.png" alt="qemu-ssh-xoyize" /></p>
|
|||
|
|
|||
|
<h4 id="accès-aux-machines-virtuelles-via-le-client-vnc">Accès aux machines virtuelles via le client VNC</h4>
|
|||
|
|
|||
|
<p>Se connecter via SSH au serveur de virtualisation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#ssh sk@192.168.225.22
|
|||
|
ssh admbust@xoyize.xyz -p 55035 -i /home/yannick/.ssh/vbox-srvbust-ed25519
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>admbust est le nom d’utilisateur du serveur debian buster</em></p>
|
|||
|
|
|||
|
<p>Exécutez la commande suivante pour connaître le numéro de port VNC. Nous en avons besoin pour accéder au Vm à partir d’un système distant.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh dumpxml manjaro-xfce-18 |grep vnc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Sortie de l’échantillon :</p>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge"><graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1'></code></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Notez le numéro de port 5900. Installez n’importe quelle application client VNC.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Pour ce guide, j’utiliserai TigerVnc. TigerVNC est disponible dans les dépôts par défaut d’Arch Linux. Pour l’installer sur des systèmes basés sur Arch, exécutez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -S tigervncnc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Tapez la commande de transfert de port SSH suivante à partir de votre système client distant sur lequel l’application client VNC est installée.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh sk@192.168.225.22 -L 5900:127.0.0.0.1:5900
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Encore une fois, 192.168.225.22 est l’adresse IP de mon serveur Ubuntu (serveur de virtualisation).</p>
|
|||
|
|
|||
|
<p>Avec le serveur xoyize.yz</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -L 5900:127.0.0.1:5900 admbust@xoyize.xyz -p 55035 -i /home/yannick/.ssh/vbox-srvbust-ed25519
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, ouvrez le client VNC à partir de votre client Arch Linux.</p>
|
|||
|
|
|||
|
<p>Tapez localhost:5900 dans le champ Serveur VNC et cliquez sur le bouton Connecter.<br />
|
|||
|
En ligne de commande</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vncviewer -x11cursor localhost::5900
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/manjaro-xfce-18.png" alt="manjaro-xfce-18" width="600" /></p>
|
|||
|
|
|||
|
<p>Commencez ensuite à installer la VM Manjaro comme vous le faites dans le système physique.</p>
|
|||
|
|
|||
|
<p>De même, vous pouvez configurer autant de machines virtuelles en fonction des spécifications matérielles du serveur.</p>
|
|||
|
|
|||
|
<p>Vous pouvez également utiliser l’utilitaire <strong>virt-viewer</strong> pour installer le système d’exploitation dans les machines invitées. virt-viewer est disponible dans la plupart des dépôts par défaut de la distribution Linux. Après avoir installé virt-viewer, exécutez la commande suivante pour établir l’accès VNC à la VM.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-viewer --connect=qemu+ssh://admbust@xoyize.xyz:55035/system?keyfile=/home/yannick/.ssh/vbox-srvbust-ed25519 --name manjaro-xfce-18
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="management-machines-virtuelles">Management machines virtuelles</h4>
|
|||
|
|
|||
|
<p>Liste : <code class="language-plaintext highlighter-rouge">sudo virsh list --all</code><br />
|
|||
|
Démarrer une VM : <code class="language-plaintext highlighter-rouge">sudo virsh start manjaro-xfce-18</code><br />
|
|||
|
Redémarrer une VM : <code class="language-plaintext highlighter-rouge">sudo virsh reboot manjaro-xfce-18</code><br />
|
|||
|
Mettre en pause : <code class="language-plaintext highlighter-rouge">sudo virsh suspend manjaro-xfce-18</code><br />
|
|||
|
Resume : <code class="language-plaintext highlighter-rouge">sudo virsh resume manjaro-xfce-18</code><br />
|
|||
|
Arrêt : <code class="language-plaintext highlighter-rouge">sudo virsh shutdown manjaro-xfce-18</code><br />
|
|||
|
Supprimer entièrement une VM : <code class="language-plaintext highlighter-rouge">sudo virsh undefine manjaro-xfce-18 && sudo virsh destroy manjaro-xfce-18</code> <br />
|
|||
|
Autres options : <code class="language-plaintext highlighter-rouge">man virsh</code></p>
|
|||
|
|
|||
|
<h3 id="archlinux">Archlinux</h3>
|
|||
|
|
|||
|
<h4 id="qemu">Qemu</h4>
|
|||
|
|
|||
|
<p>Pour savoir si votre machine est capable d’utiliser <strong>KVM</strong> :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LC_ALL=C lscpu | grep Virtualization
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Virtualization: VT-x
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si vous avez une réponse, votre cpu est compatible (selon le fabricant, il se peut que cette option soit activable depuis le bios).<br />
|
|||
|
Installation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -S qemu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour utiliser qemu</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -a $USER kvm
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les modules <strong>kvm kvm-intel/kvm-amd</strong> sont chargés automatiquement…</p>
|
|||
|
|
|||
|
<p>Création d’un disque dur virtuel <strong>qemu.img</strong> d’une taille de 1,5 Go :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qemu-img create qemu.img 1500M
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Lancement de la machine virtuelle (exemple sur une architecture x86_64):</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qemu-system-x86_64 -k fr -m 400 -hda qemu.img -boot d -cdrom cd.iso -net nic -net user
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Descriptions des options :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">-k fr</code> : clavier français`</li>
|
|||
|
<li>`-m 400 : spécifie la quantité de RAM</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">-hda</code> : l’image à utiliser comme disque dur</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">-boot d </code>: boot sur le cd</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">-cdrom</code> : l’iso à utiliser</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">-net nic</code> : crée une interface réseau</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">-net user</code> : user mode networking, le dhcp et la passerelle sont émulés. Il suffit de lancer un client dhcp pour avoir accès au réseau internet de la machine hôte (en NAT). (Note: cela ne fonctionne qu’avec les protocoles tcp et udp, donc, ICMP, et par conséquent ping ne fonctionneront pas)</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Pour un système en 32 bits, la commande à utiliser est : <code class="language-plaintext highlighter-rouge">qemu-system-i386</code></p>
|
|||
|
|
|||
|
<h4 id="kvm--interface-graphique-virtual-machine-manager">KVM + interface graphique “Virtual Machine Manager”</h4>
|
|||
|
|
|||
|
<p><img src="/images/kvm-virt.png" alt="KVM" /><br />
|
|||
|
<a href="https://virt-manager.org/">Virtual Machine Manager</a></p>
|
|||
|
|
|||
|
<p><em>Contrairement à d’autres programmes de virtualisation tels que VirtualBox et VMware, QEMU ne fournit pas d’interface graphique pour gérer les machines virtuelles (autre que la fenêtre qui apparaît lors de l’exécution d’une machine virtuelle), ni un moyen de créer des machines virtuelles persistantes avec des paramètres sauvegardés. Tous les paramètres pour exécuter une machine virtuelle doivent être spécifiés sur la ligne de commande à chaque lancement, sauf si vous avez créé un script personnalisé pour démarrer votre (vos) machine(s) virtuelle(s). Cependant, il existe plusieurs interfaces graphiques pour QEMU : <strong>virt-manager</strong> , gnome-boxes, qemu-launcherAUR, qtemuAUR, aqemuAUR</em><br />
|
|||
|
Des frontaux supplémentaires avec support QEMU sont disponibles pour libvirt.</p>
|
|||
|
|
|||
|
<p><strong>Support matériel</strong></p>
|
|||
|
|
|||
|
<p>KVM exige que le processeur de l’hôte de la machine virtuelle soit compatible avec la virtualisation (nommé VT-x pour les processeurs Intel et AMD-V pour les processeurs AMD). Vous pouvez vérifier si votre processeur prend en charge la virtualisation matérielle à l’aide de la commande suivante :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LC_ALL=C lscpu | grep Virtualization
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Virtualization: VT-x
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si rien n’est affiché après l’exécution de la commande, alors votre processeur ne prend pas en charge la virtualisation matérielle et vous ne pourrez pas utiliser KVM.</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>Remarque</strong> : Vérifier l’activation de la prise en charge de la virtualisation dans le BIOS.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p><strong>Support du noyau</strong></p>
|
|||
|
|
|||
|
<p>Les noyaux Arch Linux fournissent les modules de noyau appropriés pour supporter KVM et VIRTIO.</p>
|
|||
|
|
|||
|
<p><strong>Modules KVM</strong></p>
|
|||
|
|
|||
|
<p>Vous pouvez vérifier si les modules nécessaires (kvm et l’un de kvm_amd, kvm_intel) sont disponibles dans votre noyau avec la commande suivante (en supposant que votre noyau est compilé avec CONFIG_IKCONFIG_PROC) :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zgrep CONFIG_KVM /proc/config.gz
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONFIG_KVM_GUEST=y
|
|||
|
# CONFIG_KVM_DEBUG_FS is not set
|
|||
|
CONFIG_KVM_MMIO=y
|
|||
|
CONFIG_KVM_ASYNC_PF=y
|
|||
|
CONFIG_KVM_VFIO=y
|
|||
|
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
|
|||
|
CONFIG_KVM_COMPAT=y
|
|||
|
CONFIG_KVM=m
|
|||
|
CONFIG_KVM_INTEL=m
|
|||
|
CONFIG_KVM_AMD=m
|
|||
|
CONFIG_KVM_AMD_SEV=y
|
|||
|
CONFIG_KVM_MMU_AUDIT=y
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Le module n’est disponible que s’il est réglé sur y ou m.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p><strong>Dispositifs para-virtualisés</strong></p>
|
|||
|
|
|||
|
<p><em>La para-virtualisation fournit un moyen de communication rapide et efficace permettant aux invités d’utiliser des appareils sur la machine hôte. KVM fournit des périphériques para-virtualisés aux machines virtuelles en utilisant l’API Virtio comme couche entre l’hyperviseur et l’invité.</em></p>
|
|||
|
|
|||
|
<p>Tous les périphériques virtio ont deux parties : le périphérique hôte et le pilote invité.</p>
|
|||
|
|
|||
|
<p>Utilisez la commande suivante pour vérifier si les modules nécessaires sont disponibles :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zgrep VIRTIO /proc/config.gz
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CONFIG_BLK_MQ_VIRTIO=y
|
|||
|
CONFIG_VIRTIO_VSOCKETS=m
|
|||
|
CONFIG_VIRTIO_VSOCKETS_COMMON=m
|
|||
|
CONFIG_NET_9P_VIRTIO=m
|
|||
|
CONFIG_VIRTIO_BLK=m
|
|||
|
# CONFIG_VIRTIO_BLK_SCSI is not set
|
|||
|
CONFIG_SCSI_VIRTIO=m
|
|||
|
CONFIG_VIRTIO_NET=m
|
|||
|
CONFIG_CAIF_VIRTIO=m
|
|||
|
CONFIG_VIRTIO_CONSOLE=m
|
|||
|
CONFIG_HW_RANDOM_VIRTIO=m
|
|||
|
CONFIG_DRM_VIRTIO_GPU=m
|
|||
|
CONFIG_VIRTIO=m
|
|||
|
CONFIG_VIRTIO_MENU=y
|
|||
|
CONFIG_VIRTIO_PCI=m
|
|||
|
CONFIG_VIRTIO_PCI_LEGACY=y
|
|||
|
CONFIG_VIRTIO_BALLOON=m
|
|||
|
CONFIG_VIRTIO_INPUT=m
|
|||
|
CONFIG_VIRTIO_MMIO=m
|
|||
|
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
|
|||
|
CONFIG_RPMSG_VIRTIO=m
|
|||
|
CONFIG_CRYPTO_DEV_VIRTIO=m
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, vérifiez si les modules du noyau sont automatiquement chargés avec la commande :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lsmod | grep virtio
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Si les commandes ci-dessus ne renvoient rien, vous devez <a href="https://wiki.archlinux.org/index.php/Kernel_modules#Manual_module_handling">charger les modules du noyau manuellement</a>.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Liste des dispositifs para-virtualisés</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>dispositif de réseau (virtio-net)</li>
|
|||
|
<li>dispositif de blocage (virtio-blk)</li>
|
|||
|
<li>dispositif de contrôle (virtio-scsi)</li>
|
|||
|
<li>appareil en série (virtio-serial)</li>
|
|||
|
<li>dispositif à ballonnet (virtio-balloon)</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong>Chargement des modules du noyau</strong></p>
|
|||
|
|
|||
|
<p>Les modules kvm et kvm-intel/kvm-amd doivent être chargés automatiquement, sinon, voir la page traitant des <a href="https://wiki.archlinux.fr/Kernel_modules">modules du noyau</a>.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lsmod | grep kvm
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kvm_intel 180224 0
|
|||
|
kvm 708608 1 kvm_intel
|
|||
|
irqbypass 16384 1 kvm
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>Astuce</strong> : Si modprobing kvm_intel ou kvm_amd échoue mais que modprobing kvm réussit, (et lscpu prétend que l’accélération matérielle est supportée), vérifiez vos paramètres BIOS.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Certains fournisseurs (en particulier les fournisseurs d’ordinateurs portables) désactivent ces extensions de processeur par défaut. Pour déterminer s’il n’y a pas de support matériel ou si les extensions sont désactivées dans le BIOS, la sortie de dmesg après avoir échoué à modprobe le dira.</p>
|
|||
|
|
|||
|
<p><strong>Installer KVM</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -S qemu virt-manager virt-viewer dnsmasq ebtables vde2 bridge-utils openbsd-netcat
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installez également les paquets ebtables et iptables</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -S ebtables iptables
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Installer libguestfs (FACULTATIF)</strong></p>
|
|||
|
|
|||
|
<p>libguestfs est un ensemble d’outils utilisés pour accéder et modifier les images disque des machines virtuelles (VM). Vous pouvez l’utiliser pour :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>visualiser et modifier des fichiers à l’intérieur des invités</li>
|
|||
|
<li>la modification des scripts des VM</li>
|
|||
|
<li>surveillance du disque utilisé/ statistiques gratuites</li>
|
|||
|
<li>créer des invités</li>
|
|||
|
<li>P2V</li>
|
|||
|
<li>V2V</li>
|
|||
|
<li>effectuer des sauvegardes e.t.c</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Activez d’abord l’AUR sur /etc/pacman.conf</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/pacman.conf
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[archlinuxfr]
|
|||
|
SigLevel = Never
|
|||
|
Server = http://repo.archlinux.fr/$arch
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Mettez ensuite à jour vos bases de données Pacman.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -Syy
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installez les outils libguestfs avec l’aide d’AUR.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yay -S libguestfs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="ajout-utilisateur-au-groupe-libvirt-1">Ajout utilisateur au groupe libvirt</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gpasswd -a $USER libvirt
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Adding user yann to group libvirt
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Recharger l’adhésion au groupe</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>newgrp libvirt
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="port-forwarding-permettre-au-vm-de-sortir-sur-internet">Port forwarding (permettre au VM de sortir sur Internet)</h4>
|
|||
|
|
|||
|
<p>Les VM auront donc des adresses IP privées et l’on utilisera la translation d’adresse (NAT) pour permettre au VM de sortir sur Internet</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
echo 1 > /proc/sys/net/ipv4/ip_forward # activation temporaire
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Note : si systemd est installé le fichier /etc/sysctl.conf n’existe plus et est remplacé par un dossier sysctl.d où mettre les *.conf nécessaires. On doit y créer un fichier (ex: /etc/sysctl.d/99-sysctl.conf). Dans ce cas, pour que la commande “sysctl -p” fonctionne il faut indiquer le fichier, par ex sysctl -p /etc/sysctl.d/fichier.conf. Ou avoir créé un lien symbolique /etc/sysctl.conf vers /etc/sysctl.d/99-sysctl.conf</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/sysctl.d/99-sysctl.conf # activation au démarrage
|
|||
|
|
|||
|
net.ipv4.ip_forward = 1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="service-libvirtd-1">Service libvirtd</h4>
|
|||
|
|
|||
|
<p>Il faut lancer le service <strong>libvirtd</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl start libvirtd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour une activation au démarrage</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl enable libvirtd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="créer-et-configurer-une-passerelle-réseau-pour-kvm">Créer et configurer une passerelle réseau pour KVM</h4>
|
|||
|
|
|||
|
<p>Le pont Linux, lorsqu’il est utilisé dans KVM, permet à une machine virtuelle d’accéder à un réseau et à des services externes en dehors de l’environnement virtuel.</p>
|
|||
|
|
|||
|
<p>Il existe différentes façons de configurer le Bridge Networking sous Linux pour une utilisation en KVM. Le réseau par défaut utilisé par une machine virtuelle lancée dans KVM est le réseau NAT. Avec le réseau NAT, un réseau virtuel est créé pour les machines invitées qui est ensuite mis en correspondance avec le réseau hôte pour fournir une connectivité internet.</p>
|
|||
|
|
|||
|
<p>Lorsque vous configurez et utilisez la mise en réseau pontée, les systèmes d’exploitation invités accèdent à un réseau externe connecté directement à la machine hôte. Un pont peut être créé soit à l’aide du <strong>gestionnaire de machines virtuelles</strong>, soit à l’aide de l’outil de ligne de commande <strong>virsh</strong>, soit en éditant directement des scripts réseau, soit en utilisant les outils de gestion de réseau Linux.</p>
|
|||
|
|
|||
|
<h4 id="création-dune-passerelle-réseau-avec-le-gestionnaire-de-machines-virtuelles">Création d’une passerelle réseau avec le “Gestionnaire de machines virtuelles”</h4>
|
|||
|
|
|||
|
<p>Ouvrez le <strong>Gestionnaire de machines virtuelles</strong>, puis allez dans <br />
|
|||
|
Édition → Détails de la connexion → Réseaux virtuels</p>
|
|||
|
|
|||
|
<p>Configurez une nouvelle interface réseau en cliquant sur le + en bas de la fenêtre. Donnez un nom au réseau virtuel.<br />
|
|||
|
<img src="/images/bridge001.png" alt="" width="300" /></p>
|
|||
|
|
|||
|
<p>Cliquez sur le bouton “Forward”, dans la fenêtre suivante, fournissez des informations sur le réseau virtuel.<br />
|
|||
|
<img src="/images/bridge002.png" alt="" width="300" /></p>
|
|||
|
|
|||
|
<p>Cliquez sur “Forward” et choisissez si vous souhaitez activer l’IPv6.<br />
|
|||
|
<img src="/images/bridge003.png" alt="" width="300" /></p>
|
|||
|
|
|||
|
<p>Sélectionnez le type de réseau et la politique de transfert.<br />
|
|||
|
<img src="/images/bridge004.png" alt="" width="300" /></p>
|
|||
|
|
|||
|
<p>Terminez le paramétrage et enregistrez vos configurations. Le nouveau réseau virtuel devrait s’afficher sur la page d’aperçu.<br />
|
|||
|
<img src="/images/bridge005.png" alt="" width="300" /></p>
|
|||
|
|
|||
|
<p>Un pont sur le système hôte est automatiquement créé pour le réseau.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brctl show virbr4
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bridge name bridge id STP enabled interfaces
|
|||
|
virbr4 8000.525400c2410a yes virbr4-nic
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="utilisation-vmm">Utilisation VMM</h4>
|
|||
|
|
|||
|
<p>Démarrer l’application graphique <strong>Gestionnaire de machines virtuelles</strong> <br />
|
|||
|
Il faut au préalable vérifier si le réseau est actif<br />
|
|||
|
Edition → Détails de la connexion : Réseaux Virtuels <br />
|
|||
|
<img src="/images/kvm0.png" alt="kvm" width="300" /></p>
|
|||
|
|
|||
|
<p>Si la fenêtre est vide<br />
|
|||
|
<img src="/images/kvm1-b.png" alt="kvm" /> <br />
|
|||
|
Fichier → +Ajouter une connexion<br />
|
|||
|
<img src="/images/kvm1-a.png" alt="kvm" /> <br />
|
|||
|
<img src="/images/kvm1.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Le bouton <em>Nouveau</em> permet de lancer l’assistant de création<br />
|
|||
|
<img src="/images/kvm2.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm3.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm4.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm5.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Machine virtuelle <strong>/home/yannick/virtuel/KVM/debian10.qcow2</strong></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm6-1.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm8.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm9.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<h4 id="utilisation-courante-vmm">Utilisation courante VMM</h4>
|
|||
|
|
|||
|
<p>Dans les utilisations suivantes, si rien n’est activé automatiquement, il faut exécuter les commandes suivantes</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
# translation d'adresse (NAT) pour permettre au VM de sortir sur Internet
|
|||
|
echo 1 > /proc/sys/net/ipv4/ip_forward
|
|||
|
# lancer le service libvirtd pour l'application graphique
|
|||
|
systemctl start libvirtd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Démarrer l’application graphique <strong>Gestionnaire de machines virtuelles</strong></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm10.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Le démarrage de la machine virtuelle provoque une erreur (réseau non actif)</p>
|
|||
|
|
|||
|
<p><img src="/images/kvm11.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Cliquer sur <em>Edition</em> puis <em>Détails de la connexion</em></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm12.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Cliquer sur l’icône <em>Démarrer le réseau</em> pour l’activer</p>
|
|||
|
|
|||
|
<p><img src="/images/kvm13.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Pour modifier les paramètres de la machine virtuelle, cliquer sur <em>Edition</em> puis <em>Détails de la machine virtuelle</em></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm15.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Cliquer sur l’icône <em>Démarrer la machine virtuelle</em> de la fenêtre <strong>“Gestionnaire de machines virtuelles”</strong></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm14.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Puis cliquer sur <em>Afficher</em> et sélectionner <em>Détails</em><br />
|
|||
|
Après une installation utilisant le CD et un fichier ISO, il faut le déconnecter<br />
|
|||
|
Sélectionner <strong>IDE CD-ROM</strong> puis clique sur <strong>Déconnecter</strong></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm16.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<p>Cliquer sur l’icône <em>Démarrer la machine virtuelle</em> puis sur l’icône <em>Afficher la console graphique</em></p>
|
|||
|
|
|||
|
<p><img src="/images/kvm17.png" alt="kvm" /></p>
|
|||
|
|
|||
|
<h4 id="vérification-de-linstallation-par-virt-host-validate">Vérification de l’installation par “virt-host-validate”</h4>
|
|||
|
|
|||
|
<p>Vérifier que tout est bon :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-host-validate
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> QEMU : Vérification for hardware virtualization : PASS
|
|||
|
QEMU : Vérification if device /dev/kvm exists : PASS
|
|||
|
QEMU : Vérification if device /dev/kvm is accessible : PASS
|
|||
|
QEMU : Vérification if device /dev/vhost-net exists : PASS
|
|||
|
QEMU : Vérification if device /dev/net/tun exists : PASS
|
|||
|
QEMU : Vérification for cgroup 'cpu' controller support : PASS
|
|||
|
QEMU : Vérification for cgroup 'cpuacct' controller support : PASS
|
|||
|
QEMU : Vérification for cgroup 'cpuset' controller support : PASS
|
|||
|
QEMU : Vérification for cgroup 'memory' controller support : PASS
|
|||
|
QEMU : Vérification for cgroup 'devices' controller support : PASS
|
|||
|
QEMU : Vérification for cgroup 'blkio' controller support : PASS
|
|||
|
QEMU : Vérification for device assignment IOMMU support : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)
|
|||
|
LXC : Vérification pour Linux >= 2.6.26 : PASS
|
|||
|
LXC : Vérification for namespace ipc : PASS
|
|||
|
LXC : Vérification for namespace mnt : PASS
|
|||
|
LXC : Vérification for namespace pid : PASS
|
|||
|
LXC : Vérification for namespace uts : PASS
|
|||
|
LXC : Vérification for namespace net : PASS
|
|||
|
LXC : Vérification for namespace user : PASS
|
|||
|
LXC : Vérification for cgroup 'cpu' controller support : PASS
|
|||
|
LXC : Vérification for cgroup 'cpuacct' controller support : PASS
|
|||
|
LXC : Vérification for cgroup 'cpuset' controller support : PASS
|
|||
|
LXC : Vérification for cgroup 'memory' controller support : PASS
|
|||
|
LXC : Vérification for cgroup 'devices' controller support : PASS
|
|||
|
LXC : Vérification for cgroup 'freezer' controller support : PASS
|
|||
|
LXC : Vérification for cgroup 'blkio' controller support : PASS
|
|||
|
LXC : Vérification if device /sys/fs/fuse/connections exists : PASS
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans notre cas , une alerte <strong>IOMMU</strong> (<em>En informatique, une unité de gestion de mémoire d’entrée-sortie (IOMMU) est une unité de gestion de mémoire (MMU) qui connecte un bus E/S à accès direct à la mémoire principale (compatible DMA). Comme une MMU traditionnelle, qui traduit les adresses virtuelles visibles par le CPU en adresses physiques, l’IOMMU met en correspondance les adresses virtuelles visibles par l’appareil (appelées aussi adresses d’appareil ou adresses E/S dans ce contexte) en adresses physiques.</em>)<br />
|
|||
|
Pour activer le support <strong>IOMMU</strong> , éditer (en mode root) le fichier <strong>/etc/default/grub</strong> et ajouter <em>intel_iommu=on</em> à la ligne existante <strong>GRUB_CMDLINE_LINUX</strong> <br />
|
|||
|
<code class="language-plaintext highlighter-rouge">GRUB_CMDLINE_LINUX="intel_iommu=on"</code><br />
|
|||
|
Mettre à jour grub<br />
|
|||
|
<code class="language-plaintext highlighter-rouge">sudo grub-mkconfig -o /boot/grub/grub.cfg</code><br />
|
|||
|
puis redémarrer la machine</p>
|
|||
|
|
|||
|
<h3 id="partage-de-fichiers">Partage de fichiers</h3>
|
|||
|
|
|||
|
<p><em>Partage de fichiers entre l’hôte et les invités dans qemu/kvm</em><br />
|
|||
|
<img src="/images/partage-9p.png" alt="image" width="200px" /><br />
|
|||
|
<a href="https://www.lafilacroche.com/post/partage-9p-entre-hote-et-invite-avec-virt-manager-et-debian">9p, l’autre pays du partage</a></p>
|
|||
|
|
|||
|
<h4 id="hôte-linux">Hôte linux</h4>
|
|||
|
|
|||
|
<p>Créer un dossier de partage sur l’hôte.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir $HOME/qemu-share
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les droits en lecture/écriture pour le propriétaire et le groupe du dossier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 775 -R $HOME/qemu-share
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans le fichier <strong>/etc/libvirt/qemu.conf</strong>, chercher les lignes suivantes :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#user = "root"
|
|||
|
#group = "root"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Et remplacer par :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user = "utilisateur"
|
|||
|
group = "groupe"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>utilisateur</strong> et <strong>groupe</strong> sont remplacés par ceux du dossier que l’on veut partager sur la machine hôte et supprimer le # en début de ligne.</p>
|
|||
|
|
|||
|
<p>Redémarrer le service libvirtd pour que ces modifications soient prises en compte:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart libvirtd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>Cela va permettre à la machine virtuelle d’écrire dans le dossier partagé avec l’identité de notre utilisateur plutôt qu’avec l’identité Libvirt Qemu paramétrée par défaut. Ainsi notre utilisateur aura accès aux fichiers créés par le serveur situé sur la VM et pourra les modifier sans souci.</em></p>
|
|||
|
|
|||
|
<p>Dans <strong>virt-manager</strong>, <strong>“Edition” -> “Détails de la machine virtuelle”</strong> et dans les informations de la machine (icône “Afficher les détails du matériel virtuel”) ,cliquer sur “Ajouter un matériel”, puis sur “Système de fichiers”.Modifier suivant le modèle ci-dessous.</p>
|
|||
|
|
|||
|
<p><img src="/images/qemu-share.png" alt="qemu share" /></p>
|
|||
|
|
|||
|
<p>Pilote = <strong>default</strong><br />
|
|||
|
Mode = <strong>Squash</strong><br />
|
|||
|
Chemin source : il s’agit du dossier crée précédemment sur l’hôte <strong>/home/yannick/qemu-share</strong><br />
|
|||
|
Chemin cible : un nom au choix, par exemple : <strong>hotshare</strong></p>
|
|||
|
|
|||
|
<h4 id="invité-linux">Invité linux</h4>
|
|||
|
|
|||
|
<p>Démarrer la VM et ouvrir un terminal.<br />
|
|||
|
Créer le répertoire de montage du système de fichiers</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir $HOME/share
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage manuel du système de fichiers.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mount -t 9p -o trans=virtio,version=9p2000.L,rw hostshare $HOME/share
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage automatique au démarrage ajout de la ligne suivante au fichier <strong>/etc/fstab</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hostshare /home/utilisateur/share 9p rw,relatime,sync,dirsync,trans=virtio,version=9p2000.L 0 2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mount -a
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><em>Le partage ne peut pas être monté et édité sur plusieurs hôtes en même temps. Assurez-vous donc de le démonter avant de le monter sur un autre hôte invité.</em></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="créer-booter-installer-un-os-et-importer">Créer ,booter ,installer un os et importer</h3>
|
|||
|
|
|||
|
<h4 id="créer-une-image-via-qemu">Créer une image via qemu</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qemu-img create -f qcow2 /var/lib/libvirt/images/DOMAIN.img 20G
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>-f</strong> → format de KVM pour le fichier image, qcow2 est le format kvm par défaut, raw est compatible avec Virtualbox et VMware</li>
|
|||
|
<li><strong>20G</strong> → Remplacer par la valeur souhaitée, ce sera la taille du disque dur virtuel</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h4 id="booter-sur-une-iso-et-installer-los-via-kvm-dans-limage-précédemment-créée">Booter sur une ISO et installer l’OS via KVM dans l’image précédemment créée</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kvm -m 1024 -cdrom /CHEMIN_VERS_VOTRE_ISO -boot d /var/lib/libvirt/images/DOMAINE.img
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong>-m 1024</strong> → La quantité de ram allouée</li>
|
|||
|
<li><strong>-cdrom</strong> → spécifie le chemin vers votre ISO</li>
|
|||
|
<li><strong>-boot d</strong> → spécifie sur quelle domaine booter, un système émulé s’appelle domaine, remplacer DOMAINE par un titre parlant par exemple DebianVM</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h4 id="booter-simplement-sur-los-fraîchement-installé-directement-via-kvm">Booter simplement sur l’OS fraîchement installé directement via KVM</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kvm -boot -d /var/lib/libvirt/images/DOMAINE.img
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>Attention</strong> en utilisant KVM directement et non avec <strong>libvirt</strong>, <u>les machines virtuelles ne seront pas listés avec virtmanager ou la commande</u> : <code class="language-plaintext highlighter-rouge">virsh list</code></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h4 id="import-machine-créée-via-qemu-pour-gestion-avec-virt-manager-libvirt">Import machine créée via “qemu” pour gestion avec “virt-manager” (libvirt)</h4>
|
|||
|
|
|||
|
<p>Si vous avez déjà créé précédemment une machine virtuelle avec <strong>qemu</strong> vous pouvez importer cette machine virtuelle pour qu’elle soit gérée via <strong>virt-manager</strong> et par conséquent qu’elle utilise <strong>libvirt</strong>.</p>
|
|||
|
|
|||
|
<p>Par exemple, si vous avez une image qui se trouve dans <strong>/srv/vms/Fedora12.img</strong>, effectuez ces opérations:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-install --import --disk path=/srv/vms/Fedora12.img --os-type linux --os-variant fedora11 --ram 512 --name Fedora12
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si vous désirez utiliser la gestion de l’accélération (c’est à dire, de passer par kvm et non pas qemu seulement):</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-install --import --accelerate --disk path=/srv/vms/Fedora12.img --os-type linux --os-variant fedora11 --ram 512 --name Fedora12
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Les options <em>–name</em>, <em>–ram</em> sont obligatoires.</li>
|
|||
|
<li>Les options <em>–os-type</em> et <em>–os-variant</em> ne sont pas obligatoires mais permettent tout de même une meilleure gestion pour le démarrage et mémoire au boot.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Pour les machines virtuelles Windows, c’est toujours aussi simple:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-install --import --accelerate --disk path=/srv/vms/WinXP.img --os-type windows --os-variant winxp --ram 512 --name WindowXP
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Aussitôt la génération de la configuration effectuée, la machine va démarrer. Elle apparait alors dans <strong>virt-manager</strong>.</p>
|
|||
|
|
|||
|
<h3 id="kvmqemu-cli-avec-virsh">KVM/Qemu cli avec “virsh”</h3>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.zenzla.com/linux/1462-la-virtualisation-avec-kvm-libvirt-et-virt-manager.html">La virtualisation avec KVM, libvirt et virt-manager</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Sur l’ordinateur hôte (où kvm/qemu est installé)</p>
|
|||
|
|
|||
|
<h4 id="connexion-à-lhyperviseur">Connexion à l’hyperviseur</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh -c qemu:///system
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bienvenue dans virsh, le terminal de virtualisation interactif.
|
|||
|
|
|||
|
Taper : « help » pour l'aide ou « help » avec la commande
|
|||
|
« quit » pour quitter
|
|||
|
|
|||
|
virsh #
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="liste-des-commandes-sous-virsh">Liste des commandes sous “virsh”</h4>
|
|||
|
|
|||
|
<p>Toutes les commandes suivantes se font à la suite du <em>prompt</em> <strong>virsh</strong></p>
|
|||
|
|
|||
|
<p>Liste des machines actives</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>list
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ID Nom État
|
|||
|
----------------------------------------------------
|
|||
|
8 debian9 en cours d'exécution
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Liste des machines inactives</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>list --inactive
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Liste de toutes les machines active ou non</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Démarrer la machine virtuelle <strong>debian9</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>start debian9
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrer la machine virtuelle <strong>debian9</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>reboot debian9
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Arrêter la machine virtuelle <strong>debian9</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shutdown debian9
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Arrêter brutalement la machine virtuelle <strong>debian9</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>destroy debian9
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Afficher les informations d’une machine virtuelle</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dominfo debian9
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/virsh-dominfo.png" alt="qemu share" /></p>
|
|||
|
|
|||
|
<p>Afficher les informations de la machine (hôte) qui supporte la virtualisation, machine nœud</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nodeinfo
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/virsh-nodeinfo.png" alt="qemu share" /></p>
|
|||
|
|
|||
|
<p>Sortie du mode interactif</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>quit
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="sauvegarde-configuration-machine-virtuelle">Sauvegarde configuration machine virtuelle</h4>
|
|||
|
|
|||
|
<p>Sauvegarder la configuration de la machine virtuelle <strong>debian9</strong>, vous devez sortir du mode interactif avant de saisir</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh -c qemu:///system dumpxml debian9 > /tmp/Newdebian9.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="modificationcréation-machine-virtuelle">Modification/Création machine virtuelle</h4>
|
|||
|
|
|||
|
<p>Vous pouvez ainsi facilement modifier le fichier XML et créer une nouvelle machine à partir de ces modifications<br />
|
|||
|
Plus d’info sur le format XML sur <a href="http://libvirt.org/format.html">http://libvirt.org/format.html</a></p>
|
|||
|
|
|||
|
<p>pour créer une machine virtuelle Newdebian9 à partir d’un fichier XML</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh -c qemu:///system create /tmp/Newdebian9.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="liste-des-machines-virtuelles">Liste des machines virtuelles</h4>
|
|||
|
|
|||
|
<p>Liste des machines (actives ou non)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ID Nom État
|
|||
|
----------------------------------------------------
|
|||
|
- debian9 fermé
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="vérifier-la-présence-dun-réseau">Vérifier la présence d’un réseau</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Nom État Démarrage automatique Persistent
|
|||
|
-----------------------------------------------------------------
|
|||
|
default inactif no yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="créer-un-pont-réseau">Créer un pont réseau</h4>
|
|||
|
|
|||
|
<p>Créez un nouveau fichier passerelle XML</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano br10.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ajoutez les détails du pont au fichier.</p>
|
|||
|
|
|||
|
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><network></span>
|
|||
|
<span class="nt"><name></span>br10<span class="nt"></name></span>
|
|||
|
<span class="nt"><forward</span> <span class="na">mode=</span><span class="s">'nat'</span><span class="nt">></span>
|
|||
|
<span class="nt"><nat></span>
|
|||
|
<span class="nt"><port</span> <span class="na">start=</span><span class="s">'1024'</span> <span class="na">end=</span><span class="s">'65535'</span><span class="nt">/></span>
|
|||
|
<span class="nt"></nat></span>
|
|||
|
<span class="nt"></forward></span>
|
|||
|
<span class="nt"><bridge</span> <span class="na">name=</span><span class="s">'br10'</span> <span class="na">stp=</span><span class="s">'on'</span> <span class="na">delay=</span><span class="s">'0'</span><span class="nt">/></span>
|
|||
|
<span class="nt"><ip</span> <span class="na">address=</span><span class="s">'192.168.30.1'</span> <span class="na">netmask=</span><span class="s">'255.255.255.0'</span><span class="nt">></span>
|
|||
|
<span class="nt"><dhcp></span>
|
|||
|
<span class="nt"><range</span> <span class="na">start=</span><span class="s">'192.168.30.50'</span> <span class="na">end=</span><span class="s">'192.168.30.200'</span><span class="nt">/></span>
|
|||
|
<span class="nt"></dhcp></span>
|
|||
|
<span class="nt"></ip></span>
|
|||
|
<span class="nt"></network></span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour définir un réseau à partir d’un fichier XML sans le démarrer, utilisez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-define br10.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>Réseau br10 défini depuis br10.xml</em></p>
|
|||
|
|
|||
|
<p>Pour lancer un réseau inactif (défini au préalable), utilisez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-start br10
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>Réseau br10 démarré</em></p>
|
|||
|
|
|||
|
<p>Pour régler le réseau sur le démarrage automatique au démarrage du service :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-autostart br10
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>Réseau br10 marqué comme autodémarré</em></p>
|
|||
|
|
|||
|
<p>Cochez la case Confirmer si le drapeau de démarrage automatique est activé - Persistant devrait également indiquer oui.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Nom État Démarrage automatique Persistent
|
|||
|
---------------------------------------------------------
|
|||
|
br10 actif no Oui
|
|||
|
default inactif no Oui
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Confirmez la création du pont et l’adresse IP.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip addr show dev br10
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4: br10: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
|
|||
|
link/ether 52:54:00:f4:cb:30 brd ff:ff:ff:ff:ff:ff
|
|||
|
inet 192.168.30.1/24 brd 192.168.30.255 scope global br10
|
|||
|
valid_lft forever preferred_lft forever
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="activer-le-réseau">Activer le réseau</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-start default
|
|||
|
# Réseau default démarré
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>En cas d’erreur : <a href="http://ask.xmodulo.com/network-default-is-not-active.html">How to fix “network ‘default’ is not active” error in libvirt</a></p>
|
|||
|
|
|||
|
<h4 id="personnaliser-sa-configuration-réseau">personnaliser sa configuration réseau</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-edit default
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="démarrer-la-machine-virtuelle">Démarrer la machine virtuelle</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh start debian9
|
|||
|
# Domaine debian9 démarré
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="arrêter-la-machine-virtuelle">Arrêter la machine virtuelle</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh shutdown debian9
|
|||
|
# Le domaine debian9 est en cours d'arrêt
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="démarrage-des-machines-virtuelles-qemu-au-démarrage">Démarrage des machines virtuelles QEMU au démarrage</h4>
|
|||
|
|
|||
|
<p>Si une <u>machine virtuelle est configurée avec libvirt</u>, elle peut être configurée avec <strong>virsh autostart</strong> ou via l’interface graphique du gestionnaire de virt (vmm, virt-manager) pour démarrer au démarrage de l’hôte en allant dans les <strong>Options de démarrage</strong> de la machine virtuelle et en sélectionnant <em>“Démarrer la machine virtuelle au démarrage de l’hôte”</em>.</p>
|
|||
|
|
|||
|
<p>Démarre automatiquement le réseau au démarrage de l’hôte (instruction en ligne de commande)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-autostart default
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="vérifier-le-port-forwadding-">Vérifier le port forwadding :</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /proc/sys/net/ipv4/ip_forward
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si la valeur est a 0, dé-commenter dans <strong>/etc/sysctl.conf</strong> le paramètre <em>net.ipv4.ip_forward</em> pour l’activer au démarrage :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Uncomment the next line to enable packet forwarding for IPv4
|
|||
|
net.ipv4.ip_forward=1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Activation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sysctl -w net.ipv4.ip_forward=1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="configurer-le-pare-feu">Configurer le pare-feu</h4>
|
|||
|
|
|||
|
<p>en remplaçant avec le nom de l’interface physique, par exemple <em>eth0</em> ou <strong>enp3s0</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -A FORWARD -i interfacephysique -j ACCEPT
|
|||
|
iptables -A FORWARD -o interfacephysique -j ACCEPT
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="disque-virtuel-vdilinux-qemunbd">Disque virtuel VDI/linux (Qemu+nbd)</h3>
|
|||
|
|
|||
|
<p><em>Monter un disque virtuel VDI sur une partition linux avec Qemu et nbd</em><br />
|
|||
|
L’image VDI ne doit pas être utilisée (stopper la machine virtuelle qui l’utilise).</p>
|
|||
|
|
|||
|
<p>Nous allons utiliser QEMU pour monter le disque VDI.Il faut installer le binaire <strong>qemu-nbd</strong>, qui est contenu dans <strong>qemu-utils</strong> sous Debian , <strong>qemu-img</strong> sous Fedora.<br />
|
|||
|
<strong>nbd</strong> sous archlinux</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pacman -S nbd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier si le module <strong>nbd</strong> est chargé</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lsmod |grep nbd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Chargement module <strong>nbd</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo modprobe nbd
|
|||
|
lsmod |grep nbd # vérifier si module chargé
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nbd 45056 0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage de l’image VDI</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qemu-nbd -c /dev/nbd0 disk.vdi
|
|||
|
mount /dev/nbd0p1 /mnt # contenu disk.vdi accessible dans /mnt.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>disk.vdi</strong> : image VDI, <strong>/dev/ndb0</strong> : disque vu par le système, <strong>/dev/nbd0p1</strong> : première partition du disque.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="migrer-machines-virtual-box--kvm">Migrer machines Virtual Box → KVM</h3>
|
|||
|
|
|||
|
<h4 id="les-disques">Les disques</h4>
|
|||
|
|
|||
|
<p>Liste des disques “VirtualBox”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBoxManage list hdds
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>UUID: 3c1a7f2e-c25d-4b96-a778-128d76e89a46
|
|||
|
Parent UUID: base
|
|||
|
State: created
|
|||
|
Type: normal (base)
|
|||
|
Location: /home/yannick/virtuel/Vbox/winten/winten.vdi
|
|||
|
Storage format: VDI
|
|||
|
Capacity: 51200 MBytes
|
|||
|
Encryption: disabled
|
|||
|
|
|||
|
UUID: 401b2b2d-fb70-4261-967c-078dffbbfeab
|
|||
|
Parent UUID: base
|
|||
|
State: created
|
|||
|
Type: normal (base)
|
|||
|
Location: /home/yannick/virtuel/Vbox/Debian Buster/Debian Buster.vdi
|
|||
|
Storage format: VDI
|
|||
|
Capacity: 8192 MBytes
|
|||
|
Encryption: disabled
|
|||
|
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="les-commandes">Les commandes</h4>
|
|||
|
|
|||
|
<p>Convertir l’image disque d’une machine Virtual Box en un format de disque brut</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBoxManage clonehd disk.vdi disk.raw --format raw
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Convertira l’image brute du disque au format compressé qcow2 (le format de disque brut consomme beaucoup d’espace disque).</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qemu-img convert -f raw disk.raw -O qcow2 disk.qcow2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="convertir-les-disques">Convertir les disques</h4>
|
|||
|
|
|||
|
<p><strong>Debian Buster</strong></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.utappia.org/2016/04/virtmanager-kvm-quick-installation-and.html">VirtManager - KVM: Quick installation and basic usage video (Part 1)</a>
|
|||
|
<ul>
|
|||
|
<li><a href="https://youtu.be/CmJDdOz9NbA">https://youtu.be/CmJDdOz9NbA</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="https://www.utappia.org/2016/04/how-to-migrate-your-virtual-box.html">How to migrate your Virtual Box machines to the KVM-VirtManager (Part 2)</a>
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.youtube.com/watch?v=6Z13VOEV6PU">https://www.youtube.com/watch?v=6Z13VOEV6PU</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>VBoxManage clonehd “/home/yannick/virtuel/Vbox/Debian Buster/Debian Buster.vdi” /home/yannick/virtuel/KVM/debian_buster.raw –format raw
|
|||
|
qemu-img convert -f raw /home/yannick/virtuel/KVM/debian_buster.raw -O qcow2 /home/yannick/virtuel/KVM/debian_buster.qcow2
|
|||
|
rm /home/yannick/virtuel/KVM/debian_buster.raw</p>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong>Windows 10</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBoxManage clonehd "/home/yannick/virtuel/Vbox/winten/winten.vdi" /home/yannick/virtuel/KVM/winten.raw --format raw
|
|||
|
qemu-img convert -f raw /home/yannick/virtuel/KVM/winten.raw -O qcow2 /home/yannick/virtuel/KVM/winten.qcow2
|
|||
|
rm /home/yannick/virtuel/KVM/winten.raw
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="kvm-qemussh">KVM qemu+ssh</h3>
|
|||
|
|
|||
|
<p><em>KVM : virt-manager pour se connecter à une console distante avec qemu+ssh</em><br />
|
|||
|
Si vous exécutez <a href="https://www.linux-kvm.org/page/Main_Page">KVM</a> sur un serveur en console seule, vous avez toujours la possibilité d’utiliser le gestionnaire graphique <a href="https://virt-manager.org/">virt-manager</a>. Il suffit de préciser le <a href="https://libvirt.org/remote.html">mode de communication</a> (ssh, tls, tcp, tcp, etc).</p>
|
|||
|
|
|||
|
<p>Dans cet article, je vais montrer comment utiliser virt-manager à partir d’un bureau client Ubuntu vers un serveur exécutant KVM et libvirtd, avec la connexion “tunneled” sur ssh et authentifié avec PKI.</p>
|
|||
|
|
|||
|
<p>L’affichage VNC à distance de ces VMs est envoyé par ce même tunnel ssh.</p>
|
|||
|
|
|||
|
<p>En utilisant la solution de tunneling ssh décrite dans cet article, le service libvirtd côté serveur n’a <em>pas</em> besoin d’activer l’écoute sur TCP dans “/etc/libvirt/libvirtd.conf”.</p>
|
|||
|
|
|||
|
<h4 id="ssh-prérequis">SSH prérequis</h4>
|
|||
|
|
|||
|
<p>La première condition est que vous puissiez utiliser ssh pour vous connecter au serveur KVM distant en utilisant la clé privée pour l’authentification. Cet article montre comment configurer SSH pour l’<a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-ubuntu-1604">authentification par clé publique (en)</a>.</p>
|
|||
|
|
|||
|
<p>Après avoir activé l’authentification par clé publique, vous devriez pouvoir effectuer un ssh dans l’hôte distant en utilisant la clé privée locale.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh -i <privateKeyFile> <user>@<KVMServer>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="paquets-client-virt-manager">Paquets client virt-manager</h4>
|
|||
|
|
|||
|
<p>Au minimum, vous avez besoin de l’interface graphique du gestionnaire de virt et de l’utilitaire qui vous demande la phrase de passe (passphrase) ssh.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># absolute minimum
|
|||
|
sudo apt-get install virt-manager ssh-askpass-gnome --no-install-recommends
|
|||
|
|
|||
|
# une installation plus complète si vous effectuez un travail KVM local
|
|||
|
sudo apt-get install virt-manager
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="test-client">Test client</h4>
|
|||
|
|
|||
|
<p>La boîte de dialogue de l’interface graphique du gestionnaire de virt n’a pas la possibilité de spécifier un port ssh autre que par défaut ou la clé privée à utiliser lors de la connexion au serveur distant, mais cela se fait facilement en démarrant virt-manager avec le paramètre’-c’.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-manager -c 'qemu+ssh://myuser@192.168.1.139:2222/system?keyfile=id_rsa'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans l’exemple ci-dessus, nous nous connectons en tant que ‘myuser’ au port d’écoute ssh non par défaut de 2222, et utilisons la clé privée trouvée dans le répertoire courant (fichier’id_rsa’).</p>
|
|||
|
|
|||
|
<p>virt-manager devrait vous demander immédiatement la phrase de chiffrement protégeant la clé privée (ce n’est pas le mot de passe de l’utilisateur !), et une fois que vous l’aurez entré, vous verrez virt-manager comme si vous étiez assis sur l’hôte KVM localement.</p>
|
|||
|
|
|||
|
<p>If you want to open a remote console to a VM, then before powering on make sure you are using the “Display VNC” (not Spice!) listening to ‘localhost’ with the port automatically selected. This communication will be tunneled over SSH and does not require additional ports open on the server firewall.
|
|||
|
Si vous voulez ouvrir une console distante à une VM, alors avant de mettre sous tension, assurez-vous d’utiliser la fonction “Afficher VNC” (Display VNC) pour écouter’localhost’ avec le port automatiquement sélectionné. Cette communication sera tunnelisée par SSH et ne nécessite pas de ports supplémentaires ouverts sur le pare-feu du serveur.</p>
|
|||
|
|
|||
|
<h4 id="notes">NOTES</h4>
|
|||
|
|
|||
|
<p>Spécification du port VNC avec virt-install</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Utiliser le port statique 5900
|
|||
|
--graphics vnc,port=5900
|
|||
|
|
|||
|
# utiliser la numérotation automatique (5900 pour la 1ère VM, 5901 pour la 2ème, etc)
|
|||
|
--graphics vnc,port=-1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="exécuter-virt-manager-sans-privilèges-root">Exécuter Virt-Manager sans privilèges root</h3>
|
|||
|
|
|||
|
<p><em>Comment exécuter Virt-Manager, Libvirt avec un utilisateur normal sans privilèges root et sans mot de passe</em><br />
|
|||
|
<strong>Virt-manager</strong> et <strong>libvirt</strong> sont les principaux outils utilisés pour la virtualisation dans l’écosystème Linux. En tant qu’utilisateur final, j’utilise ces outils pour créer et exécuter des machines virtuelles. Mais chaque fois que j’essaie de faire fonctionner cet outil, le mot de passe sudo m’est demandé.<br />
|
|||
|
<strong>Solution pour exécuter ces outils sans mettre de mot de passe et changer aucune autorisation du côté de la virtualisation</strong></p>
|
|||
|
|
|||
|
<h4 id="polkit">Polkit</h4>
|
|||
|
|
|||
|
<p>PolicyKit ou simplement Polkit est un composant utilisé pour contrôler les privilèges du système dans les systèmes d’exploitation Unix et Linux.<br />
|
|||
|
Nous allons utiliser Polkit pour nous authentifier et démarrer <strong>virt-manager</strong> sans mot de passe.</p>
|
|||
|
|
|||
|
<h4 id="créer-un-groupe-pour-la-virtualisation">Créer un groupe pour la virtualisation</h4>
|
|||
|
|
|||
|
<p>Pour exécuter des services et des logiciels de virtualisation, nous avons besoin d’un groupe ayant le droit d’accéder aux ressources système associées.</p>
|
|||
|
<font color="red"><b>La plupart des systèmes d'exploitation génére le groupe sous le nom de <font color="green">libvirt</font> au cours de l'installation<br />
|
|||
|
Sinon, créez le groupe avec la commande suivante.(nécessite des privilèges root)</b></font>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo groupadd libvirt
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="mettre-lutilisateur-dans-le-groupe-de-virtualisation">Mettre l’utilisateur dans le groupe de virtualisation</h4>
|
|||
|
|
|||
|
<p>Nous devons maintenant placer notre utilisateur normal ou actuel dans le groupe de virtualisation. Comme indiqué à l’étape précédente, le nom du groupe est <strong>libvirt</strong><br />
|
|||
|
Dans cette commande, nous ajoutons le groupe secondaire nommé <strong>libvirt</strong> à l’utilisateur courant $USER</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo usermod -a -G libvirt $USER # on peut spécifier le nom utilisateur au lieu de $USER
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id $USER
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="créer-une-règle-polkit">Créer une règle Polkit</h4>
|
|||
|
|
|||
|
<p>Nous allons créer une règle polkit zvec le groupe <strong>libvirt</strong><br />
|
|||
|
Créer un fichier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/polkit-1/rules.d/80-libvirt.rules
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Cette règle donnera aux utilisateurs des groupes libvirt accès aux fonctionnalités de virtualisation sans mot de passe.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>polkit.addRule(function(action, subject) {
|
|||
|
if (action.id == "org.libvirt.unix.manage" && subject.local && subject.active && subject.isInGroup("libvirt")) {
|
|||
|
return polkit.Result.YES;
|
|||
|
}
|
|||
|
});
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Un “reboot” de la machine est nécessaire pour la prise en charge</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h1 id="comment-installer-une-image-virtuelle-sur-un-serveur-debian-linux-9-headless-sans-affichage">Comment installer une image virtuelle sur un serveur Debian Linux 9 Headless (sans affichage)</h1>
|
|||
|
|
|||
|
<p>La machine virtuelle basée sur le noyau (KVM) est un module de virtualisation pour le noyau Linux qui le transforme en hyperviseur.<br />
|
|||
|
Vous pouvez utiliser KVM pour exécuter plusieurs systèmes d’exploitation tels que Windows, * BSD et la distribution Linux à l’aide de machines virtuelles. Chaque machine virtuelle a son disque privé, sa carte graphique, une carte réseau, etc.</p>
|
|||
|
|
|||
|
<p>Procédure d’installation du serveur KVM sur un serveur Debian Linux 9.x</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>Le serveur hôte est distant, c’est un serveur sans affichage.</li>
|
|||
|
<li>Toutes les commandes sont saisies dans une <u>session ssh</u>.</li>
|
|||
|
<li>Avoir un client vnc pour installer le système d’exploitation invité.</li>
|
|||
|
<li>Le but est d’installer le logiciel KVM sur un serveur sans affichage Debian Linux 9.x et à utiliser KVM pour configurer une machine virtuelle invitée.</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h4 id="installation-kvm">Installation KVM</h4>
|
|||
|
|
|||
|
<p>Saisir la commande suivante</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils libguestfs-tools genisoimage virtinst libosinfo-bin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="autoriser-lutilisateur-à-gérer-la-machine-virtuelle">Autoriser l’utilisateur à gérer la machine virtuelle</h4>
|
|||
|
|
|||
|
<p>utilisateur courant gére des machines virtuelles.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo adduser vmuser libvirt
|
|||
|
sudo adduser vmuser libvirt-qemu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Recharger l’appartenance à un groupe à l’aide de la commande newgrp</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>newgrp libvirt
|
|||
|
newgrp libvirt-qemu
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier votre appartenance au groupe avec la commande id</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Noter que vous devez utiliser la commande suivante pour vous connecter au serveur KVM</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh --connect qemu:///system
|
|||
|
virsh --connect qemu:///system command
|
|||
|
virsh --connect qemu:///system list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="vérifier-installation-kvm-sur-debian">Vérifier installation KVM sur Debian</h4>
|
|||
|
|
|||
|
<p>Exécutez la commande egrep suivante pour vérifier que Intel VMX ou AMD SVM est pris en charge sur votre CPU</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>egrep --color 'vmx|svm' /proc/cpuinfo
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="configurer-la-mise-en-réseau-pont-sur-debian">Configurer la mise en réseau “pont” sur Debian</h4>
|
|||
|
|
|||
|
<p>Création de l’interface pont br0 (bridge Interface) comme connexion réseau dans la configuration d’invités de machine virtuelle pour l’interface eth0</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/network/interfaces.d/br0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ajouter ce qui suit:</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">### make sure all config related to eth0 deleted ##</span>
|
|||
|
auto br0
|
|||
|
iface br0 inet static
|
|||
|
address 192.168.2.23 <span class="c">## set up/netmask/broadcast/gateway as per your setup</span>
|
|||
|
broadcast 192.168.2.255
|
|||
|
netmask 255.255.255.0
|
|||
|
gateway 192.168.2.254
|
|||
|
bridge_ports eth0 <span class="c"># replace eth0 with your actual interface name</span>
|
|||
|
bridge_stp off <span class="c"># disable Spanning Tree Protocol</span>
|
|||
|
bridge_waitport 0 <span class="c"># no delay before a port becomes available</span>
|
|||
|
bridge_fd 0 <span class="c"># no forwarding delay</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrer le service réseau sur Linux (si network-manager utilisé)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart network-manager
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Sinon , reboot</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl reboot
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour voir les paramètres réseau actuels pour KVM</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Name State Autostart Persistent
|
|||
|
----------------------------------------------------------
|
|||
|
default inactive no yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous devez configurer un domaine invité KVM sur un réseau ponté. <br />
|
|||
|
Créez un fichier nommé bridge.xml</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /root/bridged.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Et ajouter la configuration suivante</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><network>
|
|||
|
<name>br0</name>
|
|||
|
<forward mode="bridge"/>
|
|||
|
<bridge name="br0"/>
|
|||
|
</network>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Enregistrez et fermez et exécuter</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-define --file /root/bridged.xml
|
|||
|
sudo virsh net-autostart br0
|
|||
|
sudo virsh net-start br0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/kvm-pont.png" alt="" /></p>
|
|||
|
|
|||
|
<h4 id="création-machine-virtuelle-à-laide-dun-programme-dinstallation-dimage-iso">Création machine virtuelle à l’aide d’un programme d’installation d’image ISO</h4>
|
|||
|
|
|||
|
<p>Créer une machine virtuelle CentOS 7.x. <br />
|
|||
|
Récupérer la dernière image ISO de CentOS 7.x</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /var/lib/libvirt/boot/
|
|||
|
sudo wget https://mirrors.kernel.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1708.iso
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Créer une machine virtuelle CentOS 7.x avec 2 Go de RAM, 2 CPU, 1 nic et 40 Go d’espace disque</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-install \
|
|||
|
--virt-type=kvm \
|
|||
|
--name centos7 \
|
|||
|
--ram 2048 \
|
|||
|
--vcpus=2 \
|
|||
|
--os-variant=rhel7 \
|
|||
|
--virt-type=kvm \
|
|||
|
--hvm \
|
|||
|
--cdrom=/var/lib/libvirt/boot/CentOS-7-x86_64-DVD-1708.iso \
|
|||
|
--network=bridge=br0,model=virtio \
|
|||
|
--graphics vnc \
|
|||
|
--disk path=/var/lib/libvirt/images/centos7.qcow2,size=40,bus=virtio,format=qcow2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour configurer la connexion vnc depuis un autre terminal sur ssh</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh dumpxml centos7 | grep vnc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><graphics type='vnc' port=' 5901 ' autoport='yes' listen='127.0.0.1'>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous pouvez également utiliser la commande suivante</p>
|
|||
|
|
|||
|
<p>sudo virsh vncdisplay centos7</p>
|
|||
|
|
|||
|
<p>Veuillez noter la valeur du port (5901). Vous devez utiliser un client SSH pour configurer le tunnel et un client VNC pour accéder au serveur vnc distant.<br />
|
|||
|
Tapez la commande de transfert de port SSH suivante à partir de votre client/bureau:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh vmuser@server1.cyberciti.biz -L 5901:127.0.0.1:5901
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Une fois le tunnel ssh établi, vous pouvez pointer votre client VNC vers votre propre adresse 127.0.0.1 (localhost) et le port 5901 comme suit:</p>
|
|||
|
|
|||
|
<p><img src="/images/kvm-vnc1.png" alt="" /><br />
|
|||
|
Client VNC pour terminer l’installation de CentOS 7.x</p>
|
|||
|
|
|||
|
<p>L’écran d’installation invité de CentOS Linux 7 devrait s’afficher comme suit:</p>
|
|||
|
|
|||
|
<p><img src="/images/kvm-vnc2.png" alt="" /><br />
|
|||
|
Installation de CentOS 7.x sur une machine virtuelle basée sur KVM</p>
|
|||
|
|
|||
|
<p>Suivez maintenant les instructions à l’écran et installez CentOS 7. Une fois installé, continuez et cliquez sur le bouton de redémarrage. Le serveur distant a fermé la connexion de notre client VNC. Vous pouvez vous reconnecter via le client KVM pour configurer le reste du serveur, y compris la session ou le pare-feu SSH.</p>
|
|||
|
|
|||
|
<h4 id="utiliser-virt-builder-pour-créer-une-machine-virtuelle">Utiliser virt-builder pour créer une machine virtuelle</h4>
|
|||
|
|
|||
|
<p>La méthode ci-dessus (virt-install) fonctionne bien, mais si vous avez besoin de créer rapidement de nouvelles machines virtuelles, utliser <strong>virt-builder</strong>.</p>
|
|||
|
|
|||
|
<h4 id="lister-les-machines-virtuelles-disponibles">lister les machines virtuelles disponibles</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-builder --list | more
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous pouvez utiliser la commande grep pour filtrer uniquement les machines virtuelles basées sur x86_64</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-builder --list | grep x86_64
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>opensuse-13.1 x86_64 openSUSE 13.1
|
|||
|
opensuse-13.2 x86_64 openSUSE 13.2
|
|||
|
opensuse-42.1 x86_64 openSUSE Leap 42.1
|
|||
|
opensuse-tumbleweed x86_64 openSUSE Tumbleweed
|
|||
|
centos-6 x86_64 CentOS 6.6
|
|||
|
centos-7.0 x86_64 CentOS 7.0
|
|||
|
centos-7.1 x86_64 CentOS 7.1
|
|||
|
centos-7.2 x86_64 CentOS 7.2
|
|||
|
centos-7.3 x86_64 CentOS 7.3
|
|||
|
centos-7.4 x86_64 CentOS 7.4
|
|||
|
cirros-0.3.1 x86_64 CirrOS 0.3.1
|
|||
|
cirros-0.3.5 x86_64 CirrOS 0.3.5
|
|||
|
debian-6 x86_64 Debian 6 (Squeeze)
|
|||
|
debian-7 x86_64 Debian 7 (wheezy)
|
|||
|
debian-8 x86_64 Debian 8 (jessie)
|
|||
|
debian-9 x86_64 Debian 9 (stretch)
|
|||
|
fedora-18 x86_64 Fedora® 18
|
|||
|
fedora-19 x86_64 Fedora® 19
|
|||
|
fedora-20 x86_64 Fedora® 20
|
|||
|
fedora-21 x86_64 Fedora® 21 Server
|
|||
|
fedora-22 x86_64 Fedora® 22 Server
|
|||
|
fedora-23 x86_64 Fedora® 23 Server
|
|||
|
fedora-24 x86_64 Fedora® 24 Server
|
|||
|
fedora-25 x86_64 Fedora® 25 Server
|
|||
|
fedora-26 x86_64 Fedora® 26 Server
|
|||
|
fedora-27 x86_64 Fedora® 27 Server
|
|||
|
freebsd-11.1 x86_64 FreeBSD 11.1
|
|||
|
scientificlinux-6 x86_64 Scientific Linux 6.5
|
|||
|
ubuntu-10.04 x86_64 Ubuntu 10.04 (Lucid)
|
|||
|
ubuntu-12.04 x86_64 Ubuntu 12.04 (Precise)
|
|||
|
ubuntu-14.04 x86_64 Ubuntu 14.04 (Trusty)
|
|||
|
ubuntu-16.04 x86_64 Ubuntu 16.04 (Xenial)
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour avoir des informations supplémentaires pour chaque système d’exploitation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-builder --notes ubuntu-16.04
|
|||
|
virt-builder --notes debian-9
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Debian 9 (stretch)
|
|||
|
|
|||
|
This is a minimal Debian install.
|
|||
|
|
|||
|
This image does not contain SSH host keys. To regenerate them use:
|
|||
|
|
|||
|
--firstboot-command "dpkg-reconfigure openssh-server"
|
|||
|
|
|||
|
This template was generated by a script in the libguestfs source tree:
|
|||
|
builder/templates/make-template.ml
|
|||
|
Associated files used to prepare this template can be found in the
|
|||
|
same directory.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="créer-une-machine-virtuelle-debian-9x">Créer une machine virtuelle Debian 9.x</h4>
|
|||
|
|
|||
|
<p>Créer une machine virtuelle Debian 9 avec 10 Go d’espace disque, 2 Go de RAM, 2 vCPU et un mot de passe aléatoire pour le compte root (commande <code class="language-plaintext highlighter-rouge">virt-builder</code>)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-builder debian-9 \
|
|||
|
--size=10G \
|
|||
|
--format qcow2 -o /var/lib/libvirt/images/debian9-vm1.qcow2 \
|
|||
|
--hostname debain9-vm1 \
|
|||
|
--network \
|
|||
|
--timezone Asia/Kolkata
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/kvm-virt-builder.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Puis, importer une image avec la commande virt-install</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virt-install --import --name debian9-vm1 \
|
|||
|
--ram 2048 \
|
|||
|
--vcpu 2 \
|
|||
|
--disk path=/var/lib/libvirt/images/debian9-vm1.qcow2,format=qcow2 \
|
|||
|
--os-variant debian9 \
|
|||
|
--network=bridge=br0,model=virtio \
|
|||
|
--noautoconsole
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>ce qui donne…</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Starting install...
|
|||
|
Creating domain...
|
|||
|
Domain creation completed.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vous pouvez vous connecter à votre VM en utilisant le mot de passe x0E4iZ8sHjA6ekb6 pour le compte root</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh list --all
|
|||
|
virsh console debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/kvm-virt-builder1.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Vous devez <u>désactiver le compte root pour la session SSH</u> et créer des clés SSH pour votre machine virtuelle . Connectez-vous comme ci-dessus:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo -s
|
|||
|
dpkg-reconfigure openssh-server
|
|||
|
useradd -r -m -d /home/vmuser -s /bin/bash vmuser
|
|||
|
passwd vmuser
|
|||
|
systemctl enable ssh
|
|||
|
#### [ Disable root user login when using ssh ] ###
|
|||
|
echo 'PermitRootLogin no' >> /etc/ssh/sshd_config
|
|||
|
systemctl restart ssh
|
|||
|
ip a s
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifiez que vous pouvez vous connecter en utilisant une adresse IP pour un utilisateur vmuser et utilisez ‘su -‘ pour devenir un utilisateur root:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh vmuser@192.168.2.132
|
|||
|
su -
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="commandes-utiles">Commandes utiles</h3>
|
|||
|
|
|||
|
<p>Trouver la liste des variantes de système d’exploitation acceptées</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>osinfo-query os | less
|
|||
|
osinfo-query os | grep debian
|
|||
|
osinfo-query os | grep freebsd
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Liste un vms/domaine en cours d’exécution</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh list
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Fermez un vms/domaine appelé debian9-vm1</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh shutdown debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Démarrer un vms/domaine appelé debian9-vm1</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh start debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Suspendre un vms/domaine appelé debian9-vm1</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh suspend debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrez (redémarrage sécurisé et en douceur) un vms/domaine appelé debian9-vm1</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh reboot debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Réinitialiser (réinitialisation matérielle / non sûre) un vms/domaine appelé debian9-vm1</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh reset debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Supprimer un vms/domaine appelé debian9-vm1</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh undefine debian9-vm1
|
|||
|
sudo virsh destroy debian9-vm1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour voir une liste complète du type de commande virsh</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh help | less
|
|||
|
virsh help | grep reboot
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>KVM Virtualisation full headless install and guest vm management</p>
|
|||
|
|
|||
|
<p>KVM Virtualisation production ready tested on :
|
|||
|
online.net > pro-6-M dedicated</p>
|
|||
|
|
|||
|
<p>KVM Virtualisation full headless install and guest vm management</p>
|
|||
|
|
|||
|
<h4 id="kvm-install-on-ubuntu-1604">KVM install on ubuntu 16.04</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt-get install qemu-kvm libvirt-bin virt-manager virtinst bridge-utils cpu-checker libguestfs-tools libosinfo-bin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="kvm-install-on-ubuntu-1804">KVM install on ubuntu 18.04</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils virt-manager libguestfs-tools libosinfo-bin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>nameserver for dedicated (if not exists)</p>
|
|||
|
|
|||
|
<p>nameserver 8.8.8.8<br />
|
|||
|
nameserver 8.8.4.4</p>
|
|||
|
|
|||
|
<h4 id="forwarding-network">Forwarding network</h4>
|
|||
|
|
|||
|
<p><strong>KVM VNC remote viewer</strong></p>
|
|||
|
|
|||
|
<p>https://www.realvnc.com/en/connect/download/viewer/linux/</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -t nat -A PREROUTING -i eno1 -p tcp --dport 5900 -j DNAT --to 127.0.0.1:5900
|
|||
|
sysctl -w net.ipv4.ip_forward=1
|
|||
|
sysctl -p /etc/sysctl.conf
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="forward-ports-to-guests-with-iptables">Forward Ports to guests with Iptables</h4>
|
|||
|
|
|||
|
<p>https://aboullaite.me/kvm-qemo-forward-ports-with-iptables/</p>
|
|||
|
|
|||
|
<p><strong>accepting nat forwarding on nic for vm ip</strong><br />
|
|||
|
do it for every libvirt bridge nat ip that need access incoming request from internet</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -I FORWARD -o virbr0 -d 192.168.122.49 -j ACCEPT
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>onliner for all ip nat forwarding on nic for all vms</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">virsh net-dhcp-leases default | grep 192.168 | awk '{print $5}' | cut -d \/ -f1 | while read ips; do iptables -I FORWARD -o virbr0 -d $ips -j ACCEPT; done; iptables-save | grep 192.168;</code></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong>forward specific port to vm</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -t nat -I PREROUTING -p tcp --dport 9867 -j DNAT --to 192.168.122.36:22
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Forwaring all traffic for publich ip alias to vm</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables -t nat -A PREROUTING -d 212.83.147.148 -j DNAT --to-destination 192.168.122.49
|
|||
|
iptables -t nat -A POSTROUTING -s 192.168.122.49 -j SNAT --to-source 212.83.147.148
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><a href="https://serverfault.com/questions/627608/redirect-all-incoming-traffic-from-a-secondary-public-ip-to-an-internal-ip-addre/627624">Redirect all incoming traffic from a secondary public IP to an internal IP address using iptables — Server Fault</a></p>
|
|||
|
|
|||
|
<h4 id="vm-create">VM create</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Beispiel:
|
|||
|
virt-install \
|
|||
|
--virt-type=kvm \
|
|||
|
--name debian8-11-1 \
|
|||
|
--ram 2048 \
|
|||
|
--vcpus=2 \
|
|||
|
--os-type linux \
|
|||
|
--os-variant generic \
|
|||
|
--virt-type=kvm \
|
|||
|
--hvm \
|
|||
|
--cdrom=/var/lib/libvirt/boot/debian-8.11.0-amd64-netinst.iso \
|
|||
|
--network=bridge=virbr0,model=virtio \
|
|||
|
--graphics vnc \
|
|||
|
--disk path=/var/lib/libvirt/images/debian-8-11-1amd64.qcow2,size=40,bus=virtio,format=qcow2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>vm stop delete</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh destroy win10-1 && virsh undefine win10-1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>debian jessie :</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-install --name debianJessie2 --ram=512 --vcpus=1 --cpu host --disk path=/var/lib/libvirt/images/debianVM2,size=8,bus=virtio,format=qcow2 --cdrom /var/lib/libvirt/boot/debian-8.11.0-amd64-netinst.iso --graphics vnc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>debian jessie with vnc custom port:</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vmname="vm1-debian8"; virt-install --name $vmname --ram=512 --vcpus=1 --cpu host --disk path=/var/lib/libvirt/images/${vmname}.qcow2,size=8,bus=virtio,format=qcow2 --cdrom /var/lib/libvirt/isos/debian-8.11.0-amd64-netinst.iso --graphics=vnc,port=5951,password=!PASSWORD! --network=bridge=virbr0,model=virtio
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>install linux without vnc on the console</strong></p>
|
|||
|
|
|||
|
<p>location parameter is needed for the console installation location links are image repo links from distro images</p>
|
|||
|
|
|||
|
<p><strong>preseed install debian</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OS="preesed-debian8";
|
|||
|
virt-install --connect=qemu:///system --name=${OS} --ram=1024 --vcpus=2 --disk path=/var/lib/libvirt/images/$OS,size=8,bus=virtio,format=qcow2 --initrd-inject=preseed.cfg --location http://ftp.de.debian.org/debian/dists/jessie/main/installer-amd64 --os-type linux --os-variant debian8 --controller usb,model=none --graphics none --noautoconsole --network bridge=virbr0 --extra-args="auto=true hostname="${OS}" domain="vm1.yourserver.com" console=tty0 console=ttyS0,115200n8 serial"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>os variant list — os-variant</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install libosinfo-bin
|
|||
|
osinfo-query os
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>win10 install:</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-install --os-type=windows --os-variant=win8.1 --name win10-9 --ram=2048 --vcpus=1 --cpu host --disk path=/var/lib/libvirt/images/win10-9,size=40,bus=virtio,format=qcow2 --disk /var/lib/libvirt/boot/win1064bit.iso,device=cdrom --disk /var/lib/libvirt/boot/virtIO-drivers.iso,device=cdrom --graphics=vnc,port=5952,password=!PASSWORD! --check all=off
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso</p>
|
|||
|
|
|||
|
<p><a href="https://launchpad.net/kvm-guest-drivers-windows/+download">KVM Guest Drivers for Windows project files : KVM Guest Drivers for Windows
|
|||
|
</a></p>
|
|||
|
|
|||
|
<h4 id="add-new-nat-network">add new nat network</h4>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Create a new libvirt network (other than your default 198.162.x.x) file:</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ vim newnetwork.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <network>
|
|||
|
<name>newnetwork-1</name>
|
|||
|
<uuid>d0e9964a-f91a-40c0-b769-a609aee41bf2</uuid>
|
|||
|
<forward mode='nat'>
|
|||
|
<nat>
|
|||
|
<port start='1' end='65535'/>
|
|||
|
</nat>
|
|||
|
</forward>
|
|||
|
<bridge name='virbr1' stp='on' delay='0' />
|
|||
|
<mac address='52:54:00:60:f8:6e'/>
|
|||
|
<ip address='192.168.142.1' netmask='255.255.255.0'>
|
|||
|
<dhcp>
|
|||
|
<range start='192.168.142.2' end='192.168.142.254' />
|
|||
|
</dhcp>
|
|||
|
</ip>
|
|||
|
</network>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Define the above network:</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ virsh net-define newnetwork.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Start the network and enable it for “autostart”</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ virsh net-start newnetwork-1
|
|||
|
$ virsh net-autostart newnetwork-1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>List your libvirt networks to see if it reflects:</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ virsh net-list
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Name State Autostart Persistent
|
|||
|
----------------------------------------------------------
|
|||
|
default active yes yes
|
|||
|
newnetwork-1 active yes yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Optionally, list your bridge devices:</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brctl show
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> bridge name bridge id STP enabled interfaces
|
|||
|
virbr0 8000.5254003339b3 yes virbr0-nic
|
|||
|
virbr1 8000.52540060f86e yes virbr1-nic
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><a href="https://kashyapc.fedorapeople.org/virt/create-a-new-libvirt-bridge.txt">link: create-a-new-libvirt-bridge</a></p>
|
|||
|
|
|||
|
<h4 id="network-destroy">network destroy</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh net-list
|
|||
|
virsh net-destroy default
|
|||
|
virsh net-undefine default
|
|||
|
service libvirtd restart
|
|||
|
ifconfig
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>link ftp://libvirt.org/libvirt/virshcmdref/html/sect-net-dumpxml.html</p>
|
|||
|
|
|||
|
<h4 id="get-ip-from-guest-vm">get ip from guest vm</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh net-dhcp-leases default | grep testvm | awk '{ print $5}'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh domiflist vm5-debian
|
|||
|
|
|||
|
Interface Type Source Model MAC
|
|||
|
-------------------------------------------------------
|
|||
|
vnet1 network default rtl8139 52:54:00:45:87:e6
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>get vm ip enstead of MAC list</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>arp -e192.168.122.194 ether 52:54:00:45:87:e6
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>oneliner</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vmname="vm5-debian"; arp -e | grep $(virsh domiflist $vmname| grep vnet | awk '{print $5}') | awk '{print $1}'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>or show vm ips from release pool output</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /var/lib/libvirt/dnsmasq/virbr0.status
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Static ip for VM</strong></p>
|
|||
|
|
|||
|
<p>virsh net-edit default</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ...
|
|||
|
<dhcp>
|
|||
|
<range start='192.168.122.100' end='192.168.122.254'/>
|
|||
|
<host mac='52:54:00:6c:3c:01' name='vm1' ip='192.168.122.11'/>
|
|||
|
...
|
|||
|
</dhcp>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>reboot the VM or network from vm (ipdown eth0; ifup eth0)</li>
|
|||
|
<li>if not works than</li>
|
|||
|
<li>virsh net-destroy $NETWORK_NAME</li>
|
|||
|
<li>virsh net-start $NETWORK_NAME</li>
|
|||
|
<li>than restart vm dhcp client</li>
|
|||
|
<li>if not works than</li>
|
|||
|
<li>stop the libvirtd service</li>
|
|||
|
<li>kill any dnsmasq processes that are still alive</li>
|
|||
|
<li>start the libvirtd service</li>
|
|||
|
<li>create accepting nat forwarding on nic for vm ips again</li>
|
|||
|
<li>restart the vm(s)</li>
|
|||
|
<li><code class="language-plaintext highlighter-rouge">virsh net-destroy default && virsh net-undefine default && virsh net-define /etc/libvirt/networks/default.xml && virsh net-start default && virsh net-autostart default; /etc/init.d/libvirt-bin restart; COMMAND=shutdown; virsh list | grep vm | awk '{print $2}' | while read vmname; do virsh $COMMAND $vmname; sleep 3; done; watch 'virsh list'; COMMAND=start; virsh list --all | grep vm | awk '{print $2}' | while read vmname; do virsh $COMMAND $vmname; sleep 3; done; watch 'virsh list'</code></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong>Stop & start all vms oneliner</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># shutdown
|
|||
|
COMMAND=shutdown; virsh list | grep vm | awk '{print $2}' | while read vmname; do virsh $COMMAND $vmname; sleep 3; done; watch 'virsh list'
|
|||
|
|
|||
|
#start
|
|||
|
COMMAND=start; virsh list --all | grep vm | awk '{print $2}' | while read vmname; do virsh $COMMAND $vmname; sleep 3; done; watch 'virsh list'
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="reset-forgotten-root-password-for-linux-kvm-qcow2-imagevm">reset forgotten root password for Linux KVM qcow2 image/vm</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt install libguestfs-tools
|
|||
|
virsh shutdown < vmname >
|
|||
|
virsh dumpxml debian9-vm1 | grep 'source file'
|
|||
|
...
|
|||
|
<source file='/var/lib/libvirt/images/debian9-vm1.qcow2'/>
|
|||
|
...openssl passwd -1 newrootPasswordguestfish --rw -a /var/lib/libvirt/images/debian9-vm1.qcow2><fs>
|
|||
|
>launch
|
|||
|
>list-filesystems
|
|||
|
>mount /dev/sda1 /
|
|||
|
>vi /etc/shadow
|
|||
|
>flush
|
|||
|
>quit
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>snapshot create & manage</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh snapshot-create-as --domain vm-d8 --name vm-d8-snap --description "jessie base"
|
|||
|
virsh snapshot-list vm-d8
|
|||
|
virsh snapshot-revert webserver vm-d8-snap
|
|||
|
virsh snapshot-delete --domain vm-d8 --snapshotname vm-d8-snap
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>RAM increasing</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh shutdown <vm name>
|
|||
|
virsh setmaxmem <vm name> 16G --config
|
|||
|
virsh setmem <vm name> 16G --config
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>CPU increasing</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh edit <vm name>
|
|||
|
<vcpu placement='stait virsh vcpuinfoc'>6</vcpu>
|
|||
|
virsh vcpuinfo <vm name>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="vm-disk-increasing-resize-in-two-steps">vm disk increasing /resize in two steps</h4>
|
|||
|
|
|||
|
<p>1- step on the kvm</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># show current info of vm disk
|
|||
|
virsh domblklist <vm name> --details
|
|||
|
qemu-img resize /var/lib/libvirt/images/VM-Name +4G
|
|||
|
fdisk -l /var/lib/libvirt/images/VM-Name
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>2- step on the vm</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># on the VM
|
|||
|
roo@vm:/ fdisk -l /dev/vdaCommand (m for help): p
|
|||
|
Device Boot Start End Sectors Size Id Type
|
|||
|
/dev/vda1 * 2048 33554432 33552385 16G 83 LinuxCommand (m for help): d
|
|||
|
[1,2.5]: 1
|
|||
|
# delete the swap also and create it again as second primary, so start and en sector will set automaticly correctly.
|
|||
|
Command (m for help): d
|
|||
|
[1,2.5]: 2
|
|||
|
Command (m for help): n
|
|||
|
[primary ,extend]: p
|
|||
|
partition number: 1
|
|||
|
# WICHTIG: start sector take the value above showed!!
|
|||
|
Command (m for help): t
|
|||
|
# ext4
|
|||
|
type: 83
|
|||
|
Command (m for help): n
|
|||
|
[primary ,extend]: p
|
|||
|
partition number: 2
|
|||
|
# start and end sector select default
|
|||
|
Command (m for help): w
|
|||
|
roo@vm:/ resize2fs /dev/sda1
|
|||
|
roo@vm:/ reboot
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h1 id="liens">Liens</h1>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.cyberciti.biz/faq/install-kvm-server-debian-linux-9-headless-server/">How to install KVM server on Debian Linux 9 Headless Server</a></li>
|
|||
|
<li><a href="https://www.zenzla.com/linux/1462-la-virtualisation-avec-kvm-libvirt-et-virt-manager.html">La virtualisation avec KVM, libvirt et virt-manager</a></li>
|
|||
|
<li><a href="https://blog.seboss666.info/2013/11/la-virtualisation-kvm-avec-libvirt/">La virtualisation KVM avec libvirt</a></li>
|
|||
|
<li><a href="https://blog.hedilenoir.com/index.php/2018/10/21/virtualisation-materielle-libre-sur-debian-jessie/">Virtualisation matérielle libre sur Linux avec QEMU/KVM + virt-manager (graphique)</a></li>
|
|||
|
<li><a href="https://www.fosslinux.com/2484/how-to-install-virtual-machine-manager-kvm-in-manjaro-and-arch-linux.htm">How to install Virtual Machine Manager (KVM) in Manjaro and Arch Linux</a></li>
|
|||
|
<li><a href="https://doc.fedora-fr.org/wiki/Virtualisation_:_KVM,_Qemu,_libvirt_en_images">KVM,Qemu,libvirt en images</a></li>
|
|||
|
<li><a href="https://blog.nicolargo.com/2012/02/apprentissage-de-qemulibvirt-par-lexemple.html">Apprentissage de Qemu/LibVirt par l’exemple</a></li>
|
|||
|
<li><a href="https://www.it-connect.fr/virtualisation-les-types-de-connexion-au-reseau/">Virtualisation – Les types de connexion au réseau</a></li>
|
|||
|
<li><a href="https://wiki.debian.org/fr/BridgeNetworkConnections">Etablir des ponts entre les connexions réseaux</a></li>
|
|||
|
<li><a href="https://libvirt.org/remote.html">Official libvirt documentation on remote connections</a></li>
|
|||
|
<li><a href="https://help.ubuntu.com/community/KVM/VirtManager">Ubuntu official virt-manager doc</a></li>
|
|||
|
<li><a href="https://www.michelebologna.net/2018/accessing-virt-manager-on-a-non-standard-ssh-port/">Specifying ‘-c’ to pass custom connection definition</a></li>
|
|||
|
<li><a href="https://www.eslot.fr/virtualisation">Virtualisation</a></li>
|
|||
|
<li><a href="https://www.cyberciti.biz/faq/how-to-reset-forgotten-root-password-for-linux-kvm-qcow2-image-vm/">Réinitialiser le mot de passe root pour la machine virtuelle KVM Linux</a></li>
|
|||
|
<li><a href="https://www.cyberciti.biz/faq/how-to-clone-existing-kvm-virtual-machine-images-on-linux/">Cloner des images de machine virtuelle KVM existantes sous Linux</a></li>
|
|||
|
<li><a href="https://www.cyberciti.biz/faq/reset-a-kvm-clone-virtual-machines-with-virt-sysprep-on-linux/">Réinitialiser une machine virtuelle clonée KVM avec virt-sysprep sous Linux</a></li>
|
|||
|
<li><a href="https://www.cyberciti.biz/faq/kvm-forward-ports-to-guests-vm-with-ufw-on-linux/">Ports de transfert KVM aux ordinateurs virtuels invités avec UFW sous Linux</a></li>
|
|||
|
<li><a href="https://www.cyberciti.biz/faq/create-vm-using-the-qcow2-image-file-in-kvm/">Créer une VM en utilisant le fichier image qcow2 dans KVM</a></li>
|
|||
|
<li><a href="https://www.ostechnix.com/setup-headless-virtualization-server-using-kvm-ubuntu/">Setup Headless Virtualization Server Using KVM In Ubuntu 18.04 LTS</a></li>
|
|||
|
<li><a href="https://computingforgeeks.com/complete-installation-of-kvmqemu-and-virt-manager-on-arch-linux-and-manjaro/">Complete Installation of KVM, QEMU and Virt Manager on Arch Linux and Manjaro</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-09-12T00:00:00+02:00"><!-- start custom article footer snippet -->
|
|||
|
|
|||
|
<!-- end custom article footer snippet -->
|
|||
|
<!--
|
|||
|
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/09/12/KVM-Partage-NFS-vm-windows.html">KVM QEMU virtualiser windows 10 sur Archlinux + partage NFS</a></div><div class="next"><span>SUIVANT</span><a href="/2020/09/13/PC1-ArchLinux-XFCE-ASUS-H110M-A.html">PC1 Ordinateur Bureau ArchLinux xfce</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>
|
|||
|
|