Après avoir lancé un conteneur Docker Rails API avec succès, j'en ai lancé un autre qui devait communiquer avec mon API.

Malheureusement, les IPs que j'utilisais la première fois ne fonctionnaient plus ; et par conséquent, mes conteneurs ne communiquaient pas entre eux.

J'ai donc cherché sur Internet, via Qwant hein - vous le savais j'utilise au minimum les GAFA - et trouvé divers outils pour m'aider à comprendre.

Docker inspect

Il est possible d'inspecter un conteneur Docker et d'ainsi avec des informations sur son architecture.

Il y a notamment Gateway qui donne l'IP par lequel le conteneur communique avec notre machine et IPAddress qui est l'adresse que l'on doit utiliser pour communiquer avec l'application.

alain@alain-Sys1:~/01_projets/e-v/server$ docker inspect 7d4a629a6569 | grep Gateway
"Gateway": "",
"IPv6Gateway": "",
        "Gateway": "172.20.0.1",
        "IPv6Gateway": "",
alain@alain-Sys1:~/01_projets/e-v/server$ docker inspect 7d4a629a6569 | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "",
        "IPAddress": "172.20.0.3",

Mes routes actuelles

Je m'étais aperçu que j'avais beaucoup de ponts sur ma machine sans trop comprendre pourquoi.

alain@alain-Sys1:~/01_projets/e-v/server$ sudo ip route
[sudo] Mot de passe de alain : 
default via 192.168.0.254 dev eth1  proto static  metric 100 
169.254.0.0/16 dev eth1  scope link  metric 1000 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown 
172.18.0.0/16 dev br-d24a2c08641d  proto kernel  scope link  src 172.18.0.1 linkdown 
172.19.0.0/16 dev br-3c5fb6c312ed  proto kernel  scope link  src 172.19.0.1 linkdown 
172.20.0.0/16 dev br-499c8064af5f  proto kernel  scope link  src 172.20.0.1 
172.21.0.0/16 dev br-285f38aa49da  proto kernel  scope link  src 172.21.0.1 linkdown 
192.168.0.0/24 dev eth1  proto kernel  scope link  src 192.168.0.37  metric 100 

Après pas mal de recherche, j'ai compris que chaque conteneur crée sont propre pont.

Il est possible de lister les ponts créés par Docker avec la ligne de commande network ls.

alain@alain-Sys1:~/01_projets/e-v/server$ docker network ls
NETWORK ID          NAME               DRIVER          SCOPE 
2b2cd3362534        bridge             bridge          local 
285f38aa49da        client_default     bridge          local 
0a6fdf0ecffd        host               host            local 
b4d8afe9a1c1        none               null            local 
499c8064af5f        server_default     bridge          local 

Maintenant, il me reste à comprendre à quel pont est lié quel conteneur si je veux pouvoir les faire communiquer.

Le port des conteneurs est disponible via ps, mais ce n'est pas très parlant. Par contre on y retrouve dans la partie IMAGE une ressemblance avec ma liste de "networks".

alain@alain-Sys1:~/01_projets/e-v/server$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
7d4a629a6569        server_web          "bundle exec rails s "   8 minutes ago       Up 8 minutes                            server_web_run_25
f9c97439252b        postgres:9.6.0      "/docker-entrypoint.s"   14 hours ago        Up 8 minutes        5432/tcp            server_db_1

Je m'aperçois de la correspondance entre server_default et server_web.

Information confirmée lors de l'inspection de la partie Containers du pont serveur_default. Je trouve bien un élément serverwebrun_25 qui est identique à la colonne NAMES du résultat de docker ps.

alain@alain-Sys1:~/01_projets/e-v/server$ docker network inspect 499c8064af5f
"Containers": {
    "d11c83b3f7b12a02e0b598b4800ff3624eeb57ad51f485019e3d7738ce51fc4b": {
        "Name": "server_web_run_25",
        "EndpointID": "629d50de72eea4cd02dd07f7e95c63775db54709bb606d7a4cae6bcacf079a17",
        "MacAddress": "02:42:ac:12:00:03",
        "IPv4Address": "172.18.0.3/16",
        "IPv6Address": ""
    },
    "f9c97439252be559bd47b663843bec6b3910ba73adc5b950e4c234233cf82858": {
        "Name": "server_db_1",
        "EndpointID": "992cdc7cee86901d3fc9ab5e7bb43b359944b1458b6bdc046740637296e31d93",
        "MacAddress": "02:42:ac:12:00:02",
        "IPv4Address": "172.18.0.2/16",
        "IPv6Address": ""
    }
},

Une fois tout ceci pris en compte, je dois être en mesure de faire communiquer un conteneur avec un autre.

Mais mon objectif est de faire communiquer mes deux conteneurs sans avoir à chercher leur IP une fois installé sur une machine qui participe au projet !

Spécifier ses IPs

L'ip du gateway est l'ip que j'ai dans les ponts de mon réseau. L'IPv4Address est donc l'IP du conteneur et il communique via le gateway avec moi.

Donc il doit y avoir un moyen de forcer tout ça. En cherchant bien on trouve ce lien.

Je configure donc mon docker-compose en lui ajoutant dans la partie web:.

networks:
      rails:
        ipv4_address: 172.16.238.10

Afin de forcer mon conteneur à avoir cette IP.

Je configure aussi le network que j'ai nommé rails en spécifiant le gateway et le driver.

networks:
  rails:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: 172.16.238.0/24
        gateway: 172.16.238.1

Ça fonctionne bien. Une fois mon conteneur lancé, je peux pinger 172.16.238.10. Mais mon navigateur n'affiche toujours rien en locahost:3000.

Je fixe alors le serveur rails à utiliser (option -b) l'IP de mon conteneur et là .... mon navigateur affiche bien mon message rails en 172.16.238.10:3000.

alain@alain-Sys1:~/01_projets/e-v/server$ docker-compose run web
Creating network "server_rails" with driver "bridge"
Starting server_db_1
=> Booting Puma
=> Rails 5.0.0.1 application starting in development on http://172.16.238.10:3000
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.6.0 (ruby 2.2.2-p95), codename: Sleepy Sunday Serenity
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://172.16.238.10:3000
Use Ctrl-C to stop

Voici donc le docker-compose.yml final.

version: '2'
services:
  db:
    image: postgres:9.6.0
  web:
    build: .
    command: bundle exec rails s -p 3000 -b 172.16.238.10
    networks:
      rails:
        ipv4_address: 172.16.238.10
    volumes:
      - .:/server
    ports:
      - "3000:3000"
    depends_on:
      - db
networks:
  rails:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: 172.16.238.0/24
        gateway: 172.16.238.1

Conclusion

Ça n'a pas été difficile de mettre tout ceci en place, bien que les configurations réseau ne soient pas mon domaine de prédilection. Je suis assez impressionné par les possibilités qu'offre Docker ainsi que par la simplicité de mise en œuvre de solutions pérennes.

Évidement, les IPs que l'on désigne ne doivent pas être déjà utilisées sous peine de ne pas pouvoir lancer le conteneur. Mais mes conteneurs communiquent maintenant à chaque fois sans problème et ce, peu importe la machine qui travaille sur le projet.

Publié dans les catégories suivantes

dockerruby
comments powered by Disqus

Téléphone

+33 637 700 504

Adresse

Bordeaux, 33300
France