前言
本篇文章就是要教会你如何在immortalwrt中用podman干掉Docker,难以想象,Docker在2025年对fw4的支持仍然一塌糊涂,是时候将它扫入垃圾堆了。相比之下,podman原生支持fw4,而且命令行语法与Docker高度兼容,迁移过来没什么难度。
安装
opkg update
opkg install podman python3-pip
pip3 install podman-compose
配置/etc/containers/containers.conf
podman的配置文件为 /etc/containers/containers.conf ,需要进行一点改动:
cp /etc/containers/containers.conf /etc/containers/containers.conf.bak
sed -i '/^#firewall_driver/afirewall_driver = "nftables"' /etc/containers/containers.conf
这个命令会在 /etc/containers/containers.conf 中查找 #firewall_driver 开头的行,并在其后增加一行 firewall_driver = "nftables" 。这里的修改参考自 https://github.com/openwrt/packages/issues/25730 。默认配置没有指定podman使用nfttable,此时podman还会试图用iptables配置防火墙,所以要改过来。
然后继续修改,将
#default_subnet = "10.88.0.0/16"
#default_subnet_pools = [
# {"base" = "10.89.0.0/16", "size" = 24},
# {"base" = "10.90.0.0/15", "size" = 24},
# {"base" = "10.92.0.0/14", "size" = 24},
# {"base" = "10.96.0.0/11", "size" = 24},
# {"base" = "10.128.0.0/9", "size" = 24},
#]
修改为
default_subnet = "172.16.0.0/16"
default_subnet_pools = [
{"base" = "172.17.0.0/16", "size" = 24},
{"base" = "172.18.0.0/16", "size" = 24},
{"base" = "172.19.0.0/16", "size" = 24},
{"base" = "172.20.0.0/16", "size" = 24},
{"base" = "172.21.0.0/16", "size" = 24},
]
这里是在配置podman默认使用的子网以及地址池,可以结合实际修改,不和路由器自身地址冲突即可。
配置dnsmasq

默认配置中,dnsmasq没有配置监听接口,所以虽然勾选了非全部地址,实际上还是会监听 0.0.0.0:53 ,而podman内置了aardvark-dns,它默认监听podman子网53端口,二者会产生冲突,所以需要在immortalwrt中配置dnsmasq监听的接口,我这里加入了lan和wireguard。
这是冲突时的错误信息,供参考:
root@ImmortalWrt:/etc/init.d# podman run --network testnet --rm alpine nslookup google.com
[WARN netavark::dns::aardvark] Failed to delete aardvark-dns entries after failed start: IO error: aardvark-dns failed to start: Error from child process
Error: netavark: IO error: Error while applying dns entries: IO error: aardvark-dns failed to start: Error from child process
Error starting server failed to bind udp listener on 172.17.0.1:53: IO error: Address in use (os error 98)
root@ImmortalWrt:/etc/init.d#
现在重启podman服务:
service podman restart
创建/etc/init.d/文件
podman特点之一是没有守护进程,所以需要自己写(找GPT生成)服务脚本,在/etc/init.d中创建名为halo的文件:
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
NAME=halo
WORKDIR="/opt/datas/halo"
start_service() {
procd_open_instance
procd_set_param command /usr/bin/podman-compose -f "$WORKDIR/compose.yaml" up -d
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn
procd_set_param user root
procd_set_param working_dir "$WORKDIR"
procd_close_instance
}
stop_service() {
cd "$WORKDIR" && /usr/bin/podman-compose -f "$WORKDIR/compose.yaml" down
}
reload_service() {
cd "$WORKDIR" && /usr/bin/podman-compose -f "$WORKDIR/compose.yaml" restart
}
service_triggers() {
procd_add_reload_trigger "podman"
}
然后启用该服务脚本:
service halo enable # 在 /etc/rc.d/ 中创建一个指向 /etc/init.d/halo 的符号链接
service halo start
这样容器就启动了。如果不使用服务脚本,只是一次性运行,可以执行
podman compose up -d
或者
podman-compose up -d
语法与Docker几乎一致。至于compose.yaml文件内容与使用Docker时完全一致,无需改动:
root@ImmortalWrt:/opt/datas/halo# cat compose.yaml
version: "3"
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.21
restart: on-failure:3
volumes:
- ./halo2:/root/.halo2
ports:
- "8001:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
environment:
# JVM 参数,默认为 -Xmx256m -Xms256m,可以根据实际情况做调整,置空表示不添加 JVM 参数
- JVM_OPTS=-Xmx256m -Xms256m
command:
# 外部访问地址,请根据实际需要修改
- --halo.external-url=https://blog.tccmu.com
配置防火墙
此时容器虽然可以从外部访问,但是其自身无法访问外面,无法执行安装主题、更新插件等任务。解决方法和之前配置Docker时一致。首先创建一个防火墙区域,然后将对应的podman1加里就完事了:


之前写过一个获取Docker容器与bridge接口对应关系的脚本,将 docker 替换 成 podman 就能继续使用了:
# podman-bridge.sh
podman network ls --format "{{.Name}}" | while read name; do
if [ "$name" != "bridge" ]; then # 排除默认的bridge网络,因为它通常已经工作
bridge_name=$(podman network inspect "$name" --format "{{ (index .Options \"com.docker.network.bridge.name\") }}" 2>/dev/null)
if [ -z "$bridge_name" ]; then
# 如果没有明确的com.docker.network.bridge.name选项,通常是br-<network_id的前12位>
network_id=$(podman network inspect "$name" --format "{{.Id}}")
bridge_name="br-${network_id:0:12}"
fi
echo "Podman network '$name' uses bridge interface: $bridge_name"
fi
done
root@ImmortalWrt:~# ./podman-bridge.sh
Podman network 'halo_default' uses bridge interface: br-44118e0e10e5
Podman network 'podman' uses bridge interface: br-2f259bab93aa
补充
如果修改配置文件后,podman默认网关信息没有更新,可以进入 /etc/containers/networks 删除podman.json ,这个目录中保存了各个网络接口配置文件。