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.
comments powered by Disqus