Вопрос или проблема
Я только что установил последнюю версию 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.
Проблемы и их причины
-
Сетевые ограничения firewalld: CentOS 8 использует
firewalld
сnftables
в качестве бэкенда по умолчанию. Это приводит к тому, что настройки сетевой безопасности могут не применяться так, как ожидается. Например, порты, опубликованные контейнерами, могут блокироваться. -
Отсутствие маскарадинга: Для обеспечения доступа контейнеров к интернету необходимо включить маскарадинг для сетевого интерфейса, который исходит из контейнеров. По умолчанию этот интерфейс (
docker0
) может не принадлежать активной зоне брандмауэра. -
Правила 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
. Однако, при выполнении вышеперечисленных шагов, можно эффективно решить эти проблемы и обеспечить надёжное сетевое взаимодействие контейнеров. Убедитесь, что у вас всегда актуальны правила брандмауэра и следите за всеми изменениями в конфигурации.