Нет сетевого подключения к/от контейнера Docker CE на CentOS 8

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

Я только что установил последнюю версию docker-ce на CentOS, но я не могу достучаться до опубликованных портов с соседнего сервера и не могу выйти наружу из контейнера.

Запускаю стандартный CentOS 8 с включенным NetworkManager и FirewallD. Значение по умолчанию для зоны брандмауэра – public.

Версии:

  • docker-ce 19.03.3 (официальный RPM от Docker)
  • containerd.io 1.2.6 (официальный RPM от Docker для CentOS 7 – пока недоступен для CentOS 8)
  • CentOS 8.0.1905 (минимальная установка)

Проведя несколько дней, изучая логи и конфигурации вовлеченных компонентов, я был готов сдаться и вернуться к Fedora 30, где это вроде как работает сразу же из коробки.

Сосредоточившись на брандмауэре, я понял, что отключение firewalld похоже решает проблему, но я бы предпочел этого не делать. При проверке сетевых правил с помощью iptables я осознал, что переход на nftables означает, что iptables теперь представляет собой абстрактный уровень, который показывает только небольшую часть правил nftables. Это означает, что большинство – если не все – конфигурации firewalld будут применяться за пределами области действия iptables.

Я был привычен находить всю правду в iptables, так что это потребует времени, чтобы привыкнуть.

Короче говоря – чтобы это работало, мне пришлось включить маскировку. Похоже, dockerd уже делал это через iptables, но, очевидно, это нужно специально включить для зоны брандмауэра, чтобы маскировка iptables работала:

# Маскировка позволяет docker входящий и исходящий трафик (это самое главное)
firewall-cmd --zone=public --add-masquerade --permanent

# Специально разрешите входящий трафик на порту 80/443 (ничего нового здесь)
firewall-cmd --zone=public --add-port=80/tcp
firewall-cmd --zone=public --add-port=443/tcp

# Перезагрузите брандмауэр, чтобы применить постоянные правила
firewall-cmd --reload

Перезагрузите или перезапустите dockerd, и и входящий, и исходящий трафик должны заработать.

Что отсутствует в предыдущих ответах, так это то, что вам сначала нужно добавить ваш docker-интерфейс в зону, которую вы настраиваете, например, public (или добавить его в зону “доверенные”, что было предложено здесь, но я сомневаюсь, что это мудро с точки зрения безопасности). Потому что по умолчанию он не назначен ни к одной зоне. Также не забудьте перезагрузить демон docker, когда закончите.

# Проверьте, какой интерфейс использует docker, например, 'docker0'
ip link show
 
# Проверьте доступные зоны firewalld, например, 'public'
sudo firewall-cmd --get-active-zones
 
# Проверьте, к какой зоне привязан интерфейс docker, скорее всего, 'no zone'
sudo firewall-cmd --get-zone-of-interface=docker0
 
# Так что добавьте интерфейс 'docker0' в зону 'public'. Изменения будут видны только после перезагрузки firewalld
sudo nmcli connection modify docker0 connection.zone public
# если nmcli не работает, также существует способ добавить интерфейс в зону (хотя и непроверенный): sudo firewall-cmd --zone=public --add-interface=docker0
 
# Маскировка позволяет docker входящий и исходящий трафик (это самое главное)
sudo firewall-cmd --zone=public --add-masquerade --permanent
# Опционально откройте необходимые входящие порты (в моих тестах это не требовалось)
# sudo firewall-cmd --zone=public --add-port=443/tcp
# Перезагрузите firewalld
sudo firewall-cmd --reload
# Перезагрузите dockerd
sudo systemctl restart docker
 
# Проверьте, работает ли ping и DNS:
docker run busybox ping -c 1 172.16.0.1
docker run busybox cat /etc/resolv.conf
docker run busybox ping -c 1 yourhost.local

Чтобы иметь возможность устанавливать детализированные правила для Docker, мне не нужно было устанавливать docker0 в какую-либо зону.

# 1. Остановите Docker
systemctl stop docker
# 2. Воссоздайте цепочку DOCKER-USER в firewalld.
firewall-cmd --permanent \
             --direct \
             --remove-chain ipv4 filter DOCKER-USER

firewall-cmd --permanent \
             --direct \
             --remove-rules ipv4 filter DOCKER-USER

firewall-cmd --permanent \
             --direct \
             --add-chain ipv4 filter DOCKER-USER

# (Игнорируйте любые предупреждения)

# 3. Общение между контейнерами Docker

firewall-cmd --permanent \
             --direct \
             --add-rule ipv4 filter DOCKER-USER 1 \
             -m conntrack --ctstate RELATED,ESTABLISHED \
             -j ACCEPT \
             -m comment \
             --comment 'Разрешить контейнерам docker подключаться к внешнему миру'

firewall-cmd --permanent \
             --direct \
             --add-rule ipv4 filter DOCKER-USER 1 \
             -j RETURN \
             -s 172.17.0.0/16 \
             -m comment \
             --comment 'разрешить внутреннюю коммуникацию docker'

# Измените подсеть Docker на вашу фактическую (например, 172.18.0.0/16)
# 4. Добавьте правила для IP-адресов, которым разрешен доступ к проверяемым портам Docker.

firewall-cmd --permanent \
             --direct \
             --add-rule ipv4 filter DOCKER-USER 1 \
             -o docker0 \
             -p tcp \
             -m multiport \
             --dports 80,443 \
             -i eth0 \
             -o docker0 \
             -s 1.2.3.4/32 \
             -j ACCEPT \
             -m comment \
             --comment 'Разрешить IP 1.2.3.4 доступ к портам docker 80 и 443'
# 5. Логировать трафик docker (если хотите)

firewall-cmd --direct \
             --add-rule ipv4 filter DOCKER-USER 0 \
             -j LOG \
             --log-prefix ' DOCKER: '
# 6. Заблокируйте все остальные IP-адреса. 
Это правило имеет наименьший приоритет, поэтому вы можете добавить разрешенные IP-адреса позже.

firewall-cmd --permanent \
             --direct \
             --add-rule ipv4 filter DOCKER-USER 10 \
             -j REJECT \
             -m comment \
             --comment 'отклонить весь другой трафик к DOCKER-USER'
# 7. Перезагрузите firewalld. Запустите Docker снова
firewall-cmd --reload
systemctl start docker

Это заканчивается правилами, определенными в /etc/firewalld/direct.xml:

<?xml version="1.0" encoding="utf-8"?>
<direct>
  <chain ipv="ipv4" table="filter" chain="DOCKER-USER"/>
  <rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment 'Разрешить контейнерам docker подключаться к внешнему миру'</rule>
  <rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-j RETURN -s 172.17.0.0/16 -m comment --comment 'разрешить внутреннюю коммуникацию docker'</rule>
  <rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-p tcp -m multiport --dports 80,443 -s 1.2.3.4/32 -j ACCEPT -m comment --comment 'Разрешить IP 1.2.3.4 доступ к портам docker 80 и 443'</rule>
  <rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-j LOG --log-prefix ' DOCKER TCP: '</rule>
  <rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="10">-j REJECT -m comment --comment 'отклонить весь другой трафик к DOCKER-USER'</rule>
</direct>

Недостатком все еще является то, что вам нужно установить containerd.io из CentOS7, как указано Сауструпом

Я снова изменил переменную FirewallBackend на iptables, и это работает для меня.

С этим обновлением подсистема фильтрации nftables является
бэкэндом брандмауэра по умолчанию для демона firewalld. Чтобы изменить бэкэнд, используйте
параметр FirewallBackend в файле /etc/firewalld.conf.

Ссылка: Centos8 Устаревшая функциональность

У меня нет слишком много информации об этом изменении поведения. Некоторые из правил iptables, которые Docker пытается использовать, не работают согласно логам CentOS8:

WARNING: COMMAND_FAILED: ‘/usr/sbin/iptables -w10 -D FORWARD -i
docker0 -o docker0 -j DROP’ не удалось: iptables: Плохое правило (существует ли
соответствующее правило в этой цепочке?).

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

Решение проблемы отсутствия сетевого подключения к контейнеру Docker CE на CentOS 8

При установке Docker CE на CentOS 8, вы можете столкнуться с проблемами, связанными с отсутствием сетевого подключения в контейнерах Docker. Это часто связано с конфигурацией сетевой безопасности, особенно когда такие службы, как firewalld, включены. В данной статье мы постараемся проанализировать проблему и предложить пошаговое решение для обеспечения сетевого подключения в ваших контейнерах Docker.

Проблемы и их причины

  1. Сетевые ограничения firewalld: CentOS 8 использует firewalld с nftables в качестве бэкенда по умолчанию. Это приводит к тому, что настройки сетевой безопасности могут не применяться так, как ожидается. Например, порты, опубликованные контейнерами, могут блокироваться.

  2. Отсутствие маскарадинга: Для обеспечения доступа контейнеров к интернету необходимо включить маскарадинг для сетевого интерфейса, который исходит из контейнеров. По умолчанию этот интерфейс (docker0) может не принадлежать активной зоне брандмауэра.

  3. Правила iptables: Поскольку Docker использует собственные правила iptables для управления сетевым трафиком, отсутствие необходимых правил может привести к тому, что контейнеры не смогут взаимодействовать с внешней сетью или между собой.

Решение проблемы

Шаг 1: Проверка интерфейса Docker

Сначала необходимо выявить, какой сетевой интерфейс использует Docker:

ip link show

Чаще всего это docker0. Теперь нужно проверить, к какой зоне firewalld принадлежит этот интерфейс:

sudo firewall-cmd --get-zone-of-interface=docker0

Если результат будет "нет зоны", это указывает на то, что для интерфейса docker0 не применяются никакие правила.

Шаг 2: Добавление интерфейса к зоне

Необходимо добавить интерфейс docker0 в зону public или trusted. Лучше всего выбрать зону public с правильной конфигурацией политики безопасности:

sudo nmcli connection modify docker0 connection.zone public

или

sudo firewall-cmd --zone=public --add-interface=docker0 --permanent
Шаг 3: Включение маскарадинга

Теперь необходимо активировать маскарадинг для этой зоны:

sudo firewall-cmd --zone=public --add-masquerade --permanent

Также открываем необходимые порты (например, для HTTP и HTTPS):

sudo firewall-cmd --zone=public --add-port=80/tcp --permanent
sudo firewall-cmd --zone=public --add-port=443/tcp --permanent
Шаг 4: Применение изменений

После внесения всех изменений не забудьте перезагрузить настройки firewalld и сам Docker:

sudo firewall-cmd --reload
sudo systemctl restart docker
Шаг 5: Проверка подключения

Теперь можно протестировать подключение из контейнера к сети и между контейнерами. Используйте следующие команды:

docker run --rm busybox ping -c 1 8.8.8.8
docker run --rm busybox cat /etc/resolv.conf

Также можно проверить внутреннюю связь между контейнерами:

docker run -d --name container1 busybox sleep 3600
docker run -d --name container2 --link container1 busybox sleep 3600
docker exec container2 ping -c 1 container1

Заключение

Проблемы с подключением в Docker на CentOS 8 часто случаются из-за строгой конфигурации брандмауэра firewalld. Однако, при выполнении вышеперечисленных шагов, можно эффективно решить эти проблемы и обеспечить надёжное сетевое взаимодействие контейнеров. Убедитесь, что у вас всегда актуальны правила брандмауэра и следите за всеми изменениями в конфигурации.

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

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