Comunicazione tra più progetti composti da docker


253

Ho due docker-compose.ymlfile separati in due cartelle diverse:

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

Come posso assicurarmi che un container in frontpossa inviare richieste a un container in api?

So che l' --default-gatewayopzione può essere impostata utilizzando docker runper un singolo contenitore, in modo che un indirizzo IP specifico possa essere assegnato a questo contenitore, ma sembra che questa opzione non sia disponibile durante l'utilizzo docker-compose.

Attualmente finisco per fare un docker inspect my_api_container_ide guardo il gateway nell'output. Funziona ma il problema è che questo IP è attribuito casualmente, quindi non posso fare affidamento su di esso.

Un'altra forma di questa domanda potrebbe quindi essere:

  • Posso attribuire un indirizzo IP fisso a un particolare contenitore usando docker-compose?

Ma alla fine quello che sto cercando è:

  • Come possono comunicare tra loro due diversi progetti composti da docker?

4
Ho appena esaminato questo oggi di nuovo. Gli sviluppatori hanno finalmente ceduto e permesso la denominazione arbitraria della rete. Utilizzando il file di composizione versione 3.5 è possibile specificare un nome per la rete predefinita nella chiave "reti". Questo creerà una rete denominata senza il solito prefisso del nome del progetto se non esiste.
cstrutton,

Risposte:


325

Devi solo assicurarti che i container con cui vuoi parlare siano sulla stessa rete. Le reti sono un costrutto docker di prima classe e non specifico per la composizione.

# 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

Nota: alla rete della tua app viene assegnato un nome basato sul "nome del progetto", che si basa sul nome della directory in cui risiede, in questo caso è front_stato aggiunto un prefisso

Possono quindi parlare tra loro usando il nome del servizio. Da frontte puoi fare ping apie viceversa.


1
Jivan non è una soluzione. I container non dovrebbero avere bisogno di sapere nulla sull'host o essere manipolati in questo modo. La mia risposta è stata piuttosto breve, ho aggiornato con maggiori dettagli.
johnharris85,

3
Robert Moskal solo se vai in giro per ottenere l'ip del tuo docker host nei container. Meglio farli comunicare su una rete comune definita da docker.
johnharris85,

2
Si noti che il prefisso "front_" alla rete viene creato automaticamente dalla cartella in cui è in esecuzione. Quindi, se il tuo primo file comporre docker si troverà in "esempio / docker-compose.yml", si chiamerebbe invece "esempio_default".
AngryUbuntuNerd il

7
Puoi anche fornire un nome a una rete usando la nameproprietà, che disabiliterà la prepending automatica con il nome del progetto. Quindi entrambi i progetti possono utilizzare quella rete e crearla automaticamente se non esiste ancora.
SteveB,

2
@SteveB - Nota che la proprietà name funziona solo con i file
docker

78

Solo una piccola aggiunta alla grande risposta di @ johnharris85, quando si esegue un file di composizione docker, defaultviene creata una " " rete in modo da poterla semplicemente aggiungere all'altro file di composizione come rete esterna:

# 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

Per me questo approccio era più adatto perché non possedevo il primo file comporre docker e volevo comunicare con esso.


vagando nel modo corretto di assegnare un IP statico a questa rete esterna. Sono riuscito a farlo all'interno del services:tag, la sintassi sarebbe networks:quindi nidificata front_default:(rimuovere il "-") e quindi ipv4_address: '172.20.0.44'
annidiamo

76

AGGIORNAMENTO: a partire dalla versione 3.5 del file di composizione:

Questo ora funziona:

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

networks:
  proxynet:
    name: custom_network

docker-compose up -dentrerà a far parte di una rete chiamata "custom_network". Se non esiste, verrà creato!

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

Ora puoi farlo:

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

Questo creerà un contenitore che sarà sulla rete esterna.

Non riesco ancora a trovare alcun riferimento nei documenti, ma funziona!


Devi avviare i due servizi in un ordine specifico? Puoi iniziare uno dei due e il primo creerà la rete e il secondo si unirà ad essa?
slashdottir,

4
Il primo servizio (proxy sopra) crea la rete. La sintassi nel secondo esempio la unisce.
cstrutton,

2
@slashdottir È possibile non segnare la rete come esterno nel secondo servizio e sarà creato se non esiste ancora.
SteveB,

2
Funziona Ho appena lanciato una gocciolina DO con l'ultima finestra mobile composta. Ho modificato l'esempio in un vero esempio funzionante.
cstrutton,

1
Nel mio caso, questa si è rivelata una soluzione più adatta della risposta accettata. Il problema con la rete esterna era che era necessario avviare i contenitori in ordine predefinito. Per il mio cliente, questo non era accettabile. Una rete denominata (dal 3.5) si è rivelata la soluzione perfetta. Grazie.
Ygor,

25

Tutti i contenitori da apipossono unirsi alla rete front predefinita con la seguente configurazione:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

Vedi la guida alla composizione della finestra mobile: usando una rete preesistente (vedi in fondo)


12

Le informazioni sui post precedenti sono corrette, ma non contengono dettagli su come collegare i contenitori, che devono essere collegati come "collegamenti_ esterni".

Spero che questo esempio ti renda più chiaro:

  • Supponiamo di avere app1 / docker-compose.yml, con due servizi (svc11 e svc12) e app2 / docker-compose.yml con altri due servizi (svc21 e svc22) e supponiamo di dover connetterti in modo incrociato:

  • svc11 deve connettersi al contenitore di svc22

  • svc21 deve connettersi al contenitore di svc11.

Quindi la configurazione dovrebbe essere così:

questo è 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

questo è 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

6

A partire da Compose 1.18 (specifica 3.5), puoi semplicemente sovrascrivere la rete predefinita usando il tuo nome personalizzato per tutti i file Compose YAML di cui hai bisogno. È semplice come aggiungere loro quanto segue:

networks:
  default:
    name: my-app

Quanto sopra presuppone che tu abbia versionimpostato su 3.5(o superiore se non lo deprecano in 4+).

Altre risposte hanno indicato lo stesso; questo è un riassunto semplificato.


2

Assicurerei che tutti i container si trovino docker-composenella stessa rete componendoli contemporaneamente, usando:

docker compose --file ~/front/docker-compose.yml --file ~/api/docker-compose.yml up -d

Ciò mi consentirà, ad esempio, di creare un linko depends_onda un contenitore di fronte a un contenitore di API?
Jivan,

in realtà quando faccio quello che mi suggerisci, risposte composte da docker build path ~/front/api either does not exist or is not accessibleo con il contrario,build path ~/api/front either does not exist or is not accessible
Jivan,

1
Se le stai componendo allo stesso tempo, non dovresti averne bisogno. Verrà creata una rete con tutti i contenitori su di essa, tutti saranno in grado di comunicare tramite il nome del servizio dal file di composizione ( non il nome del contenitore).
Nauraushaun,

Potrebbe essere più semplice se i due file di composizione si trovano nella stessa cartella. Ma non penso che sia necessario - penso che dovrebbe funzionare in entrambi i modi.
Nauraushaun,

2
Questa soluzione non funziona, vedi il mio commento su questa discussione: github.com/docker/compose/issues/3530#issuecomment-222490501
johnharris85

2

AGGIORNAMENTO: a partire dalla versione 3.5 del file di composizione:

Ho riscontrato il problema simile e l'ho risolto aggiungendo una piccola modifica in uno dei miei progetti docker-compose.yml.

Ad esempio abbiamo due API scoringe ner. Scoringapi deve inviare una richiesta aner api per elaborare la richiesta di input. Per fare ciò, si suppone che entrambi condividano la stessa rete.

Nota: ogni contenitore ha una propria rete che viene creata automaticamente al momento dell'esecuzione dell'app all'interno della finestra mobile. Ad esempio, la rete API verrà creata come ner_defaulte il punteggio della rete API verrà chiamato comescoring default . Questa soluzione funzionerà per la versione: "3".

Come nello scenario sopra il mio punteggio api vuole comunicare con ner api quindi aggiungerò le seguenti righe. Ciò significa che ogni volta che creo il contenitore per ner api, questo viene automaticamente aggiunto alla rete scoring_default.

networks:
  default:
      external:
        name: scoring_default

ner / finestra mobile-compose.yml

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

networks:
  default:
      external:
        name: scoring_default

scoring / finestra mobile-compose.yml

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

Possiamo vedere come i contenitori sopra riportati facciano ora parte della stessa rete chiamata scoring_defaultusando il comando:

la finestra mobile ispeziona 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": ""
    },
    ...
}

1

Puoi aggiungere un .envfile in tutti i tuoi progetti contenenti COMPOSE_PROJECT_NAME=somename.

COMPOSE_PROJECT_NAME sovrascrive il prefisso utilizzato per assegnare un nome alle risorse, in questo modo verranno utilizzati tutti i tuoi progettisomename_default come rete, consentendo ai servizi di comunicare tra loro come se fossero nello stesso progetto.

NB: riceverai avvisi per i contenitori "orfani" creati da altri progetti.


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

0

Per usare un'altra rete comporre docker, basta fare queste (per condividere le reti tra comporre docker):

  1. Esegui il primo progetto composto da docker up -d
  2. Trova il nome di rete della prima finestra mobile-componi da: docker network ls(Contiene il nome del progetto della directory principale)
  3. Quindi utilizzare quel nome con questa struttura in basso nel secondo file comporre finestra mobile.

secondo 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

0

Un'altra opzione è solo far funzionare il primo modulo con 'docker-compose' controllare l'ip relativo al modulo e collegare il secondo modulo con la rete precedente come esterno e puntare l'ip interno

esempio app1 - nuova rete creata nelle linee di servizio, contrassegna come esterno: vero nella parte inferiore app2 - indica la "nuova rete" creata da app1 quando sale, segna come esterno: vero nella parte inferiore e impostato nella configurazione per connettersi, l'ip che app1 ha in questa rete.

Con questo, dovresti essere in grado di parlare tra loro

* in questo modo è solo per il focus del test locale, al fine di non fare una configurazione troppo complessa ** So che è molto 'patch mode' ma funziona per me e penso che sia così semplice che alcuni altri possano trarne vantaggio


0

Se sei

  • cercando di comunicare tra due container da diversi progetti di composizione docker e non vuoi usare la stessa rete (perché diciamo che avrebbero un contenitore PostgreSQL o Redis sulla stessa porta e preferiresti non cambiare queste porte e non usarlo nella stessa rete)
  • svilupparsi localmente e voler imitare la comunicazione tra due progetti di composizione docker
  • esecuzione di due progetti di composizione docker su localhost
  • sviluppando in particolare app Django o API Django Rest Framework (drf) e eseguendo app all'interno del container su alcune porte esposte
  • ottenere Connection refusedmentre si tenta di comunicare tra due contenitori

E tu vuoi

  • il contenitore api_acomunica api_b(o viceversa) senza la stessa "rete docker"

(esempio sotto)

puoi usare "host" del secondo contenitore come IP del tuo computer e porta mappata dall'interno del contenitore Docker. Puoi ottenere l'IP del tuo computer con questo script (da: Trovare gli indirizzi IP locali usando lo stdlib di 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

Esempio:

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

all'interno del api_acontenitore si esegue l'app Django: manage.py runserver 0.0.0.0:8000

e secondo docker-compose.yml di altri progetti:

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

all'interno del api_bcontenitore si esegue l'app Django: manage.py runserver 0.0.0.0:8001

E cercando di connettersi da contenitore api_aper api_bpoi URLapi_b contenitore sarà: http://<get_ip_from_script_above>:8001/

Può essere particolarmente utile se stai usando anche più di due (tre o più) progetti di composizione docker ed è difficile fornire una rete comune per tutto questo - è una buona soluzione e soluzione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.