Связь между несколькими проектами Docker-Compose

256

У меня есть два отдельных docker-compose.ymlфайла в двух разных папках:

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

Как я могу убедиться, что контейнер frontможет отправлять запросы в контейнер api?

Я знаю, что эта --default-gatewayопция может быть установлена ​​с использованием docker runотдельного контейнера, так что этому контейнеру может быть назначен определенный IP-адрес, но кажется, что эта опция недоступна при использовании docker-compose.

В настоящее время я делаю docker inspect my_api_container_idи смотрю на шлюз в выводе. Это работает, но проблема в том, что этот IP-адрес присваивается случайным образом, поэтому я не могу на него полагаться.

Таким образом, другой формой этого вопроса может быть:

  • Могу ли я присвоить фиксированный IP-адрес конкретному контейнеру с помощью docker-compose?

Но в итоге я присматриваю за:

  • Как два разных проекта, создаваемых в Docker, могут общаться друг с другом?
Дживан
источник
4
Я только сегодня снова посмотрел на это. Разработчики наконец уступили и позволили произвольное именование сети. Используя compose file version 3.5, вы можете указать имя для сети по умолчанию под ключом «networks». Это создаст именованную сеть без обычного префикса имени проекта, если он не существует ..
cstrutton

Ответы:

329

Вам просто нужно убедиться, что контейнеры, с которыми вы хотите общаться друг с другом, находятся в одной сети. Сети представляют собой первоклассную конструкцию докера и не предназначены для создания.

# 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

Примечание: сети вашего приложения присваивается имя на основе «имени проекта», которое основано на имени каталога, в котором оно находится, в этом случае front_был добавлен префикс

Затем они могут общаться друг с другом, используя имя службы. От frontтебя можно сделать ping apiи наоборот.

johnharris85
источник
1
Дживан, это не решение проблемы. Ваши контейнеры не должны знать что-либо о хосте или манипулировать подобным образом. Мой ответ был довольно коротким, но я обновил более подробно.
johnharris85
3
Роберт Москаль, только если вы взломаете ip вашего хоста докера в контейнеры. Лучше, чтобы они общались в общей определенной докером сети.
johnharris85
2
Обратите внимание, что префикс "front_" для сети создается автоматически из папки, в которой он запущен. Поэтому, если ваш первый файл docker-compose будет расположен в «example / docker-compose.yml», он будет называться «example_default».
AngryUbuntuNerd
7
Вы также можете указать имя сети, используя nameсвойство, которое отключит автоматическое добавление с именем проекта. Тогда любой проект может использовать эту сеть и автоматически создать ее, если она еще не существует.
SteveB
2
@SteveB - обратите внимание, что свойство name работает только с файлами docker-compose версии 3.5 и выше
kramer65
79

ОБНОВЛЕНИЕ: Начиная с версии 3.5 файла:

Теперь это работает:

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

networks:
  proxynet:
    name: custom_network

docker-compose up -dприсоединится к сети под названием «custom_network». Если его не существует, он будет создан!

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

Теперь вы можете сделать это:

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

Это создаст контейнер, который будет во внешней сети.

Я не могу найти никаких ссылок в документах, но это работает!

cstrutton
источник
Нужно ли запускать две службы в определенном порядке? Можете ли вы запустить любой из них, и первый создаст сеть, а второй присоединится к ней?
slashdottir
4
Первый сервис (прокси выше) создает сеть. Синтаксис во втором примере присоединяется к нему.
cstrutton
2
@slashdottir Вы не можете пометить сеть как внешнюю во второй службе, и она будет создана, если она еще не существует.
SteveB
2
Это работает. Я просто набросал капельку DO с последней композицией докера. Я отредактировал пример к фактическому рабочему примеру.
crrutton
1
В моем случае это оказалось более подходящим решением, чем принятый ответ. Проблема с внешней сетью заключалась в том, что требовалось запускать контейнеры в предопределенном порядке. Для моего клиента это было неприемлемо. Именованная сеть (начиная с 3.5) оказалась идеальным решением. Спасибо.
Игорь
78

Просто небольшое замечание к отличному ответу @ johnharris85: когда вы запускаете файл компоновки Docker, создается defaultсеть " ", так что вы можете просто добавить его в другой файл компоновки как внешнюю сеть:

# 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

Для меня этот подход был более подходящим, потому что у меня не было первого файла docker-compose, и я хотел с ним связаться.

Таль Иоффе
источник
просто бродить правильный способ назначить статический IP для этой внешней сети. Мне удалось сделать это в services:теге, networks:затем синтаксис будет вложен front_default:(удалите «-»), а затем мы вложим статический IP:ipv4_address: '172.20.0.44'
Junior Mayhé
12

Информация предыдущих постов верна, но не содержит подробностей о том, как связывать контейнеры, которые должны быть связаны как "external_links".

Надеюсь, этот пример прояснит вам:

  • Предположим, у вас есть app1 / docker-compose.yml с двумя службами (svc11 и svc12) и app2 / docker-compose.yml с еще двумя службами (svc21 и svc22), и предположим, что вам нужно соединиться перекрестным образом:

  • svc11 должен подключиться к контейнеру svc22

  • svc21 должен подключиться к контейнеру svc11.

Итак, конфигурация должна быть такой:

это 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

это 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

Начиная с Compose 1.18 (спецификация 3.5), вы можете просто переопределить сеть по умолчанию, используя собственное имя для всех необходимых вам файлов Compose YAML. Это так же просто, как добавить к ним следующее:

networks:
  default:
    name: my-app

Выше предполагается, что вы versionустановили 3.5(или выше, если они не устарели в 4+).

Другие ответы указывают на то же самое; это упрощенное резюме.

emyller
источник
3

ОБНОВЛЕНИЕ: Начиная с версии 3.5 файла:

Я столкнулся с подобной проблемой и решил ее, добавив небольшое изменение в один из моих проектов docker-compose.yml.

Например, у нас есть два API scoringи ner. ScoringAPI должен отправить запрос в nerAPI для обработки входного запроса. Для этого они оба должны использовать одну и ту же сеть.

Примечание. Каждый контейнер имеет свою собственную сеть, которая автоматически создается во время запуска приложения в Docker. Например, будет создана сеть ner api, а сеть ner_defaultapi будет названа как scoring default. Это решение будет работать для версии: «3».

Так как в приведенном выше сценарии мой API скоринга хочет связаться с NER API, то я добавлю следующие строки. Это означает, что всякий раз, когда я создаю контейнер для ner api, он автоматически добавляется в сеть scoring_default.

networks:
  default:
      external:
        name: scoring_default

Нер / Докер-compose.yml

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

networks:
  default:
      external:
        name: scoring_default

скоринг / докер-compose.yml

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

Мы можем видеть это, как вышеперечисленные контейнеры теперь являются частью одной сети, вызываемой scoring_defaultс помощью команды:

Докер проверяет 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
источник
2

Я хотел бы убедиться, что все контейнеры docker-composeподключены к одной и той же сети, составив их одновременно, используя:

docker compose --file ~/front/docker-compose.yml --file ~/api/docker-compose.yml up -d
Nauraushaun
источник
Будет ли это позволяет мне, например, чтобы сделать linkили depends_onиз одного контейнера спереди одного контейнера апи?
Дживан
на самом деле, когда я делаю то, что вы предлагаете, docker-compose отвечает build path ~/front/api either does not exist or is not accessibleили наоборот,build path ~/api/front either does not exist or is not accessible
Jivan
1
Если вы пишете их одновременно, вам это не нужно. Будет создана сеть со всеми вашими контейнерами, и все они смогут обмениваться данными через имя службы из файла compose ( не имя контейнера).
Наураушаун
Это может быть проще, если два файла композиции находятся в одной папке. Но я не думаю, что это необходимо - я думаю, что это должно работать в любом случае.
Наураушаун
2
Это решение не работает, см. Мой комментарий к этой теме: github.com/docker/compose/issues/3530#issuecomment-222490501
johnharris85
1

Вы можете добавить .envфайл во все ваши проекты, содержащие COMPOSE_PROJECT_NAME=somename.

COMPOSE_PROJECT_NAME переопределяет префикс, используемый для именования ресурсов, поэтому все ваши проекты будут использовать somename_defaultих в качестве своей сети, что позволяет службам взаимодействовать друг с другом, как они были в одном проекте.

NB. Вы получите предупреждения об «осиротевших» контейнерах, созданных из других проектов.

Exagone313
источник
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
источник
0

Для использования другой сети docker-compose вы просто делаете это (чтобы разделить сети между docker-compose):

  1. Запустите первый проект docker-compose с помощью up -d
  2. Найдите сетевое имя первого docker-compose по: docker network ls(содержит имя проекта корневого каталога)
  3. Затем используйте это имя по этой структуре ниже во втором файле docker-compose.

второй 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

Другой вариант - просто запустить первый модуль с помощью 'docker-compose', проверить ip, связанный с этим модулем, и подключить второй модуль к предыдущей сети, как внешний, и указать внутренний ip.

пример app1 - новая сеть, созданная в служебных строках, пометить как внешнюю: true в нижней части app2 - указать «новую сеть», созданную app1 при повышении, пометить как внешнюю: true в нижней части и установить в конфигурации для подключения, ip, который app1 есть в этой сети.

При этом вы сможете разговаривать друг с другом

* этот способ предназначен только для локального тестирования, чтобы не выполнять слишком сложную настройку ** Я знаю, что это очень «патч-способ», но он работает для меня, и я думаю, что он настолько прост, что некоторые другие могут воспользоваться этим

Леонардо Рей
источник
0

Если ты

  • пытаясь установить связь между двумя контейнерами из разных проектов docker-compose и не хотят использовать одну и ту же сеть (потому что, скажем, у них будет контейнер PostgreSQL или Redis на одном и том же порту, и вы предпочитаете не менять эти порты и не использовать его в той же сети)
  • развиваются локально и хотят имитировать связь между двумя проектами создания докеров
  • запуск двух проектов docker-compose на localhost
  • разработка, в частности, приложений Django или API Django Rest Framework (drf) и запуск приложения внутри контейнера на каком-то открытом порту
  • получать Connection refusedпри попытке общаться между двумя контейнерами

И вы хотите

  • Контейнер api_aвзаимодействует api_b(или наоборот) без той же «сети докеров»

(пример ниже)

Вы можете использовать «хост» второго контейнера в качестве IP-адреса вашего компьютера и порта, который отображается изнутри контейнера Docker. Вы можете получить IP-адрес вашего компьютера с помощью этого сценария (из: Нахождение локальных IP-адресов с помощью stdlib 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

Пример:

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

внутри api_aконтейнера вы запускаете приложение Django: manage.py runserver 0.0.0.0:8000

и второй docker-compose.yml из другого проекта:

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

внутри api_bконтейнера вы запускаете приложение Django: manage.py runserver 0.0.0.0:8001

И при попытке подключения из контейнера api_aк api_bURL-адресу api_bконтейнера будет: http://<get_ip_from_script_above>:8001/

Это может быть особенно ценно, если вы используете даже более двух (трех или более) проектов, создающих Docker, и сложно обеспечить общую сеть для всего этого - это хороший обходной путь и решение

Рафал
источник