Skip to content

Découverte de Docker

Configuration

Prérequis

Il n'est pas nécessaire d'avoir des compétences spécifiques pour ce tutoriel, si ce n'est une certaine familiarité avec les command line et l'utilisation d'un éditeur de texte. Une expérience antérieure dans le développement d'applications web sera utile, mais n'est pas nécessaire.

Configuration de votre ordinateur

Comme dit précédemment il vous faudra avoir un outil docker fonctionnel. Pour vérifier que tout focntionne testons une commande docker :

docker run registry.takima.io/school/proxy/hello-world
Unable to find image 'registry.takima.io/school/proxy/hello-world:latest' locally
latest: Pulling from registry.takima.io/school/proxy/hello-world
03f4658f8b78: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
Status: Downloaded newer image for registry.takima.io/school/proxy/hello-world:latest

Hello from Docker.
...

Ce message indique que votre installation semble fonctionner correctement.

Si ce n'est pas le cas parcourez le Getting Start pour installer correctement docker

Exécution de votre premier conteneur

Maintenant que vous avez tout configuré, il est temps de mettre les mains dans le cambouis.
Dans cette section, vous allez exécuter un conteneur Alpine Linux (une distribution Linux légère) sur votre système et découvrir la commande docker run.

Pour commencer, exécutez la commande suivante dans votre terminal pour récuperer (télécharger) l'image depuis le registry takima :

$ docker pull registry.takima.io/school/proxy/alpine

Puis on va tag cette image pour créer une copie et lui donner un nom plus commode à utiliser pour nos prochaines lignes de commandes :

$ docker tag registry.takima.io/school/proxy/alpine alpine

Note

En fonction de la manière dont vous avez installé Docker sur votre système, vous pourriez voir une erreur de permission refusée après avoir exécuté la commande ci-dessus. Essayez les commandes du tutoriel de démarrage pour vérifier votre installation. Si vous êtes sous Linux, vous devrez peut-être préfixer vos commandes docker avec sudo. Vous pouvez également créer un groupe Docker pour résoudre ce problème.

La commande pull récupère l'image Alpine depuis notre registre Docker et la sauvegarde sur notre système. Vous pouvez utiliser la commande docker images pour voir la liste de toutes les images sur votre système.

Nous aurions pu aussi récupérer une image Docker publique (Docker Hub) qui contient une multitude d'images standard en utilisant :

$ docker pull alpine

Cependant Docker Hub est soumis à un rate limit donc nous allons éviter de pull dessus dans cette formation et utiliser le registry Takima.

$ docker images
RÉPERTOIRE             TAG                 ID DE L'IMAGE        CRÉÉ               TAILLE VIRTUELLE
alpine                 dernière             c51f86c28340        il y a 4 semaines     1,109 Mo
registry.takima.io/school/proxy/alpine                dernière             c51f86c28340        il y a 4 semaines     1,109 Mo
registry.takima.io/school/proxy/hello-world          dernière             690ed74de00f        il y a 5 mois       960 o

Exécuter un Docker

Génial ! Exécutons maintenant un conteneur Docker basé sur cette image. Pour cela, nous allons utiliser la commande docker run.

$ docker run alpine ls -l
total 48
drwxr-xr-x    2 root     root          4096 2 mars  16:20 bin
drwxr-xr-x    5 root     root           360 18 mars 09:47 dev
drwxr-xr-x   13 root     root          4096 18 mars 09:47 etc
drwxr-xr-x    2 root     root          4096 2 mars  16:20 home
drwxr-xr-x    5 root     root          4096 2 mars  16:20 lib
...
...

Qu'est-il arrivé ? En coulisses, il s'est passé beaucoup de choses. Lorsque vous appelez run :

  1. Le client Docker contacte le daemon Docker.

  2. Le daemon Docker vérifie si l'image (dans ce cas, Alpine) est disponible localement, et si ce n'est pas le cas, la télécharge depuis le registry Docker. (Comme nous avons exécuté docker pull registry.takima.io/school/proxy/alpine auparavant puis tag cette image en la nommant alpine, l'étape de téléchargement n'est pas nécessaire)

  3. Le daemon Docker crée le conteneur, puis exécute une commande dans ce conteneur.

  4. Le daemon Docker transmet la sortie de la commande au client Docker.

Lorsque vous exécutez docker run alpine, vous avez fourni une commande (ls -l), alors Docker a démarré la commande spécifiée et vous avez vu la liste.

Essayons quelque chose de plus utile : afficher un Hello World bien sur!

$ docker run alpine echo "hello from alpine"
hello from alpine

OK, voilà une sortie réelle. Dans ce cas, le client Docker a exécuté fidèlement la commande echo dans notre conteneur Alpine, puis l'a quitté. Si vous avez remarqué, tout cela s'est produit très rapidement. Imaginez démarrer une machine virtuelle, exécuter une commande, puis la détruire. Maintenant, vous savez pourquoi on dit que les conteneurs sont rapides !

Essayons une autre commande.

$ docker run alpine /bin/sh

Attendez, il ne s'est rien passé ! Est-ce un bogue ? Eh bien, non. Ces exécutions interactives se ferment après avoir exécuté les commandes scriptées, sauf si elles sont exécutées dans un terminal interactif. Pour éviter que cet exemple ne se ferme, vous devez utiliser docker run -it alpine /bin/sh .

Vous êtes maintenant à l'intérieur du shell du conteneur et vous pouvez naviguer dans le conteneur. Si vous lancez exit ou que vous tapez CTRL-D, vous quitterez le shell du conteneur et il s'arrêtera également (attention il ne se détruira pas). Le conteneur est censé être éphémère.

$ exit

Maintenant, voyons comment lister les conteneurs avec la commande docker ps. docker ps est la commande qui listera tous les conteneurs en cours d'exécution.

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Comme vous n'avez pas de conteneur qui tourne actuelement (seulement des conteneurs qui ont été lancés mais qui sont maintenant stoppés), cette commande renvoie une liste vide. Essayons une petite variante : docker ps -a

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
36171a5da744        alpine              "/bin/sh"                5 minutes ago       Exited (0) 2 minutes ago                        fervent_newton
a6a9d46d0b2f        alpine             "echo 'hello from alp"    6 minutes ago       Exited (0) 6 minutes ago                        lonely_kilby
ff0a5c3750b9        alpine             "ls -l"                   8 minutes ago       Exited (0) 8 minutes ago                        elated_ramanujan
c317d0a9e3d2        hello-world         "/hello"                 34 seconds ago      Exited (0) 12 minutes ago                       stupefied_mcclintock

Vous voyez maintenant une liste de tous les conteneurs que vous avez exécutés. Remarquez que la colonne "STATUS" indique que ces conteneurs ont été arrêtés il y a quelques minutes. Vous vous demandez probablement s'il y a un moyen d'exécuter plus d'une commande dans un conteneur.

Essayons cela maintenant :

$ docker run -it alpine /bin/sh
/ # ls
bin      dev      etc      home     lib      linuxrc  media    mnt      proc     root     run      sbin     sys      tmp      usr      var
/ # uname -a
Linux 97916e8cb5dc 4.4.27-moby #1 SMP Wed Oct 26 14:01:48 UTC 2016 x86_64 Linux

L'exécution de la commande run avec l'option -it nous connecte à un terminal interactif dans le conteneur. Maintenant, vous pouvez exécuter autant de commandes que vous le souhaitez dans le conteneur. Prenez le temps d'exécuter vos commandes préférées.

Astuce

run -it est une commande très utile pour déboguer le bas niveau d'un conteneur.

Vous savez faire tourner un container et le lancer en mode interactif. Mais il manque une fonctionnalité essentielle lorsque l'on veut faire tourner un service. Pour l'illustrer lancer un nginx :

$ docker run registry.takima.io/school/proxy/nginx

Question

Que se passe-t-il dans ce cas ? Que se passe-t-il si vous fermez votre shell ou ctr+c par exemple (fermez votre shell relancez le et lancez un docker ps -a)

En fait votre conteneur s'est lancé et ne vous rend pas la main et vous avez alors le log nginx sur votre shell. Lorsque vous quittez votre shell, le conteneur se stoppe et votre nginx se stoppe donc également. Ce n'est pas un comportement souhaitable lorsque l'on veut lancer des services en tache de fond, c'est ce qu'on apelle un daemon. Docker nous permet de le faire avec une simple option -d

relancez votre conteneur Nginx en mode service

$ docker run -d --name mon-nginx registry.takima.io/school/proxy/nginx 
b611eea1536bcfc79f87e1bfd57a3f10bbe4577f03e405329f5626cd66a64e54

Maintenant lancez un docker ps. Vous verrez votre docker nginx tourner

Voilà docker run n'a plus de secret pour vous, et c'est parfait car c'est probablement la commande que vous utiliserez le plus fréquemment. Il est judicieux de prendre le temps de vous familiariser avec elle. Pour en savoir plus sur run, utilisez docker run --help pour voir la liste de tous les indicateurs qu'elle prend en charge. Au fur et à mesure de votre progression, vous verrez quelques variantes de docker run.

Pour la suite taguez votre image nginx :

$ docker tag registry.takima.io/school/proxy/nginx nginx

A tout moment vous pouvez inspecter un container avec docker container inspect, par exemple pour récupérer son status :

# get the state of a container
docker container inspect \
--format '{{.State.Status}}' \
mon-nginx

Success

Point cours pour voir les Network Docker

Les Network Docker

Faire tourner un applicatif c'est bien mais lorsque l'on fait du web c'est essentiel de pouvoir publier son application et que cette application bénéficie d'une connectivité (IP), mais c'est aussi essentiel d'isoler les conteneurs dans des réseaux séparés. Après tout c'est aussi l'une des promesses de docker l'isolation.

Objectif:

  • Comprendre les concepts de base des réseaux Docker.
  • Créer et gérer des réseaux Docker.
  • Connecter des conteneurs à des réseaux personnalisés.

Vérifier les réseaux Docker existants

Pour lister les reseaux actuels :

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
df8d9a03e3e1   bridge    bridge    local
f0b4def22265   host      host      local
a7cd984404b5   none      null      local

Ce sont les réseaux par défault. On peut créer autant de nouveau réseaux isolés que l'on souhaite et lorsque l'on créé un reseau il sera de type bridge par défaut

Lorsque l'on créer un conteneur il se trouve attaché par défaut au réseau nommé bridge. On déconseille donc de l'utilser pour faire tourner nos applications.

Créer un réseau personnalisé

Créez un réseau Docker personnalisé en utilisant la commande docker network create. Par exemple, créez un réseau nommé "app" :

docker network create app

Vous pouvez vérifier que le réseau a été créé en utilisant la commande docker network ls.

Exécuter des conteneurs connectés au réseau personnalisé

Créez deux conteneurs connectés au réseau "app". Par exemple, nous pouvons créer un conteneur web et un conteneur de base de données :

docker run -d --name webapp --network app nginx

Le conteneur webapp est maintenant connecté au réseau `app``

Vérifier la connectivité

Vous pouvez maintenant vérifier si un conteneur présent sur ce réseau app peut communiquer avec la webapp. Exécutez un conteneur de test connecté au même réseau :

docker run -it --rm --network app registry.takima.io/school/proxy/busybox sh

À l'intérieur de ce conteneur de test, essayez de "pinguer" le conteneur webapp en utilisant leurs noms de conteneurs comme hôtes. Assurez-vous que la connectivité fonctionne avec un wget sur le port 80 par exemple .

$ wget webapp
Connecting to webapp (172.19.0.2:80)
saving to 'index.html'
index.html           100% |**********************************************************************************************|   615  0:00:00 ETA
'index.html' saved

$ cat index.html

Supprimer le réseau

Pour supprimer le réseau personnalisé que vous avez créé, utilisez la commande suivante :

docker network rm app

Notes

Si un réseau est utilisé, impossible de le détruire.

Success

Point cours sur la publication des conteneurs

La publication

Nous avons isolé les conteneurs dans un réseau et c'est parfait pour la sécurité. Mais certains services sont plus utiles lorsqu'ils sont accèssibles. Nous allons donc voir comment publier un service sur le Host qui l'héberge.

Objectif :

  • Comprendre comment publier des ports de conteneurs Docker.
  • Tester l'accessibilité des applications via les ports publiés.

Vérification des ports existants

Avant de commencer, listez les conteneurs actuellement en cours d'exécution sur votre système à l'aide de la commande suivante :

docker ps

Cette commande affichera les conteneurs actifs, mais notez qu'aucun port n'est actuellement publié pour eux.

Créer un conteneur avec des ports publiés

Créez un conteneur avec un serveur web Nginx et publiez son port 80 sur un port de votre machine hôte, par exemple, le port 8080. Utilisez la commande suivante :

docker run -d -p 8080:80 --name monsite registry.takima.io/school/proxy/nginx

Cela démarrera un conteneur Nginx avec son port 80 publié sur le port 8080 de votre machine hôte.

Accès à l'application via le port publié

Ouvrez un navigateur web et accédez à http://localhost:8080. Vous devriez voir la page d'accueil Nginx, ce qui signifie que le serveur web du conteneur est accessible via le port publié.

Gestion des ports publiés

Pour afficher les ports publiés par un conteneur en cours d'exécution, utilisez la commande docker port. Par exemple :

docker port monsite

Arrêter et supprimer les conteneurs

Lorsque vous avez terminé, arrêtez et supprimez les conteneurs que vous avez créés :

docker stop monsite
docker rm monsite

Tip

rm -f est utile pour aller plus vite.

Success

Point cours sur les Volumes Docker

Les volumes Docker

placez vous dans un dossier /td-volumes

Création d'un Conteneur avec un Volume

Nous allons ici utiliser un bind volume : Il s'agit d'un volume monté depuis un dossier du host (celui qui lance les dockers)

  1. Créez un répertoire vide sur votre système hôte pour servir de volume. Par exemple :

    mkdir mon_volume
    

  2. Créez un conteneur en utilisant la commande docker run avec un volume monté à partir du répertoire que vous venez de créer. Assurez-vous de remplacer chemin_vers_votre_volume par le chemin absolu du répertoire que vous avez créé à l'étape précédente : !!! tip Si vous êtes bien dans le dossier utilisé la variables de dossier courrant $(pwd) "$(pwd)"/mon_volume:/containerDir

    docker run -d -v "$(pwd)"/mon_volume:/data --name mon-conteneur nginx
    

  3. Vérifiez que le conteneur est en cours d'exécution en utilisant docker ps.

Utilisation du Volume depuis le Conteneur

  1. Exécutez un shell interactif dans le conteneur que vous venez de créer :

    docker exec -it mon-conteneur /bin/bash
    

  2. À l'intérieur du conteneur, créez un fichier ou un répertoire dans le répertoire monté :

    touch /data/mon_fichier.txt
    

  3. Quittez le shell du conteneur en utilisant exit.

Vérification de la Persistance des Données

  1. Arrêtez et supprimez le conteneur :

    docker stop mon-conteneur
    docker rm mon-conteneur
    

  2. Vérifiez que le répertoire et le fichier que vous avez créés sont toujours présents dans le répertoire du volume sur votre système hôte :

    ls mon_volume
    

Création d'un Deuxième Conteneur avec le Même Volume

  1. Créez un deuxième conteneur en utilisant le même volume que le premier :

    docker run -d -v "$(pwd)"/mon_volume:/data --name mon-conteneur-bis nginx
    

  2. Exécutez un shell interactif dans le deuxième conteneur :

    docker exec -it mon-conteneur-bis /bin/bash
    

  3. Vérifiez que le fichier ou le répertoire que vous avez créé est présent dans le deuxième conteneur, même s'il s'agit d'un conteneur différent.

  4. Quittez le shell du deuxième conteneur en utilisant exit.

clean

  1. Supprimez le deuxième conteneur :

    docker stop mon-conteneur-bis
    docker rm mon-conteneur-bis
    

  2. Supprimez le répertoire du volume sur votre système hôte :

    rm -rf mon_volume
    

Success

Point cours sur les Images Docker

Images Docker

Dans cette section, plongeons plus en profondeur dans ce que sont les images Docker. Vous allez construire votre propre image, utiliser cette image pour exécuter une application localement, et enfin, pousser certaines de vos propres images vers Docker Hub.

Les images Docker sont la base des conteneurs. Dans l'exemple précédent, vous avez pull une image nginx depuis le registre et avez demandé au client Docker d'exécuter un conteneur basé sur cette image. Pour voir la liste des images disponibles localement sur votre système, exécutez la commande docker images.

$ docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
dockersamples/static-site   latest              92a386b6e686        2 hours ago        190.5 MB
nginx                  latest              af4b3d7d5401        3 hours ago        190.5 MB

Vous aurez une liste différente d'images sur votre machine. Le TAG fait référence à une version de l'image et l'image ID est l'identifiant unique correspondant de cette image.

Pour simplifier, vous pouvez considérer une image comme un référentiel Git : les images peuvent être commitées avec des modifications et avoir plusieurs versions. Lorsque vous ne fournissez pas de numéro de version spécifique, le client par défaut est "latest" (dernière version).

Par exemple, vous pourriez extraire une version spécifique de l'image ubuntu comme suit :

$ docker pull registry.takima.io/school/proxy/ubuntu:12.04

Si vous ne spécifiez pas le numéro de version de l'image, le client Docker utilisera, comme mentionné précédemment, une version nommée "latest" (dernière version).

Donc, par exemple, la commande docker pull ci-dessous extraira une image nommée registry.takima.io/school/proxy/ubuntu:latest :

$ docker pull registry.takima.io/school/proxy/ubuntu

Pour obtenir une nouvelle image Docker, vous pouvez soit l'obtenir depuis un registre (tel que le Docker Hub ou bien un registre personnel comme nous sommes en train de faire) soit la créer vous-même. Il existe des centaines de milliers d'images disponibles sur le Docker Hub. Vous pouvez également rechercher des images directement depuis la ligne de commande à l'aide de docker search.

Une distinction importante concernant les images se situe entre les images de base (base images) et les images enfants (child images).

  • Les images de base sont des images qui n'ont pas d'images parent, généralement des images avec un système d'exploitation tel qu'Ubuntu, Alpine ou Debian.

  • Les images enfants sont des images qui se construisent sur des images de base et ajoutent des fonctionnalités supplémentaires.

Un autre concept clé est l'idée d'images officielles et d'images utilisateur (user images). (Les deux peuvent être des images de base ou des images enfants.)

  • Les images officielles sont des images vérifiées par Docker. Docker, Inc. sponsorise une équipe dédiée responsable de la révision et de la publication de tout le contenu des référentiels officiels. Cette équipe travaille en collaboration avec les mainteneurs de logiciels, des experts en sécurité et la communauté Docker élargie. Elles ne sont pas préfixées par un nom d'organisation ou d'utilisateur. Dans la liste des images ci-dessus, les images python, node, alpine et nginx sont des images officielles (de base). Pour en savoir plus à leur sujet, consultez la documentation sur les images officielles.

  • Les images utilisateur sont des images créées et partagées par des utilisateurs comme vous. Elles se construisent sur des images de base et ajoutent des fonctionnalités supplémentaires. Typiquement, elles sont formatées comme utilisateur/nom-de-l'image. La valeur utilisateur dans le nom de l'image correspond à votre nom d'utilisateur ou d'organisation Docker Hub.

Créez votre première image

Maintenant que vous avez une meilleure compréhension des images, il est temps de créer la vôtre. Notre principal objectif ici est de créer une image qui isole une petite application Flask.

L'objectif de cet exercice est de créer une image Docker qui exécutera une application Flask.

Nous allons commencer par rassembler les composants pour un générateur aléatoire d'images de chats construit avec Python Flask, puis dockeriser cela en écrivant un Dockerfile. Enfin, nous allons construire l'image, puis l'exécuter.

Créez une application Python Flask qui affiche des images de chats aléatoires.

Dans le cadre de cet atelier, nous avons créé une petite application Python Flask amusante qui affiche une image de chat aléatoire au chargement - car, vous savez, qui n'aime pas les chats ?

Commencez par créer un répertoire appelé flask-app où nous allons créer les fichiers suivants :

  • app.py
  • requirements.txt
  • templates/index.html
  • Dockerfile

Assurez-vous de vous déplacer vers cd flask-app avant de commencer à créer les fichiers, car vous ne voulez pas ajouter tout un tas d'autres fichiers à votre image.

app.py

Créer le fichier python app.py avec ce contenu:

from flask import Flask, render_template
import random

app = Flask(__name__)

# liste des images
images = [
"https://c.tenor.com/GTcT7HODLRgAAAAM/smiling-cat-creepy-cat.gif",
"https://media0.giphy.com/media/10dU7AN7xsi1I4/giphy.webp?cid=ecf05e47gk63rd81vzlot57qmebr7drtgf6a3khmzvjsdtu7&rid=giphy.webp&ct=g",
"https://media0.giphy.com/media/S6VGjvmFRu5Qk/giphy.webp?cid=ecf05e478yofpawrhffnnvb3sgjkos96vyfo5mtqhds35as6&rid=giphy.webp&ct=g",
"https://media3.giphy.com/media/JIX9t2j0ZTN9S/200w.webp?cid=ecf05e47gk63rd81vzlot57qmebr7drtgf6a3khmzvjsdtu7&rid=200w.webp&ct=g"
    ]

@app.route('/')
def index():
    url = random.choice(images)
    return render_template('index.html', url=url)

if __name__ == "__main__":
    app.run(host="0.0.0.0")

requirements.txt

Ce fichier requirements.txt référence les modules Python necessaire pour lancer notre app Python

Flask==0.10.1

templates/index.html

Créez le dossier templates et créez dans ce dossier le fichier index.html avec le contenu suivant:

<html>
  <head>
    <style type="text/css">
      body {
        background: black;
        color: white;
      }
      div.container {
        max-width: 500px;
        margin: 100px auto;
        border: 20px solid white;
        padding: 10px;
        text-align: center;
      }
      h4 {
        text-transform: uppercase;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h4>Cat Gif of the day</h4>
      <img src="{{url}}" />
      <p>
        <small
          >Courtesy:
          <a
            href="http://www.buzzfeed.com/copyranter/the-best-cat-gif-post-in-the-history-of-cat-gifs"
            >Buzzfeed</a
          ></small
        >
      </p>
    </div>
  </body>
</html>

Rédigez un Dockerfile

Dernier fichier et pas des moindre le Dockerfile.

Nous voulons créer une image Docker avec cette application web. Comme mentionné précédemment, toutes les images utilisateur sont basées sur une image de base.

Étant donné que notre application est écrite en Python, nous allons créer notre propre image embarquant notre app Python basée sur Alpine. Nous allons le faire en utilisant un Dockerfile.

Tip

L'image Alpine est souvent utilisé comme image de base car elle est très légère

Un Dockerfile est un fichier texte qui contient une liste de commandes que le daemon Docker appelle lors de la création d'une image. Le Dockerfile contient toutes les informations dont Docker a besoin pour exécuter l'application : une image Docker de base qui servira de socle , l'emplacement de votre code de projet, ses dépendances éventuelles, et les commandes à exécuter au démarrage.

C'est un moyen simple d'automatiser le processus de création d'images.

  1. Créez un fichier appelé Dockerfile et ajoutez-y le contenu comme décrit ci-dessous.

    Nous allons commencer par spécifier notre image de base en utilisant le mot clé FROM :

    FROM registry.takima.io/school/proxy/alpine:3.6
    
  2. La prochaine étape consiste généralement à écrire les commandes de copie des fichiers et à installer les dépendances nécessaire pour notre application. Mais d'abord, nous allons installer le package Python pip dans la distribution Linux Alpine. Cela n'installera pas seulement le package pip, mais aussi d'autres dépendances, y compris l'interpréteur Python. Ajoutez la commande RUN suivante :

    RUN apk add --update py2-pip
    
  3. Ajoutons les fichiers qui composent l'application Flask.

    Installez toutes les dépendances Python nécessaires pour le bon fonctionnement de notre application. Cela sera accompli en ajoutant les lignes suivantes :

    COPY requirements.txt /usr/src/app/
    RUN pip install --no-cache-dir -r /usr/src/app/requirements.txt
    

    Copiez les fichiers que vous avez créés précédemment dans notre image en utilisant la commande COPY.

    COPY app.py /usr/src/app/
    COPY templates/index.html /usr/src/app/templates/
    
  4. Spécifiez le numéro de port qui doit être exposé. Comme notre application Flask s'exécute sur le port 5000, c'est ce que nous allons exposer.

    EXPOSE 5000
    
  5. La dernière étape est de définir la commande pour lancer l'application : python ./app.py. Utilisez la commande ENTRYPOINT pour cela :

    ENTRYPOINT ["python", "/usr/src/app/app.py"]
    

    Le but principal de ENTRYPOINT est d'indiquer au conteneur la commande qu'il doit exécuter par défaut lors de son démarrage.

    Tip

    En vérité ENTRYPOINT servira à définir l'executable et le CMD servira à définir les paramètres de l'executable

  6. Vérifiez votre Dockerfile.

    Notre Dockerfile est maintenant prêt. Voici à quoi il ressemble :

    # notre image de base
    FROM registry.takima.io/school/proxy/alpine:3.6
    
    # Installer Python et pip
    RUN apk add --update py2-pip
    
    # Installer les modules Python nécessaires par l'application Python
    COPY requirements.txt /usr/src/app/
    RUN pip install --no-cache-dir -r /usr/src/app/requirements.txt
    
    # Copier les fichiers nécessaires pour l'exécution de l'application
    COPY app.py /usr/src/app/
    COPY templates/index.html /usr/src/app/templates/
    
    # Indiquer le numéro de port que le conteneur doit exposer
    EXPOSE 5000
    
    # Exécuter l'application
    ENTRYPOINT ["python", "/usr/src/app/app.py"]
    

Builder notre image

Maintenant que notre Dockerfileest prêt, il est temps de builder notre application. La commande docker build s'occupe du travail de créer une image Docker à partir du Dockerfile.

Lorsque vous exécutez la commande docker build, assurez-vous de remplacer <YOUR_USERNAME> par votre nom d'utilisateur. Ce nom d'utilisateur devrait être le même que celui que vous avez créé lors de votre inscription sur Docker Hub. Si vous ne l'avez pas encore fait mettez le nom que vous souhaitez pour votre tag.

La commande docker build est assez simple. Elle prend un nom de balise ou tag facultatif avec l'option -t et l'emplacement du répertoire contenant le Dockerfile. Le point . indique le répertoire actuel :

$ docker build -t <YOUR_USERNAME>/myfirstapp .
Sending build context to Docker daemon 9.728 kB
Step 1 : FROM alpine:latest
 ---> 0d81fc72e790
Step 2 : RUN apk add --update py-pip
 ---> Running in 8abd4091b5f5
fetch http://dl-4.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-4.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
(1/12) Installing libbz2 (1.0.6-r4)
(2/12) Installing expat (2.1.0-r2)
(3/12) Installing libffi (3.2.1-r2)
(4/12) Installing gdbm (1.11-r1)
(5/12) Installing ncurses-terminfo-base (6.0-r6)
(6/12) Installing ncurses-terminfo (6.0-r6)
(7/12) Installing ncurses-libs (6.0-r6)
(8/12) Installing readline (6.3.008-r4)
(9/12) Installing sqlite-libs (3.9.2-r0)
(10/12) Installing python (2.7.11-r3)
(11/12) Installing py-setuptools (18.8-r0)
(12/12) Installing py-pip (7.1.2-r0)
Executing busybox-1.24.1-r7.trigger
OK: 59 MiB in 23 packages
 ---> 976a232ac4ad
Removing intermediate container 8abd4091b5f5
Step 3 : COPY requirements.txt /usr/src/app/
 ---> 65b4be05340c
Removing intermediate container 29ef53b58e0f
Step 4 : RUN pip install --no-cache-dir -r /usr/src/app/requirements.txt
 ---> Running in a1f26ded28e7
Collecting Flask==0.10.1 (from -r /usr/src/app/requirements.txt (line 1))
  Downloading Flask-0.10.1.tar.gz (544kB)
Collecting Werkzeug>=0.7 (from Flask==0.10.1->-r /usr/src/app/requirements.txt (line 1))
  Downloading Werkzeug-0.11.4-py2.py3-none-any.whl (305kB)
Collecting Jinja2>=2.4 (from Flask==0.10.1->-r /usr/src/app/requirements.txt (line 1))
  Downloading Jinja2-2.8-py2.py3-none-any.whl (263kB)
Collecting itsdangerous>=0.21 (from Flask==0.10.1->-r /usr/src/app/requirements.txt (line 1))
  Downloading itsdangerous-0.24.tar.gz (46kB)
Collecting MarkupSafe (from Jinja2>=2.4->Flask==0.10.1->-r /usr/src/app/requirements.txt (line 1))
  Downloading MarkupSafe-0.23.tar.gz
Installing collected packages: Werkzeug, MarkupSafe, Jinja2, itsdangerous, Flask
  Running setup.py install for MarkupSafe
  Running setup.py install for itsdangerous
  Running setup.py install for Flask
Successfully installed Flask-0.10.1 Jinja2-2.8 MarkupSafe-0.23 Werkzeug-0.11.4 itsdangerous-0.24
You are using pip version 7.1.2, however version 8.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
 ---> 8de73b0730c2
Removing intermediate container a1f26ded28e7
Step 5 : COPY app.py /usr/src/app/
 ---> 6a3436fca83e
Removing intermediate container d51b81a8b698
Step 6 : COPY templates/index.html /usr/src/app/templates/
 ---> 8098386bee99
Removing intermediate container b783d7646f83
Step 7 : EXPOSE 5000
 ---> Running in 31401b7dea40
 ---> 5e9988d87da7
Removing intermediate container 31401b7dea40
Step 8 : CMD python /usr/src/app/app.py
 ---> Running in 78e324d26576
 ---> 2f7357a0805d
Removing intermediate container 78e324d26576
Successfully built 2f7357a0805d

Si vous n'avez pas l'image registry.takima.io/school/proxy/alpine:3.6, le docker commencera par la télécharger, puis créera votre image. Par conséquent, la sortie de la commande sera sensiblement différente. Si tout s'est bien passé, votre image devrait être prête ! Exécutez docker images ls et vérifiez si votre image (<YOUR_USERNAME>/myfirstapp) apparaît.

Exécutez votre image

La prochaine étape de cette section consiste à exécuter l'image pour voir si elle fonctionne réellement.

$ docker run -p 8888:5000 --name myfirstapp YOUR_USERNAME/myfirstapp
 * Running on http://0.0.0.0:5000/ (Appuyez sur CTRL+C pour quitter)

Accédez à http://localhost:8888, et votre application devrait être en ligne.

gif_cat

Appuyez sur le bouton "Actualiser" dans le navigateur Web pour voir quelques images de chat supplémentaires.

Docker Compose

Pourquoi faire ?

Maintenant que vous savez builder une image, lancer un conteneur, créer des volumes et des networks, vous allez vite vous apercevoir que cela peut être fastidieux de lancer toutes ces commandes une part une pour tout reconstruire ou bien tout supprimmer. Alors bien sur vous pourriez créer de multiple script bash par exemple pour lancer tout cela, puis un autre pour tous supprimer. Mais cela s'avère difficilement maintenanble et non scalable. Et en plus c'est une approche impérative. Heureusement Docker nous aide à éviter cela avec un outil : Docker Compose. Et en plus, c'est cool, car c'est du déclaratif. Et ça, lorsque l'on veut déployer des infras, on aime beaucoup.

Utilisation

Pour utiliser docker compose il vous faudra décrire votre stack à déployer (ensemble des objets docker : conteneurs, volume, network et bien d'autre).

  1. placer vous dans un nouveau dossier et créez un fichier compose.yaml :

    version: '3'
    services:
      webapp:
        image: registry.takima.io/school/proxy/nginx
        ports:
          - "8082:80"
        networks:
          - my-network
        volumes:
          - my-volume:/app/data
        environment:
          - DATABASE_URL=mysql://dbuser:dbpassword@db/dbname
      db:
        image: mysql:5.7
        networks:
          - my-network
        environment:
          - MYSQL_ROOT_PASSWORD=rootpassword
          - MYSQL_DATABASE=dbname
          - MYSQL_USER=dbuser
          - MYSQL_PASSWORD=dbpassword
        volumes:
          - db-data:/var/lib/mysql
    
    networks:
      my-network:
        driver: bridge
    
    volumes:
      my-volume:
      db-data:
    
  2. Lancez la stack

    $ docker compose up -d
    
  3. Verifiez l'état des objets

    $ docker compose ps
    
    $ docker ps
    $ docker volume ls
    $ docker network ls
    

    Question

    Que constatez vous au niveau du nom des objets Docker

  4. stopez la stack compose

    $ docker compose stop
    
  5. supprimmez la stack compose

    $ docker compose down --volumes
    

    Note

    L'option --volumes permet le purger les volumes. A utiliser avec parcimonie pour ne pas perdre de données !

Maintenant que vous savez comment exécuter des conteneurs Docker et créer des Dockerfiles, ou des stack entière avec compose, passons à la partie pratique.

© Takima 2023

"