Split Docker tutorials into basis, orchestration and dockerfiles
This commit is contained in:
parent
2d364556a2
commit
2c48fa7942
36 changed files with 477 additions and 188 deletions
|
@ -1,22 +0,0 @@
|
|||
SOURCES = tutorial.md installation.md what.md first.md supervisor.md goodpractices.md compose.md project.md
|
||||
PANDOCOPTS = --latex-engine=xelatex \
|
||||
--standalone \
|
||||
--normalize \
|
||||
--number-sections \
|
||||
--smart \
|
||||
-M lang=french \
|
||||
-M fontsize=12pt \
|
||||
-M papersize=a4paper \
|
||||
-M mainfont="Linux Libertine O" \
|
||||
-M monofont="FantasqueSansMono-Regular" \
|
||||
-M sansfont="Linux Biolinum O" \
|
||||
--include-in-header=../header.tex
|
||||
|
||||
|
||||
all: tutorial.pdf
|
||||
|
||||
tutorial.pdf: ${SOURCES}
|
||||
pandoc ${PANDOCOPTS} -o $@ $+
|
||||
|
||||
clean::
|
||||
rm tutorial.pdf
|
Binary file not shown.
Before Width: | Height: | Size: 92 KiB |
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
|
@ -1,205 +0,0 @@
|
|||
\newpage
|
||||
|
||||
# Compose
|
||||
|
||||
Avec notre conteneur utilisant `supervisor`, nous ne respectons pas
|
||||
cette dernière bonne pratique d'un seul processus par conteneur :-(
|
||||
|
||||
L'intérêt est de permettre à chaque conteneur d'effectuer une tâche
|
||||
simple et générique, de manière à pouvoir être réutilisé pour d'autres
|
||||
projets dans le futur. Par exemple, notre conteneur InfluxDB pourra
|
||||
être utilisé pour stocker des relevés de métriques d'autres systèmes
|
||||
ou des logs. Chronograf peut être connecté à d'autres serveurs afin
|
||||
de corréler les métriques, ...
|
||||
|
||||
|
||||
## Séparer le `Dockerfile`
|
||||
|
||||
Commençons par séparer notre `Dockerfile` en deux : dans une partie
|
||||
nous allons garder la partie InfluxDB, de l'autre la partie Chronograf.
|
||||
|
||||
Il va vous falloir créer deux dossiers distincts, il en faut un par
|
||||
`Dockerfile` : réutilisez l'image `influxdb` créée précédemment et créez le
|
||||
dossier pour l'image `chronograf`.
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
Pour tester la bonne marche de vos conteneurs, vous pouvez le lancer votre
|
||||
conteneur chronograf avec la commande suivante (en considérant que votre
|
||||
conteneur influxdb de la première partie est toujours lancé).
|
||||
|
||||
```shell
|
||||
docker run --rm --link YOUR_INFLUX_CNTR_NAME:influxdb chronograf
|
||||
```
|
||||
|
||||
Remplacez `YOUR_INFLUX_CNTR_NAME` par le nom du conteneur qui fait tourner
|
||||
votre influxdb. En créant ce lien, `chronograf` sera capable de contacter une
|
||||
machine nommée `influxdb` (indiqué par la partie du lien après les `:`).
|
||||
|
||||
|
||||
### Visualiser les données dans `chronograf`
|
||||
|
||||
Avant d'arrêter `telegraf` et nos conteneurs pour passer à une nouvelle étape,
|
||||
prenez le temps d'afficher les données que vous avez collecté depuis le début
|
||||
du TP.
|
||||
|
||||
Après avoir ajouté le serveur (en remplaçant `localhost` proposé par défaut par
|
||||
`influxdb` issue du *link*), ajouter deux visualisations avec les requêtes
|
||||
suivantes :
|
||||
|
||||
```sql
|
||||
SELECT used, available, cached FROM mem WHERE tmpltime()
|
||||
SELECT mean(usage_idle) FROM cpu WHERE tmpltime() GROUP BY time(20s), cpu
|
||||
```
|
||||
|
||||
|
||||
## Automatiser la construction et le lancement
|
||||
|
||||
Commencez par lancer tous vos conteneurs à la main pour voir les
|
||||
étapes que vous allez devoir automatiser.
|
||||
|
||||
Au lieu de faire un script pour construire et lancer tous vos
|
||||
conteneurs, définissez à la racine de votre projet un fichier
|
||||
`docker-compose.yml` qui contiendra les méthodes de construction et
|
||||
les paramètres d'exécution.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
services:
|
||||
influxdb:
|
||||
...
|
||||
chronograf:
|
||||
build: grafana/
|
||||
image: nginx
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./:/tmp/toto
|
||||
links:
|
||||
- influxdb
|
||||
```
|
||||
|
||||
Ce fichier est un condensé des options que vous passez habituellement
|
||||
au `docker run`.
|
||||
|
||||
### `version`
|
||||
|
||||
Notez toutefois la présence d'une ligne `version` ; il ne s'agit pas de la
|
||||
version de vos conteneurs, mais de la version du format de fichier
|
||||
docker-compose qui sera utilisé. Sans indication de version, la version
|
||||
originale sera utilisée.
|
||||
|
||||
|
||||
### `services`
|
||||
|
||||
Cette section énumère la liste des services (ou conteneurs) qui seront gérés
|
||||
par `docker-compose`.
|
||||
|
||||
Il peuvent dépendre d'une image à construire localement, dans ce cas ils auront
|
||||
un fils `build`. Ou ils peuvent utiliser une image déjà existante, dans ce cas
|
||||
ils auront un fils `image`.
|
||||
|
||||
Les autres fils sont les paramètres classiques que l'on va passer à `docker
|
||||
run`.
|
||||
|
||||
|
||||
### `volumes`
|
||||
|
||||
Cette section est le pendant de la commandes `docker volume`.
|
||||
|
||||
L'idée est d'éviter de créer des *Data Volume Container* qui ont une partie de
|
||||
système de fichiers inutile, et de ne garder que l'idée d'emplacement servant
|
||||
pour du stockage persistant.
|
||||
|
||||
On les déclare simplement en leur donnant un nom et un driver comme suit :
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
mysql-data:
|
||||
driver: local
|
||||
```
|
||||
|
||||
Leur utilisation est identique à un *Data Volume Container* : on référence le
|
||||
nom ainsi que l'emplacement à partager :
|
||||
|
||||
```yaml
|
||||
[...]
|
||||
mysql:
|
||||
[...]
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
```
|
||||
|
||||
|
||||
### `network`
|
||||
|
||||
Cette section est le pendant de la commandes `docker network`.
|
||||
|
||||
Par défaut, Docker relie tous les conteneurs sur un bridge et fait du NAT pour
|
||||
que les conteneur puisse accéder à l'Internet. Mais ce n'est pas le seul mode
|
||||
possible !
|
||||
|
||||
De la même manière que pour les `volumes`, cette section déclare les réseaux
|
||||
qui pourront être utilisés par les `services`. On pourrait donc avoir :
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
knotdns-slave-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
|
||||
#### Driver `host`
|
||||
|
||||
Le driver `host` réutilise la pile réseau de la machine hôte. Le conteneur
|
||||
pourra donc directement accéder au réseau, sans NAT et sans redirection de
|
||||
port. Les ports alloués par le conteneur ne devront pas entrer en conflits avec
|
||||
les ports ouverts par la machine hôte.
|
||||
|
||||
|
||||
#### Driver `null`
|
||||
|
||||
Avec le driver `null`, la pile réseau est recréée et aucune interface (autre
|
||||
que l'interface de loopback) n'est présente. Le conteneur ne peut donc pas
|
||||
accéder à Internet, ni aux autres conteneur, ...
|
||||
|
||||
Lorsque l'on exécute un conteneur qui n'a pas besoin d'accéder au réseau, c'est
|
||||
le driver à utiliser. Par exemple pour un conteneur dont le but est de vérifier
|
||||
un backup de base de données.
|
||||
|
||||
|
||||
#### Driver `bridge`
|
||||
|
||||
Le driver `bridge` crée un nouveau bridge qui sera partagée entre tous les
|
||||
conteneurs qui la référencent.
|
||||
|
||||
Avec cette configuration, les conteneurs ont accès à une résolution DNS des
|
||||
noms de conteneurs qui partagent leur bridge. Ainsi, sans avoir à utiliser la
|
||||
fonctionnalité de `link` au moment du `run`, il est possible de se retrouvé
|
||||
lié, même après que l'on ait démarré. La résolution se fera dynamiquement.
|
||||
|
||||
|
||||
### Utiliser le `docker-compose.yml`
|
||||
|
||||
Consultez <http://docs.docker.com/compose/compose-file/> pour une liste
|
||||
exhaustive des options que vous pouvez utiliser.
|
||||
|
||||
Une fois que votre `docker-compose.yml` est prêt, lancez tout d'abord
|
||||
`docker-compose build` pour commencer la phase de build de tous les conteneurs
|
||||
listés dans le fichier.
|
||||
|
||||
Une fois le build terminé, vous pouvez lancer la commande suivante et admirer
|
||||
le résultat :
|
||||
|
||||
```shell
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Encore une fois, testez la bonne connexion entre chronograf (accessible sur
|
||||
<http://localhost:10000>) et influxdb.
|
||||
|
||||
|
||||
## Rendu
|
||||
|
||||
Pour cette partie, vous devrez rendre la dernière itération de votre
|
||||
`docker-compose.yml`.
|
|
@ -1,18 +0,0 @@
|
|||
\newpage
|
||||
|
||||
# Entrypoint
|
||||
|
||||
Jusque là, à chaque redémarrage d'InfluxDB, il est nécessaire de reconfigurer
|
||||
Grafana pour lui indiquer la nouvelle IP du conteneur. En effet, le data
|
||||
container préserve les données, mais un changement d'IP n'est pas
|
||||
répercuté. Pour cela, il nous fait un script d'initialisation, qui va écrire
|
||||
l'ip de notre conteneur Docker dans la table `data_source` :
|
||||
|
||||
Petit indice, les requêtes SQL sont les suivantes :
|
||||
|
||||
```
|
||||
DELETE FROM "data_source";
|
||||
INSERT INTO "data_source" VALUES(1,1,0,'influxdb','influx','direct','http://${}:8086/','user','pass','metrics',0,'','',0,'null','2015-10-29 09:00:00','2015-10-29 09:05:00');
|
||||
```
|
||||
|
||||
La base se trouve dans `/var/lib/grafana/grafana.db`.
|
|
@ -1,128 +0,0 @@
|
|||
\newpage
|
||||
|
||||
Premières étapes
|
||||
================
|
||||
|
||||
Dans un premier temps, nous allons créer une image Docker comme si l'on
|
||||
réalisait une installation sur une machine classique : en suivant une recette,
|
||||
sans trop se préoccuper des fonctionnalitées que propose Docker.
|
||||
|
||||
La machine (notre première image Docker) contiendra tout le nécessaire pour
|
||||
faire fonctionner notre service de monitoring.
|
||||
|
||||
|
||||
## Les caches
|
||||
|
||||
Nous avons vu que chaque instruction de notre `Dockerfile` génère une
|
||||
couche. Chaque couche sert de cache d'une construction d'image à
|
||||
l'autre. Ainsi, lorsque vous modifiez une instruction dans votre `Dockerfile`,
|
||||
les instructions précédentes ne sont pas réexécutées mais sont ressorties du
|
||||
cache.
|
||||
|
||||
Le cache se base principalement sur le contenu de chaque instruction du
|
||||
`Dockerfile` (pour les `COPY` et `ADD`, il va aussi regarder la date de
|
||||
dernière modification de fichier à copier ou à ajouter). Donc tant qu'une
|
||||
instruction n'est pas modifiée dans le `Dockerfile`, le cache sera utilisé.
|
||||
|
||||
Il est possible de ne pas utiliser le cache et de relancer toutes les étapes du
|
||||
`Dockerfile` en ajoutant l'option `--no-cache` au moment du `docker build`.
|
||||
|
||||
Les couches du cache peuvent être partagées entre plusieurs conteneur,
|
||||
c'est ainsi que vous pouvez partager facilement une plus grosse partie
|
||||
du système de fichiers.
|
||||
|
||||
Pour profiter du cache, on va placer de préférences les étapes les plus
|
||||
génériques (qui seraient les plus susceptibles d'apparaître dans d'autres
|
||||
images), en haut du `Dockerfile`.
|
||||
|
||||
Commençons donc notre `Dockerfile` : choisissez une image de base pour remplir
|
||||
votre `FROM`, et indiquez votre nom avec l'instruction `MAINTAINER` (pour
|
||||
indiquez que c'est vous qui maintenez ce conteneur, si des utilisateurs ont besoin
|
||||
de vous avertir pour le mettre à jour par exemple).
|
||||
|
||||
|
||||
## `RUN` ou script ?
|
||||
|
||||
### InfluxDB
|
||||
|
||||
Ensuite vient la suite d'instructions pour installer d'InfluxDB. Le paquet
|
||||
n'est pas disponible dans les dépôts. La
|
||||
[procédure décrite du site](https://docs.influxdata.com/influxdb/v1.0/introduction/installation/#ubuntu-debian)
|
||||
incite à télécharger le paquet mis à disposition puis à l'installer via `dpkg
|
||||
-i`.
|
||||
|
||||
Deux solutions s'offrent à nous :
|
||||
|
||||
* télécharger le paquet hors du conteneur, le copier, puis l'installer.
|
||||
* faire un `RUN` avec toutes ces opérations (sans oublier l'installation
|
||||
préalable de `wget`/`curl`).
|
||||
|
||||
La copie étant définitive (supprimer le fichier ne le supprimera pas des
|
||||
couches où il a pu exister), on préférera la seconde méthode, malgré que `wget`
|
||||
restera en déchet. La première méthode aura plus sa place dans un dépôt de
|
||||
projet où les binaires auront été préalablement compilés, il ne restera plus
|
||||
qu'à les copier dans le conteneur au bon emplacement.
|
||||
|
||||
Écrivons une commande `RUN` qui va télécharger la dernière version
|
||||
d'InfluxDB, qui va l'installer et supprimer le fichier.
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
À ce stade, nous pouvons déjà terminer le conteneur (`EXPOSE`, `CMD`, ...) et
|
||||
[tester](http://localhost:8083) qu'InfluxDB est bien utilisable.
|
||||
|
||||
Il est possible que vous ayez à écraser le fichier de configuration via un
|
||||
`COPY` (ou de manière plus maligne en utilisant `--volume` au moment du `docker
|
||||
run`, cela ne fonctionne pas qu'avec les dossiers !). Ou peut-être ferez-vous
|
||||
un `ENTRYPOINT` ?
|
||||
|
||||
|
||||
### `telegraf`
|
||||
|
||||
`telegraf` est un programme qui permet de collecter des métriques systèmes. Il
|
||||
travaille de paire avec InfluxDB, qu'il utilise pour stocker les valeurs
|
||||
relevées.
|
||||
|
||||
Vous pouvez monitorer les métriques de n'importe quelle machine, simplement en
|
||||
installant `telegraf` et en lui indiquant l'emplacement de son serveur
|
||||
InfluxDB. Nous allons installer `telegraf` sur notre machine à l'aide de la
|
||||
[documentation](https://docs.influxdata.com/telegraf/v1.0/introduction/installation/).
|
||||
|
||||
Ces quelques lignes devraient suffir à lancer la collecte, à condition que
|
||||
votre InfluxDB écoute sur le port 8086 local :
|
||||
|
||||
```bash
|
||||
TELEGRAF_VERSION=1.0.0
|
||||
wget https://dl.influxdata.com/telegraf/releases/telegraf-${TELEGRAF_VERSION}_linux_amd64.tar.gz
|
||||
tar xf telegraf-${TELEGRAF_VERSION}_linux_amd64.tar.gz
|
||||
TELEGRAF_CONFIG_PATH=./telegraf/etc/telegraf/telegraf.conf ./telegraf/usr/bin/telegraf
|
||||
```
|
||||
|
||||
Rendez-vous ensuite dans [l'interface d'InfluxDB](http://localhost:8083/) pour
|
||||
voir si la collecte se passe bien.
|
||||
|
||||
Dans l'interface sélectionnez la base `telegraf` puis explorez les valeurs :
|
||||
|
||||
```sql
|
||||
SHOW MEASUREMENTS
|
||||
SHOW FIELD KEYS
|
||||
SELECT usage_idle FROM cpu WHERE cpu = 'cpu-total' ORDER BY time DESC LIMIT 5
|
||||
```
|
||||
|
||||
Laissons tourner `telegraf` afin de constituer un petit historique de valeurs.
|
||||
|
||||
|
||||
## Rendu
|
||||
|
||||
### Questions
|
||||
|
||||
1. Dans quel langage est écrit `telegraf` ?
|
||||
|
||||
1. Quelle(s) particularité(s) de ce langage permet de se passer de la variable
|
||||
`LD_LIBRARY_PATH` au lancement de `telegraf`, alors qu'on ne l'a pas
|
||||
installé ?
|
||||
|
||||
### Éléments à rendre
|
||||
|
||||
Avant de passer à la suite, placez votre `Dockerfile` et les éventuels fichiers
|
||||
annexes dans un dossier `influxdb`.
|
|
@ -1,226 +0,0 @@
|
|||
\newpage
|
||||
|
||||
Retour sur les bonnes pratiques
|
||||
===============================
|
||||
|
||||
Pour chaque bonne pratique ci-dessous, vérifiez que vous la respectez
|
||||
bien, faites les modifications nécessaires.
|
||||
|
||||
## Utilisez le fichier `.dockerignore`
|
||||
|
||||
Dans la plupart des cas, vos `Dockerfile` seront dans des dossiers contenant
|
||||
beaucoup de fichiers qui ne sont pas nécessaire à la construction de votre
|
||||
conteneur (par exemple, vous pouvez avoir un `Dockerfile` placé à la racine
|
||||
d'un dépôt git : il va avoir besoin des binaires compilés, mais pas des
|
||||
sources).
|
||||
|
||||
Afin d'améliorer les performances lors de la construction, vous pouvez exclure
|
||||
les fichiers et dossiers inutiles au conteneur en ajoutant un fichier
|
||||
`.dockerignore` dans le répertoire de votre `Dockerfile`.
|
||||
|
||||
Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez
|
||||
utiliser du globing.
|
||||
|
||||
Pour plus d'informations, vous pouvez consulter la documentation accessible à
|
||||
<http://docs.docker.com/reference/builder/#dockerignore-file>.
|
||||
|
||||
|
||||
## N'installez rien de superflu
|
||||
|
||||
Afin de réduire la quantité de dépendances à installer, n'installez pas de
|
||||
paquets dont vous n'avez pas vraiment l'utilité : il n'y a pas de raison par
|
||||
exemple d'avoir un éditeur de texte dans un environnement qui sera utilisé
|
||||
comme serveur web. Un autre conteneur pourra contenir cet éditeur de texte dans
|
||||
les cas où vous avez besoin de modifier des données.
|
||||
|
||||
En plus, cela réduira le temps de build et la taille des images produites !
|
||||
|
||||
|
||||
## Minimisez le nombre de couches
|
||||
|
||||
Vous devez trouver l'équilibre idéal entre la lisibilité de votre `Dockerfile`
|
||||
(qui assure la maintenabilité sur le long-terme) et le nombre de couches
|
||||
créées.
|
||||
|
||||
|
||||
## Ordonnez vos lignes de commandes complexes
|
||||
|
||||
### Allez à la ligne pour séparer les longues lignes de commandes complexes
|
||||
|
||||
Aérez vos `Dockerfile` !
|
||||
|
||||
N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque
|
||||
vous codez.
|
||||
|
||||
Lorsqu'une ligne devient complexe, allez à la ligne :
|
||||
|
||||
```
|
||||
RUN apt-get update && apt-get install -y \
|
||||
nginx \
|
||||
php5-fpm
|
||||
```
|
||||
|
||||
Notez les backslashs à la fin des lignes, indiquant qu'elle n'est pas terminée.
|
||||
|
||||
### Triez les arguments par ordre alphabétique
|
||||
|
||||
Lorsque c'est possible, ordonnez vos lignes suivant un ordre logique. Par
|
||||
exemple :
|
||||
|
||||
```
|
||||
RUN apt-get update && apt-get install -y \
|
||||
bzr \
|
||||
cvs \
|
||||
git \
|
||||
mercurial \
|
||||
subversion
|
||||
```
|
||||
|
||||
|
||||
## Profitez du système de cache
|
||||
|
||||
Le processus de construction de votre image Docker va lire les informations de
|
||||
votre Dockerfile dans l'ordre. Pour chaque instruction, Docker va essayer de
|
||||
trouver si une image n'est pas déjà disponible dans le cache (plutôt que de
|
||||
créer une nouvelle image identique).
|
||||
|
||||
Il y a un certain nombre de règles à connaître pour bien utiliser ce mécanisme :
|
||||
|
||||
- En démarrant d'une image de base déjà présente dans le cache (`docker
|
||||
images`), l'instruction suivante est comparée avec toutes les autres images
|
||||
existantes qui en dérivent directement. Si aucune image correspondant n'est
|
||||
trouvé pour l'instruction, le cache est invalidé pour le reste de cette
|
||||
construction.
|
||||
- Dans la plupart des cas, Docker va simplement comparer l'instruction lue avec
|
||||
le(s) différente(s) image(s) qui dérive(nt) de la commande précédente. Si
|
||||
aucune commande correspondante n'est trouvé, le cache se retrouve invalidé
|
||||
pour les instructions suivantes.
|
||||
- Pour les instructions `ADD` et `COPY`, en plus de la comparaison précédente,
|
||||
la somme de contrôle du fichier est ajoutée. Si le fichier a été modifié, le
|
||||
cache se retrouve invalidé.
|
||||
- Une fois que le cache est invalidé, toutes les commandes restantes à exécuter
|
||||
dans le `Dockerfile` vont être exécutées.
|
||||
|
||||
|
||||
## Concevez des conteneur éphémères
|
||||
|
||||
Les conteneurs que vous générez doivent être aussi éphémères que possible : ils
|
||||
devraient pouvoir être arrêtés, détruits et recréés sans nécessiter d'étape de
|
||||
reconfiguration. La configuration devrait se faire au lancement du conteneur ou
|
||||
lors de sa construction.
|
||||
|
||||
|
||||
## Cas d'`apt-get` et des gestionnaires de paquets
|
||||
|
||||
- N'exécutez pas `apt-get update` seul sur une ligne. Cela risque de poser des
|
||||
problèmes de cache, car la ligne ne va jamais changer et le cache sera
|
||||
toujours utilisé. Vous risquez de récupérer des paquets qui ne sont pas à
|
||||
jour.
|
||||
- Évitez de mettre à jour le système fourni (via `apt-get upgrade` ou `apt-get
|
||||
update`). Si l'image n'est pas à jour, contactez son mainteneur. Si vous avez
|
||||
besoin d'une version à jour d'un paquet distribué avec l'image, préférez
|
||||
l'utilisation d'`apt-get install -y foo` qui mettra à jour exclusivement le
|
||||
paquet `foo`, sans altérer le reste du système.
|
||||
- Pour assurer une bonne gestion du cache, n'hésitez pas à indiquer les
|
||||
versions des programmes que vous voulez installer sur votre ligne de commande
|
||||
`apt-get`.
|
||||
|
||||
|
||||
## Exposez les ports standards
|
||||
|
||||
La commande `EXPOSE` vous permet d'indiquer les ports sur lesquels votre
|
||||
conteneur s'attend à recevoir des paquets venant de l'extérieur. Ces ports ne
|
||||
sont pas partagés avec l'hôte ou les autres conteneur, donc vous n'avez pas de
|
||||
raison de ne pas utiliser les ports standards.
|
||||
|
||||
Si vous faites cela, il y a de forte chance qu'il n'y ait pas besoin de
|
||||
modifier la configuration des autres logiciels contenu dans d'autres conteneurs
|
||||
puis qu'ils sont généralement configurés pour se connecter aux ports standards.
|
||||
|
||||
S'il y a un conflit sur la machine hôte, il sera toujours temps de créer une
|
||||
redirection à ce moment là.
|
||||
|
||||
|
||||
## La bonne utilisation de l'`ENTRYPOINT`
|
||||
|
||||
L'entrypoint peut être utilisé de deux manières différentes :
|
||||
|
||||
- Vous pouvez l'utiliser de telle sorte que la commande passée au `docker run`,
|
||||
après le nom de l'image, corresponde aux arguments attendu par le programme
|
||||
indiqué dans l'entrypoint. Par exemple pour nginx :
|
||||
|
||||
```
|
||||
ENTRYPOINT ["nginx"]
|
||||
CMD ["-g daemon off;"]
|
||||
```
|
||||
|
||||
- Vous pouvez aussi utiliser un script qui servira à faire les initialisations
|
||||
ou les configurations nécessaire au bon fonctionnement du conteneur
|
||||
(rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour
|
||||
l'image de PostgreSQL possède cet entrypoint :
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$1" = 'postgres' ]; then
|
||||
chown -R postgres "$PGDATA"
|
||||
|
||||
if [ -z "$(ls -A "$PGDATA")" ]; then
|
||||
gosu postgres initdb
|
||||
fi
|
||||
|
||||
exec gosu postgres "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
|
||||
## `[""]`, `'` et sans `[]`
|
||||
|
||||
Les instructions `ENTRYPOINT` et `CMD` peuvent prendre deux formes :
|
||||
|
||||
- `["cmd", "arg1", "arg2"]` : ici, un simple `exexve` sera effectué avec ces
|
||||
arguments. Si d'éventuels variables se trouve dans les arguments, elles ne
|
||||
seront pas remplacées.
|
||||
- `cmd arg1 arg2` : ici l'exécution se fera au sein d'un `sh -c`, donc les
|
||||
variables seront remplacés et étendues.
|
||||
|
||||
Les commandes sous forme de tableau étant parsées par un parser JSON, vous ne
|
||||
pouvez pas utiliser les simple quotes.
|
||||
|
||||
|
||||
## Volumes
|
||||
|
||||
L'instruction `VOLUME` doit être utilisée pour exposer tous les espaces de
|
||||
stockage de données, configuration, ...
|
||||
|
||||
|
||||
## Réduisez les privilèges
|
||||
|
||||
Utilisez l'instruction `USER` dès que vous le pouvez, lorsqu'un service ne
|
||||
réclame pas de privilège particulier.
|
||||
|
||||
Il vous faudra sans doute créer l'utilisateur et son groupe dans le Dockerfile.
|
||||
|
||||
|
||||
## Profitez du système de liaison et de résolution de nom
|
||||
|
||||
Dès lors que vous effectuez un lien avec un autre conteneur, son nom (ou son
|
||||
alias) est ajouté au fichier `/etc/hosts`. Cela signifie que lorsqu'un nom de
|
||||
domaine correspondant au nom du conteneur (ou son alias) sera recherché, l'IP
|
||||
sera bien celle du conteneur. Lorsque vous configurez un conteneur, utilisez de
|
||||
préférence un nom plutôt qu'une IP, qui changera à coup sûr.
|
||||
|
||||
Au moment du `docker run`, vous pouvez préciser d'autres noms d'ĥôtes
|
||||
particuliers en utilisant l'option `--add-host`.
|
||||
|
||||
|
||||
## Exécutez un seul processus par conteneur
|
||||
|
||||
Dans la majorité des cas, vous ne devriez jamais lancer plus d'un seul
|
||||
processus par conteneur. Il est préférable de répartir chaque application dans
|
||||
un conteneur distinct qui n'effectue que le travail pour lequel il est
|
||||
chargé. Les options de liaison entre conteneur sont à votre disposition pour
|
||||
vous aider à cette tâche.
|
|
@ -1,50 +0,0 @@
|
|||
\newpage
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
## `docker-compose`
|
||||
|
||||
Pour ce TP, nous allons avoir besoin de `docker-compose`.
|
||||
|
||||
Ce projet ne bénéficie pas d'une intégration au sein du projet Docker et doit
|
||||
être téléchargé séparément, car originellement, le projet était développé par
|
||||
une équipe indépendante. S'étant révélé primordiale, ils ont trouvé une place
|
||||
au sein du projet Docker, mais l'incompatibilité des langages utilisés fait que
|
||||
`docker-compose` n'est toujours pas intégré dans docker.
|
||||
|
||||
### Par le gestionnaire de paquets
|
||||
|
||||
Les distributions à jour vous proposeront un paquet `docker-compose` qui
|
||||
fonctionnera avec la version de Docker qu'ils fournissent.
|
||||
|
||||
### Par la distribution binaire
|
||||
|
||||
L'équipe en charge de Docker compose met à disposition un exécutable contenant
|
||||
tous les scripts. Nous pouvons l'installer en suivant la procédure suivante :
|
||||
|
||||
```shell
|
||||
curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-Linux-x86_64 \
|
||||
> /usr/bin/docker-compose
|
||||
chmod +x /usr/bin/docker-compose
|
||||
```
|
||||
|
||||
### `pip`
|
||||
|
||||
Le projet étant écrit en Python, il est également disponible via `pip`, si vous
|
||||
préférez cette méthode. N'oubliez pas de préciser une version compatible avec
|
||||
votre version de Docker.
|
||||
|
||||
|
||||
### Vérification du fonctionnement
|
||||
|
||||
Comme avec Docker, nous pouvons vérifier le bon fonctionnement de
|
||||
`docker-compose` en exécutant la commande :
|
||||
|
||||
```
|
||||
42sh$ docker-compose --version
|
||||
docker-compose version: 1.8.0
|
||||
```
|
||||
|
||||
Si vous obtenez une réponse similaire, c'est que vous êtes prêt à commencer le
|
||||
TP ! Alors n'attendons pas, partons à l'aventure !
|
|
@ -1,50 +0,0 @@
|
|||
\newpage
|
||||
|
||||
Rendu
|
||||
=====
|
||||
|
||||
## Projet
|
||||
|
||||
Amusez-vous à la piscine, il n'y a pas de projet en plus des exercices fait en
|
||||
TP !
|
||||
|
||||
En complément de ce TP, vous pouvez jetez un œil à
|
||||
[Docker Swarm](https://docs.docker.com/engine/swarm) !
|
||||
|
||||
|
||||
## Modalité de rendu
|
||||
|
||||
Un service automatique s'occupe de réceptionner vos rendus, de faire les
|
||||
vérifications nécessaires et de vous envoyer un accusé de réception (ou de
|
||||
rejet).
|
||||
|
||||
Ce service écoute sur l'adresse <virli@nemunai.re>, c'est donc à cette adresse
|
||||
et exclusivement à celle-ci que vous devez envoyer vos rendus. Tout rendu
|
||||
envoyé à une autre adresse et/ou non signé ne sera pas pris en compte.
|
||||
|
||||
|
||||
## Tarball
|
||||
|
||||
Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
|
||||
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
||||
|
||||
Les réponses aux questions sont à regrouper dans un fichier `questions.txt` à
|
||||
placer à la racine de votre rendu.
|
||||
|
||||
Voici une arborescence type:
|
||||
|
||||
```
|
||||
login_x-TP2/questions.txt
|
||||
login_x-TP2/docker-compose.yml
|
||||
login_x-TP2/influxdb
|
||||
login_x-TP2/influxdb/Dockerfile
|
||||
login_x-TP2/influxdb/influxdb.conf
|
||||
login_x-TP2/chronograf
|
||||
login_x-TP2/chronograf/Dockerfile
|
||||
login_x-TP2/chronograf/chronograf.conf
|
||||
login_x-TP2/mymonitoring
|
||||
login_x-TP2/mymonitoring/Dockerfile
|
||||
login_x-TP2/mymonitoring/chronograf.conf
|
||||
login_x-TP2/mymonitoring/influxdb.conf
|
||||
login_x-TP2/mymonitoring/supervisor.conf
|
||||
```
|
|
@ -1,100 +0,0 @@
|
|||
\newpage
|
||||
|
||||
Plusieurs daemons dans un conteneur
|
||||
===================================
|
||||
|
||||
Notre système de monitoring commence enfin à ressembler à quelque chose. Mais
|
||||
ce serait tellement plus pratique de voir tous ces tableaux de nombres sous
|
||||
forme de graphiques !
|
||||
|
||||
Nous allons pour cela ajouter `chronograf` dans notre image.
|
||||
|
||||
Avant de modifier votre `Dockerfile`, créez un nouveau dossier de rendu :
|
||||
`mymonitoring`, dans lequel vous recopierez l'état actuel de notre image
|
||||
`influxdb`.
|
||||
|
||||
|
||||
## Chronograf
|
||||
|
||||
Commençons par compléter la commande d'installation existante pour `influxdb`,
|
||||
afin d'installer simultanément `chronograf`.
|
||||
|
||||
La documentation de la procédure est disponible
|
||||
[à cette adresse](https://docs.influxdata.com/chronograf/v1.0/introduction/installation/).
|
||||
|
||||
|
||||
## Script d'init
|
||||
|
||||
Lors du dernier TP, nous avons vu que les conteneurs s'arrêtaient dès que le
|
||||
premier processus du conteneur (celui qui a le PID 1, à la place d'`init`)
|
||||
terminait son exécution, quelque soit le statut de ses éventuels fils.
|
||||
|
||||
Pour lancer tous nos daemons, nous avons donc besoin d'écrire un script qui
|
||||
lance puis attend que les deux deamons aient terminés de s'exécuter.
|
||||
|
||||
Écrivons ce script. Hints : `wait(1)`.
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
Pour vérifier que votre conteneur fonctionne correctement, vous pouvez le
|
||||
lancer :
|
||||
|
||||
```shell
|
||||
docker run --rm -p 10000:10000 mymonitoring
|
||||
```
|
||||
|
||||
Puis accéder à chronograf : <http://localhost:10000/>. Donnez un nom à votre
|
||||
configuration, puis cliquez sur *Add*. Les paramètres préremplis dans le
|
||||
formulaire sont corrects.
|
||||
|
||||
Vous devriez obtenir l'écran suivant (notez la partie `Status: Online, v1.0.0`) :
|
||||
|
||||

|
||||
|
||||
|
||||
## Autorestart
|
||||
|
||||
L'avantage de détruire le conteneur à la mort du père, est que s'il s'agit de
|
||||
notre processus principal et qu'il est seul (par exemple `nginx` pour un
|
||||
conteneur qui délivre des pages web), il va être possible de redémarrer le
|
||||
conteneur automatiquement grâce à la *restart policy* que l'on peut définir au
|
||||
moment du `docker run` :
|
||||
|
||||
```shell
|
||||
docker run -d -p 80:80 --restart=on-failure nginx
|
||||
```
|
||||
|
||||
Il existe trois règles de redémarrage différentes :
|
||||
|
||||
- **`no` :** il s'agit de la règle par défaut. Lorsque l'exécution du conteneur
|
||||
se termine, il n'est pas redémarré.
|
||||
- **`on-failure[:max-retries]` :** redémarre uniquement si le code de sortie du
|
||||
conteneur n'est pas 0. Il est possible de préciser pour cette option le
|
||||
nombre maximum de redémarrage qui sera tenté.
|
||||
- **`always` :** redémarre le conteneur dans tous les cas, quelque soit son
|
||||
code de sortie et indéfiniment.
|
||||
|
||||
Le script d'init que vous avez réalisé ne tient sans doute pas compte de
|
||||
cela. Mais plein de gens ont cette problématique et l'application `supervisor`
|
||||
répond parfaitement à notre problématique !
|
||||
|
||||
|
||||
## `supervisor`
|
||||
|
||||
Première étape : installer `supervisor`, le paquet se trouve dans les dépôts.
|
||||
|
||||
L'étape suivante consiste à remplir puis copier le fichier de configuration
|
||||
dans le conteneur. Vous allez devoir écraser dans votre conteneur le fichier
|
||||
`/etc/supervisord.conf` pour démarrer à la fois `chronograf` et `influxdb`.
|
||||
|
||||
Vous pouvez vous aider de la documentation disponible à :
|
||||
<http://supervisord.org/configuration.html>
|
||||
|
||||
|
||||
La même procédure de test que précédemment peut être suivie.
|
||||
|
||||
|
||||
## Rendu
|
||||
|
||||
Nous ne toucherons plus à cette image, placez-la dans un dossier
|
||||
`mymonitoring`.
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
title: Virtualisation légère -- TP n^o^ 2
|
||||
subtitle: Aller plus loin avec Docker
|
||||
author: Pierre-Olivier *Nemunaire* Mercier
|
||||
institute: EPITA
|
||||
date: Jeudi 15 septembre 2016
|
||||
...
|
||||
|
||||
Durant ce deuxième TP, nous allons approfondir l'utilisation de Docker !
|
||||
|
||||
Tous les éléments de ce TP (exercices et questions) sont à rendre à
|
||||
<virli@nemunai.re> au plus tard le jeudi 6 octobre 2016 à 8 h 42. Consultez la
|
||||
dernière section de chaque partie pour plus d'information sur les éléments à
|
||||
rendre.
|
||||
|
||||
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
||||
vous devrez 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/).
|
||||
Vous pouvez utiliser l'adresse <signcheck@nemunai.re> pour savoir si vous vous
|
||||
y prenez correctement.
|
||||
|
||||
\hypersetup{linkcolor=black}
|
||||
\tableofcontents
|
|
@ -1,18 +0,0 @@
|
|||
\newpage
|
||||
|
||||
But du TP
|
||||
=========
|
||||
|
||||
Aujourd'hui, nous allons réaliser un système de monitoring.
|
||||
|
||||
Le résultat attendu d'ici la fin du TP, est un groupe de conteneurs
|
||||
indépendants les uns des autres, réutilisables en fonction des besoins.
|
||||
|
||||
Nous collecterons les données d'utilisation de votre machine avec
|
||||
[Telegraf](https://www.influxdata.com/time-series-platform/telegraf/). Ces
|
||||
données seront envoyés vers
|
||||
[InfluxDB](https://www.influxdata.com/time-series-platform/influxdb/), puis
|
||||
elles seront affichées sous forme de graphique grâce à
|
||||
[Chronograf](https://www.influxdata.com/time-series-platform/chronograf/).
|
||||
|
||||

|
Loading…
Add table
Add a link
Reference in a new issue