CentOS 8 上 Docker CE 容器无网络连接

CentOS 8 上 Docker CE 容器无网络连接

我刚刚在 CentOS 上安装了最新版本的docker-ce,但我无法从邻近服务器访问已发布的端口无法到达外面来自容器本身。

运行普通的 CentOS 8,并启用 NetworkManager 和 FirewallD。默认防火墙区域是public

版本:

  • docker-ce19.03.3(官方 Docker RPM)
  • containerd.io1.2.6(适用于 CentOS 7 的官方 Docker RPM - 尚不适用于 CentOS 8)
  • CentOS 8.0.1905(最小安装)

答案1

在花了几天时间查看所涉及组件的日志和配置后,我正准备放弃并恢复到 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/tcp
firewall-cmd --zone=public --add-port=443/tcp

# Reload firewall to apply permanent rules
firewall-cmd --reload

重新启动或重启dockerd,入口和出口都应该正常工作。

答案2

之前的答案中缺少的是,你首先需要将你的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' yet
sudo firewall-cmd --get-zone-of-interface=docker0

# So add the 'docker0' interface to the 'public' zone. Changes will be visible only after firewalld reload
sudo 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 firewalld
sudo firewall-cmd --reload
# Reload dockerd
sudo systemctl restart docker

# Test ping and DNS works:
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

答案3

为了能够为 Docker 设置细粒度规则,我不需要将 docker0 设置为任何区域。

# 1. Stop Docker
systemctl stop docker
# 2. Recreate DOCKER-USER chain in 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

# (Ignore any warnings)

# 3. Docker Container <-> Container communication

firewall-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 again
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 '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>

缺点仍然是你需要从 CentOS7 安装 containerd.io,正如 Saustrup 所述

答案4

我已将 FirewallBackend 变量再次更改为 iptables,并且它对我来说有效。

在此更新中,nftables 过滤子系统是 Firewalld 守护进程的默认防火墙后端。要更改后端,请使用 /etc/firewalld.conf 文件中的 FirewallBackend 选项。

关联:Centos8 已弃用的功能

我没有太多关于此行为更改的信息。根据 CentOS8 日志,Docker 尝试使用的某些 iptables 规则不起作用:

警告:COMMAND_FAILED:'/usr/sbin/iptables -w10 -D FORWARD -i docker0 -o docker0 -j DROP' 失败:iptables:错误规则(该链中是否存在匹配的规则?)。

相关内容