yannstatic/static/2020/09/12/KVM-QEMU-virtualisation-linux.html

3864 lines
290 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>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}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
2024-11-28 11:42:23 +01:00
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/syntaxe-markdown.html">Aide</a></li></ul>
2024-10-31 20:18:37 +01:00
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Virtualisation KVM/QEMU</h1></header></div><meta itemprop="headline" content="Virtualisation KVM/QEMU"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=virtuel">virtuel</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">12&nbsp;sept.&nbsp;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">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><p><img src="/images/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 laccélération matérielle lorsquelle 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é dun processeur Intel)</p>
<p>Une différence entre les deux est que la <strong>QEMU</strong> fonctionne sur un processeur sans avoir besoin dune extension de virtualisation matérielle (Intel VT/VT-d, AMD-V) alors que la <strong>KVM</strong> lutilise. Les extensions de virtualisation matérielle vous permettent daccéder directement au matériel sur la machine physique. Linconvé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 dexé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 lon appelle des hyperviseurs.<br />
<strong>Il existe plusieurs types dhyperviseurs, 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 seffectue grâce à un logiciel installé sur un système dexploitation. Donc la machine virtualisée ninteragit 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 dautres.</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, cest un client</strong>.<br />
Et la liaison entre Qemu et KVM est faite via lAPI libvirt ( management du réseau, stockages, clavier, souris, etc )</p>
</blockquote>
<p><a href="http://libvirt.org/">libvirt</a> est une bibliothèque permettant dinteragir avec différentes solutions de virtualisation (cet article sintéressera uniquement à KVM/QEMU, mais Xen, VirtualBox et dautres sont aussi possibles)<br />
<a href="http://virt-manager.org/">Virtual Machine Manager</a> est un ensemble dapplications 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 limage dune machine</li>
<li><strong>virt-image</strong> permet de créer un nouvelle machine à partir dune image</li>
<li><strong>virt-install</strong> permet de créer une nouvelle machine ou dimporter 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 doptimiser lémulation lorsque quelle concerne la même architecture).QEMU peut utiliser KVM lors de lexécution dune architecture cible identique à larchitecture hôte. Par exemple, lorsque vous exécutez qemu-system-x86 sur un processeur compatible x86, vous pouvez profiter de laccé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 dexploitation 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 cest 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 dun client vnc pour installer le système dexploitation 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 lutilisateur normal/régulier puisse gérer les machines virtuelles. Ajouter lutilisateur $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 ladhésion à un groupe avec laide 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 à laide 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 dune autre couleur dans le résultat</p>
<h4 id="service-libvirtd">Service libvirtd</h4>
<p>On vérifie quil 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 lhô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 lutilisation du réseau par défaut de libvirt, libvirt va connecter linterface 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 dabord sil 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 ny 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 davoir 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 lhôte à linvité.</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> : Lemplacement pour sauvegarder le hdd et la taille de la machine virtuelle. Dans notre exemple, jai alloué une taille de hdd de 8 Go.</li>
<li><strong>-cdrom</strong> : Lemplacement de limage ISO de linstallateur. Veuillez noter que vous devez avoir limage ISO actuelle à cet endroit.</li>
<li><strong>-graphics vnc</strong> : Permet à la VNC daccé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 nest apparu parce que vous avez lancé virt-install sur un terminal qui navait pas dinformation daffichage X disponible, donc il ne pouvait pas démarrer virt-viewer pour afficher la console de la machine virtuelle.<br />
Éventuellement, linstallation 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 lattente de linstallation virt-install. Comme la VM est toujours en cours dexécution, linstallation 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 linstallation, si virt-manager a la permission de gérer lhyperviseur 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 linterface graphique du gestionnaire de virt na 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 lexemple ci-dessus, nous nous connectons en tant quemyuser 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 fichierid_rsa.</p>
<p>virt-manager devrait vous demander immédiatement la phrase de chiffrement protégeant la clé privée (ce nest pas le mot de passe de lutilisateur !), et une fois que vous laurez entré, vous verrez virt-manager comme si vous étiez assis sur lhô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 dutilisateur 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 dun 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">&lt;graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1'&gt;</code></p>
<blockquote>
<p>Notez le numéro de port 5900. Installez nimporte quelle application client VNC.</p>
</blockquote>
<p>Pour ce guide, jutiliserai TigerVnc. TigerVNC est disponible dans les dépôts par défaut dArch Linux. Pour linstaller 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 lapplication 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 ladresse 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 lutilitaire <strong>virt-viewer</strong> pour installer le système dexploitation 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 laccè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 &amp;&amp; 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 dutiliser <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 dun disque dur virtuel <strong>qemu.img</strong> dune 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> : limage à 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> : liso à 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 quavec 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 à dautres programmes de virtualisation tels que VirtualBox et VMware, QEMU ne fournit pas dinterface graphique pour gérer les machines virtuelles (autre que la fenêtre qui apparaît lors de lexécution dune 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 lhô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 à laide 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 nest affiché après lexé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 lactivation 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 lun 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 nest disponible que sil 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 dutiliser des appareils sur la machine hôte. KVM fournit des périphériques para-virtualisés aux machines virtuelles en utilisant lAPI Virtio comme couche entre lhyperviseur et linvité.</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 laccélération matérielle est supportée), vérifiez vos paramètres BIOS.</p>
</blockquote>
<p>Certains fournisseurs (en particulier les fournisseurs dordinateurs portables) désactivent ces extensions de processeur par défaut. Pour déterminer sil ny 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 doutils utilisés pour accéder et modifier les images disque des machines virtuelles (VM). Vous pouvez lutiliser pour :</p>
<ul>
<li>visualiser et modifier des fichiers à linté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 dabord lAUR 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 laide dAUR.</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 ladhé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 lon utilisera la translation dadresse (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 &gt; /proc/sys/net/ipv4/ip_forward # activation temporaire
</code></pre></div></div>
<blockquote>
<p>Note : si systemd est installé le fichier /etc/sysctl.conf nexiste 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, lorsquil est utilisé dans KVM, permet à une machine virtuelle daccéder à un réseau et à des services externes en dehors de lenvironnement 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 dexploitation invités accèdent à un réseau externe connecté directement à la machine hôte. Un pont peut être créé soit à laide du <strong>gestionnaire de machines virtuelles</strong>, soit à laide de loutil 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 dune 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 lIPv6.<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 safficher sur la page daperç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 lapplication 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 lassistant 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 nest 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 &gt; /proc/sys/net/ipv4/ip_forward
# lancer le service libvirtd pour l'application graphique
systemctl start libvirtd
</code></pre></div></div>
<p>Démarrer lapplication 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 licône <em>Démarrer le réseau</em> pour lactiver</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 licô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 licône <em>Démarrer la machine virtuelle</em> puis sur licô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 linstallation 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 &gt;= 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 dentré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, lIOMMU met en correspondance les adresses virtuelles visibles par lappareil (appelées aussi adresses dappareil 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 lhô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, lautre pays du partage</a></p>
<h4 id="hôte-linux">Hôte linux</h4>
<p>Créer un dossier de partage sur lhô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 lon 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 lidentité de notre utilisateur plutôt quavec lidentité 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” -&gt; “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 sagit du dossier crée précédemment sur lhô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 lOS via KVM dans limage 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é sappelle 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 lOS 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 quelle soit gérée via <strong>virt-manager</strong> et par conséquent quelle 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 laccélération (cest à 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, cest 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 lordinateur hôte (où kvm/qemu est installé)</p>
<h4 id="connexion-à-lhyperviseur">Connexion à lhyperviseur</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 dune 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 &gt; /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 dinfo 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 dun 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 dun 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">&lt;network&gt;</span>
<span class="nt">&lt;name&gt;</span>br10<span class="nt">&lt;/name&gt;</span>
<span class="nt">&lt;forward</span> <span class="na">mode=</span><span class="s">'nat'</span><span class="nt">&gt;</span>
<span class="nt">&lt;nat&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;/nat&gt;</span>
<span class="nt">&lt;/forward&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;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">&gt;</span>
<span class="nt">&lt;dhcp&gt;</span>
<span class="nt">&lt;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">/&gt;</span>
<span class="nt">&lt;/dhcp&gt;</span>
<span class="nt">&lt;/ip&gt;</span>
<span class="nt">&lt;/network&gt;</span>
</code></pre></div></div>
<p>Pour définir un réseau à partir dun 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 ladresse 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: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; 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 derreur : <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 linterface graphique du gestionnaire de virt (vmm, virt-manager) pour démarrer au démarrage de lhô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 lhôte”</em>.</p>
<p>Démarre automatiquement le réseau au démarrage de lhô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 lactiver 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 linterface 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 />
Limage VDI ne doit pas être utilisée (stopper la machine virtuelle qui lutilise).</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 limage 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 limage disque dune 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 limage brute du disque au format compressé qcow2 (le format de disque brut consomme beaucoup despace 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é dutiliser 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 dun bureau client Ubuntu vers un serveur exécutant KVM et libvirtd, avec la connexion “tunneled” sur ssh et authentifié avec PKI.</p>
<p>Laffichage 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 na <em>pas</em> besoin dactiver 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 lauthentification. 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é lauthentification par clé publique, vous devriez pouvoir effectuer un ssh dans lhô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 &lt;privateKeyFile&gt; &lt;user&gt;@&lt;KVMServer&gt;
</code></pre></div></div>
<h4 id="paquets-client-virt-manager">Paquets client virt-manager</h4>
<p>Au minimum, vous avez besoin de linterface graphique du gestionnaire de virt et de lutilitaire 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 linterface graphique du gestionnaire de virt na 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 lexemple 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 (fichierid_rsa).</p>
<p>virt-manager devrait vous demander immédiatement la phrase de chiffrement protégeant la clé privée (ce nest pas le mot de passe de lutilisateur !), et une fois que vous laurez entré, vous verrez virt-manager comme si vous étiez assis sur lhô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 dutiliser la fonction “Afficher VNC” (Display VNC) pour écouterlocalhost 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 quutilisateur final, jutilise ces outils pour créer et exécuter des machines virtuelles. Mais chaque fois que jessaie de faire fonctionner cet outil, le mot de passe sudo mest 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 dexploitation 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 dun groupe ayant le droit daccé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 lutilisateur 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> à lutilisateur 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" &amp;&amp; subject.local &amp;&amp; subject.active &amp;&amp; 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 dexploitation tels que Windows, * BSD et la distribution Linux à laide de machines virtuelles. Chaque machine virtuelle a son disque privé, sa carte graphique, une carte réseau, etc.</p>
<p>Procédure dinstallation du serveur KVM sur un serveur Debian Linux 9.x</p>
<ol>
<li>Le serveur hôte est distant, cest 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 dexploitation invité.</li>
<li>Le but est dinstaller 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 lutilisateur à 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 lappartenance à un groupe à laide 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 linterface pont br0 (bridge Interface) comme connexion réseau dans la configuration dinvités de machine virtuelle pour linterface 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>&lt;network&gt;
&lt;name&gt;br0&lt;/name&gt;
&lt;forward mode="bridge"/&gt;
&lt;bridge name="br0"/&gt;
&lt;/network&gt;
</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 à laide dun programme dinstallation dimage 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 despace 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>&lt;graphics type='vnc' port=' 5901 ' autoport='yes' listen='127.0.0.1'&gt;
</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 linstallation de CentOS 7.x</p>
<p>Lécran dinstallation invité de CentOS Linux 7 devrait safficher 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 dexploitation</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 despace 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' &gt;&gt; /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 dexploitation 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 dexé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 &gt; 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 &amp;&amp; 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> &lt;network&gt;
&lt;name&gt;newnetwork-1&lt;/name&gt;
&lt;uuid&gt;d0e9964a-f91a-40c0-b769-a609aee41bf2&lt;/uuid&gt;
&lt;forward mode='nat'&gt;
&lt;nat&gt;
&lt;port start='1' end='65535'/&gt;
&lt;/nat&gt;
&lt;/forward&gt;
&lt;bridge name='virbr1' stp='on' delay='0' /&gt;
&lt;mac address='52:54:00:60:f8:6e'/&gt;
&lt;ip address='192.168.142.1' netmask='255.255.255.0'&gt;
&lt;dhcp&gt;
&lt;range start='192.168.142.2' end='192.168.142.254' /&gt;
&lt;/dhcp&gt;
&lt;/ip&gt;
&lt;/network&gt;
</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> ...
&lt;dhcp&gt;
&lt;range start='192.168.122.100' end='192.168.122.254'/&gt;
&lt;host mac='52:54:00:6c:3c:01' name='vm1' ip='192.168.122.11'/&gt;
...
&lt;/dhcp&gt;
</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 &amp;&amp; virsh net-undefine default &amp;&amp; virsh net-define /etc/libvirt/networks/default.xml &amp;&amp; virsh net-start default &amp;&amp; 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 &amp; 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 &lt; vmname &gt;
virsh dumpxml debian9-vm1 | grep 'source file'
...
&lt;source file='/var/lib/libvirt/images/debian9-vm1.qcow2'/&gt;
...openssl passwd -1 newrootPasswordguestfish --rw -a /var/lib/libvirt/images/debian9-vm1.qcow2&gt;&lt;fs&gt;
&gt;launch
&gt;list-filesystems
&gt;mount /dev/sda1 /
&gt;vi /etc/shadow
&gt;flush
&gt;quit
</code></pre></div></div>
<p><strong>snapshot create &amp; 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 &lt;vm name&gt;
virsh setmaxmem &lt;vm name&gt; 16G --config
virsh setmem &lt;vm name&gt; 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 &lt;vm name&gt;
&lt;vcpu placement='stait virsh vcpuinfoc'&gt;6&lt;/vcpu&gt;
virsh vcpuinfo &lt;vm name&gt;
</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 &lt;vm name&gt; --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 lexemple</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>
&emsp;</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}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>