Не удалось подключиться к локальному хосту изнутри контейнера.
В настоящее время я тестирую роль Ansible с помощью Molecule. По сути, Molecule запускает контейнер, совместимый с Ansible, и выполняет для него роль.
Чтобы протестировать контейнер, Molecule также встраивает модульные тесты с использованием Testinfra. Модульные тесты Python запускаются из контейнера, поэтому вы можете проверить соответствие роли.
Поскольку я работаю над ролью на основе Nginx, один из модульных тестов просто curl http://localhost:80
Я получаю следующее сообщение об ошибке в ответ:
curl: (7) Не удалось подключиться к локальному порту 80: отказано в подключении
Когда я:
- запустить машину Vagrant
- применить роль с Ansible
- подключиться через
vagrant ssh
- выдать
curl http://localhost
команда
nginx отвечает правильно.
Поэтому я считаю, что:
- роль работает правильно и Nginx установлен правильно
- У Docker есть другой способ настройки сети. В некотором смысле, localhost и 127.0.0.1 больше не совпадают.
Мои вопросы следующие:
- Я прав?
- Можно ли преодолеть эту разницу, чтобы завиток работал?
2 ответа
Контейнеры Docker по умолчанию запускаются в собственном сетевом пространстве имен. Это пространство имен включает отдельный интерфейс обратной связи (127.0.0.1), который отличается от того же интерфейса на хосте и любых других контейнерах. Если вы хотите получить доступ к приложению из другого контейнера или через опубликованный порт на хосте, вам необходимо прослушивать все интерфейсы (0.0.0.0), а не петлевой интерфейс.
Еще одна проблема, с которой я часто сталкиваюсь, заключается в том, что на каком-то уровне соединения (хост или внутри контейнера) имя "localhost" сопоставляется со значением IPv6: ::1
в файле /etc/host, и где-то в этом соединении допустимо только значение IPv4 (либо там, где был опубликован порт, приложение прослушивает, либо IPv6 не включен на хосте или механизме докера). Поэтому обязательно попытайтесь подключиться к адресу IPv4 напрямую, 127.0.0.1, чтобы устранить любые потенциальные проблемы с IPv6.
Учитывая curl
Команда и как ее исправить, я не могу ответить на этот вопрос без более подробной информации о том, как вы запускаете curl (находится ли он в отдельном контейнере), как вы запускаете свое приложение и как они объединяются в сети (вы создали новая сеть в докере для запуска вашего приложения и модульных тестов). Типичное решение состоит в том, чтобы создать новую сеть в Docker, запустить оба контейнера в этой сети и подключиться через включенный DNS докера к контейнеру или имени службы назначения, например curl http://my_app/
,
Редактировать: основываясь на комментариях, если ваше приложение и команда curl работают внутри одного контейнера, то curl http://127.0.0.1/
должно сработать. Там нет никаких изменений, я знаю о необходимости с curl
чтобы он работал внутри контейнера против виртуальной машины. Вероятно, ошибка, которую вы видите, связана с тем, что приложение не запускается и прослушивает порт должным образом, возможно, из-за гонки, когда команда curl выполняется слишком рано, или из-за неверных базовых предположений о том, как работает инструмент. Начните с изменения модульного теста, чтобы убедиться, что приложение работает и прослушивает порт с помощью команд, таких как ps -ef
а также ss -lt
,
На самом деле это не имеет никакого отношения к различиям между Docker и Vagrant (то есть контейнеры и виртуальные машины).
Код testInfra фактически выполняется снаружи контейнера / виртуальной машины, поэтому факт subprocess.call(['curl', 'http://localhost'])
терпит неудачу.
Чтобы запустить команду из контейнера / виртуальной машины, я должен использовать:
host.check_output('curl http://localhost')