2014-11-28 16:59:04 +00:00
|
|
|
% Virtualisation légère
|
2014-11-28 18:21:38 +00:00
|
|
|
% Travaux pratiques
|
|
|
|
% Pierre-Olivier *Nemunaire* Mercier
|
2014-11-28 16:59:04 +00:00
|
|
|
% Samedi 29 novembre 2014
|
|
|
|
|
2014-11-28 07:46:24 +00:00
|
|
|
# Installation
|
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
## Noyau Linux
|
|
|
|
|
|
|
|
Ce TP requiert d'avoir un noyau Linux en version 3.8 au minimum. De plus, il
|
|
|
|
doit être compilé avec les options suivantes :
|
|
|
|
|
|
|
|
```
|
|
|
|
General setup --->
|
|
|
|
[*] Control Group support --->
|
|
|
|
[*] Freezer cgroup subsystem
|
|
|
|
[*] Device controller for cgroups
|
|
|
|
[*] Cpuset support
|
|
|
|
[*] Include legacy /proc/<pid>/cpuset file
|
|
|
|
[*] Simple CPU accounting cgroup subsystem
|
|
|
|
[*] Resource counters
|
|
|
|
[*] Memory Resource Controller for Control Groups
|
|
|
|
[*] Memory Resource Controller Swap Extension
|
|
|
|
[*] Memory Resource Controller Swap Extension enabled by default
|
|
|
|
[*] Enable perf_event per-cpu per-container group (cgroup) monitoring
|
|
|
|
[*] Group CPU scheduler --->
|
|
|
|
[*] Group scheduling for SCHED_OTHER
|
|
|
|
[*] Group scheduling for SCHED_RR/FIFO
|
|
|
|
<*> Block IO controller
|
|
|
|
-*- Namespaces support
|
|
|
|
[*] UTS namespace
|
|
|
|
[*] IPC namespace
|
|
|
|
[*] User namespace
|
|
|
|
[*] PID Namespaces
|
|
|
|
[*] Network namespace
|
|
|
|
[*] Networking support --->
|
|
|
|
Networking options --->
|
|
|
|
<M> 802.1d Ethernet Bridging
|
|
|
|
<M> 802.1Q VLAN Support
|
|
|
|
Device Drivers --->
|
|
|
|
[*] Network device support --->
|
|
|
|
<M> MAC-VLAN support
|
|
|
|
<M> Virtual ethernet pair device
|
|
|
|
Character devices --->
|
|
|
|
-*- Unix98 PTY support
|
|
|
|
[*] Support multiple instances of devpts
|
|
|
|
```
|
|
|
|
|
|
|
|
Une fois que vous aurez installé LXC, vous pouvez vérifier la compatibilité de
|
|
|
|
la configuration de votre noyau en utilisant la commande `lxc-checkconfig`.
|
|
|
|
|
|
|
|
|
|
|
|
## Docker
|
|
|
|
|
|
|
|
### Par le gestionnaire de paquets
|
|
|
|
|
2014-11-28 18:21:38 +00:00
|
|
|
Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet et la commande ont été
|
|
|
|
nommés `docker.io`.
|
|
|
|
|
|
|
|
Sous les autres distribution, `docker` correspond a priori bien à la solution
|
|
|
|
de virtualisation légère que l'on va utiliser.
|
2014-11-28 16:59:04 +00:00
|
|
|
|
|
|
|
### Manuellement
|
|
|
|
|
|
|
|
L'équipe en charge de Docker met à disposition un script pour
|
|
|
|
installer Docker sur n'importe quel système :
|
|
|
|
|
|
|
|
```sh
|
|
|
|
curl -sSL https://get.docker.com/ | sh
|
|
|
|
```
|
|
|
|
|
|
|
|
## LXC
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-11-28 07:46:24 +00:00
|
|
|
# Docker
|
|
|
|
|
|
|
|
Docker est un outil haut niveau permettant de faire fonctionner
|
|
|
|
facilement les conteneurs.
|
|
|
|
|
|
|
|
## Composition de Docker
|
|
|
|
|
2014-11-28 18:21:38 +00:00
|
|
|
Docker est un daemon lancé au démarrage de votre machine, avec lequel
|
|
|
|
vous interagissez via un client qui se connecte au daemon au moyen
|
2014-11-28 07:46:24 +00:00
|
|
|
d'une socket (le client peut donc être sur une machine distincte du
|
2014-11-28 18:21:38 +00:00
|
|
|
daemon où sont exécutés les conteneurs).
|
2014-11-28 07:46:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
## Mon premier conteneur
|
|
|
|
|
|
|
|
Afin de tester la bonne marche de votre installation, exécutez la
|
|
|
|
commande :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run hello-world
|
|
|
|
```
|
|
|
|
|
|
|
|
Cette commande va automatiquement exécuter une série de commandes pour
|
|
|
|
vous, comme indiqué dans le message affiché en retour :
|
|
|
|
|
|
|
|
D'abord, le démon va rechercher s'il possède localement l'image
|
|
|
|
*hello-world*. Si ce n'est pas le cas, il va aller la récupérer sur
|
|
|
|
hub.docker.com. Ce site met à votre disposition un grand nombre
|
|
|
|
d'images prêt à l'emploi : des systèmes de base comme Ubuntu, Debian,
|
|
|
|
Centos, etc. jusqu'à des conteneurs prêts à l'emploi : le serveur web
|
|
|
|
nginx, la base de données MySQL, un serveur node.js, etc.
|
|
|
|
|
|
|
|
Vous pouvez directement utiliser le client pour rechercher une image
|
|
|
|
sur le hub, en utilisant la commande `search` :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker search mariadb
|
|
|
|
```
|
|
|
|
|
|
|
|
Vous pouvez mettre à jour vos images locales ou simplement
|
|
|
|
pré-télécharger des images depuis le hub en utilisant la commande
|
|
|
|
`pull` :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker pull ubuntu
|
|
|
|
```
|
|
|
|
|
|
|
|
Pour consulter la liste des images dont vous disposez localement (soit
|
|
|
|
parce que vous les avez téléchargées, soit parce que vous les avez
|
|
|
|
créées vous-même), utilisez la commande `images` :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker images
|
|
|
|
```
|
|
|
|
|
|
|
|
Vous devez constater la présence de deux images « Ubuntu », ayant un
|
|
|
|
*TAG* différent. Souvent, il existe plusieurs versions d'une même
|
|
|
|
image. Pour Ubuntu par exemple, vous avez la possibilité de lancer la
|
|
|
|
version `vivid`, `trusty` ou `precise`.
|
|
|
|
|
|
|
|
Chaque image est identifiable par son *Image ID* unique, les noms
|
|
|
|
d'images ainsi que leurs tags sont, comme les tags Git, une manière
|
|
|
|
humainement plus simple de faire référence aux identifiants.
|
|
|
|
|
|
|
|
Chaque nom d'image possède au moins un tag associé: *latest*, c'est le
|
|
|
|
tag qui est automatiquement recherché lorsque vous ne le précisez pas
|
|
|
|
en lançant l'image
|
|
|
|
|
|
|
|
|
|
|
|
## Exécuter un programme dans un conteneur
|
|
|
|
|
|
|
|
Maintenant que nous avons à notre disposition l'image d'un conteneur
|
|
|
|
Ubuntu, lançons-la !
|
|
|
|
|
|
|
|
La commande `run` de Docker prend comme derniers arguments le
|
|
|
|
programme à lancer dans le conteneur ainsi que ses éventuels
|
|
|
|
arguments. Essayons d'afficher un Hello World :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run ubuntu /bin/echo "Hello World"
|
|
|
|
```
|
|
|
|
|
|
|
|
Dans notre exemple, c'est bien le `/bin/echo` présent dans le
|
|
|
|
conteneur qui est appelé (et non pas le programme `/bin/echo` de la
|
|
|
|
machine hôte qui est transféré dans le conteneur).
|
|
|
|
|
|
|
|
|
|
|
|
## Modifier un conteneur
|
|
|
|
|
|
|
|
À chaque fois que vous lancez un `run`, un nouveau conteneur est créé
|
|
|
|
à partir de l'image que vous précisez (via un mécanisme de
|
|
|
|
Copy-On-Write, c'est donc très rapide et ne consomme pas beaucoup
|
|
|
|
d'espace disque). Cela signifie que lorsque vous exécutez une commande
|
|
|
|
modifiant le contenu d'un conteneur, cela ne modifie pas l'image de
|
|
|
|
base, mais crée une nouvelle image. Que vous pouvez ensuite utiliser
|
|
|
|
comme image de base.
|
|
|
|
|
|
|
|
Commençons par entrer dans un nouveau conteneur pour modifier l'image
|
|
|
|
:
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -it ubuntu /bin/bash
|
|
|
|
```
|
|
|
|
|
|
|
|
Vous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a
|
|
|
|
rien de superflu : vous n'avez pas d'éditeur de texte : ni vim, ni
|
|
|
|
emacs, même pas vi !
|
|
|
|
|
|
|
|
La première chose à faire est de mettre à jour la liste des paquets :
|
|
|
|
|
|
|
|
```
|
|
|
|
apt-get update
|
|
|
|
```
|
|
|
|
|
|
|
|
Il peut arriver que des paquets présents dans l'image officielle ne
|
|
|
|
soient pas à jour. Afin de garder un environnement cohérent, il est
|
|
|
|
recommandé de ne pas utiliser le gestionnaire de paquets pour mettre à
|
|
|
|
jour les paquets, mais plutôt de contacter le mainteneur de l'image
|
|
|
|
pour qu'il la mette à jour.
|
|
|
|
|
|
|
|
Installons maintenant un programme :
|
|
|
|
|
|
|
|
```
|
|
|
|
apt-get install nano
|
|
|
|
```
|
|
|
|
|
|
|
|
En attendant la fin de l'installation, jetez un œil à la commande dans
|
|
|
|
un autre terminal :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker ps
|
|
|
|
```
|
|
|
|
|
|
|
|
Cette commande liste les conteneurs actifs. Notez le *Container ID*
|
|
|
|
ainsi que le *NAMES* du conteneur du conteneur actuellement en cours
|
|
|
|
d'installation de nano.
|
|
|
|
|
|
|
|
Lorsque l'installation de `nano` est terminée, quittez l'image en tapant `exit`.
|
|
|
|
|
|
|
|
Sauvegardez votre image modifiée avec la commande `commit` pour
|
|
|
|
pouvoir commencer directement de votre image avec `nano` :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker commit CONTAINER my_nano
|
|
|
|
```
|
|
|
|
|
|
|
|
En remplaçant `CONTAINER` par le nom ou l'identifiant de votre
|
|
|
|
container. `my_nano` est le nom que vous voudrez utiliser à la place
|
|
|
|
d'`ubuntu` :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -it my_nano /bin/bash
|
|
|
|
```
|
|
|
|
|
|
|
|
Vous constatez cette fois que vous pouvez lancer `nano`, alors que
|
|
|
|
vous ne pouvez toujours pas le faire dans un conteneur issue d'une
|
|
|
|
image `ubuntu` !
|
|
|
|
|
|
|
|
|
|
|
|
## Dockerfile
|
|
|
|
|
|
|
|
Pour construire une image, vous n'êtes pas obligé de passer par une
|
|
|
|
série de commits. Docker dispose d'un mécanisme permettant
|
|
|
|
d'automatiser la construction de nouvelles images. Vous pouvez arriver
|
|
|
|
au même résultat que ce que l'on a réussi à faire précédemment en
|
|
|
|
utilisant le Docker file suivant :
|
|
|
|
|
|
|
|
```
|
|
|
|
FROM ubuntu:latest
|
|
|
|
|
|
|
|
RUN apt-get update
|
|
|
|
RUN apt-get install -y nano
|
|
|
|
```
|
|
|
|
|
|
|
|
La syntaxe d'un `Dockerfile` est simple, le premier mot de chaque
|
|
|
|
ligne est l'intitulé d'une instruction (que l'on écrit généralement en
|
|
|
|
majuscule), elle est suivie de ses arguments.
|
|
|
|
|
|
|
|
Dans notre exemple, nous utilisons `FROM` qui indique une image de
|
|
|
|
départ à utiliser ; `RUN` est une commande qui sera exécutée dans le
|
|
|
|
conteneur.
|
|
|
|
|
|
|
|
Pour lancer la construction de la nouvelle image, créer un nouveau
|
|
|
|
dossier ne contenant que votre fichier `Dockerfile`, placez-vous
|
|
|
|
dedans, puis utilisez la commande `build` :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker build -name=my_editor .
|
|
|
|
```
|
|
|
|
|
|
|
|
Une fois la construction de l'image terminée, vous pouvez la lancer et
|
|
|
|
constater l'existence de notre éditeur favori :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -it my_editor /bin/bash
|
|
|
|
```
|
|
|
|
|
|
|
|
Consultez https://docs.docker.com/reference/builder/ pour la liste
|
|
|
|
complète des instructions reconnues.
|
|
|
|
|
|
|
|
|
|
|
|
## Exposer des ports
|
|
|
|
|
|
|
|
Construisons maintenant un conteneur avec un serveur web :
|
|
|
|
|
|
|
|
```
|
|
|
|
FROM my_editor
|
|
|
|
|
|
|
|
RUN apt-get update
|
|
|
|
RUN apt-get install -y nginx
|
|
|
|
|
|
|
|
EXPOSE 80
|
|
|
|
```
|
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
L'instruction `EXPOSE` sera traité plus tard par le client Docker
|
|
|
|
(équivalent à l'argument `--expose`). Il s'agit de préciser les ports
|
|
|
|
sur lesquels votre image écoute.
|
2014-11-28 07:46:24 +00:00
|
|
|
|
|
|
|
En utilisant l'option `-P` du `run`, vous allez pouvoir assigner une
|
|
|
|
redirection de port aléatoire sur la machine hôte vers votre
|
|
|
|
conteneur :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker build -name=my_webserver .
|
|
|
|
docker run -it -P my_webserver /bin/bash
|
|
|
|
service nginx start
|
|
|
|
```
|
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
Dans un autre terminal, lancer un `docker ps` et consulter la colonne
|
|
|
|
*PORTS* pour connaître le port choisit par Docker pour effectuer la
|
|
|
|
redirection.
|
|
|
|
|
|
|
|
Rendez-vous ensuite dans votre navigateur sur http://localhost:49153/.
|
|
|
|
|
2014-11-28 07:46:24 +00:00
|
|
|
À vous de jouer : utilisez l'instruction `COPY` pour afficher votre
|
|
|
|
propre `index.html` remplaçant celui installé de base par nginx.
|
|
|
|
|
|
|
|
|
|
|
|
## Lancement de commande automatique
|
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
Vous pouvez placer dans un `Dockerfile` une instruction `CMD` qui sera
|
|
|
|
exécutée si aucune commande n'est passée lors du `run`, par exemple :
|
2014-11-28 07:46:24 +00:00
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
```
|
2014-11-28 07:46:24 +00:00
|
|
|
CMD nginx -g "daemon off;"
|
2014-11-28 16:59:04 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
```
|
|
|
|
docker build -name=my_nginx .
|
|
|
|
docker run -d -P my_nginx
|
|
|
|
```
|
|
|
|
|
|
|
|
L'option `-d` passée au `run` lance le conteneur en tâche de
|
|
|
|
fond. Si vous constatez via un `docker ps` que le conteneur s'arrête
|
|
|
|
directement, retirer cette option pour voir ce qui ne va pas, ou
|
|
|
|
utilisez la commande `docker logs`.
|
|
|
|
|
|
|
|
|
|
|
|
## Volumes
|
|
|
|
|
|
|
|
Il est possible de partager des répertoires entre plusieurs
|
|
|
|
conteneurs. Pour ce faire, il faut déclarer dans le `Dockerfile` une
|
|
|
|
ou plusieurs instructions `VOLUME` avec le chemin du répertoire à
|
|
|
|
considérer comme volume (il est également possible de le faire via
|
|
|
|
l'option `--volume` du client). Ces deux lignes sont équivalentes :
|
|
|
|
|
|
|
|
```
|
|
|
|
VOLUME /var/log/nginx
|
|
|
|
```
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -v /var/log/nginx my_nginx
|
|
|
|
```
|
|
|
|
|
|
|
|
Pour monter les volumes dans un autre conteneur, on utilise l'argument
|
|
|
|
`--volume-from` du client, en indiquant le nom du conteneur avec
|
|
|
|
lequel on souhaite partager les volumes :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -it --volume-from romantic_archimedes ubuntu /bin/bash
|
|
|
|
```
|
|
|
|
|
|
|
|
Vous constaterez que le répertoire `/var/log/nginx` est partagé entre
|
|
|
|
`romantic_archimedes` et le dernier conteneur lancé.
|
|
|
|
\newline
|
|
|
|
|
|
|
|
Le concept principal de Docker est de concevoir des conteneurs
|
|
|
|
applicatifs : on va préférer assigner un unique rôle à un conteneur
|
|
|
|
(donc géralement on ne va lancer qu'une seule application par
|
|
|
|
conteneur) et concevoir un service complet en créant un groupe de
|
|
|
|
conteneur, partageant des données entre-eux par des volumes.
|
|
|
|
|
|
|
|
Une lecture intéressante sur ce sujet est sans doute cet article de
|
|
|
|
Michael Crosby: http://crosbymichael.com/advanced-docker-volumes.html
|
|
|
|
|
|
|
|
### Data Volume Container
|
|
|
|
|
|
|
|
Dans de nombreuses situation, il est intéressant de séparer les
|
|
|
|
données de l'application, et donc d'avoir un conteneur exécutant
|
|
|
|
l'application et un second stockant les données.
|
|
|
|
|
|
|
|
Cela est particulièrement utile dans le cas d'une base de données : on
|
|
|
|
veut pouvoir mettre à jour le conteneur exécutant le serveur, sans
|
|
|
|
pour autant perdre les données.
|
|
|
|
|
|
|
|
L'idée derrière le concept de `Data Volume Container` est de partager
|
|
|
|
un volume avec un conteneur dont le seul rôle est de stocker les
|
|
|
|
données.
|
|
|
|
|
|
|
|
Il est parfaitement possible de partager un volume avec un conteneur
|
|
|
|
qui n'est plus lancé. En effet, tant que vous n'avez pas demandé
|
|
|
|
explicitement à un conteneur d'être supprimé, il est préservé dans un
|
|
|
|
coin en attendant des jours meilleurs.
|
|
|
|
|
|
|
|
Voici comment on pourrait lancer un conteneur exécutant une base de
|
|
|
|
données :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -v /var/lib/mysql --name dbdata busybox
|
|
|
|
docker run --volume-from dbdata -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql
|
|
|
|
```
|
|
|
|
|
|
|
|
Le premier conteneur, sans commande passée, va s'arrêter dès son
|
|
|
|
lancement. Busybox est l'une des plus petites images possédant tous
|
|
|
|
les outils de base (il est possible d'obtenir un shell en cas de
|
|
|
|
besoin). Il expose un volume qui sera utiliser comme stockage
|
|
|
|
persistant.
|
|
|
|
|
|
|
|
Le second conteneur va lancer le serveur MySQL et utiliser le
|
|
|
|
répertoire partagé pour stocker les données.
|
|
|
|
|
|
|
|
Lorsqu'il y aura besoin de mettre à jour le conteneur MySQL, les
|
|
|
|
données ne seront pas perdues (et s'il y avait besoin de migrer les
|
|
|
|
données entre les deux versions des conteneurs, un conteneur
|
|
|
|
intermédiaire pourrait parfaitement s'en charger).
|
|
|
|
|
|
|
|
Cela facile également les sauvegardes, qui peuvent s'exécuter dans un
|
|
|
|
conteneur distinct, dédié à la tâche de sauvegarde.
|
|
|
|
|
2014-11-28 07:46:24 +00:00
|
|
|
|
|
|
|
## Lier les conteneurs
|
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
En plus de vouloir partager des répertoires entre deux conteneurs, il
|
|
|
|
est souvent nécessaire de partager des ports.
|
|
|
|
|
|
|
|
Pour automatiser le partage d'informations sur les IP et ports
|
|
|
|
exposés, la commande `run` possède l'option `--link` qui permet de
|
|
|
|
définir dans les variables d'environnement du conteneur que l'on va
|
|
|
|
lancer.
|
2014-11-28 07:46:24 +00:00
|
|
|
|
2014-11-28 16:59:04 +00:00
|
|
|
Le détail des variables ajoutées dans cette situation est disponible
|
|
|
|
ici : https://docs.docker.com/userguide/dockerlinks/#environment-variables
|
|
|
|
|
|
|
|
On utiliser généralement cette liaison pour fournir au conteneur
|
|
|
|
hébergeant un site web dynamique l'IP et le port où trouver la base de
|
|
|
|
données :
|
|
|
|
|
|
|
|
```
|
|
|
|
docker run -e MYSQL_ROOT_PASSWORD=mysecretpassword -d --name db1 mysql
|
|
|
|
docker run --link db1 my_nginx
|
|
|
|
```
|
|
|
|
|
|
|
|
### Ambasador
|
|
|
|
|
|
|
|
Afin d'abstraire le plus possible l'infrastructure sous-jacente et
|
|
|
|
d'autoriser les migrations de conteneurs, on utilise le modèle
|
|
|
|
*ambassador*.
|
|
|
|
|
|
|
|
On lancera systématiquement un conteneur entre deux conteneurs que
|
|
|
|
l'on veut lier : l'ambassadeur. Celui-ci s'occupera de router
|
|
|
|
correctement le trafic. En cas de changement de route (si l'un des
|
|
|
|
conteneurs change de machine hôte par exemple), on a simplement à
|
|
|
|
redémarrer l'ambassadeur plutôt que le conteneur principal.
|
|
|
|
|
|
|
|
La documentation officielle pour ce modèle est disponible à
|
|
|
|
https://docs.docker.com/articles/ambassador_pattern_linking/
|
2014-11-28 07:46:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
# LXC
|
2014-11-28 16:59:04 +00:00
|
|
|
|
|
|
|
Contrairement à Docker, l'utilisation de LXC est beaucoup plus proche
|
|
|
|
de l'administration système classique, car l'approche est beaucoup
|
|
|
|
plus bas niveau.
|
|
|
|
|
|
|
|
## Lancer un conteneur
|
|
|
|
|
|
|
|
Avec le paquet LXC que vous avez installé, vous avez également
|
|
|
|
récupéré un certain nombre de modèles de système (souvent installés
|
|
|
|
dans le dossier `/usr/share/lxc/templates/`).
|
|
|
|
|
|
|
|
La méthode la plus simple pour lancer un conteneur LXC est d'utiliser
|
|
|
|
l'un de ces modèles qui va installer tout un environnement pour
|
|
|
|
vous. On utilise pour cela la commande `lxc-create` :
|
|
|
|
|
|
|
|
```
|
|
|
|
lxc-create --name toto_first --template ubuntu
|
|
|
|
```
|
|
|
|
|
|
|
|
Ce modèle va créer un dossier dans `/var/lib/lxc/` portant le nom que
|
|
|
|
vous avez précisé. Ce dossier va contenir la configuration LXC du
|
|
|
|
conteneur, la table des partitions s'il y a besoin de faire des
|
|
|
|
montages particuliers et enfin le dossier `rootfs` contenant le
|
|
|
|
système en lui-même.
|
|
|
|
|
|
|
|
On peut maintenant démarrer le conteneur :
|
|
|
|
|
|
|
|
```
|
|
|
|
lxc-start --name toto_first
|
|
|
|
```
|
|
|
|
|
|
|
|
À la différence de Docker qui va ne lancer que l'application (ou les
|
|
|
|
applications listées dans la ligne de commande) dans son
|
|
|
|
environnement, LXC va appeler `/sbin/init` et démarrer tous les
|
|
|
|
services que l'on peut s'attendre à trouver dans n'importe quelle
|
|
|
|
machine virtuelle plus classique (la seule différence réside donc dans
|
|
|
|
le fait que le noyau est partagé avec l'hôte).
|
|
|
|
|
|
|
|
Généralement on lance `lxc-start` avec l'option `--daemon`, puis on
|
|
|
|
utilise `lxc-console` qui permet de se détacher de la console via le
|
|
|
|
binding `^A+q`.
|
|
|
|
|
|
|
|
Connectez-vous, lancez quelques commandes puis éteignez la machine
|
|
|
|
avec `sudo poweroff` ou dans un autre terminal via `lxc-stop --name
|
|
|
|
toto_first`.
|
|
|
|
|
|
|
|
|
|
|
|
## Persistance des données
|
|
|
|
|
|
|
|
Contrairement à Docker, lorsque vous arrêtez un conteneur, les
|
|
|
|
modifications apportées sont conservées. Si vous appelez à nouveau
|
|
|
|
`lxc-start --name toto_first`, vous constaterez que votre historique
|
|
|
|
contient les dernières commandes que vous avez tapé et si vous avez
|
|
|
|
apporté d'autres modifications sur le système, celles-ci sont toujours
|
|
|
|
visibles.
|
|
|
|
|
|
|
|
|
|
|
|
## Le réseau
|
|
|
|
|
|
|
|
Le modèle ubuntu que vous avez utilisé initialise un fichier de
|
|
|
|
configuration sans paramètres pour le réseau. Vous n'avez donc pas
|
|
|
|
d'interface dans le conteneur pour le connecter au réseau.
|
|
|
|
|
|
|
|
Un excellent article détaillant les différents types de réseau est
|
|
|
|
accessible à :
|
|
|
|
https://blog.flameeyes.eu/2010/09/linux-containers-and-networking
|
|
|
|
|
|
|
|
N'ayant qu'une seule interface physique sur la machine et n'ayant pas
|
|
|
|
accès à la configuration des VLAN de la pièce, il ne nous reste que
|
|
|
|
deux méthodes pour obtenir du réseau dans nos conteneurs : Virtual
|
|
|
|
Ethernet ou MACVLAN.
|
|
|
|
|
|
|
|
### Virtual Ethernet
|
|
|
|
|
|
|
|
Virtual Ethernet est la configuration la plus simple. On met en place un pont
|
|
|
|
sur la machine hôte, puis on crée une interface `veth` par conteneur
|
|
|
|
que l'on veut lancer. On n'oubliera pas d'ajouter ces interfaces au pont.
|
|
|
|
|
|
|
|
Voici un extrait de configuration correspondant au paramétrage d'une
|
|
|
|
interface `eth0` pour un conteneur donné :
|
|
|
|
|
|
|
|
```
|
|
|
|
lxc.network.type = veth
|
|
|
|
lxc.network.flags = up
|
|
|
|
lxc.network.link = br0
|
|
|
|
```
|
|
|
|
|
|
|
|
Cette technique a pour inconvénient de laisser au noyau le soin de
|
|
|
|
router les paquets selon leur adresse IP, ce qui peut être lent et
|
|
|
|
coûteux étant donné que la carte est placé en mode de promiscuité.
|
|
|
|
|
|
|
|
|
|
|
|
### MACVLAN
|
|
|
|
|
|
|
|
Ici, le noyau va orienter les paquets en fonction de leur adresse MAC
|
|
|
|
de destination.
|
|
|
|
|
|
|
|
```
|
|
|
|
lxc.network.type = macvlan
|
|
|
|
lxc.network.macvlan.mode = bridge
|
|
|
|
lxc.network.flags = up
|
|
|
|
lxc.network.link = br0
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Stockage
|
|
|
|
|
|
|
|
Par défaut, le stockage se fait dans l'arborescence du système hôte,
|
|
|
|
mais il est possible d'utiliser d'autres backends tels que Btrfs, LVM,
|
|
|
|
overlayfs, AUFS ou ZFS.
|
|
|
|
|
|
|
|
Pour utiliser un type de stockage particulier, préciser lors de la
|
|
|
|
création de l'environnement du conteneur `-B [btrfs|zfs|lvm|...]`.
|