Зв'язок між декількома проектами докер-композицій


254

У мене є два окремих 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?

Зрештою, за чим я доглядаю:

  • Як два різні докерські проекти можуть спілкуватися один з одним?

4
Я просто сьогодні знову заглянув у це. Розроблені нарешті поступилися і дозволили довільно називати мережу. Використовуючи композиційний файл версії 3.5, ви можете вказати ім'я для мережі за замовчуванням під клавішею "мережі". Це створить іменовану мережу без звичного префіксу назви проекту, якщо його не існує ..
cstrutton

Відповіді:


325

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

# 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і навпаки.


1
Дживан, це не рішення. Ваші контейнери не повинні нічого знати про хазяїна або маніпулювати таким чином. Хоча моя відповідь була досить короткою, я оновив детальніше.
johnharris85

3
Роберт Москаль, тільки якщо ви зламаєтесь, щоб отримати ip вашого хокера докера в контейнери. Краще, щоб вони спілкувалися в загальній мережі, визначеній докер.
johnharris85

2
Зверніть увагу, що префікс "front_" до мережі створюється автоматично з папки, в якій працює. Тож якщо ваш перший файл докер-композиції буде розташований у "example / docker-compose.yml", він буде називатися "example_default".
AngryUbuntuNerd

7
Ви також можете надати ім’я мережі за допомогою nameвластивості, що вимкне автоматичну попередню попередню назву проекту. Тоді будь-який проект може використовувати цю мережу та створювати її автоматично, якщо вона ще не існує.
СтівБ

2
@SteveB - Зауважте, що властивість імені працює лише з файлів докер-композиції версії 3.5 і вище
kramer65

78

Лише невелике звернення до чудової відповіді @ johnharris85, коли ви запускаєте файл для створення докерів, створюється " 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

Для мене такий підхід більше підходив, оскільки я не мав перший файл докер-композиції і хотів спілкуватися з ним.


просто мандруючи правильним способом призначення статичного IP для цієї зовнішньої мережі. Я керував, щоб зробити це в services:тезі, синтакс буде networks:потім вкладений front_default:(видаліть "-"), і тоді ми ipv4_address: '172.20.0.44'
вкладемо

76

ОНОВЛЕННЯ: Станом на файл файлу версії 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

Це створить контейнер, який буде знаходитися у зовнішній мережі.

Я не можу знайти жодних посилань у документах, але це працює!


Чи потрібно запускати два сервіси у визначеному порядку? Чи можете ви запустити будь-яку, і перша створить мережу, а друга приєднається до неї?
slashdottir

4
Перша послуга (проксі вище) створює мережу. Синтаксис у другому прикладі приєднується до нього.
cstrutton

2
@slashdottir Ви не можете позначати мережу як зовнішню у другому сервісі, і вона буде створена, якщо вона ще не існує.
SteveB

2
Це справді працює. Я просто закрутив краплі DO із останнім докерським складом. Я відредагував приклад на фактичному робочому прикладі.
cstrutton

1
У моєму випадку це виявилося більш підходящим рішенням, ніж прийнята відповідь. Проблема із зовнішньою мережею полягала в тому, що вона вимагала запускати контейнери у визначеному порядку. Для мого клієнта це було неприйнятно. Іменована мережа (починаючи з 3.5) виявилася ідеальним рішенням. Дякую.
ygor


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+).

Інші відповіді вказували на те саме; це спрощений підсумок.


2

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

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

Чи дозволить мені, наприклад, зробити linkабо depends_onз одного контейнера переднього до одного контейнера з api?
Jivan

насправді, коли я роблю те, що ви пропонуєте, відповіді на докер-композицію 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
Якщо ви складаєте їх одночасно, вам не потрібно. Буде створена мережа з усіма вашими контейнерами на ній, усі вони зможуть спілкуватися через ім’я служби з файлу композиту ( не імені контейнера).
Наурашаун

Це може бути простіше, якщо два композиційні файли знаходяться в одній папці. Але я не думаю, що це потрібно - я думаю, що це має працювати в будь-якому випадку.
Nauraushaun

2
Це рішення не працює, дивіться мій коментар до цієї теми
johnharris85

2

ОНОВЛЕННЯ: Станом на файл файлу версії 3.5:

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

Наприклад, у нас є два api scoringта ner. Scoringapi потрібно надіслати запит до nerapi для обробки вхідного запиту. Для цього вони обидва повинні використовувати спільну мережу.

Примітка. У кожного контейнера є своя мережа, яка автоматично створюється під час запуску програми всередині докера. Наприклад, мережа ner api буде створена як, ner_defaultа мережа api мереж буде позначена як scoring default. Це рішення буде працювати для версії: '3'.

Як і у вищенаведеному сценарії, мій бал апі хоче спілкуватися з ner api, то я додаю наступні рядки. Що означає щоразу, коли я створю контейнер для ner api, він автоматично додається до мережі scoring_default.

networks:
  default:
      external:
        name: scoring_default

ner / docker-compose.yml

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

networks:
  default:
      external:
        name: scoring_default

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

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

Ми можемо бачити, як вищевказані контейнери є частиною тієї ж мережі, яка називається scoring_defaultза допомогою команди:

docker перевірити скоринг_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

Ви можете додати .envфайл у всі свої проекти, що містять COMPOSE_PROJECT_NAME=somename.

COMPOSE_PROJECT_NAME переосмислює префікс, який використовується для іменування ресурсів, оскільки такі ваші проекти будуть використовуватись somename_defaultяк їх мережа, що дозволяє послугам спілкуватися один з одним, як вони були в одному проекті.

NB: Ви отримаєте попередження про "осиротілі" контейнери, створені з інших проектів.


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

Для використання іншої мережі докер-композицій ви просто зробите це (щоб ділитися мережами між docker-compose):

  1. Запустіть перший проект док-композиції за up -d
  2. Знайдіть мережеве ім'я першого docker-compose за: docker network ls(Він містить назву проекту кореневого каталогу)
  3. Потім використовуйте це ім'я за цією структурою внизу у другому файлі док-композиції.

другий 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 - нову мережу, створену в сервісних рядках, позначте як зовнішню: істина внизу app2 - вкажіть "нову мережу", створену програмою1, коли піднімається вгору, позначте як зовнішню: істина внизу, і встановіть у конфігурацію щоб підключитися, ip, що app1 має в цій мережі.

З цим ви повинні мати можливість поговорити один з одним

* цей спосіб призначений лише для локального тестового фокусування, щоб не робити занадто складну конфігурацію ** Я знаю, що це дуже "виправлення", але працює для мене, і я думаю, що це так просто, що деякі інші можуть скористатися цим


0

Якщо ви

  • намагаючись спілкуватися між двома контейнерами з різних проектів, що створюють докер, і не хочуть використовувати одну мережу (тому що скажімо, вони мали б контейнер PostgreSQL або Redis на одному порту, і ви вважаєте за краще не змінювати ці порти і не використовувати його в одній мережі)
  • розвиваються на місцевому рівні і хочуть наслідувати комунікацію між двома проектами для створення докерів
  • запуску двох докер-композиційних проектів у 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_b URL-адресиapi_b контейнера буде: http://<get_ip_from_script_above>:8001/

Це може бути особливо цінним, якщо ви використовуєте навіть більше, ніж два (три або більше) докер-композиційних проектів, і важко забезпечити спільну мережу для всіх - це хороший спосіб вирішення та рішення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.