Docker

Bonjour !

Présentation

Quand on aime bien essayer des choses, librairies, etc… et qu’on a qu’un seul ordinateur (ce qui est déjà pas mal), on se retrouve assez vite avec un peu tout et n’importe quoi sur le dit ordinateur. Il m’est déjà arrivé de me retrouver dans l’obligation de devoir tout ré-installer car j’avais voulu tester un nouvel outil qui nécessitait des dépendances qui avaient un peu tout cassé. Donc, j’ai pris l’habitude de monter des VMs pour ce genre de choses mais bon … c’est un peu lourd.

La question est donc : est-ce qu’une solution comme Docker peut m’aider ?

Objectifs

L’objectif principal est de comprendre Docker. C’est tout. Si j’ai quelque chose ce soir : tant mieux ! C’est parti !

Docker

Présentation

Je ne vais pas le lancer dans une présentation de Docker. D’autres le font beaucoup mieux que moi : ici, , encore & surtout . Le dernier lien (GrafiKart) est celui que je conseillerais le plus, car c’est celui que j’ai trouvé le plus clair (Korben le site dans un article)

Ma vision

Ma vision est que Docker est un système de containers plus léger & plus souple que des VMs (très restrictif). Les containers vont permettre la constitution de “système” tournant sur un hôte et hébergeant tel ou tel service en fonction des besoins. Le besoin pouvant être l’exécution d’un programme, l’exposition d’un serveur, la mise à disposition d’un système complexe, etc… Il est ainsi possible de télécharger une image d’un “outil” que vous voulez tester. Avec l’image (ici), vous pouvez en quelques minutes monter un serveur WordPress vous permettant de “tester” rapidement la solution … Ou alors vous pouvez monter des env des développements : un avec apache/php56, apache/php70, nginx, … Chaque container étant indépendant et étanche du système, il n’y a pas de risque de “casser” quelque chose et au pire c’est rapide (en théorie) à remettre en place. Et enfin, une architecture complexe avec de multi-containers : le lien ici vous montre un exemple.

Bon … on commence comment ?

Il faut bien reconnaître qu’après quelques lectures, j’étais un peu perdu sur la terminologie et/ou méthodes … Même si chaque tutos / vidéos possèdent des commandes communes, j’ai senti la confusion venir en me demandant : “bon … on commence comment ? et par où” ? Le truc c’est que tout est possible et je n’ai pas eu l’impression qu’il y avait vraiment de bonnes ou de mauvaises méthodes … juste des résultats plus ou moins satisfaisant.

Quelques notions …

Loin de moi, l’idée de dire que ce qui est écrit ici est correct mais c’est ma vision à ce stade :

  • Image : c’est un template de container. Des milliers sont disponibles sur https://hub.docker.com/. Sur la base d’une image, vous pouvez lancer ou construire directement un container
  • Container: (une définition !) c’est l’instanciation de l’image. L’image étant le template, le container va être l’exécution du template.
  • DockerFile : fichier qui va donner la recette de constution d’une image. Dans le fichier, on définit les règles de construction de l’image.
  • Docker-composer : il est possible de créer une architecture multi-containers et c’est là que peut intervenir docker-composer. Plus simplement, il peut également permettre de simplifier le lancement d’une image à qui on veut “passer” des paramètres,
  • docker-compose.yml : c’est le fichier utilisé par docker-composer pour exécuter le container sur la base d’une image sélectionnée et des paramètres inclus dans le fichier.

Let’s Go !

Préparation

Aller hop, on se lance. On va essayer de faire quelque chose. Niveau méthodologie, je vais commencer par une image “standalone” avec ce dont j’ai besoin dedans. Je pense que le multi-container avec gestion des networks etc… ce sera pour un autre demain. De même, je vais commencer par utiliser un DockerFile. Il est possible de créer une image en mode live mais bon : faut faire des choix !

Installation

Pour l’installation, les docs de Docker sont très clair donc : Docker & Docker-composer.

Premiers pas

La première chose à faire est de créer un fichier Dockerfile avec à minima:

# Image de base
FROM debian:latest

Pour construire l’image :

docker build -t [name]/angular-cli . 

Un conseil ‘ N’OUBLIEZ PAS LE POINT !!! Sinon, ça marche pas :

"docker build" requires exactly 1 argument(s).

Lancement : selection_021 Ici, j’ai lancé directement en demandant mode interactif. Le résultat de la commande ls montre qu’on a bien à faire à un nouveau système. Par contre, toute modification sera perdue si je coupe le container. Si j’étais sport je pourrais faire un rm -Rf * mais je suis pas sport :). A noter qu’il serait possible de modifier directement directement l’image et de persister les modifications. Mais ce n’est pas le mode que j’ai choisi.

Une première commande

La première commande que je souhaite passer et la mise à jour des sources logicielles. Pour cela, il faut modifier le fichier Dockerfile et ajouter la commande :

RUN apt-get update 

Il faut relancer le build (même commande que précédemment) mais bizarrement il fait plus de choses : selection_022 Dans l’image, deux choses apparaissent : la mise à jour des sources mais également (tout en bas), la notion d’intermediate container avec un changement d’ID. En fait, dans Docker les images ont des IDs mais ils existent aussi des notions de tags. Il est alors possible d’avoir une image qui possède plusieurs tags décrivant les évolutions de l’image (fonctionnement très proche de Git).

Installation de NodeJs & NPM

Même principe : modification du fichier Dockerfile, relance du build et lancement du container et pour les commandes :

RUN apt-get install curl -y
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
RUN apt-get install nodejs -y

selection_023

Angular-cli

Je ne sais pas pourquoi je fais une rubrique. J’ai simplement ajouté la ligne d’installation dans le DockerFile …

Partage du répertoire

L’idée est d’avoir le container et l’hôte partagé un espace disque afin de permettre de modifier le code et que la prise en compte soit automatique. Pour ce faire, il faut commencer par créer l’espace qui va héberger le code. Dans DockerFile, il faut ajouter la commande de création de l’espace et sa “transformation” en espace de travail

RUN mkdir -p /app
WORKDIR /app

Au lancement de l’application, un paramètre supplémentaire doit être passé à la commande run afin de mapper un répertoire à celui de l’hôte:

docker run -ti -v /opt/data/projets/mda/:/app [name]/angular-cli

et une fois connecté, un petit ls -al: selection_024.

ng serve

Afin d’avoir le résultat dans un navigateur, il faut lancer la commande ng serve dans le bon répertoire. Le souci est que le répertoire contenant le projet change et est mappé au moment de la création du container. La commande doit donc être lancée au moment de la création du container et pas au moment de la création de l’image :

CMD ["/script.sh"]

. Cette entrée permet de dire à Docker d’exécuter ce script au moment du lancement. Cependant, comme l’idée est d’avoir une machine angular-cli, la commande que je souhaite appeler est ng. Que ce soit pour builder, lancer un serveur, etc… j’aimerais que ng soit ma commande par défaut mais que je puisse choisir au lancement de docker la commande que souhaite lancer. Pour ce faire, il faut changer l’”exécutable” par défaut utiliser par Docker :

ENTRYPOINT ["ng"]

Dans ce cas, le contenu et l’interprétation de CMD est différente : cela devient la valeur par défaut passé en paramètre au point d’entrée. Dans mon cas :

CMD ["--help"]

Lancement

Pour lancer le container avec le mappage des ports et des répertoires, il faut utiliser la commande suivante :

docker run --rm -it -v /opt/data/projets/mda/:/app -p 4200:4200 -p 49152:49152 xiii29/angular-cli serve

Tout se passe bien sauf que depuis l’extérieure de la machine, je n’arrive pas à “joindre” le serveur au sein du container. Un wget http://localhost:4200 tourne en boucle et ne retourne rien. Grâce à la commande

docker exec -ti [ID] bash

, je peux me connecter dans le container et pour le coup, un wget fonctionne … y’a un souci dans le mapping des ports ?

0.0.0.0

En faisant la liste des containers en cours :

docker ps 

, j’obtiens :

0.0.0.0:4200->4200/tcp, 0.0.0.0:49152->49152/tcp 

. On voit que l’adresse IP sur laquelle est effectuée le mapping est 0.0.0.0 et pas localhost alors que ng serve affiche http://localhost:4200 quand il se lance. C’est peut-être une piste ?

docker run --rm -it -v /opt/data/projets/mda/:/app -p 4200:4200 -p 49152:49152 xiii29/angular-cli serve  --host 0.0.0.0 

Et d’un coup : ça fonctionne !

docker-compose.yml

Afin d’éviter taper des lignes de commandes longue comme le bras (regarder plus haut), il est possible de créer un fichier docker-compose.yml qui pourra être interprété par docker-composer. L’idée est ainsi d’avoir un fichier directement dans mon projet Angular2 et de pouvoir simplement lancer :

docker-compose up

pour avoir mon serveur de dev en ligne. Voici le contenu du fichier :

version: '2'
services:
  app:
    image: xiii29/angular-cli
    command: serve --host 0.0.0.0
    ports:
      - 4200:4200
      - 49152:49152
    volumes:
      - ./:/app

Il s’agit simplement d’une version fichier des lignes de commande.

Bilan

Le plus compliqué a été sans doute de trouver le moyen de démarrer. Ensuite, honnêtement, les choses ont été simples du coté de Docker. Le souci principal que j’ai rencontré est le mapping des ports (et je ne suis pas sûr que la correction soit la meilleure) mais pour le reste : j’adopte Docker ! Comme indiqué dans un des liens : il faut commencer petit à petit, utiliser ce dont on a besoin, chercher, apprendre :). Peut-être qu’un jour, j’aurais plusieurs micro-containers mais ce sera après-demain. Pour un autre demain, il faut que j’arrive à faire fonctionner tout cela sous Windows ! Mais ce sera pour un autre demain :).

Commandes pratiques

L’objectif n’est pas de lister toutes les commandes mais uniquement les commandes dont je me suis beaucoup servi pendant cette “découverte” : ici.

Liens