virli/tutorial/dockerfiles/entrypoint.md

6.1 KiB

\newpage

Le point d'entrée du conteneur

Le point d'entrée ou l'entrypoint correspond à la ligne de commande qui sera exécutée au lancement du conteneur. Deux paramètres de notre Dockerfile permettent d'agir sur cette ligne de commande : CMD{.dockerfile} et ENTRYPOINT{.dockerfile}.

  • CMD{.dockerfile} est la commande par défaut : lorsqu'au moment de run, aucun paramètre n'est passé après le nom de l'image, le contenu du dernier CMD{.dockerfile} rencontré sera utilisé.

  • ENTRYPOINT{.dockerfile}, s'il est défini, sera réellement exécuté, qu'il y ait ou non des arguments pour remplacer la ligne de commande. Lorsque des arguments sont passés ou qu'un CMD{.dockerfile}, ceux-ci sont passés en argument de l'ENTRYPOINT{.dockerfile}.

Par exemple, avec le Dockerfile suivant, construisant l'image sample-echo :

```dockerfile FROM ubuntu CMD ["world"] ENTRYPOINT ["/bin/echo", "Hello"] ```

Nous obtenons les résultats suivants :

``` 42sh$ docker run sample-echo Hello world ```

Dans ce premier cas, il n'y a pas d'argument après le nom de l'image, c'est donc le contenu de CMD{.dockerfile} qui est utilisé ; il est donc passé en argument à l'ENTRYPOINT{.dockerfile}. Concrètement, la première ligne de commande exécutée est :

```json ["/bin/echo", "Hello", "world"] ```

Essayons maintenant avec des arguments :

``` 42sh$ docker run sample-echo $USER Hello neo ```

Le contenu de la variable $USER, interprété par notre shell, est utilisé à la place de CMD{.dockerfile}.

Si l'on a besoin d'exécuter un ENTRYPOINT{.dockerfile} différent, il reste la possibilité de le surcharger au moyen d'un argument :

``` 42sh$ docker run --entrypoint /bin/sh sample-echo 01abc345# _ ```

::::: {.exercice}

Personnalisation basique

Afin de faire bénéficier à nos utilisateurs d'une immersion parfaite, nous allons faire en sorte que notre image puisse être utilisée ainsi :

```bash docker run -d -p 80:80 youp0m -bind :80 ```

Plutôt que de laisser l'utilisateur se débrouiller avec le chemin interne dans lequel il va trouver le bon binaire :

```bash docker run -d -p 80:80 youp0m /srv/youp0m -bind :80 ```

Essayez les deux commandes, si vous avez utilisé l'instruction CMD{.dockerfile} dans votre Dockerfile jusqu'à présent, vous devriez vous trouver dans le deuxième cas.

Pour améliorer la situation, définissez l'ENTRYPOINT{.dockerfile} de votre image sur le binaire /srv/youp0m.

:::::

Point d'entrée avancé

Dans certains cas, il peut être nécessaire au lancement d'un conteneur de faire un minimum d'étapes d'initialisation avant que le conteneur ne soit opérationnel (rappelez-vous les options que l'on passait à l'image mysql pour créer un utilisateur et une base).

Notre but, dans cette partie, sera de créer un utilisateur administrateur (pouvant passer le contrôle d'accès http://localhost:8080/admin/) :

```bash docker run -i --rm -p 8080:8080 -e YOUP0M_PASSWORD=admin youp0m ```

Bases du script

Notre script d'ENTRYPOINT{.dockerfile} sera appelé avec en argument, ceux passés par l'utilisateur après le nom de l'image, ou, à défaut, le contenu de CMD.

C'est donc l'ENTRYPOINT{.dockerfile} qui est responsable de la bonne utilisation de ceux-ci, de leur modification, ...

À la fin d'un script d'ENTRYPOINT{.dockerfile}, afin de garder comme premier processus du conteneur le programme qui nous intéresse, on réalise un execve(2), sans fork(2) :

```bash exec /srv/youp0m $@ ```

Dans cet exemple : exec est la commande interne à notre shell pour lui indiquer de remplacer son fil d'exécution par cette commande (sans exec, il va fork(2) avant). $@ est ici pour transmettre tel quel la liste des arguments passés au script (il s'agit de ceux donnés par l'utilisateur, sur la ligne de commande du run, ou du contenu de CMD{.dockerfile} si l'utilisateur n'a rien précisé).

Format du fichier htpasswd

Le format attendu est celui d'un fichier htpasswd typique d'Apache. Nous pouvons obtenir un fichier valide avec :

```bash ( echo -n "$YOUP0M_USERNAME" echo -n ":" openssl passwd -crypt "$YOUP0M_PASSWORD" ) > myhtpasswd ```

Il faut ensuite passer le chemin du fichier créé sur la ligne de commande grâce à l'option -htpasswd.

::::: {.exercice}

Écrivez un script d'ENTRYPOINT{.dockerfile}, analysant les variables d'environnement, à la recherche de YOUP0M_USERNAME et YOUP0M_PASSWORD pour initialiser le fichier .htpasswd qui sera ajouté à la liste des arguments à passer au service.

Par exemple :

``` 42sh$ docker run -d -p 8081:8081 -e YOUP0M_USERNAME=admin \ -e YOUP0M_PASSWORD=admin youp0m -bind=:8081

42sh$ curl -u admin:badpasswd http://localhost:8081/admin/ You are not allowed to perform this request.

42sh$ curl -u admin:admin http://localhost:8081/admin/

</div>

:::::


## Étendre un `ENTRYPOINT` existant

Vous venez de réaliser un script d'*entrypoint* pour votre conteneur. Il ajoute
assurément de nombreuses fonctionnalités indispensables. Mais que se passe-t-il
si quelqu'un souhaite étendre votre image, ou simplement pour ajouter une
fonctionnalité ?

La plupart des images officielles[^cf-nginx] prêtes à l'emploi disposent d'un
dossier `/docker-entrypoint.d`, à la racine de l'image ; et d'un script
d'*entrypoint* qui va se charger d'appeler chacun des scripts du dossier avant
de lancer la commande par défaut.

[^cf-nginx]: Consultez le dépôt de l'image `nginx` par exemple. Il possède 3
    scripts pour 3 fonctionnalités différentes.

Chaque fonctionnalité distincte de l'*entrypoint* est placée dans un script
séparé, et quelqu'un qui souhaite ajouter son propre script peut le faire
facilement, soit au moyen d'un volume, soit en étendant l'image.