virli/tutorial/dockerfiles/dockerfile.md
2018-10-17 22:30:02 +02:00

4.3 KiB

\newpage

Dockerfile

Ma première image ... par Dockerfile

Pour construire une image, nous ne sommes pas obligés 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 Dockerfile suivant :

``` FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y nano
</div>

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.

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` :

<div lang="en-US">
docker image build --tag=my_editor .
</div>

Une fois la construction de l'image terminée, vous pouvez la lancer et
constater l'existence de notre éditeur favori :

<div lang="en-US">
docker container run -it my_editor /bin/bash
</div>


## `RUN` dans le `Dockerfile`

Dans un `Dockerfile`, chaque ligne est exécutée indépendamment des autres et
correspondra à une nouvelle couche de notre image.

Cela signifie que l'exemple suivant **ne fonctionne pas** :

<div lang="en-US">
COPY db.sql /db.sql
RUN service mysqld start
RUN mysql -u root -p toor virli < /db.sql
</div>

Cet exemple ne fonctionne pas car le serveur MySQL qui est lancé dans le
premier `RUN`, n'est plus lancé au moment du deuxième `RUN`. En effet, chaque
commande du `Dockerfile` a pour but de modifier le système de fichiers.

Pour avoir le résultat escompté, il faut exécuter les commandes ensemble :

<div lang="en-US">
COPY db.sql /db.sql
RUN service mysqld start && mysql -u root -p toor virli < /db.sql
</div>

Après le `RUN`, MySQL sera de nouveau arrêté, si on veut l'utiliser dans le
conteneur, il ne faudra pas oublier de lancer le processus.


## Exposer des ports

Construisons maintenant un conteneur avec un serveur web :

<div lang="en-US">
FROM my_editor

RUN apt-get update
RUN apt-get install -y nginx

EXPOSE 80
</div>

L'instruction `EXPOSE` sera traitée 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 :

<div lang="en-US">
docker image build --tag=my_webserver .
docker container run -it -P my_webserver /bin/bash
service nginx start
</div>

Dans un autre terminal, lancer un `docker ps` et consulter la colonne *PORTS*
pour connaître le port choisi 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 :

<div lang="en-US">
CMD nginx -g "daemon off;"
</div>

<div lang="en-US">
docker image build --tag=my_nginx .
docker container run -d -P my_nginx
</div>

L'option `-d` passée au `run` lance le conteneur en tâche de fond. Si vous
constatez via un `docker container ls` que le conteneur s'arrête directement,
retirez cette option pour voir ce qui ne va pas, ou utilisez la commande
`docker container logs`.


## D'autres instructions ?

Consultez <https://docs.docker.com/engine/reference/builder/> pour la liste
complète des instructions reconnues.


## Rendu

Rendez le fichier `Dockerfile` et son contexte (`index.html`, fichiers de conf
éventuels, ...) que vous avez utilisé pour réaliser votre image `my_webserver`.

Une attention particulière sera apportée au respect des différentes bonnes
pratiques vues en cours pour l'écriture du `Dockerfile`.