\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}](https://docs.docker.com/engine/reference/builder/#entrypoint) 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 ) :
```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/ ```
::::: ## É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.