Как организовать сетевое взаимодействие между контейнерами в Docker Compose

Ответ

В Docker Compose контейнеры (сервисы) взаимодействуют друг с другом через внутреннюю виртуальную сеть, которую Compose создает автоматически для проекта.

Ключевой механизм — встроенный DNS-сервер. Каждый сервис получает DNS-имя, совпадающее с его названием в docker-compose.yml. Это позволяет обращаться к одному контейнеру из другого по имени, как к обычному хосту в сети.

Пример docker-compose.yml:

version: '3.8'

services:
  api:
    build: ./api
    # Порт 8000 доступен только внутри сети Docker
    expose:
      - "8000"

  frontend:
    build: ./frontend
    # Пробрасываем порт 80 контейнера на порт 8080 хоста
    ports:
      - "8080:80"

В этом примере:

  1. Сервис frontend может отправить запрос к сервису api по адресу http://api:8000.
  2. Docker Compose автоматически разрешит имя api во внутренний IP-адрес соответствующего контейнера.
  3. Пользователь может получить доступ к frontend через http://localhost:8080, но не может напрямую обратиться к api извне, так как его порт не проброшен с помощью ports.

Ответ 18+ 🔞

А, ну это же про ту самую магию, когда твои контейнеры начинают друг друга находить, будто у них встроенный радар! Смотри, как это работает, а то некоторые думают, там кабели эфирные тянуть надо.

Понимаешь, Docker Compose — он не просто так, он хитрая жопа. Когда ты его запускаешь, он берёт и создаёт для всего этого балагана свою собственную, закрытую сетку. Как будто детский сад с забором. Внутри этой сетки у каждого сервиса-контейнера появляется своё DNS-имя, прямо как кличка.

И главный фокус в том, что имя это — ровно то, которое ты написал в docker-compose.yml. Хочешь к api обратиться? Пиши http://api:8000 из другого контейнера, и всё, хуй с горы — запрос улетит куда надо. Внутренний DNS-сервер, который Compose поднимает, сам всё разберёт, какой контейнер за каким IP сидит.

Вот смотри на этот пример, тут всё как на ладони:

version: '3.8'

services:
  api:
    build: ./api
    # Порт 8000 доступен только внутри сети Docker
    expose:
      - "8000"

  frontend:
    build: ./frontend
    # Пробрасываем порт 80 контейнера на порт 8080 хоста
    ports:
      - "8080:80"

Что здесь происходит, ёпта? Сервис frontend может спокойно стучаться к api по адресу http://api:8000. Это как если бы они в одной комнате стояли и один другому крикнул: «Эй, API, дай сюда данные!».

А вот для внешнего мира, для нас с тобой, порт 8000 у api — невидимка, потому что он только expose, а не ports. Это как внутренняя линия, для своих. Зато frontend выставил свою рожу наружу через ports: - "8080:80". Так что мы, пользователи, лезем на http://localhost:8080, а он уже внутри сам разбирается с api.

Короче, вся фишка в том, что Compose сам настраивает эту паутину связей. Тебе только имена правильно прописать, а он уже под капотом ебушки-воробушки наколдует, чтобы они друг друга видели. Удобно же, а?