Communication entre plusieurs projets de composition de docker

253

J'ai deux docker-compose.ymlfichiers distincts dans deux dossiers différents:

  • ~/front/docker-compose.yml
  • ~/api/docker-compose.yml

Comment puis-je m'assurer qu'un conteneur dans frontpeut envoyer des demandes à un conteneur dans api?

Je sais que cette --default-gatewayoption peut être définie à l'aide docker rund'un conteneur individuel, afin qu'une adresse IP spécifique puisse être attribuée à ce conteneur, mais il semble que cette option ne soit pas disponible lors de l'utilisation docker-compose.

Actuellement, je finis par faire un docker inspect my_api_container_idet regarde la passerelle dans la sortie. Cela fonctionne, mais le problème est que cette adresse IP est attribuée au hasard, donc je ne peux pas me fier à elle.

Une autre forme de cette question pourrait donc être:

  • Puis-je attribuer une adresse IP fixe à un conteneur particulier en utilisant docker-compose?

Mais à la fin ce que je cherche c'est:

  • Comment deux projets de composition de docker différents peuvent-ils communiquer entre eux?
Jivan
la source
4
Je viens de me pencher à nouveau sur ce sujet aujourd'hui. Les développeurs ont finalement cédé et ont autorisé des noms de réseau arbitraires. En utilisant la version 3.5 du fichier de composition, vous pouvez spécifier un nom pour le réseau par défaut sous la clé «réseaux». Cela créera un réseau nommé sans le préfixe de nom de projet habituel s'il n'existe pas.
cstrutton

Réponses:

325

Il vous suffit de vous assurer que les conteneurs dont vous souhaitez vous entretenir se trouvent sur le même réseau. Les réseaux sont une construction de docker de première classe et ne sont pas spécifiques à la composition.

# front/docker-compose.yml
version: '2'
services:
  front:
    ...
    networks:
      - some-net
networks:
  some-net:
    driver: bridge

...

# api/docker-compose.yml
version: '2'
services:
  api:
    ...
    networks:
      - front_some-net
networks:
  front_some-net:
    external: true

Remarque: le réseau de votre application reçoit un nom basé sur le «nom du projet», qui est basé sur le nom du répertoire dans lequel il vit, dans ce cas un préfixe a front_été ajouté

Ils peuvent ensuite se parler en utilisant le nom du service. De frontvous pouvez faire ping apiet vice versa.

johnharris85
la source
1
Jivan c'est une non-solution. Vos conteneurs ne devraient pas avoir besoin de savoir quoi que ce soit sur l'hôte ou d'être manipulés comme ça. Ma réponse était assez courte cependant, j'ai mis à jour avec plus de détails.
johnharris85
3
Robert Moskal uniquement si vous piratez pour obtenir l'IP de votre hôte docker dans les conteneurs. Mieux vaut les faire communiquer sur un réseau défini par un docker commun.
johnharris85
2
Veuillez noter que le préfixe "front_" du réseau est créé automatiquement à partir du dossier sur lequel il s'exécute. Donc, si votre premier fichier docker-compose se trouve dans "example / docker-compose.yml", il sera appelé "example_default" à la place.
AngryUbuntuNerd
7
Vous pouvez également fournir un nom à un réseau à l'aide de la namepropriété, ce qui désactivera l'ajout automatique avec le nom du projet. Ensuite, l'un ou l'autre projet peut utiliser ce réseau et le créer automatiquement s'il n'existe pas encore.
SteveB
2
@SteveB - Notez que la propriété name ne fonctionne qu'à partir des fichiers docker-compose version 3.5 et plus
kramer65
78

Juste un petit ajout à la grande réponse de @ johnharris85, lorsque vous exécutez un fichier de composition docker, un " default" réseau est créé afin que vous puissiez simplement l'ajouter à l'autre fichier de composition en tant que réseau externe:

# front/docker-compose.yml 
version: '2' 
  services:   
    front_service:
    ...

...

# api/docker-compose.yml
version: '2'
services:
  api_service:
    ...
    networks:
      - front_default
networks:
  front_default:
    external: true

Pour moi, cette approche était plus adaptée car je ne possédais pas le premier fichier Docker-compose et je voulais communiquer avec lui.

Tal Joffe
la source
errant juste la bonne façon d'attribuer une adresse IP statique à ce réseau externe. J'ai réussi à le faire dans la services:balise, la sintax serait networks:alors imbriquée front_default:(supprimez le "-") puis nous imbriquons une IP statique:ipv4_address: '172.20.0.44'
Junior Mayhé
76

MISE À JOUR: Depuis la version 3.5 du fichier de composition:

Cela fonctionne maintenant:

version: "3.5"
services:
  proxy:
    image: hello-world
    ports:
      - "80:80"
    networks:
      - proxynet

networks:
  proxynet:
    name: custom_network

docker-compose up -drejoindra un réseau appelé 'custom_network'. S'il n'existe pas, il sera créé!

root@ubuntu-s-1vcpu-1gb-tor1-01:~# docker-compose up -d
Creating network "custom_network" with the default driver
Creating root_proxy_1 ... done

Maintenant, vous pouvez le faire:

version: "2"
services:
  web:
    image: hello-world
    networks:
      - my-proxy-net
networks:
  my-proxy-net:
    external:
      name: custom_network

Cela créera un conteneur qui sera sur le réseau externe.

Je ne trouve pas encore de référence dans la documentation mais cela fonctionne!

cstrutton
la source
Devez-vous démarrer les deux services dans un ordre spécifique? Pouvez-vous démarrer l'un ou l'autre, et le premier créera le réseau et le second le rejoindra?
slashdottir
4
Le premier service (proxy ci-dessus) crée le réseau. La syntaxe du deuxième exemple la rejoint.
cstrutton
2
@slashdottir Vous ne pouvez pas marquer le réseau comme externe dans le deuxième service et il sera créé s'il n'existe pas encore.
SteveB
2
Ça marche. Je viens de créer une gouttelette DO avec la dernière composition de docker. J'ai modifié l'exemple en un exemple de travail réel.
cstrutton
1
Dans mon cas, cela s'est avéré être une solution plus appropriée que la réponse acceptée. Le problème avec le réseau externe était qu'il nécessitait de démarrer les conteneurs dans un ordre prédéfini. Pour mon client, ce n'était pas acceptable. Un réseau nommé (depuis 3.5) s'est avéré être une solution parfaite. Merci.
Ygor
25

Tous les conteneurs de apipeuvent rejoindre le réseau front par défaut avec la configuration suivante:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

Voir le guide de composition de docker: utiliser un réseau préexistant (voir en bas)

dedek
la source
12

Les informations des articles précédents sont correctes, mais elles ne contiennent pas de détails sur la façon de lier les conteneurs, qui doivent être connectés en tant que "liens_externes".

J'espère que cet exemple vous rendra plus clair:

  • Supposons que vous ayez app1 / docker-compose.yml, avec deux services (svc11 et svc12), et app2 / docker-compose.yml avec deux autres services (svc21 et svc22) et supposez que vous devez vous connecter de manière croisée:

  • svc11 doit se connecter au conteneur de svc22

  • svc21 doit se connecter au conteneur de svc11.

La configuration devrait donc être comme ceci:

c'est app1 / docker-compose.yml:


version: '2'
services:
    svc11:
        container_name: container11
        [..]
        networks:
            - default # this network
            - app2_default # external network
        external_links:
            - container22:container22
        [..]
    svc12:
       container_name: container12
       [..]

networks:
    default: # this network (app1)
        driver: bridge
    app2_default: # external network (app2)
        external: true

c'est app2 / docker-compose.yml:


version: '2'
services:
    svc21:
        container_name: container21
        [..]
        networks:
            - default # this network (app2)
            - app1_default # external network (app1)
        external_links:
            - container11:container11
        [..]
    svc22:
       container_name: container22
       [..]

networks:
    default: # this network (app2)
        driver: bridge
    app1_default: # external network (app1)
        external: true
Daniel Blanco
la source
6

Depuis Compose 1.18 (spécification 3.5), vous pouvez simplement remplacer le réseau par défaut en utilisant votre propre nom personnalisé pour tous les fichiers Compose YAML dont vous avez besoin. C'est aussi simple que de leur ajouter ce qui suit:

networks:
  default:
    name: my-app

Ce qui précède suppose que vous l'avez versiondéfini 3.5(ou au-dessus s'ils ne le déprécient pas dans 4+).

D'autres réponses ont montré la même chose; il s'agit d'un résumé simplifié.

emyller
la source
2

Je m'assurerais que tous les conteneurs sont docker-composeconnectés au même réseau en les composant ensemble en même temps, en utilisant:

docker compose --file ~/front/docker-compose.yml --file ~/api/docker-compose.yml up -d
Nauraushaun
la source
Cela me permettra-t-il, par exemple, de faire un linkou depends_ond'un conteneur de façade à un conteneur d'api?
Jivan
en fait, quand je fais ce que vous proposez, des réponses de composition de docker, build path ~/front/api either does not exist or is not accessibleou avec l'inverse,build path ~/api/front either does not exist or is not accessible
Jivan
1
Si vous les composez en même temps, vous ne devriez pas en avoir besoin. Un réseau sera créé avec tous vos conteneurs dessus, ils pourront tous communiquer via le nom du service depuis le fichier de composition ( pas le nom du conteneur).
Nauraushaun
Cela pourrait être plus facile si les deux fichiers de composition se trouvent dans le même dossier. Mais je ne pense pas que ce soit nécessaire - je pense que cela devrait fonctionner de toute façon.
Nauraushaun
2
Cette solution ne fonctionne pas, voir mon commentaire sur ce fil: github.com/docker/compose/issues/3530#issuecomment-222490501
johnharris85
2

MISE À JOUR: Depuis la version 3.5 du fichier de composition:

J'ai rencontré le problème similaire et je l'ai résolu en ajoutant un petit changement dans l'un de mes projets docker-compose.yml.

Par exemple, nous avons deux api scoringet ner. Scoringapi doit envoyer une demande à l' nerapi pour traiter la demande d'entrée. Pour ce faire, ils doivent tous deux partager le même réseau.

Remarque: Chaque conteneur possède son propre réseau qui est automatiquement créé au moment de l'exécution de l'application dans Docker. Par exemple, le réseau ner api sera créé comme ner_defaultet le réseau api de notation sera nommé comme scoring default. Cette solution fonctionnera pour la version: '3'.

Comme dans le scénario ci-dessus, mon api de notation veut communiquer avec ner api, alors j'ajouterai les lignes suivantes. Ce qui signifie que chaque fois que je crée le conteneur pour ner api, il est automatiquement ajouté au réseau scoring_default.

networks:
  default:
      external:
        name: scoring_default

ner / docker-compose.yml

version: '3'
services:
  ner:
    build: .
    ...

networks:
  default:
      external:
        name: scoring_default

notation / docker-compose.yml

version: '3'
services:
  api:
    build: .
    ...

Nous pouvons voir comment les conteneurs ci-dessus font maintenant partie du même réseau appelé scoring_defaultà l'aide de la commande:

docker inspect scoring_default

{
    "Name": "scoring_default",
        ....
    "Containers": {
    "14a6...28bf": {
        "Name": "ner_api",
        "EndpointID": "83b7...d6291",
        "MacAddress": "0....",
        "IPv4Address": "0.0....",
        "IPv6Address": ""
    },
    "7b32...90d1": {
        "Name": "scoring_api",
        "EndpointID": "311...280d",
        "MacAddress": "0.....3",
        "IPv4Address": "1...0",
        "IPv6Address": ""
    },
    ...
}
Nomiluks
la source
1

Vous pouvez ajouter un .envfichier dans tous vos projets contenant COMPOSE_PROJECT_NAME=somename.

COMPOSE_PROJECT_NAME remplace le préfixe utilisé pour nommer les ressources, car tous vos projets utiliseront somename_defaultcomme réseau, ce qui permet aux services de communiquer entre eux comme ils l'étaient dans le même projet.

NB: Vous recevrez des avertissements pour les conteneurs "orphelins" créés à partir d'autres projets.

Exagone313
la source
0
version: '2'
services:
  bot:
    build: .
    volumes:
      - '.:/home/node'
      - /home/node/node_modules
    networks:
      - my-rede
    mem_limit: 100m
    memswap_limit: 100m
    cpu_quota: 25000
    container_name: 236948199393329152_585042339404185600_bot
    command: node index.js
    environment:
      NODE_ENV: production
networks:
  my-rede:
    external:
      name: name_rede_externa
Pedro
la source
0

Pour utiliser un autre réseau de composition de docker, vous n'avez qu'à effectuer ces opérations (pour partager des réseaux entre compositions de docker):

  1. Exécutez le premier projet docker-compose en up -d
  2. Recherchez le nom de réseau du premier docker-compose par: docker network ls(Il contient le nom du projet de répertoire racine)
  3. Utilisez ensuite ce nom par cette structure ci-dessous dans le deuxième fichier docker-compose.

deuxième docker-compose.yml

version: '3'
services:
  service-on-second-compose:  # Define any names that you want.
    .
    .
    .
    networks:
      - <put it here(the network name that comes from "docker network ls")>

networks:
  - <put it here(the network name that comes from "docker network ls")>:
    external: true
Ali Hallaji
la source
0

Une autre option consiste simplement à exécuter le premier module avec la vérification «docker-compose» de l'ip associée au module, et à connecter le deuxième module au réseau précédent comme externe, et à pointer l'IP interne

exemple app1 - nouveau réseau créé dans les lignes de service, marque comme externe: vrai en bas app2 - indique le "nouveau réseau" créé par app1 lorsqu'il monte, marque comme externe: vrai en bas, et défini dans la configuration pour se connecter, l'ip que app1 a dans ce réseau.

Avec cela, vous devriez pouvoir vous parler

* cette façon est juste pour le focus de test local, afin de ne pas faire une configuration trop complexe ** Je sais que c'est très `` patch '' mais fonctionne pour moi et je pense que c'est si simple que d'autres peuvent en profiter

leonardo rey
la source
0

Si vous êtes

  • essayer de communiquer entre deux conteneurs de projets de composition de docker différents et ne pas vouloir utiliser le même réseau (parce que disons qu'ils auraient un conteneur PostgreSQL ou Redis sur le même port et que vous préféreriez ne pas changer ces ports et ne pas l'utiliser) sur le même réseau)
  • développer localement et vouloir imiter la communication entre deux projets de composition docker
  • exécution de deux projets docker-compose sur localhost
  • développer en particulier les applications Django ou l'API Django Rest Framework (drf) et exécuter l'application à l'intérieur du conteneur sur un port exposé
  • obtenir Connection refuseden essayant de communiquer entre deux conteneurs

Et tu veux

  • le conteneur api_acommunique avec api_b(ou vice versa) sans le même "réseau docker"

(exemple ci-dessous)

vous pouvez utiliser "l'hôte" du deuxième conteneur comme IP de votre ordinateur et le port mappé depuis l'intérieur du conteneur Docker. Vous pouvez obtenir l'IP de votre ordinateur avec ce script (à partir de: Trouver des adresses IP locales en utilisant stdlib de Python ):

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

Exemple:

project_api_a/docker-compose.yml:

networks:
  app-tier:
    driver: bridge

services:
  api:
    container_name: api_a
    image: api_a:latest
    depends_on:
      - postgresql
    networks:
      - app-tier

à l'intérieur du api_aconteneur, vous exécutez l'application Django: manage.py runserver 0.0.0.0:8000

et le deuxième docker-compose.yml d'un autre projet:

project_api_b/docker-compose-yml :

networks:
  app-tier:
    driver: bridge

services:
  api:
    container_name: api_b
    image: api_b:latest
    depends_on:
      - postgresql
    networks:
      - app-tier

à l'intérieur du api_bconteneur, vous exécutez l'application Django: manage.py runserver 0.0.0.0:8001

Et essayer de se connecter du conteneur api_aà l' api_bURL du api_bconteneur sera: http://<get_ip_from_script_above>:8001/

Cela peut être particulièrement utile si vous utilisez encore plus de deux (trois ou plus) projets de composition de docker et qu'il est difficile de fournir un réseau commun pour tout cela - c'est une bonne solution de contournement et une bonne solution.

Rafał
la source