« Docker » : différence entre les versions
Aucun résumé des modifications |
Aucun résumé des modifications |
||
Ligne 85 : | Ligne 85 : | ||
| | ||
</div> </div> </div> | </div> </div> </div> | ||
= = | |||
= Construire une app = | |||
Nous allons commencer en bas de la hiérarchie de Docker pour remonter. La hiérarchie Docker est constituée comme suit : | |||
-Stack : Définit les interactions entre les services<br/> -Services : Définit comment les containers se comportent en production<br/> -Conteneur : On y est. | |||
Classiquement, lorsque l'on construit une application en python par exemple, on commence par télécharger un environnement Python pour ensuite coder par dessus. Avec Docker, on peut se contenter de récupérer une image contenant une instance de Python sans installation. Ensuite notre build contiendra l'image de Python avec toutes ses dépendances, ainsi que notre application; tout sera "packagé" ensemble, et on sera sûrs que tout fonctionne. Cela évite d'avoir à prendre en compte des différences entre l'environnement de développement et celui de production. | |||
Ces images portables sont définies par un fichier de configuration appellé Dockerfile. | |||
== Définir un container avec Dockerfile == | |||
Le Dockerfil définit tout ce qui va aller dans l'environnement à l'intérieur du conteneur; les ressources comme les interfaces réseau sont virtualisées dans cet environnement isolé, alors il va falloir mapper les ports vers le monde extérieur, et être spécifique quant aux fichiers que l'on veut copier dans l'environnement. Après ça, le conteneur devrait fonctionner partout. | |||
On va commencer avec Python. Il faut créer un nouveau dossier, s'y rendre, créer un fichier appellé "Dockerfile" et y coller ce texte : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px"><div class="language-do highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Use an official Python runtime as a parent image</span> | |||
<span class="k">FROM</span><span class="s"> python:2.7-slim</span> | |||
<span class="c"># Set the working directory to /app</span> | |||
<span class="k">WORKDIR</span><span class="s"> /app</span> | |||
<span class="c"># Copy the current directory contents into the container at /app</span> | |||
<span class="k">COPY</span><span class="s"> . /app</span> | |||
<span class="c"># Install any needed packages specified in requirements.txt</span> | |||
<span class="k">RUN </span>pip install <span class="nt">--trusted-host</span> pypi.python.org <span class="nt">-r</span> requirements.txt | |||
<span class="c"># Make port 80 available to the world outside this container</span> | |||
<span class="k">EXPOSE</span><span class="s"> 80</span> | |||
<span class="c"># Define environment variable</span> | |||
<span class="k">ENV</span><span class="s"> NAME World</span> | |||
<span class="c"># Run app.py when the container launches</span> | |||
<span class="k">CMD</span><span class="s"> ["python", "app.py"]</span> | |||
</code></pre> | |||
</div> </div> </div> | |||
Ce fichier fait référence à deux fichiers encore inexistants, app.py et requirements.txt. On va les créer. | |||
== L'application proprement dite == | |||
Dans le dossier lui-même, créer les deux fichiers. | |||
Notre app sera alors complète: puisque que le Dockerfile contient la commande COPY, app.py et requirements.txt seront pris en compte à la création de l'image. La sortie de l'application sera dispo via http grâce au EXPOSE, qui permet d'accéder à la sortie depuis le "monde extérieur" sur le port 80. | |||
requirements.txt: | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px"><pre class="highlight"><code>Flask | |||
Redis</code></pre> | |||
</div> | |||
app.py: | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px"><div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> | |||
<span class="kn">from</span> <span class="nn">redis</span> <span class="kn">import</span> <span class="n">Redis</span><span class="p">,</span> <span class="n">RedisError</span> | |||
<span class="kn">import</span> <span class="nn">os</span> | |||
<span class="kn">import</span> <span class="nn">socket</span> | |||
<span class="c"># Connect to Redis</span> | |||
<span class="n">redis</span> <span class="o">=</span> <span class="n">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">"redis"</span><span class="p">,</span> <span class="n">db</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">socket_connect_timeout</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">socket_timeout</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> | |||
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> | |||
<span class="nd">@app.route</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span> | |||
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span> | |||
<span class="k">try</span><span class="p">:</span> | |||
<span class="n">visits</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">incr</span><span class="p">(</span><span class="s">"counter"</span><span class="p">)</span> | |||
<span class="k">except</span> <span class="n">RedisError</span><span class="p">:</span> | |||
<span class="n">visits</span> <span class="o">=</span> <span class="s">"<i>cannot connect to Redis, counter disabled</i>"</span> | |||
<span class="n">html</span> <span class="o">=</span> <span class="s">"<h3>Hello {name}!</h3>"</span> \ | |||
<span class="s">"<b>Hostname:</b> {hostname}<br/>"</span> \ | |||
<span class="s">"<b>Visits:</b> {visits}"</span> | |||
<span class="k">return</span> <span class="n">html</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"NAME"</span><span class="p">,</span> <span class="s">"world"</span><span class="p">),</span> <span class="n">hostname</span><span class="o">=</span><span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">(),</span> <span class="n">visits</span><span class="o">=</span><span class="n">visits</span><span class="p">)</span> | |||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span> | |||
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">'0.0.0.0'</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span> | |||
</code></pre> | |||
</div> </div> </div> | |||
Ici le <code class="highlighter-rouge">pip install -r requirements.txt </code>installe les bibliothèques Flask et Redis pour Python. L'application affiche aussi la variable d'environnement NAME et la sortie d'un appel à socket.gethostname(). Ici, Redis ne devrait pas fonctionner puisqu'on a fait qu'installer sa bibliothèque, et pas Redis lui-même. | |||
<blockquote> | |||
NB : Redis est un système de BDD "anti-SQL". | |||
NB2 : demander le hostname depuis un conteneur renvoie le container ID, qui est comme le PID d'un exécutable. | |||
</blockquote> | |||
== Construire l'application == | |||
On est prêts à construire notre application ! Il faut s'assurer que l'on est dans notre dossier et qu'il contient bien nos trois fichiers (Dockerfile, requirements.txt et app.py). On va lancer la construction : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px">docker build -t montest .</div> | |||
L'argument -t permet de taguer mon image pour qu'elle ait un nom reconnaissable (ici "montest"); ne pas oublier le . qui renvoie au dossier actuel. | |||
Docker va alors exécuter le Dockerfile; installer requirements.txt dans l'image en partant de l'image Python, etc... | |||
Une fois le processus terminé, mon dossier n'as pas changé; mais l'image est bien apparu dans ma liste d'images, ce que je peux voir avec un docker image ls. | |||
| | ||
=== Problèmes de proxy/dns: === | |||
Un Proxy peut être indiqué dans le dockerfile avec: | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px"><div class="language-conf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Set proxy server, replace host:port with values for your servers | |||
</span><span class="n">ENV</span> <span class="n">http_proxy</span> <span class="n">host</span>:<span class="n">port</span> | |||
<span class="n">ENV</span> <span class="n">https_proxy</span> <span class="n">host</span>:<span class="n">port</span> | |||
</code></pre> | |||
</div> </div> </div> | |||
Un DNS peut être indiqué à Docker en modifiant/créant le fichier /etc/docker/daemon.json et en y mettant: | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px"><pre class="highlight"><code><span class="p">{</span><span class="w"> | |||
</span><span class="s2">"dns"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"your_dns_address"</span><span class="p">,</span><span class="w"> </span><span class="s2">"8.8.8.8"</span><span class="p">]</span><span class="w"> | |||
</span><span class="p">}</span></code></pre> | |||
</div> | |||
Il faut ensuite sauvegarder le fichier et redémarrer le service docker. | |||
= Tester l'application = | |||
Notre image est créée, il est temps de créer ce conteneur et de tester ! | |||
il suffit d'un : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px">docker run -p 4000:80 montest</div> | |||
L'argument -p 4000:80 mappe le port 4000 de ma machine au port 80 dans le conteneur : j'ai alors accès à mon application en visitant l'url suivante : 127.0.0.1:4000 . | |||
J'y vois la sortie de mon application. Ca marche aussi avec un curl http://localhost:4000 | |||
On peut aussi lancer l'application en arrière-plan (detached) : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px">docker run -d -p 4000:80 montest</div> | |||
J'ai alors l'identifiant de conteneur et je suis renvoyée au terminal : le conteneur est en arrière-plan. Je le vois avec docker container ls : je vois que le container ID (en abrégé) correspond à ce que renvoie l'app. | |||
Je peux stopper le conteneur avec : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px">docker container stop <containerID></div> | |||
= Partager l'image = | |||
On peut uploader cette image et la faire tourner ailleurs. | |||
En effet il va être nécessaire de savoir comment push des registres lors de la mise en prod. Un registre est une collection de dépôts, et un dépôt est une collection d'images. Un peu comme Github, mais le code est déjà construit. On peut créer plusieurs dépôts sur un registre avec un seul compte; la ligne de commande docker utilise le registre public de docker par défaut. Il en existe d'autres. | |||
On peut même créer son propre registre ! | |||
== Se logger == | |||
Il va falloir se logger avec son compte docker (qu'on peut créer sur [[hub.docker.com|hub.docker.com)]] et noter son identifiant. | |||
Une fois que c'est fait, je peux me connecter sur le site et créer un repo. | |||
Je peux ensuite logger via le terminal avec <code>docker login</code>. | |||
== Tagger l'image == | |||
La notation pour associer une image a un dépôt est <code>nomutilisateur/repo:tag. </code>Le tag est optionnel mais recommandé, car c'est c'est le mécanisme utilisé par DOcker pour donner des numéros de versions. Il faut donc que les noms aient du sens. | |||
Je vais donc faire ici : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px"> | |||
docker tag montest justinep/monrepotest:letest #montest est l'image, justinep mon identifiant Docker, letest est le tag que je donne. | |||
</div> | |||
Un <code>docker image ls </code>me permet de voir mon image tagguée. | |||
== Publier l'image == | |||
Je peux uploader l'image avec : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px">docker push justinep/monrepotest:letest</div> | |||
== Récupérer l'image depuis le dépôt et la faire tourner (Pull and Run) == | |||
Désormais, je peux faire un : | |||
<div style="background:#eeeeee; border:1px solid #cccccc; padding:5px 10px">docker run -p 4000:80 justinep/monrepotest:letest</div> | |||
pour faire tourner l'image : si elle n'est pas sur ma machine locale, elle est téléchargée et lancée. | |||
Peu importe où je suis, Docker récupère l'image avec Python et tout le reste, et fait tourner le code; tout ça dans un paquet bien ficelé, sans qu'il n'y ai rien de plus à installer. |
Version du 14 novembre 2018 à 21:11
Les notes de cettes pages sont prises à partir de la documentation de docker : https://docs.docker.com/get-started/
Présentation de Docker
Docker est une plateforme qui permet de développer, déployer et faire tourner des applications en conteneurs. L'usage de conteneur s'appelle la conteneurisation. Les conteneurs sont:
- Flexibles : Tout peut être conteneurisé
- Légers
- Interchangeables
- Portables
- Scalables
- Empilables
Un conteneur est lancé en faisant tourner une image : une image est un exécutable qui inclut tout ce dont a besoin le programme, et le conteneur est l'environnement d'exécution qui permet à cette image de fonctionner. Une fois lancé le conteneur est un processus utilisateur, que l'on peut lister avec docker ps. Les conteneurs partagent entre eux les ressources système et le noyau Linux.
À la différence d'une VM, un conteneur peut tourner nativement sur n'importe quelle machine Linux; une même machine Linux peut utiliser plusieurs conteneurs, cette technologie est plus économe que les VM.
Préparer l'environnement Docker
On va commencer par installer Docker.
https://docs.docker.com/install/
Le versioning fonctionne sur le modèle : Année.Mois.Patch
Une fois installé, on peut tester avec docker --version
.
On a plus d'informations avec docker info:
justine@Justine-pc:~$ docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 1
Server Version: 18.09.0
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: d6de12e2f362cb9dc49ad957911996d3de59b338
runc version: 4fc53a81fb7c994640722ac585fa9ca548971871
init version: fec3683
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.18.0-10-generic
Operating System: Ubuntu 18.10
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 15.59GiB
Name: ***
ID: EN3D:SYGK:2WYA:TZM5:MHRP:FBOH:GQVD:VFKW:SDG6:V3FW:XSKK:5MAI
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine
WARNING: No swap limit support
On peut ensuite ajouter son utilisateur au groupe docker:
sudo adduser user docker
Tester l'installation de Docker
Le test le plus simple consiste à faire tourner l'image hello-world :
justine@Justine-pc:~$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
d1725b59e92d: Pull complete
Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Hello-world est une image simple qui permet de valider l'installation.
On peut lister les images télechargées avec docker image ls
...et lister les conteneurs avec docker container ls --all
Récapitulatif des commandes issu de la documentation Docker :
List Docker CLI commands
docker
docker container --help
Display Docker version and info
docker --version
docker version
docker info
Execute Docker image
docker run hello-world
List Docker images
docker image ls
List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls --all
docker container ls -aq
Construire une app
Nous allons commencer en bas de la hiérarchie de Docker pour remonter. La hiérarchie Docker est constituée comme suit :
-Stack : Définit les interactions entre les services
-Services : Définit comment les containers se comportent en production
-Conteneur : On y est.
Classiquement, lorsque l'on construit une application en python par exemple, on commence par télécharger un environnement Python pour ensuite coder par dessus. Avec Docker, on peut se contenter de récupérer une image contenant une instance de Python sans installation. Ensuite notre build contiendra l'image de Python avec toutes ses dépendances, ainsi que notre application; tout sera "packagé" ensemble, et on sera sûrs que tout fonctionne. Cela évite d'avoir à prendre en compte des différences entre l'environnement de développement et celui de production.
Ces images portables sont définies par un fichier de configuration appellé Dockerfile.
Définir un container avec Dockerfile
Le Dockerfil définit tout ce qui va aller dans l'environnement à l'intérieur du conteneur; les ressources comme les interfaces réseau sont virtualisées dans cet environnement isolé, alors il va falloir mapper les ports vers le monde extérieur, et être spécifique quant aux fichiers que l'on veut copier dans l'environnement. Après ça, le conteneur devrait fonctionner partout.
On va commencer avec Python. Il faut créer un nouveau dossier, s'y rendre, créer un fichier appellé "Dockerfile" et y coller ce texte :
<code><span class="c"># Use an official Python runtime as a parent image</span>
<span class="k">FROM</span><span class="s"> python:2.7-slim</span>
<span class="c"># Set the working directory to /app</span>
<span class="k">WORKDIR</span><span class="s"> /app</span>
<span class="c"># Copy the current directory contents into the container at /app</span>
<span class="k">COPY</span><span class="s"> . /app</span>
<span class="c"># Install any needed packages specified in requirements.txt</span>
<span class="k">RUN </span>pip install <span class="nt">--trusted-host</span> pypi.python.org <span class="nt">-r</span> requirements.txt
<span class="c"># Make port 80 available to the world outside this container</span>
<span class="k">EXPOSE</span><span class="s"> 80</span>
<span class="c"># Define environment variable</span>
<span class="k">ENV</span><span class="s"> NAME World</span>
<span class="c"># Run app.py when the container launches</span>
<span class="k">CMD</span><span class="s"> ["python", "app.py"]</span>
</code>
Ce fichier fait référence à deux fichiers encore inexistants, app.py et requirements.txt. On va les créer.
L'application proprement dite
Dans le dossier lui-même, créer les deux fichiers.
Notre app sera alors complète: puisque que le Dockerfile contient la commande COPY, app.py et requirements.txt seront pris en compte à la création de l'image. La sortie de l'application sera dispo via http grâce au EXPOSE, qui permet d'accéder à la sortie depuis le "monde extérieur" sur le port 80.
requirements.txt:
<code>Flask Redis</code>
app.py:
<code><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="kn">from</span> <span class="nn">redis</span> <span class="kn">import</span> <span class="n">Redis</span><span class="p">,</span> <span class="n">RedisError</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">socket</span>
<span class="c"># Connect to Redis</span>
<span class="n">redis</span> <span class="o">=</span> <span class="n">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">"redis"</span><span class="p">,</span> <span class="n">db</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">socket_connect_timeout</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">socket_timeout</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">visits</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">incr</span><span class="p">(</span><span class="s">"counter"</span><span class="p">)</span>
<span class="k">except</span> <span class="n">RedisError</span><span class="p">:</span>
<span class="n">visits</span> <span class="o">=</span> <span class="s">"<i>cannot connect to Redis, counter disabled</i>"</span>
<span class="n">html</span> <span class="o">=</span> <span class="s">"<h3>Hello {name}!</h3>"</span> \
<span class="s">"<b>Hostname:</b> {hostname}<br/>"</span> \
<span class="s">"<b>Visits:</b> {visits}"</span>
<span class="k">return</span> <span class="n">html</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"NAME"</span><span class="p">,</span> <span class="s">"world"</span><span class="p">),</span> <span class="n">hostname</span><span class="o">=</span><span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">(),</span> <span class="n">visits</span><span class="o">=</span><span class="n">visits</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">'0.0.0.0'</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">80</span><span class="p">)</span>
</code>
Ici le pip install -r requirements.txt
installe les bibliothèques Flask et Redis pour Python. L'application affiche aussi la variable d'environnement NAME et la sortie d'un appel à socket.gethostname(). Ici, Redis ne devrait pas fonctionner puisqu'on a fait qu'installer sa bibliothèque, et pas Redis lui-même.
NB : Redis est un système de BDD "anti-SQL".
NB2 : demander le hostname depuis un conteneur renvoie le container ID, qui est comme le PID d'un exécutable.
Construire l'application
On est prêts à construire notre application ! Il faut s'assurer que l'on est dans notre dossier et qu'il contient bien nos trois fichiers (Dockerfile, requirements.txt et app.py). On va lancer la construction :
L'argument -t permet de taguer mon image pour qu'elle ait un nom reconnaissable (ici "montest"); ne pas oublier le . qui renvoie au dossier actuel.
Docker va alors exécuter le Dockerfile; installer requirements.txt dans l'image en partant de l'image Python, etc...
Une fois le processus terminé, mon dossier n'as pas changé; mais l'image est bien apparu dans ma liste d'images, ce que je peux voir avec un docker image ls.
Problèmes de proxy/dns:
Un Proxy peut être indiqué dans le dockerfile avec:
<code><span class="c"># Set proxy server, replace host:port with values for your servers
</span><span class="n">ENV</span> <span class="n">http_proxy</span> <span class="n">host</span>:<span class="n">port</span>
<span class="n">ENV</span> <span class="n">https_proxy</span> <span class="n">host</span>:<span class="n">port</span>
</code>
Un DNS peut être indiqué à Docker en modifiant/créant le fichier /etc/docker/daemon.json et en y mettant:
<code><span class="p">{</span><span class="w"> </span><span class="s2">"dns"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"your_dns_address"</span><span class="p">,</span><span class="w"> </span><span class="s2">"8.8.8.8"</span><span class="p">]</span><span class="w"> </span><span class="p">}</span></code>
Il faut ensuite sauvegarder le fichier et redémarrer le service docker.
Tester l'application
Notre image est créée, il est temps de créer ce conteneur et de tester !
il suffit d'un :
L'argument -p 4000:80 mappe le port 4000 de ma machine au port 80 dans le conteneur : j'ai alors accès à mon application en visitant l'url suivante : 127.0.0.1:4000 .
J'y vois la sortie de mon application. Ca marche aussi avec un curl http://localhost:4000
On peut aussi lancer l'application en arrière-plan (detached) :
J'ai alors l'identifiant de conteneur et je suis renvoyée au terminal : le conteneur est en arrière-plan. Je le vois avec docker container ls : je vois que le container ID (en abrégé) correspond à ce que renvoie l'app.
Je peux stopper le conteneur avec :
Partager l'image
On peut uploader cette image et la faire tourner ailleurs.
En effet il va être nécessaire de savoir comment push des registres lors de la mise en prod. Un registre est une collection de dépôts, et un dépôt est une collection d'images. Un peu comme Github, mais le code est déjà construit. On peut créer plusieurs dépôts sur un registre avec un seul compte; la ligne de commande docker utilise le registre public de docker par défaut. Il en existe d'autres.
On peut même créer son propre registre !
Se logger
Il va falloir se logger avec son compte docker (qu'on peut créer sur hub.docker.com) et noter son identifiant.
Une fois que c'est fait, je peux me connecter sur le site et créer un repo.
Je peux ensuite logger via le terminal avec docker login
.
Tagger l'image
La notation pour associer une image a un dépôt est nomutilisateur/repo:tag.
Le tag est optionnel mais recommandé, car c'est c'est le mécanisme utilisé par DOcker pour donner des numéros de versions. Il faut donc que les noms aient du sens.
Je vais donc faire ici :
docker tag montest justinep/monrepotest:letest #montest est l'image, justinep mon identifiant Docker, letest est le tag que je donne.
Un docker image ls
me permet de voir mon image tagguée.
Publier l'image
Je peux uploader l'image avec :
Récupérer l'image depuis le dépôt et la faire tourner (Pull and Run)
Désormais, je peux faire un :
pour faire tourner l'image : si elle n'est pas sur ma machine locale, elle est téléchargée et lancée.
Peu importe où je suis, Docker récupère l'image avec Python et tout le reste, et fait tourner le code; tout ça dans un paquet bien ficelé, sans qu'il n'y ai rien de plus à installer.