From 50913a74937554aa2db1e9229ee53cda5d83323b Mon Sep 17 00:00:00 2001 From: nemunaire Date: Wed, 7 Oct 2015 03:45:39 +0200 Subject: [PATCH] Tuto 1: wip --- tutorial/1/Makefile | 19 ++ tutorial/1/cgroups.md | 50 ++++ tutorial/1/installation.md | 52 ++++ tutorial/1/lxc.md | 148 +++++++++ tutorial/1/namespaces.md | 129 ++++++++ tutorial/1/tutorial.md | 21 ++ tutorial/Makefile | 9 - tutorial/tutorial.md | 593 ------------------------------------- 8 files changed, 419 insertions(+), 602 deletions(-) create mode 100644 tutorial/1/Makefile create mode 100644 tutorial/1/cgroups.md create mode 100644 tutorial/1/installation.md create mode 100644 tutorial/1/lxc.md create mode 100644 tutorial/1/namespaces.md create mode 100644 tutorial/1/tutorial.md delete mode 100644 tutorial/Makefile delete mode 100644 tutorial/tutorial.md diff --git a/tutorial/1/Makefile b/tutorial/1/Makefile new file mode 100644 index 0000000..cff9342 --- /dev/null +++ b/tutorial/1/Makefile @@ -0,0 +1,19 @@ +SOURCES = tutorial.md installation.md lxc.md cgroups.md namespaces.md +TEMPLATE = ../../template.tex +PANDOCOPTS = --latex-engine=xelatex \ + --standalone \ + --normalize \ + --number-sections \ + -M lang=frenchb \ + -M fontsize=12pt \ + -M papersize=a4paper \ + --template=${TEMPLATE} + + +all: tutorial.pdf + +tutorial.pdf: ${SOURCES} + pandoc ${PANDOCOPTS} -o $@ $+ + +clean:: + rm tutorial.pdf diff --git a/tutorial/1/cgroups.md b/tutorial/1/cgroups.md new file mode 100644 index 0000000..eb26291 --- /dev/null +++ b/tutorial/1/cgroups.md @@ -0,0 +1,50 @@ +\newpage + +# Utiliser les *cgroups* + +## Premiers tests + +### Création d'un nouveau groupe + +### Rattachement de processus + +### Consultatation de l'état + +### Changement d'état + + +## Script de monitoring + +### Monitoring instantanné vers la console + +#### Option pour choisir l'intervalle de polling + +### Monitoring vers InfluxDB + +### Permettre à l'utilisateur de monitorer des process + +#### Séparer en deux scripts + +#### Ajouter les bonnes capabilities sur le premier script + +#### Rendre ok avec les exécutions concurrentes du second script + +### Monitorer chaque fils indépendamment + + +## Rendu + +### Script de monitoring + +Rendez la révision la plus avancées de vos scripts de monitoring de process via +les *cgroups*. + +### Questions + +1. Un même processus peut-il être dans plusieurs cgroups de type différents (freezer et cpuacct par exemple) ? + +1. Que sera-t-il possible de limiter via un nouveau cgroup dans la prochaine + version du noyau (4.3) ? + +1. Comment peut-on limiter le nombre de processus lancés par un utilisateur ou + un groupe ? diff --git a/tutorial/1/installation.md b/tutorial/1/installation.md new file mode 100644 index 0000000..c35499f --- /dev/null +++ b/tutorial/1/installation.md @@ -0,0 +1,52 @@ +\newpage + +# Installation + +## 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//cpuset file + [*] Simple CPU accounting cgroup subsystem + [*] 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 ---> + <*> 802.1d Ethernet Bridging + 802.1Q VLAN Support +Device Drivers ---> + [*] Network device support ---> + MAC-VLAN support + <*> 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`. + + +## LXC + +Pour installer LXC, utilisez le gestionnaire de paquets de votre +distribution. Toute les bonnes distributions fournissent un paquet `lxc`. + +Aucune configuration ne devrait vous être demandé durant l'installation. Une +fois l'installation terminée, exécutez la commande `lxc-checkconfig` pour +vérifier que votre noyau possède bien toutes les options nécessaires. diff --git a/tutorial/1/lxc.md b/tutorial/1/lxc.md new file mode 100644 index 0000000..8800147 --- /dev/null +++ b/tutorial/1/lxc.md @@ -0,0 +1,148 @@ +\newpage + +# Utiliser LXC + +Le but de cette première partie est d'appréhender la virtualisation légère au +travers d'un programme, `lxc`, qui va mettre en place pour nous un +environnement distinct. + + +## 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 (`config`), +la table des partitions (`fstab`) s'il y a besoin de faire des montages +particuliers et enfin le dossier `rootfs` contenant le système en lui-même. + +Une fois l'installation terminée, on peut démarrer le conteneur : + +``` +lxc-start --name toto_first +``` + +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`, car on ne s'attend +pas à ce que la machine s'arrête lorsque l'on va quitter notre terminal. Dans +ce cas, utiliser la commande `lxc-console` pour vous attacher à votre +conteneur. À tout moment, vous pouvez vous détacher de la console (sans que +cela n'affecte l'état du conteneur) en pressant les touches : `^A q`. + +Connectez-vous, lancez quelques commandes puis éteignez la machine avec `sudo +poweroff` dans le conteneur. Vous pouvez aussi lancer la commande `lxc-stop +--name toto_first` dans un autre terminal, depuis la machine hôte. + + +## 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 à +. + +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. Malheureusement, ces deux méthodes nécessitent de mettre en place un +pont Ethernet sur votre machine : + + +### Installation du pont réseau + +#### Bridge interface + +#### Port forwarding + + +### 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 +``` + + +## Utilisation du conteneur + +### Redémarrage du conteneur + +### Installation de InFluxDB et Graphana + +### Test de l'installation + + +## Rendu + +### Configuration du conteneur + +En plus des modifications que vous avez effectuées durant le TP, modifiez la +configuration du conteneur afin qu'il ne puisse pas utiliser plus que 256 MB de +RAM et 512 MB de swap. + +Limitez ensuite les `capabilities(7)` de ce conteneur afin qu'il s'exécute avec +le strict minimum de droits, nécessaire au bon fonctionnement des programmes +installés. + +**Rendez le fichier `config` de ce premier conteneur.** N'hésitez pas à laisser + des commentaires justifiant vos éventuels choix. + +### Questions + +1. Quel type de virtualisation réseau avez-vous utilisé ? pourquoi ? + +1. Quels sont les autres types de virtualisation réseau existants ? Expliquez + en chacun une phrase leurs particularités. + +1. Dans quel langage InfluxDB a-t-il était écrit ? Quelle est la particularité + des binaires générés par ce langage ? + +1. Quels sont les avantages et les inconvénients associés au linkage statique + et au linkage dynamique ? (pas forcément que dans le cadre de la + virtualisation légère). + +1. J'ai utilisé la méthode *Virtual Ethernet* pour relier mes conteneurs à + Internet, via un PAT (`br0`). Quelle(s) règle(s) `iptables` devrais-je + écrire sur mon hôte afin de permettre l'accès à InfluxDB depuis une autre + machine ? diff --git a/tutorial/1/namespaces.md b/tutorial/1/namespaces.md new file mode 100644 index 0000000..43fb6cc --- /dev/null +++ b/tutorial/1/namespaces.md @@ -0,0 +1,129 @@ +\newpage + +# Utiliser les *namespaces* + +## Comparaison de *namespace* + +Écrivez un script ou un programme, `cmpns`, dans le langage courant de votre +choix, permettant de déterminer si deux programmes s'exécutent dans les mêmes +*namespaces*. + +### Exemples + +```sh +42sh$ cmpns $(pgrep influxdb) $(pgrep init) + - ipc: differ + - mnt: differ + - net: differ + - pid: differ + - user: same + - uts: same +``` + +```sh +42sh$ cmpns $(pgrep init) self + - ipc: same + - mnt: same + - net: same + - pid: same + - user: same + - uts: same +``` + +Ici, `self` fait référence au processus actuellement exécuté. + + +## Rejoindre un *namespace* + +Dans le langage courant de votre choix, écrivez un programme : `setns`, +permettant, à la manière de `unshare(1)` et `unshare(2)`, d'utiliser `setns(2)` +via votre interpréteur. + +Les options attendues sont : + +* rejoindre un namespace IPC : `-i`, `--ipc` ; +* rejoindre un namespace mount : `-m`, `--mount` ; +* rejoindre un namespace net : `-n`, `--net` ; +* rejoindre un namespace PID : `-p`, `--pid` ; +* rejoindre un namespace UTS : `-u`, `--uts` ; +* rejoindre un namespace user : `-U`, `--user`. + +### Exemples + +```sh +42sh# setns /bin/bash +bash# _ +``` + +#### IPC and PID Namespaces + +```sh +42sh# setns --ipc=/proc/42/ns/ipc -p /proc/42/ns/pid /bin/echo toto +toto +``` + +#### Net Namespace + +```sh +42sh# setns --net=/proc/42/ns/net ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default + link/loopback 00:00:00:00:00:00 brd 00:00:00:00::00 + inet 127.0.0.1/8 brd 127.255.255.255 scope lo + valid_lft forever preferred_lft + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +``` + +#### UTS Namespace + +```sh +42sh# hostname --fqdn +koala.zoo.paris +42sh# setns --uts=/proc/42/ns/uts hostname --fqdn +lynx.zoo.paris +``` + + +## My Little Container + +En utilisant le langage courant de votre choix, concevez l'exécutable `mlc`, +permettant de lancer une application dans un environnement différent (comme un +`chroot`, mais sans permettre de s'en échapper) et avec des privilèges réduits. + +Votre solution doit créer au moins un nouveau *namespace* mount et PID. + +Vous aurez sans doute besoin de : `clone(2)`, `capabilities(7)`, `capset(2)`, `pivot_root(2)`, + +### Exemples + +```sh +42sh# ls newroot +bin etc home usr root proc var + +42sh# mlc newroot/ /bin/bash + bash# ls ../../../ + bin etc home usr root proc var + + bash# escape_chroot ls + bin etc home usr root proc var + + bash# ls -ld /proc/[0-9]* | wc -l + 2 + + bash# curl http://www.linuxcontainers.org/ | md5sum + 0123456789abcdef + + bash# ping 8.8.8.8 + Operation not permitted +``` + + +## Rendu + +Pour chaque exercice de cette partie, vous pouvez rendre un seul fichier s'il +s'agit d'un script ; sinon, vous devez rendre une tarball contenant un +`Makefile` permettant de générer les éventuels exécutables et/ou un `README` +expliquant comment s'en servir. + +Vous devez donc rendre 3 fichiers : `cmpns` ou `cmpns.tar.bz2`, `setns` ou +`setns.tar.bz2` et `mlc` ou `mlc.tar.bz2`. diff --git a/tutorial/1/tutorial.md b/tutorial/1/tutorial.md new file mode 100644 index 0000000..c830263 --- /dev/null +++ b/tutorial/1/tutorial.md @@ -0,0 +1,21 @@ +% Virtualisation légère -- TP n^o^ 1 +% Pierre-Olivier *nemunaire* Mercier +% Jeudi 8 octobre 2015 + +Le but de ce premier TP est d'utiliser les commandes et les appels systèmes vu +durant le cours. + +Tous les éléments de ce TP (exercices et questions) sont à rendre à + au plus tard le mercredi 21 octobre 2015 à 23 h 42. Consultez la +dernière section de chaque partie pour plus d'information sur les éléments à +rendre. Vous pouvez placer les réponses aux questions dans le corps du courriel +ou dans un fichier joint. + +En tant que personnes sensibilisées à la sécurité des échanges électroniques, +vous devriez m'envoyer vos rendus signés avec votre clef PGP. Pensez à +[me](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x842807A84573CC96) faire +signer votre clef et n'hésitez pas à +[faire signer votre clef](http://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/). + +\hypersetup{linkcolor=black} +\tableofcontents diff --git a/tutorial/Makefile b/tutorial/Makefile deleted file mode 100644 index 2003d49..0000000 --- a/tutorial/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -all: tutorial.pdf - -.md.pdf: - pandoc --latex-engine=xelatex --toc --normalize -M lang=frenchb --standalone -N --template=../template.tex -M fontsize=12pt -M papersize=a4paper -o $@ $< - -.md.tex: - pandoc --latex-engine=xelatex --toc --normalize -M lang=frenchb --standalone -N --template=../template.tex -M fontsize=12pt -M papersize=a4paper -o $@ $< - -.SUFFIXES: .md .tex .pdf diff --git a/tutorial/tutorial.md b/tutorial/tutorial.md deleted file mode 100644 index 0ae59a1..0000000 --- a/tutorial/tutorial.md +++ /dev/null @@ -1,593 +0,0 @@ -% Virtualisation légère -% Pierre-Olivier *Nemunaire* Mercier -% Samedi 29 novembre 2014 - -# Installation - -## 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//cpuset file - [*] Simple CPU accounting cgroup subsystem - [*] 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 ---> - 802.1d Ethernet Bridging - 802.1Q VLAN Support -Device Drivers ---> - [*] Network device support ---> - MAC-VLAN support - <*> 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 - -Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet et la commande ont été -nommés `docker.io`. Vous pouvez vous créer un alias `alias docker=docker.io` si -celui-ci n'a pas déjà été défini. - -Sous les autres distributions, `docker` correspond a priori bien à la solution -de virtualisation légère que l'on va utiliser. - -### 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 -``` - -### Vérifier la bonne marche de l'installation - -Vous devriez maintenant être capable de lancer la commande suivante : - -``` -docker version -``` - -Une sortie similaire au bloc suivant devrait apparaître sur votre écran : - -``` -Client version: 1.3.2 -Client API version: 1.15 -Go version (client): go1.3.3 -Git commit (client): 39fa2fa -OS/Arch (client): linux/amd64 -Server version: 1.3.2 -Server API version: 1.15 -Go version (server): go1.3.3 -Git commit (server): 39fa2fa -``` - -Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission -denied.`, ajoutez votre utilisateur au groupe `docker` et **relancer votre -session** : - -``` -sudo gpasswd -a $USER docker -``` - - -## LXC - -Votre distribution fournit sans doute un paquet `lxc`. - - -# Docker - -Docker est un outil haut niveau permettant de faire fonctionner facilement les -conteneurs. - -## Composition de Docker - -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 d'une socket (le -client peut donc être sur une machine distincte du daemon où sont exécutés les -conteneurs). - - -## 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 : 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, dans le -but de le construire. Chaque ligne est exécutée indépendamment des autres ; -cela signifie que l'exemple suivant ne fonctionne pas : - -``` -COPY db.sql /db.sql -RUN service mysqld start -RUN mysql -u root -p toor virli < /db.sql -``` - -Cet exemple ne fonctionne pas car le serveur MySQL est lancé dans le premier -RUN, n'est plus lancé au moment du deuxième RUN. Pour avoir le résultat -escompté, il faut exécuter les commandes ensemble : - -``` -COPY db.sql /db.sql -RUN service mysqld start && mysql -u root -p toor virli < /db.sql -``` - -Après le `RUN`, MySQL sera de nouveau arrêté, si on veut l'utiliser dans le -conteneur, il ne faudra pas oublier lancer le processus. - -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 --tag=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 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 -``` - -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. - -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 --tag=my_webserver . -docker run -it -P my_webserver /bin/bash -service nginx start -``` - -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 . - -À 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 - -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 : - -``` -CMD nginx -g "daemon off;" -``` - -``` -docker build --tag=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. - - -## Lier les conteneurs - -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. - -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 -(ici)[https://docs.docker.com/articles/ambassador_pattern_linking/]. - - -# LXC - -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 -(ici)[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|...]`.