Связать контейнеры с фронтендом и бэкендом

Решил простую задачку. Использовал БД Postgres, на бэкенде Spring Boot, фронтенд на AngularJS. Сейчас пытаюсь всё это упаковать в 3 контейнера чтобы развернуть потом на виртуалке. Вот тут с Докером у меня проблемы. Файл docker-compose.yaml такой:

version: '3.0'

services:

    pgdb:
        build:
            context: services/database
            dockerfile: Dockerfile
        image: 'image_db'
        container_name: 'container_db'        
        ports:
            - 15433:5432  # Чтобы подключиться к БД с хоста
        environment:
            - 'POSTGRES_DB=db1'
            - 'POSTGRES_USER=user1'
            - 'POSTGRES_PASSWORD=pswd1'
        volumes:
            - pgdata:/var/lib/postgresql/data

    back:
        build:
            context: services/backend
            dockerfile: Dockerfile
        image: 'image_back'
        container_name: 'container_back'
        environment:
            - 'SPRING_DATASOURCE_URL=jdbc:postgresql://pgdb:5432/db1'
        depends_on:
            - pgdb

    front:
        build:
            context: services/frontend
            dockerfile: Dockerfile
        image: 'image_front'
        container_name: 'container_front'
        ports:
            - 8099:80

volumes:
    pgdata:
  1. Сервис 'pgdb': здесь я указал проброс портов - 15433:5432 чтобы можно было с хоста подключиться к БД и посмотреть данные в таблицах.

  2. Сервис 'back': тут я указываю переменную окружения 'SPRING_DATASOURCE_URL=jdbc:postgresql://pgdb:5432/db1' в которой написано pgdb:5432 то есть название сервиса с базой данных, чтобы он подключился к этому контейнеру. Также в самом коде бэкенда в файле application.yaml у меня прописаны url/логин/пароль от БД, и на каком порту стартует бэкенд:

server:
    port: 8083
  1. Сервис 'front': в его Dockerfile я указал родительский образ nginx и добавляю туда папку html с файлами фронтенда:
FROM nginx
WORKDIR /usr/share/nginx/html
COPY html .

Я так понимаю nginx внутри контейнера стартует на порту 80, поэтому я добавил проброс портов - 8099:80 чтобы на хост машине открывать в браузере localhost:8099 и попадать в контейнер с фронтендом.
А также в файле .js у меня указан url для бэкенда apiPath = localhost:8083 , так как бэкенд как раз на порту 8083 запущен.

Я везде использую разные значения для портов намеренно, чтобы разобраться как это всё работает.

Вроде если я правильно понимаю сейчас моя схема вот такая: введите сюда описание изображения

Фронтенд внутри своего контейнера будет обращаться на свой внутренний localhost:8083 Собственно это как раз тот момент, который я не пойму как сделать. Надо как-то сказать контейнеру с фронтом , что надо стучаться в localhost:8083 который внутри бэкендовского контейнера.

Но если запустить docker-compose.yaml так как есть сейчас, то ожидаемо не работает. Я открываю на самом компе адрес localhost:8099 , попадаю в контейнер с фронтендом и вижу там запущенный фронтенд, но там только вёрстка, никаких данных нет, так как он долбится внутри своего контейнера, а не в контейнер с бэкендом.

Но при этом если сделать в консоли команду docker network ls то я вижу что появилась сеть с именем prod_default ('prod' это название папки внутри которой файл docker-compose.yaml лежит). И если посмотреть сеть командой
docker network inspect prod_default то вижу такое:

[
    {
        "Name": "prod_default",
        "Id": "fa63163cd8c2637746e65e7504782461abca065a7fe51ebf458c12cb525fe577",
        "Created": "2022-12-02T02:47:00.354470961+07:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.22.0.0/16",
                    "Gateway": "172.22.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "77b45daf889b0cbb06a2842efc0722c9505b191c27ce6792bd3483377ac9d069": {
                "Name": "container_back",
                "EndpointID": "cfe28da474636bdc4f7c85edbd3369232f6362254db3730503489f7978b79274",
                "MacAddress": "02:42:ac:16:00:04",
                "IPv4Address": "172.22.0.4/16",
                "IPv6Address": ""
            },
            "bf55e093b29959cb2c5418ca3d532b00aec04f161381ed1c528b7e0657f2e957": {
                "Name": "container_front",
                "EndpointID": "5e03aedb5786f59bf76b7d806fc525cf0eb5df4a28b03aa9c32ec6319e9ceb9b",
                "MacAddress": "02:42:ac:16:00:02",
                "IPv4Address": "172.22.0.2/16",
                "IPv6Address": ""
            },
            "debfe3a6eeccdcb8b3a88f5cfe9c533b6c6da79a0d6109e31d68c0276721d25a": {
                "Name": "container_db",
                "EndpointID": "ece93f0546c71eaf38a0a49d3ddee046cf72b150c64d272631ed295a974a4281",
                "MacAddress": "02:42:ac:16:00:03",
                "IPv4Address": "172.22.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "prod",
            "com.docker.compose.version": "1.21.2"
        }
    }
]

То есть получается при запуске docker-compose создалась некая дефолтная сеть, хотя я нигде и не прописывал её. И там видно раздел "Containers" где все 3 контейнера и перечислены. Но если они по умолчанию попадают в некую дефолтную сеть, странно тогда что контейнер с фронтом не видит контейнер с бекендом.

В общем, подскажите плиз как связать эти 2 контейнера? :-))


Ответы (1 шт):

Автор решения: Дмитрий

Все же лучше побольше ознакомиться с документацией, но вкратце примерно так:

  • сеть типа brige создается автоматически при запуске Докера, но её не стоит использовать для общения между контейнерами.
  • для общения между контейнерами вам нужна пользовательская сеть докер, к которой будет подключены ваши контейнеры. И в "собственной сети" контейнерам нужно задавать имена. Грубо говоря хотя бы потому, что вы не можете гарантировать фиксированный IP контейнера в сети докер при перезапуске
  • соединение вашего фронта с бэкендом и бекенда с базой это никак не localhost, это обращение к другому контейнеру (узлу) в пользовательской сети
  • вот не советую прокидывать порты во все контейнеры в лоб. Нормальный вариант (имхо) когда с хост машины прокинут порт в (условный) nginx в контейнере, а контейнеры базы и бэкенда могут быть доступны с хост машины, а не снаружи. Ну т.е. указать проброс порта в контейнер БД/бэкенда, как проброс 127.0.0.1:<порт хоста>:<порт сервиса в контейнере>
→ Ссылка