Tuto 2: wip
This commit is contained in:
parent
50913a7493
commit
76495b9045
19
tutorial/2/Makefile
Normal file
19
tutorial/2/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
SOURCES = tutorial.md installation.md docker.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
|
384
tutorial/2/docker.md
Normal file
384
tutorial/2/docker.md
Normal file
@ -0,0 +1,384 @@
|
||||
\newpage
|
||||
|
||||
# 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 <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
|
||||
```
|
||||
|
||||
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 <http://localhost:49153/>.
|
||||
|
||||
À 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 à
|
||||
<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/>.
|
53
tutorial/2/installation.md
Normal file
53
tutorial/2/installation.md
Normal file
@ -0,0 +1,53 @@
|
||||
\newpage
|
||||
|
||||
# Installation
|
||||
|
||||
## 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
|
||||
```
|
21
tutorial/2/tutorial.md
Normal file
21
tutorial/2/tutorial.md
Normal file
@ -0,0 +1,21 @@
|
||||
% Virtualisation légère -- TP n^o^2
|
||||
% Pierre-Olivier *Nemunaire* Mercier
|
||||
% Jeudi 22 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 à
|
||||
<virli@nemunai.re> 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
|
Loading…
Reference in New Issue
Block a user