angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Docker-Композиция проектов с одинаковыми именами сервисов

Используйте имя сервиса Docker-Compose только в том случае, если сервис находится только во внутренней сети проекта Docker-Compose.

25 августа 2023
В Docker
post main image
https://www.pexels.com/@mikael-blomkvist

Если у нас есть идентичные проекты Docker-Compose с одинаковыми именами сервисов, соединенные сетью Docker , то мы должны убедиться, что обращаемся к нужному сервису. В сети Docker существует два способа доступа к сервису:

  • По имени сервиса
  • По имени контейнера

У меня есть несколько проектов Docker-Compose, которые практически идентичны, каждый проект находится в своей директории и имеет собственное окружение.

Я предполагал, что сервис внутри проекта Docker-Compose всегда будет использовать другой сервис внутри того же проекта Docker-Compose при использовании имени сервиса (не имени контейнера). И что при его отсутствии будет выдаваться ошибка. Я ошибся. На самом деле произойдет то, что вы сможете получить доступ к сервису с тем же именем в другом проекте Docker-Compose.

Как обычно, я работаю на Ubuntu 22.04.

Настройка проекта

У нас есть две директории с нашими (почти) идентичными проектами.

├── my_app1
│   ├── docker-compose.yml
│   └── .env
├── my_app2
│   ├── docker-compose.yml
│   └── .env

Два файла 'docker-compose.yml' идентичны. Файлы '.env' отличаются тем, что содержат только одну переменную окружения - 'COMPOSE_PROJECT_NAME'. Эта переменная используется не только для создания имен контейнеров, но и внутри наших контейнеров для идентификации проекта Docker-Compose.

Здесь мы используем 'nicolaka/netshoot' Docker image . В нем есть много полезных утилит, в том числе правильно работающий 'netcat', 'nc', который мы используем для создания слушателей daemon.

Вот эти файлы:

# my_app1/.env
COMPOSE_PROJECT_NAME=my_app1

and

# my_app2/.env
COMPOSE_PROJECT_NAME=my_app2

и

# docker-compose.yml

version: '3.7' 

x-service_defaults: &service_defaults
  env_file:
    - ./.env
  restart: always

services:
  app:
    << : *service_defaults
    image: nicolaka/netshoot
    command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - app:\" | /usr/bin/nc -l 80"
    
    networks: 
      - internal_network
      - app_network

  web:
    << : *service_defaults
    image: nicolaka/netshoot
    command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - web:\" | /usr/bin/nc -l 81"

    networks: 
      - internal_network
      - app_network

networks:
  internal_network:
  app_network:
    external:
      name: my_app_network

Перед началом работы создадим внешнюю сеть Docker :

docker network create my_app_network

Выполнение некоторых проверок

Откройте несколько терминалов и запустите оба проекта, выполнив в каждой директории следующую команду:

docker-compose up

Проверьте, что следующие контейнеры созданы и запущены:

my_app1_app_1
my_app1_web_1
my_app2_app_1
my_app2_web_1

Теперь в другом терминале выполните команду:

docker run -it --network=my_app_network --rm busybox

Получить доступ к сервису в наших контейнерах, используя имя контейнера:

telnet my_app_1_app_1 80

Ответ будет следующим:

Connected to my_app1_app_1
From my_app1 - app:

Все работает, как и ожидалось. Введите текст. Это будет передано эхом. Проверить это можно также в терминале проекта 'my_app1' Docker-Compose.

Генерация ошибки

Сначала войдем в сервис 'app' проекта 'my_app1' :

docker exec -it my_app1_app_1 bash

Теперь обратимся к сервису 'web' в том же проекте Docker-Compose, используя имя сервиса:

telnet web 81

Ответ:

Connected to web
From my_app1 - web:

Отлично, это то, что мы ожидали.

Теперь давайте сделаем так, чтобы сервис 'web' в проекте 'my_app1' (временно) исчез. Для этого мы его удалим.

В другом терминале переходим в каталог 'my_app1' и набираем:

docker-compose stop web

Теперь снова обращаемся к сервису 'web' в том же проекте:

telnet web 81

В ответ получаем:

Connected to web
From my_app2 - web:

О-о. Теперь мы обращаемся к сервису 'web' в 'my_app2' , тогда как хотели обратиться к сервису 'web' в 'my_app1'. Заметим, что существуют (гораздо) лучшие, но и гораздо более сложные способы моделирования.

Решения

Здесь возможны два варианта решения, в зависимости от ситуации:

Решение 1. Если служба 'web' не нуждается во внешней сети, то удаляем ее из внешней сети.

Делаем это для обоих проектов (помните, что файлы 'docker-compose.yml' идентичны):

  web:
    << : *service_defaults
    image: nicolaka/netshoot
    command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - web:\" | /usr/bin/nc -l 81"

    networks: 
      - internal_network
      #- app_network

Уберите контейнеры вниз, а затем снова вверх, и снова остановите службу 'web' проекта 'my_app1' .

Теперь, если попытаться обратиться к службе 'web' , см. выше:

telnet web 81

, то через некоторое время будет получен ответ:

telnet: bad address 'web'

Хорошо. При недоступности сервиса выдается сообщение об ошибке.

Решение 2. Если сервис 'web' также должен быть внешним, то при обращении к нему мы всегда используем имя контейнера сервиса 'web' , даже если мы находимся в одном проекте Docker-Compose.

Это не совсем удачное решение, но другого выхода нет. Если служба 'app' хочет получить доступ к службе 'web' в том же проекте Docker-Compose, мы можем сконструировать имя контейнера с помощью переменной 'COMPOSE_PROJECT_NAME' :

container_name = <COMPOSE_PROJECT_NAME>_<service name>_1

Для сервиса 'web' в проекте 'my_app1':

web_container_name = my_app1_web_1

Резюме

Я столкнулся с этим, когда переходил от одного контейнера к двум. Стали происходить странные вещи, данные между контейнерами перемешивались. Обнаружив проблему, я смоделировал ее с помощью приведенного выше кода. Затем я исправил ее для своего проекта. Извлеченный урок: Никогда не предполагайте.

Ссылки / кредиты

Docker - Change pre-defined environment variables in Docker Compose
https://docs.docker.com/compose/environment-variables/envvars

nicolaka / netshoot
https://github.com/nicolaka/netshoot

Подробнее

Docker Docker-compose

Оставить комментарий

Комментируйте анонимно или войдите в систему, чтобы прокомментировать.

Комментарии

Оставьте ответ

Ответьте анонимно или войдите в систему, чтобы ответить.