这个问题其实 docker 和 podman 都存在。

当前版本的 docker 采用 iptables 动态创建和销毁规则, 而 podman 则通过 CNI 插件配置, 可以使用 firewalld 作为backend.

由于容器的特性– 随时创建,随时销毁。 这二者添加的 iptables 规则自然也都是动态的。这里有个问题是,如果一些其它服务执行了 flush 操作把iptables 规则清空了,则bridge网络的容器端口转发就会失效, 因为我们通过 -p 来映射端口,实际上是在 iptables 的 nat 表里创建了转发规则。

podman Github 有一个相关issue https://github.com/containers/podman/issues/5431 已经半年多了,不过最近一看,发现问题以另外一种方式解决了。

比如有人提到问题产生的场景:

Regarding the reload thing, on Fedora, NetworkManager has this postinstall line: test -f /usr/bin/firewall-cmd && firewall-cmd --reload --quiet || : Meaning when you upgrade the package, you lose rules created by podman.

解决方案就是给network命令新增加了一个reload 的子命令, 即 podman network reload.

这个命令的作用是,当你发现iptables 规则被flush掉后(对于Fedora是nft 规则), 可以用这个命令来修复缺失的规则. 而以前的做法是,只能销毁容器并重建, 有了这个reload命令,确实方便了许多。

Yes it was #8571. We now have the podman network reload command to recreate the iptables rules. This does not make the rules permanent but if they are deleted after a firewall reload you can run this command with the –all option to recreate the rules without having to restart containers.

PR 是在 Dec 8, 2020 merge的, 这个merge被包含在当前最新的 3.0.0版 中.

A new command, podman network reload, has been added. This command will re-configure the network of all running containers, and can be used to recreate firewall rules lost when the system firewall was reloaded (e.g. via firewall-cmd –reload).

命令用法:

podman network reload [CONTAINER...]

# 针对所有容器用-a参数
podman network reload -a

关于podman cni firewall 插件 配置

cni 默认有一些内置插件,放在单独的仓库 https://github.com/containernetworking/plugins, 这里我们用到的 firewall 插件就是其中之一。

编辑 /etc/cni/net.d/87-podman-bridge.conflist 修改firewall类型的backendfirewalld 即可启用firewalld作为防火墙规则后端:

    {
        "type": "firewall",
        "backend": "firewalld"
    },

取值来自 plugins/meta/firewall/firewall.go

// FirewallNetConf represents the firewall configuration.
type FirewallNetConf struct {
	types.NetConf

	// Backend is the firewall type to add rules to.  Allowed values are
	// 'iptables' and 'firewalld'.
    Backend string `json:"backend"`

    // ...
}

其实不配置也OK, 默认逻辑是:

Default to firewalld if it’s running, Otherwise iptables

refs

https://github.com/containernetworking/cni

https://github.com/containernetworking/plugins

https://www.cni.dev/plugins/meta/firewall/