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

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

Запуск простого ванильного CentOS 8 с включенными NetworkManager и FirewallD. Зона брандмауэра по умолчанию - это public.

Варианты исполнения:

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

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

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

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

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

# Masquerading allows for docker ingress and egress (this is the juicy bit)firewall-cmd --zone=public --add-masquerade --permanent# Specifically allow incoming traffic on port 80/443 (nothing new here)firewall-cmd --zone=public --add-port=80/tcpfirewall-cmd --zone=public --add-port=443/tcp# Reload firewall to apply permanent rulesfirewall-cmd --reload

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

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

# Check what interface docker is using, e.g. 'docker0'ip link show# Check available firewalld zones, e.g. 'public'sudo firewall-cmd --get-active-zones# Check what zone the docker interface it bound to, most likely 'no zone' yetsudo firewall-cmd --get-zone-of-interface=docker0# So add the 'docker0' interface to the 'public' zone. Changes will be visible only after firewalld reloadsudo nmcli connection modify docker0 connection.zone public# Masquerading allows for docker ingress and egress (this is the juicy bit)sudo firewall-cmd --zone=public --add-masquerade --permanent# Optional open required incomming ports (wasn't required in my tests)# sudo firewall-cmd --zone=public --add-port=443/tcp# Reload firewalldsudo firewall-cmd --reload# Reload dockerdsudo systemctl restart docker# Test ping and DNS works:docker run busybox ping -c 1 172.16.0.1docker run busybox cat /etc/resolv.confdocker run busybox ping -c 1 yourhost.local

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

# 1. Stop Dockersystemctl stop docker
# 2. Recreate DOCKER-USER chain in firewalld. firewall-cmd --permanent \             --direct \             --remove-chain ipv4 filter DOCKER-USERfirewall-cmd --permanent \             --direct \             --remove-rules ipv4 filter DOCKER-USERfirewall-cmd --permanent \             --direct \             --add-chain ipv4 filter DOCKER-USER# (Ignore any warnings)
# 3. Docker Container <-> Container communicationfirewall-cmd --permanent \             --direct \             --add-rule ipv4 filter DOCKER-USER 1 \             -m conntrack --ctstate RELATED,ESTABLISHED \             -j ACCEPT \             -m comment \             --comment 'Allow docker containers to connect to the outside world'firewall-cmd --permanent \             --direct \             --add-rule ipv4 filter DOCKER-USER 1 \             -j RETURN \             -s 172.17.0.0/16 \             -m comment \             --comment 'allow internal docker communication'# Change the Docker Subnet to your actual one (e.g. 172.18.0.0/16)
# 4. Add rules for IPs allowed to access the Docker exposed ports.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 'Allow IP 1.2.3.4 to docker ports 80 and 443'
# 5. log docker traffic (if you like)firewall-cmd --direct \             --add-rule ipv4 filter DOCKER-USER 0 \             -j LOG \             --log-prefix ' DOCKER: '
# 6. Block all other IPs. This rule has lowest precedence, so you can add allowed IP rules later.firewall-cmd --permanent \             --direct \             --add-rule ipv4 filter DOCKER-USER 10 \             -j REJECT \             -m comment \             --comment 'reject all other traffic to DOCKER-USER'
# 7. Reload firewalld, Start Docker againfirewall-cmd --reloadsystemctl 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 'Allow docker containers to connect to the outside world'</rule>  <rule ipv="ipv4" table="filter" chain="DOCKER-USER" priority="0">-j RETURN -s 172.17.0.0/16 -m comment --comment 'allow internal docker communication'</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 'Allow IP 1.2.3.4 to docker ports 80 and 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 'reject all other traffic to DOCKER-USER'</rule></direct>

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

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

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

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

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

ПРЕДУПРЕЖДЕНИЕ: COMMAND_FAILED: '/usr/sbin/iptables -w10 -D FORWARD -i docker0 -o docker0 -j DROP' сбой: iptables: Неверное правило (существует ли в этой цепочке соответствующее правило?).

Мой даже не работает с полностью отключенным firewalld. У кого-нибудь есть какие-нибудь идеи??