Доступ http из одного проекта docker-compose к другому

В данный момент мы часто имеем ситуацию, когда каждый отдельный проект имеет настройки docker контейнеров, что производятся через конфигурационный файл docker compose. Пока обращение контейнеров друг к другу происходит в рамках одного такого файла конфигурации, все понятно. Но что, если мы имеем, скажем 2 или 3 подпроекта, которые должны общаться по сети (например по http)? Это могут быть, как вариант, микро сервисы. В данной статье будет показано как настроить такое взаимодействие.

Для имитации 2 разных проектов создадим 2 отдельных файла docker-compose.yml

version: '3.6'

services:
    web:
        image: nginx
        hostname: project1
        ports:
            - "127.0.0.101:80:80"
        networks:
            some_network:
                aliases:
                    - project1.local
                    - www.project1.local

networks:
    some_network:
        # Общая сеть со смежными проектами
        name: 'our_network'
version: '3.6'

services:
    web:
        image: nginx
        hostname: project2
        ports:
            - "127.0.0.102:80:80"
        networks:
            some_network:
                aliases:
                    - project2.local
                    - www.project2.local

networks:
    some_network:
        # Общая сеть со смежными проектами
        name: 'our_network'

В каждом проекте по 1 сервису (контейнеру) с именем web. В обоих случаях создаем контейнер на базе образа nginx. Прокидываем порт 80 на разные host IP. В этом случае в браузере будут доступны проекты по URL http://127.0.0.101 и http://127.0.0.102. Если у вас заняты эти IP (не запустится nginx в каком либо из проектов), то используйте другие IP вида 127.*.*.*

Теперь запустим окружение первого проекта в папке project1:

$ docker compose up -d    
                     
[+] Running 2/2
 ⠿ Network our_network       Created                                                                                                                                               0.1s
 ⠿ Container project1-web-1  Started     

Сейчас в браузере можно открыть страницу Welcome to nginx! по адресу http://127.0.0.101. А внутри самого контейрера можно обратиться и по доменному имени за счет заданого алиаса.

$ docker compose exec web curl project1.local 

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
...

В то же время домен из второго проекта доступен не будет:

$ docker compose exec web curl project2.local                  
curl: (6) Could not resolve host: project2.local

Чтобы он стал доступен мы запустим окружение второго проекта в папке project2:

$ docker compose up -d   
                                         
[+] Running 1/1
 ⠿ Container project2-web-1  Started              

Теперь в папке первого проекта project1 можем увидеть доступность домена второго проекта из контейнера первого:

$ docker compose exec web curl project2.local  
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
...

И в папке второго проекта project2 можем убедиться, что доступен домен первого проекта из контейнера второго:

$ docker compose exec web curl project1.local  
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
...

Магия происходит за счет задания сети имени name: 'our_network'. Эта возможность доступна, если вы используйте формат docker-compose.yml не ниже версии 3.5. Когда таким образом указывается имя сети, то к нему не добавляется префикс проекта. В итоге контейнер одного проекта видит сеть под тем же именем, что и другой проект. Можно убедиться в наличии сети с таким именем при помощи команды docker network ls:

$ docker network ls | grep our

3448ab685c12   our_network                        bridge    local

Если бы такой сети мы не создали, то запуск первого проекта привел бы к созданию сети по умолчанию project1_default, а второго – project2_default.

Мы могли бы создать сеть без docker-compose.yml, через команду docker:

$ docker network create -d bridge our_network2

ddfd35c35b68d034950f415e06fc4074b62eedf23e6680508181f773740d43e5


$ docker network ls | grep our                

f292f72ce35d   our_network                        bridge    local
ddfd35c35b68   our_network2                       bridge    local

Тогда в описании сети нужно было бы указать параметр external. Однако, удобнее, чтобы сеть создавалась автоматически при запуске любого из проектов.

Важный момент. Если контейнерам явно указана сеть (как в примерах выше), то скорее всего, для таких контейнеров не будет доступна сеть default. Что приведет к проблемам обращения к ним из контейнеров сети default. Чтобы избежать таких проблем, нужно в списке сетей контейнера с явно указанной сетью также указывать и сеть default:

## Располагается в секции контейнера
networks:
    default: # Здесь указан сеть default
    some_network:
        aliases:
            - project2.local
            - www.project2.local

Код примеров доступен в репозитории https://github.com/itelmenko/myblog/tree/main/examples/docker-network

Полезные ссылки

  • https://docs.docker.com/compose/networking/#specify-custom-networks
  • https://docs.docker.com/compose/compose-file/compose-file-v2/#network-configuration-reference

5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest
3 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Антон
Гость
Антон
10 месяцев назад

Очень помогло, спасибо

Aleksandr Domanskiy
Гость
Aleksandr Domanskiy
6 месяцев назад

Спасибо
Сделал отдельный контейнер с PostgreSQL 14. Развернул из docker-compose

Отдельным docker-compose развернул php и nginx

Сети у всех с одинаковым названием.
Через DBever коннект к БД есть
А вот из php доступа нет.
В итоге помогло


networks:
laravel:
driver: bridge
external: true
name: laravel

Теперь у меня один контейнер с PGSQL14 для кучи проектов. Удобнее чем под каждый проект поднимать свой контейнер с БД