Sem conectividade de rede de / para o contêiner Docker CE no CentOS 8

Acabei de instalar a versão mais recente do docker-ce em CentOS, mas eu não é possível alcançar portas publicadas de um servidor vizinho e não pode chegar ao exterior do próprio recipiente.

Executando um vanilla CentOS 8 simples com NetworkManager e FirewallD habilitado. A zona padrão do firewall é public.

Versao:

  • docker-ce 19.03.3 (Docker RPM oficial)
  • containerd.io 1.2.6 (Docker RPM oficial para CentOS 7-ainda não disponível para CentOS 8)
  • CentOS 8.0.1905 (instalação mínima)

Depois de passar alguns dias olhando logs e configurações para os componentes envolvidos, eu estava prestes a jogar a toalha e voltar para o Fedora 30, onde isso parece funcionar direto da caixa.

Concentrando-se em firewalling, percebi que desativar firewalld parecia fazer o truque, mas eu preferiria não fazer isso. Ao inspecionar regras de rede com iptables, Eu percebi que a mudança para nftables significar iptables agora é uma camada de abstração que mostra apenas uma pequena parte do nftables regra. Isso significa que a maioria-se não todos-do firewalld a configuração será aplicada fora do escopo de iptables.

Eu estava acostumado a ser capaz de encontrar toda a verdade em iptables, então isso vai levar algum tempo para se acostumar.

Longa história curta - para que isso funcionasse, eu tive que permitir mascarar. Parecia dockerd já fez isso através iptables, mas aparentemente isso precisa ser habilitado especificamente para a zona de firewall para iptables masquerading para trabalhar:

# 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

Reiniciar ou reiniciar dockerd, e a entrada e a saída devem funcionar.

O que está faltando nas respostas anteriores é o fato de que você primeiro precisa adicionar sua interface docker à zona que você configura, por exemplo, pública (ou adicioná-la à zona "confiável" sugerida aqui mas duvido que seja sábio, do ponto de vista da segurança). Porque, por padrão, não é atribuído a uma zona. Lembre - se também de recarregar o daemon do docker quando terminar.

# 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

Para poder definir regras refinadas para o Docker, não precisei definir o docker0 para nenhuma zona.

# 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

Isso termina em regras definidas em/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>

Desvantagem ainda é que você precisa instalar containerd.io de CentOS7 como afirmado por Saustrup

Mudei a variável FirewallBackend para iptables novamente e funciona para mim.

Com esta atualização, o subsistema de filtragem nftables é o back-end padrão do firewall para o daemon firewalld. Para alterar o back-end, use a opção FirewallBackend no/etc / firewalld.arquivo conf.

Link: Centos8 Depreciado_funcionalidade

Não tenho muita informação sobre essa mudança de comportamento. Algumas das regras iptables que o Docker tenta usar não estão funcionando de acordo com os logs do CentOS8:

Aviso: COMMAND_FAILED: '/ usr / sbin / iptables - W10-D FORWARD-I docker0 - o docker0 - J DROP ' falhou: iptables: Bad rule (existe uma regra correspondente nessa cadeia?).

O meu nem funciona com firewalld completamente desativado. Alguém tem alguma ideia ??