На хост-машине нет IPv6-адресов, но приложения в контейнерах Docker по-прежнему пытаются прослушивать на :: и получают ошибку Errno 97 “Семейство адресов не поддерживается протоколом”

Вопрос или проблема

У меня есть машина, на которой не настроены адреса ipv6 на любом интерфейсе (включая loopback). Более того, в файле /etc/hosts на хостовой машине нет записей ipv6 для “localhost”.

Тем не менее, есть несколько приложений, которые запускаются в контейнерах docker и не могут стартовать с ошибкой socker.error [Errno 97] Address family not supported by protocol. Я свел это к следующему поведению

  • приложение делает по сути следующий вызов: socket.getaddrinfo(None, 8080, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
  • оно возвращает кучу addrinfo(10, 1, 6, '', ('::', 8080, 0, 0)), (2, 1, 6, '', ('0.0.0.0', 8080)): первая запись явно является ipv6 версией “0.0.0.0”
  • приложение пытается привязаться ко всем возвращённым адресам / портам
  • не удается, когда оно пытается прослушать на ::, потому что, как я понимаю, на конфигурированных интерфейсах нет адресов ipv6

Окружение / ограничения:

  • приложения написаны на Python 2.7
  • у меня нет контроля над исходным кодом (хорошо, это Python, так что, технически, у меня есть — но все же)
  • я могу контролировать, как работает demon docker, если это имеет какое-то значение
  • я могу перенастроить сеть / ОС на хостовой машине, но вся ситуация с “нет ipv6 на интерфейсах” вне моего контроля
  • контейнеры запускаются в сетевом режиме network=host

Странно, но когда я запускаю python3 -c 'import socket; print(socket.getaddrinfo(None, 8080, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG))' на хостовой машине, я получаю только это: [(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('0.0.0.0', 8080))], то есть адреса ipv6 не возвращаются, но почему-то внутри контейнера реализация сокетов считает, что :: доступен.

Что я могу сделать, чтобы продвинуться в решении этой проблемы?

Ответ или решение

Решение проблемы: Ошибка при попытке привязки к IPv6 в контейнерах Docker

Вы столкнулись с проблемой, когда приложения в контейнерах Docker пытаются прослушивать адрес IPv6 ::, находясь на машине без настроенных IPv6-адресов. Эта ситуация может вызвать ошибку socket.error [Errno 97] Address family not supported by protocol, и давайте разберемся, как ее можно решить.

Проблема

При вызове функции socket.getaddrinfo() с параметрами, позволяющими использовать оба протокола (IPv4 и IPv6), ваше приложение получает список адресов, включая IPv6, даже если на хост-машине нет настроенных IPv6-интерфейсов. В данном случае адаптер AI_ADDRCONFIG не предотвращает возврат IPv6-адресов, что приводит к ошибке при попытке привязки к адресу ::, который не поддерживается.

Ответ на проблему

  1. Проверка конфигурации Docker: Убедитесь, что конфигурация Docker не влияет на разрешение имен и адресацию. Возможно, настройки сети Docker каким-то образом подразумевают использование IPv6. Вы можете отключить IPv6 в Docker, изменив файл конфигурации /etc/docker/daemon.json. Добавьте следующее:

    {
       "ipv6": false
    }

    После этого перезапустите службу Docker:

    sudo systemctl restart docker
  2. Изменение настроек хост-системы: Если у вас есть возможность, вы можете временно включить поддержку IPv6 на хосте, даже если это не основная задача. Это можно сделать, добавив IPv6-адреса к интерфейсам. Например:

    sudo ip -6 addr add ::1/128 dev lo

    Однако, если данный подход не может быть применён, рассмотрите последующие решения.

  3. Патч или работа с виртуальной средой: Поскольку у вас нет контроля над исходным кодом приложения, вы можете обернуть его в скрипт, который будет перенаправлять обращения для IPv6, исключая их. Этот подход требует создания дополнительного моста между приложениями и сетевыми интерфейсами. Рассмотрите возможность использования socat или аналогичных утилит для перенаправления трафика. Пример команды для этого:

    socat TCP-LISTEN:8080,fork TCP:127.0.0.1:8080
  4. Использование пользовательской сети Docker: Вместо использования режима сети host, создайте пользовательскую сеть Docker, настроенную на использование только IPv4. Вы можете создать сеть с помощью:

    docker network create --driver bridge --subnet 192.168.0.0/24 my_custom_network

    Затем запустите контейнеры в этой сети:

    docker run --network my_custom_network ...
  5. Изоляция проблемы: Попробуйте протестировать приложение в изолированной среде, например, запустив его в другом контейнере с другой конфигурацией, чтобы понять, сохраняется ли ошибка. Это может дать дополнительную информацию по возникшей проблеме.

Заключение

В данной ситуации ключ к решению проблемы заключается в настройках сети Docker и обеспечении того, чтобы приложения не пытались использовать протоколы, которые не поддерживаются вашей хост-системой. Рассматривая вышеперечисленные шаги, вы сможете обезопасить свое окружение от подобных ошибок и обеспечить корректное функционирование приложений в контейнерах. Если у вас появятся дополнительные вопросы или трудности, не стесняйтесь обратиться к сообществу или профессиональным разработчикам для получения более детальной информации.

Оцените материал
Добавить комментарий

Капча загружается...