Red Hat 系 network 网络管理下 Docker 的小坑

当同事反馈 Docker 容器无法正常上网时,我们通过分析发现这是由于 IPv4 转发被关闭引起的。最终我们发现,在 Red Hat 系列系统中,使用 /etc/rc.d/init.d/network 来管理网络时,重启网络服务实际上执行的是 stopstart 命令的组合。而在执行 stop 命令时,会运行 sysctl -w net.ipv4.ip_forward=0,从而导致 IPv4 转发被禁用。
这个问题早在 Red Hat Enterprise Linux 5 中就已经被提出(参考 Bug 552653)。实际上,这个问题一直延续到 Red Hat Enterprise Linux 7。

但在执行 start 命令的时候,会执行 apply_sysctl 函数,而 apply_sysctl 函数引用来源于 /etc/init.d/functions 文件。

❯ cat /etc/rc.d/init.d/network
. /etc/init.d/functions
start)
...(略)
apply_sysctl # 应用 sysctl

stop)
...(略)
sysctl -w net.ipv4.ip_forward=0 > /dev/null 2>&1

/etc/init.d/functions 文件中 apply_sysctl 函数,会对 /etc/sysctl.d 目录下的配置文件进行重新加载应用。

❯ cat /etc/init.d/functions
...(略)

# Apply sysctl settings, including files in /etc/sysctl.d
apply_sysctl() {
    if [ -x /lib/systemd/systemd-sysctl ]; then
    /lib/systemd/systemd-sysctl
    else
        for file in /usr/lib/sysctl.d/*.conf ; do
            is_ignored_file "$file" && continue
            [ -f /run/sysctl.d/${file##*/} ] && continue
            [ -f /etc/sysctl.d/${file##*/} ] && continue
            test -f "$file" && sysctl -e -p "$file" >/dev/null 2>&1
        done
        for file in /run/sysctl.d/*.conf ; do
            is_ignored_file "$file" && continue
            [ -f /etc/sysctl.d/${file##*/} ] && continue
            test -f "$file" && sysctl -e -p "$file" >/dev/null 2>&1
        done
        for file in /etc/sysctl.d/*.conf ; do
            is_ignored_file "$file" && continue
            test -f "$file" && sysctl -e -p "$file" >/dev/null 2>&1
        done
        sysctl -e -p /etc/sysctl.conf >/dev/null 2>&1
    fi
}

因此,如果您在 /etc/sysctl.d 目录下有配置文件启用了 net.ipv4.ip_forward=1,则不必担心该问题。然而,如果您只是通过 echo 1 > /proc/sys/net/ipv4/ip_forward 手动配置 IPv4 转发,将会受到影响。

实际上,使用 Docker 时,一般不需要手动配置 net.ipv4.ip_forward=1,因为 Docker 默认会自动启用 IPv4 转发功能(--ip_forward=true)。但是,如果您使用 /etc/rc.d/init.d/network 管理网络,则必须将以下内容添加到 /etc/sysctl.d/99-sysctl.conf 中:

❯ echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.d/99-sysctl.conf

在 Docker 的源码仓库中可以看到相关实现:moby/libnetwork/drivers/bridge/setup_ip_forwarding.go

const (
    ipv4ForwardConf     = "/proc/sys/net/ipv4/ip_forward"
    ipv4ForwardConfPerm = 0o644
)

func configureIPForwarding(enable bool) error {
    var val byte
    if enable {
        val = '1'
    }
    return os.WriteFile(ipv4ForwardConf, []byte{val, '\n'}, ipv4ForwardConfPerm)
}

结论:如果您在 Red Hat Enterprise Linux 5-7 系列中使用 Docker 服务,并且使用桥接网络模式 (bridge) 和 /etc/rc.d/init.d/network 进行网络管理,则必须执行以下配置,以确保 IPv4 转发功能正常:

❯ echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.d/99-sysctl.conf

或者,您可以在重启网络服务后,再次重启 Docker 服务,以确保容器网络正常。当然,如果您使用 host 网络模式,则不受此问题影响。

实际因为 Rocky Linux 最低版本是 Rocky Linux 8,并通过 NetworkManager 进行网络管理,所以就不存在此问题。😂

Avatar photo

关于 木子

Founder of the Rocky Linux Chinese community, MVP、VMware vExpert、TVP, advocate for cloud native technologies, with over ten years of experience in site reliability engineering (SRE) and the DevOps field. Passionate about Cloud Computing、Microservices、CI&CD、DevOps、Kubernetes, currently dedicated to promoting and implementing Rocky Linux in Chinese-speaking regions.
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇