Resin.io环境下Docker特权容器管理主机iptables规则的实现
在Resin.io环境下用特权容器管理主机iptables并自动清理规则
需求背景
你在树莓派的Resin.io框架里跑Mosquitto服务,设备有两个网络接口(分别连互联网和内网),希望只让Mosquitto暴露给局域网。之前用单容器的方案有几个头疼的问题:
- 容器里的服务必须用特权权限运行
- 没法用Docker DNS(通过容器名解析IP)
所以改用独立的防火墙容器来统一配置,完美解决这些问题的同时,还能在容器停止时自动清理iptables规则,避免残留问题。
核心配置拆解
1. docker-compose.yml 配置
在你提供的基础配置上,我补了个重启策略,确保容器意外退出能自动恢复:
version: '2' services: firewall: build: ./firewall container_name: firewall network_mode: host privileged: true restart: unless-stopped # 新增:意外退出自动重启
network_mode: host:让容器直接使用主机的网络命名空间,这样才能操作主机的iptablesprivileged: true:必须开启,否则容器没有权限修改主机的iptables规则
2. Dockerfile 编写
我们用Resin官方的树莓派基础镜像,把防火墙脚本复制进去并设置为入口点:
# 根据你的树莓派型号选择镜像,比如raspberrypi3/4/zero等 FROM resin/raspberrypi3-debian:latest # 安装iptables(部分基础镜像可能自带,保险起见加上) RUN apt-get update && apt-get install -y --no-install-recommends iptables && rm -rf /var/lib/apt/lists/* # 复制防火墙脚本到容器内并赋予执行权限 COPY firewall.sh /usr/local/bin/firewall.sh RUN chmod +x /usr/local/bin/firewall.sh # 设置入口点,让脚本在前台运行 ENTRYPOINT ["/usr/local/bin/firewall.sh"]
3. 关键的防火墙脚本(firewall.sh)
这个脚本要完成两个核心任务:添加iptables规则,以及捕获SIGTERM信号并清理规则:
#!/bin/bash # 定义清理规则的函数 cleanup() { echo "收到停止信号,开始清理iptables规则..." # 用-D(删除)对应添加时的-A,确保精准移除目标规则 iptables -D INPUT -i wlan0 -p tcp --destination-port 1883 -j DROP echo "规则已清理,容器退出" exit 0 } # 捕获Docker停止容器时发送的SIGTERM信号 trap cleanup SIGTERM # 添加iptables规则:禁止从wlan0接口访问1883端口(如果内网是eth0就替换成eth0) echo "添加iptables规则:禁止wlan0接口的TCP 1883端口访问..." iptables -A INPUT -i wlan0 -p tcp --destination-port 1883 -j DROP # 让脚本在前台持续运行,避免容器执行完脚本直接退出 echo "防火墙规则已生效,容器持续运行中..." tail -f /dev/null
trap cleanup SIGTERM:这是核心逻辑,当Docker发送停止信号给容器时,会自动触发清理函数,删掉之前添加的规则tail -f /dev/null:让脚本一直前台运行,保证容器存活,才能持续监听停止信号
部署步骤
- 在项目根目录下创建
firewall文件夹,把Dockerfile和firewall.sh放进去 - 把上面的docker-compose.yml放在项目根目录
- 正常通过Resin.io的部署流程推送代码即可
这样一来,防火墙容器会自动添加规则,当你停止容器时,规则也会被自动清理,完全不会留下残留问题,而且Mosquitto容器可以不用特权权限,还能正常使用Docker DNS啦~
内容的提问来源于stack exchange,提问作者Moritz




