Назад | Перейти на главную страницу

Ошибка HTTP в контейнере Docker, размещенном в OpenStack

В настоящее время у меня Docker работает на нескольких виртуальных машинах, размещенных в OpenStack.

При попытке выполнить HTTP-запросы из контейнеров на этих машинах, запрос почти всегда зависает в ожидании ответа. При выполнении запросов HTTPS время ожидания запроса неизменно истекает, поскольку не удается завершить рукопожатие TLS. В любом случае кажется, что запросы завершаются ошибкой после получения пары сотен байтов данных ответа (если есть). Те же запросы выполняются без каких-либо проблем с хост-машины (т.е. проблема не в брандмауэре уровня хоста).

Я наткнулся на этот (и некоторые связанные сообщения в блоге), которые предполагают, что это может быть связано с тем, что сетевой мост Docker имеет другой MTU по сравнению с сетевым интерфейсом хоста, но я проверил, что оба MTU одинаковы (1500 байт в каждом случае). Я также пробовал поиграть с --mtu переключиться на демон Docker, чтобы посмотреть, смогу ли я заставить его работать, но безуспешно.

Я также встречал несколько похожих случаев, которые предполагают, что это может быть связано с разгрузкой контрольной суммы TCP и / или сегментации (например, Вот), но никаких возиться с ethtool -K {interface} tx off rx off или аналогичный дают любой положительный результат.

Поведение кажется специфичным для сетевого моста - использование --net=host когда запуск контейнеров действительно решает проблему. Однако по соображениям безопасности я не хочу использовать этот обходной путь в нашей производственной системе.

Также обратите внимание, что та же самая настройка (та же версия Docker, те же параметры конфигурации) отлично работает на моей машине разработки или при запуске на экземпляре, размещенном в AWS - в чем бы ни заключалась проблема, похоже, она проявляется только при работе под OpenStack.

Для справки я использую следующую команду для тестирования:

docker run -it alpine:3.3 wget http://ipv4.download.thinkbroadband.com/5MB.zip

Это должно (теоретически) загрузить тестовый файл размером 5 МБ при запуске. Однако wget команда просто зависает. Также, вероятно, стоит отметить, что проблема не в гостевой ОС - использование образа Ubuntu (например) по-прежнему демонстрирует такое же поведение.

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

Также, если это актуально, вот вывод docker version в рассматриваемой системе:

Client:
 Version:      1.12.1
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   23cf638
 Built:        Thu Aug 18 05:22:43 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.1
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   23cf638
 Built:        Thu Aug 18 05:22:43 2016
 OS/Arch:      linux/amd64

Выход uname -a на хосте выглядит следующим образом:

Linux docker-builder-1 4.4.0-38-generic #57~14.04.1-Ubuntu SMP Tue Sep 6 17:20:43 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

ОБНОВИТЬ

Оказывается, все работает, как ожидалось, если Docker размещен в образе Ubuntu 16.04.

На этом этапе я могу двигаться дальше, перестроив все свои виртуальные машины для использования образа Ubuntu 16.04, но я все еще не знаю, в чем заключалась исходная проблема. Мне все еще интересно услышать какие-либо предложения относительно того, в чем была причина исходной проблемы и как ее исправить.

TL; DR

Адаптируйте флаг MTU dockerd к MTU вашей виртуальной машины.

пример

Одна из ОС моего экземпляра OpenStack - ubuntu16.04.

  1. Проверьте MTU вашей виртуальной машины с помощью ifconfig(1450 в моем случае)
  2. cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service
  3. vi /etc/systemd/system/docker.service
  4. ExecStart=/usr/bin/docker daemon -H fd:// --mtu 1450
  5. systemctl daemon-reload
  6. service docker restart