Вопрос или проблема
У меня есть машина, на которой не настроены адреса 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-адресов, что приводит к ошибке при попытке привязки к адресу ::
, который не поддерживается.
Ответ на проблему
-
Проверка конфигурации Docker: Убедитесь, что конфигурация Docker не влияет на разрешение имен и адресацию. Возможно, настройки сети Docker каким-то образом подразумевают использование IPv6. Вы можете отключить IPv6 в Docker, изменив файл конфигурации
/etc/docker/daemon.json
. Добавьте следующее:{ "ipv6": false }
После этого перезапустите службу Docker:
sudo systemctl restart docker
-
Изменение настроек хост-системы: Если у вас есть возможность, вы можете временно включить поддержку IPv6 на хосте, даже если это не основная задача. Это можно сделать, добавив IPv6-адреса к интерфейсам. Например:
sudo ip -6 addr add ::1/128 dev lo
Однако, если данный подход не может быть применён, рассмотрите последующие решения.
-
Патч или работа с виртуальной средой: Поскольку у вас нет контроля над исходным кодом приложения, вы можете обернуть его в скрипт, который будет перенаправлять обращения для IPv6, исключая их. Этот подход требует создания дополнительного моста между приложениями и сетевыми интерфейсами. Рассмотрите возможность использования
socat
или аналогичных утилит для перенаправления трафика. Пример команды для этого:socat TCP-LISTEN:8080,fork TCP:127.0.0.1:8080
-
Использование пользовательской сети Docker: Вместо использования режима сети
host
, создайте пользовательскую сеть Docker, настроенную на использование только IPv4. Вы можете создать сеть с помощью:docker network create --driver bridge --subnet 192.168.0.0/24 my_custom_network
Затем запустите контейнеры в этой сети:
docker run --network my_custom_network ...
-
Изоляция проблемы: Попробуйте протестировать приложение в изолированной среде, например, запустив его в другом контейнере с другой конфигурацией, чтобы понять, сохраняется ли ошибка. Это может дать дополнительную информацию по возникшей проблеме.
Заключение
В данной ситуации ключ к решению проблемы заключается в настройках сети Docker и обеспечении того, чтобы приложения не пытались использовать протоколы, которые не поддерживаются вашей хост-системой. Рассматривая вышеперечисленные шаги, вы сможете обезопасить свое окружение от подобных ошибок и обеспечить корректное функционирование приложений в контейнерах. Если у вас появятся дополнительные вопросы или трудности, не стесняйтесь обратиться к сообществу или профессиональным разработчикам для получения более детальной информации.