Komunikacja między wieloma projektami tworzącymi dokery


254

Mam dwa osobne docker-compose.ymlpliki w dwóch różnych folderach:

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

Jak mogę się upewnić, że kontener w frontmoże wysyłać żądania do kontenera w api?

Wiem, że tę --default-gatewayopcję można ustawić za pomocą docker rundla pojedynczego kontenera, dzięki czemu można przypisać określony adres IP do tego kontenera, ale wydaje się, że ta opcja nie jest dostępna podczas korzystania docker-compose.

Obecnie kończę docker inspect my_api_container_idi patrzę na bramę w danych wyjściowych. Działa, ale problem polega na tym, że to IP jest losowo przypisywane, więc nie mogę na nim polegać.

Inną formą tego pytania może być zatem:

  • Czy mogę przypisać stały adres IP do konkretnego kontenera przy użyciu funkcji dokowania-tworzenia?

Ale w końcu to, na czym mi zależy:

  • W jaki sposób dwa różne projekty dokowania mogą się ze sobą komunikować?

4
Po prostu znów się temu przyjrzałem. Twórcy wreszcie ustąpili i zezwolili na dowolne nazewnictwo sieci. Za pomocą komponentu pliku w wersji 3.5 możesz określić nazwę domyślnej sieci pod kluczem „sieci”. Spowoduje to utworzenie nazwanej sieci bez zwykłego przedrostka nazwy projektu, jeśli nie istnieje.
cstrutton

Odpowiedzi:


325

Musisz tylko upewnić się, że kontenery, z którymi chcesz rozmawiać, znajdują się w tej samej sieci. Sieci są pierwszorzędną konstrukcją dokującą i nie są specyficzne do tworzenia.

# 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

Uwaga: sieć Twoja aplikacja jest nadać nazwę opartą na „Nazwa projektu”, która oparta jest na nazwie katalogu Zamieszkuje w tym przypadku prefiks front_został dodany

Następnie mogą rozmawiać ze sobą przy użyciu nazwy usługi. Od frontmożna zrobić ping apii vice versa.


1
Jivan to nie rozwiązanie. Twoje kontenery nie powinny wiedzieć nic o hoście ani manipulować w ten sposób. Moja odpowiedź była jednak krótka, zaktualizowałem ją bardziej szczegółowo.
johnharris85

3
Robert Moskal tylko wtedy, gdy włamiesz się, aby uzyskać adres IP hosta dokera w kontenerach. Lepiej, aby komunikowali się we wspólnej sieci zdefiniowanej przez dokera.
johnharris85

2
Uwaga: prefiks „front_” do sieci jest tworzony automatycznie z folderu, w którym jest uruchomiony. Więc jeśli twój pierwszy plik skomponowania dokera zostałby umieszczony w „example / docker-compose.yml”, zamiast tego byłby nazwany „przykład_default”.
AngryUbuntuNerd

7
Możesz także podać nazwę sieci za pomocą namewłaściwości, która wyłączy automatyczne dodawanie z nazwą projektu. Wówczas każdy projekt może korzystać z tej sieci i utworzyć ją automatycznie, jeśli jeszcze nie istnieje.
SteveB

2
@SteveB - Należy pamiętać, że właściwość name działa tylko w przypadku plików skomponowanych w
oknie dokowanym w

78

Tylko małe przyzwolenie na świetną odpowiedź @ johnharris85, kiedy uruchamiasz plik komponowania dokera, defaulttworzona jest sieć „ ”, dzięki czemu możesz po prostu dodać go do innego pliku tworzenia jako sieć zewnętrzna:

# 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

Dla mnie to podejście było bardziej odpowiednie, ponieważ nie posiadałem pierwszego pliku skomponowanego w oknie dokowanym i chciałem się z nim komunikować.


po prostu wędruje we właściwy sposób, aby przypisać statyczny adres IP dla tej sieci zewnętrznej. services:Zmodyfikowałem to, aby zrobić to w obrębie tagu, sintax zostanie networks:następnie zagnieżdżony front_default:(usuń „-”), a następnie zagnieżdżymy statyczny adres IP:ipv4_address: '172.20.0.44'
Junior Mayhé

76

AKTUALIZACJA: Od momentu skomponowania pliku w wersji 3.5:

To teraz działa:

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

networks:
  proxynet:
    name: custom_network

docker-compose up -ddołączy do sieci o nazwie „custom_network”. Jeśli nie istnieje, zostanie utworzony!

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

Teraz możesz to zrobić:

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

Spowoduje to utworzenie kontenera, który będzie w sieci zewnętrznej.

Nie mogę znaleźć żadnego odniesienia w dokumentacji, ale działa!


Czy musisz uruchomić dwie usługi w określonej kolejności? Czy możesz uruchomić jeden z nich, a pierwszy utworzy sieć, a drugi do niej dołączy?
slashdottir

4
Pierwsza usługa (proxy powyżej) tworzy sieć. Łączy się składnia w drugim przykładzie.
cstrutton

2
@slashdottir Można nie oznaczyć sieć jako zewnętrzny w drugim serwisu i zostanie on utworzony, jeśli jeszcze nie istnieje.
SteveB

2
To działa. Właśnie wyrzuciłem kroplę DO z najnowszą kompozycją dokera. Edytowałem przykład do rzeczywistego przykładu roboczego.
cstrutton

1
W moim przypadku było to bardziej odpowiednie rozwiązanie niż przyjęta odpowiedź. Problem z siecią zewnętrzną polegał na tym, że wymagał uruchamiania kontenerów w ustalonej kolejności. Dla mojego klienta było to nie do przyjęcia. Sieć nazwana (od wersji 3.5) okazała się idealnym rozwiązaniem. Dzięki.
ygor

25

Wszystkie kontenery z apimogą dołączyć do front domyślnej sieci z następującą konfiguracją:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

Zobacz przewodnik tworzenia dokerów: za pomocą istniejącej sieci (patrz na dole)


12

Informacje z poprzednich postów są poprawne, ale nie zawierają szczegółowych informacji na temat łączenia kontenerów, które powinny być połączone jako „external_links”.

Mam nadzieję, że ten przykład wyjaśni ci:

  • Załóżmy, że masz app1 / docker-compose.yml z dwiema usługami (svc11 i svc12) oraz app2 / docker-compose.yml z dwoma dodatkowymi usługami (svc21 i svc22) i załóżmy, że musisz połączyć się w sposób krzyżowy:

  • svc11 musi połączyć się z kontenerem svc22

  • svc21 musi połączyć się z kontenerem svc11.

Konfiguracja powinna wyglądać następująco:

to jest 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

to jest 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

Od wersji Compose 1.18 (specyfikacja 3.5) możesz po prostu zastąpić domyślną sieć, używając własnej niestandardowej nazwy dla wszystkich potrzebnych plików Compose YAML. Jest to tak proste, jak dodanie do nich następujących elementów:

networks:
  default:
    name: my-app

Powyżej zakłada się, że versionustawiłeś 3.5(lub wyżej, jeśli nie będą one zastępować w 4+).

Inne odpowiedzi wskazują na to samo; to jest uproszczone podsumowanie.


2

Chciałbym upewnić się, że wszystkie kontenery są docker-composepodłączone do tej samej sieci, tworząc je razem w tym samym czasie, używając:

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

Czy pozwoli mi to na przykład na zrobienie jednego linklub depends_onjednego pojemnika z przodu na jeden pojemnik z API?
Jivan

właściwie kiedy robię to, co sugerujesz, odpowiedzi build path ~/front/api either does not exist or is not accessiblew oknie dokowanym lub na odwrótbuild path ~/api/front either does not exist or is not accessible
Jivan,

1
Jeśli komponujesz je w tym samym czasie, nie musisz tego robić. Zostanie utworzona sieć ze wszystkimi twoimi kontenerami, wszystkie będą mogły komunikować się za pośrednictwem nazwy usługi z pliku tworzenia ( nie nazwy kontenera).
Nauraushaun

Może być łatwiej, jeśli dwa pliki tworzenia będą znajdować się w tym samym folderze. Ale nie uważam, że jest to konieczne - myślę, że tak powinno działać.
Nauraushaun

2
To rozwiązanie nie działa, zobacz mój komentarz do tego wątku: github.com/docker/compose/issues/3530#issuecomment-222490501
johnharris85

2

AKTUALIZACJA: Od momentu skomponowania pliku w wersji 3.5:

Natknąłem się na podobny problem i rozwiązałem go, dodając niewielką zmianę w jednym z moich projektów docker-compose.yml.

Na przykład mamy dwa API scoringi ner. ScoringInterfejs API musi wysłać do nerinterfejsu API żądanie przetworzenia żądania wejściowego. Aby to zrobić, oboje powinni dzielić tę samą sieć.

Uwaga: każdy kontener ma własną sieć, która jest automatycznie tworzona w momencie uruchomienia aplikacji w oknie dokowanym. Na przykład zostanie utworzona sieć ner api jak ner_defaulti sieć oceniająca api zostanie nazwana jako scoring default. To rozwiązanie będzie działać dla wersji: „3”.

Jak w powyższym scenariuszu mój punktacyjny interfejs API chce komunikować się z interfejsem Ner API, więc dodam następujące wiersze. Co oznacza, że ​​ilekroć tworzę kontener dla interfejsu API, to automatycznie dodaje się do sieci scoring_default.

networks:
  default:
      external:
        name: scoring_default

ner / docker-compose.yml

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

networks:
  default:
      external:
        name: scoring_default

scoreing / docker-compose.yml

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

Widzimy to, jak powyższe kontenery są teraz częścią tej samej sieci nazywanej scoring_defaultza pomocą polecenia:

doker sprawdza punktację domyślną

{
    "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

Możesz dodać .envplik do wszystkich swoich projektów zawierających COMPOSE_PROJECT_NAME=somename.

COMPOSE_PROJECT_NAME przesłania prefiks używany do nazywania zasobów, ponieważ wszystkie twoje projekty będą używać somename_defaultich sieci, dzięki czemu usługi mogą komunikować się ze sobą, tak jak były w tym samym projekcie.

Uwaga: Otrzymasz ostrzeżenia dla „osieroconych” kontenerów utworzonych z innych projektów.


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

Aby użyć innej sieci składającej się z dokerów, wystarczy wykonać następujące czynności (aby udostępnić sieci między kompozycjami dokerów):

  1. Uruchom pierwszy projekt skomponowania dokera przez up -d
  2. Znajdź nazwę sieci pierwszego skomponowanego okna dokowanego przez: docker network ls(Zawiera nazwę projektu katalogu głównego)
  3. Następnie użyj tej nazwy według tej struktury poniżej w drugim pliku tworzenia dokerów.

drugi 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

Inną opcją jest po prostu uruchomienie pierwszego modułu za pomocą funkcji „docker-compose”, sprawdzenie adresu IP powiązanego z modułem i połączenie drugiego modułu z poprzednią siecią, jak zewnętrzny, i skierowanie wewnętrznego adresu IP

przykład app1 - nowa sieć utworzona w liniach serwisowych, oznacz jako zewnętrzny: prawda na dole app2 - wskaż „nową sieć” utworzoną przez app1, gdy idzie w górę, zaznacz jako zewnętrzny: prawda na dole i ustaw w konfiguracji do połączenia, ip, które aplikacja1 ma w tej sieci.

Dzięki temu powinieneś być w stanie ze sobą rozmawiać

* ten sposób służy wyłącznie do testowania lokalnego, aby nie robić zbyt skomplikowanej konfiguracji ** Wiem, że jest to bardzo łatwa metoda, ale działa dla mnie i myślę, że jest tak prosta, że ​​inni mogą z tego skorzystać


0

Jeśli jesteś

  • próbuje komunikować się między dwoma kontenerami z różnych projektów tworzących dokery i nie chce korzystać z tej samej sieci (ponieważ powiedzmy, że miałyby kontener PostgreSQL lub Redis na tym samym porcie i wolisz nie zmieniać tych portów i nie używać ich w tej samej sieci)
  • rozwijają się lokalnie i chcą naśladować komunikację między dwoma projektami komponowania dokerów
  • uruchamianie dwóch projektów tworzenia dokerów na localhost
  • tworzenie aplikacji Django lub API Django Rest Framework (drf) i uruchamianie aplikacji w kontenerze na niektórych odsłoniętych portach
  • uzyskiwanie Connection refusedpodczas próby komunikacji między dwoma kontenerami

A ty chcesz

  • kontener api_akomunikuje się z api_b(lub odwrotnie) bez tej samej „sieci dokerów”

(przykład poniżej)

możesz użyć „hosta” drugiego kontenera jako adresu IP komputera i portu odwzorowanego z wnętrza kontenera Docker. Możesz uzyskać adres IP swojego komputera za pomocą tego skryptu (z: Znajdowanie lokalnych adresów IP za pomocą stdlib Pythona ):

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

Przykład:

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

wewnątrz api_akontenera uruchomiona jest aplikacja Django: manage.py runserver 0.0.0.0:8000

i drugi docker-compose.yml z innego projektu:

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

wewnątrz api_bkontenera uruchomiona jest aplikacja Django: manage.py runserver 0.0.0.0:8001

I próba połączenia z kontenera api_ado api_badresu URL api_bkontenera będzie: http://<get_ip_from_script_above>:8001/

Może być szczególnie cenny, jeśli używasz nawet więcej niż dwóch (trzech lub więcej) projektów dokowania i trudno jest zapewnić wspólną sieć dla wszystkich - jest to dobre obejście i rozwiązanie

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.