Swarm作用域Docker桥接网络无法配置子网与驱动选项,如何控制Swarm容器出口IP?
Let's break down your problem and walk through practical solutions step by step. First, the root cause of your custom options failing with a swarm-scoped bridge network: Docker Swarm restricts configuration for bridge networks in swarm mode. Swarm takes over management of these networks and ignores most bridge-specific customizations (like com.docker.network.bridge.enable_ip_masquerade, custom subnets, or bridge names) because it treats swarm-scoped bridge networks as standardized, node-local resources managed by the cluster.
Solution 1: Use Local-Scope Bridge Networks (Best Match for Your Original Setup)
If you're running a single-node swarm, or can replicate the same network configuration across all swarm nodes, this is the most straightforward fix that preserves your original setup:
Create the identical local-scoped bridge network on every swarm node
Run this command on each node in your swarm cluster to ensure consistent network configuration:docker network create --driver=bridge --scope=local --subnet=172.123.0.0/16 -o "com.docker.network.bridge.enable_ip_masquerade"="false" -o "com.docker.network.bridge.name"="my_local_bridge" my_local_bridgeAttach your swarm service to the local network as an external resource
Swarm won't automatically recognize local-scoped networks, so you need to mark the network as external when creating your service:docker service create --name my_service --network my_local_bridge --network-opt external=true nginxYour custom subnet and masquerade disable settings will now work as intended. You can reuse your original iptables SNAT rule to enforce the external exit IP:
sudo iptables -t nat -A POSTROUTING -s 172.123.0.0/16 ! -o my_local_bridge -j SNAT --to-source <your_external_ip>
Solution 2: Adjust iptables Rules for Swarm-Scope Bridge Networks
If you must use a swarm-scoped bridge network, you'll need to manually override the default MASQUERADE rules that Swarm automatically creates. Here's how:
Identify the swarm bridge network's actual subnet and interface
Rundocker network inspect my_swarm_bridgeto get the auto-assigned subnet (e.g.,172.21.0.0/16in your example). Useip link showto find the bridge interface name (typically something likebr-<short_network_id>).Remove Swarm's default MASQUERADE rule
First, list the NAT POSTROUTING rules to find the relevant line:sudo iptables -t nat -L POSTROUTING -n --line-numbersDelete the MASQUERADE rule targeting your swarm subnet (replace
<rule_number>with the correct line):sudo iptables -t nat -D POSTROUTING <rule_number>Add your custom SNAT rule
Replace placeholders with your values to enforce the external exit IP:sudo iptables -t nat -A POSTROUTING -s <swarm_subnet> ! -o <bridge_interface> -j SNAT --to-source <your_external_ip>Persist and auto-maintain the rules
Swarm will re-add the MASQUERADE rule if the network restarts, the Docker daemon restarts, or the service is updated. To fix this automatically:- Create a script
swarm_snat_fix.sh(update placeholders for your environment):#!/bin/bash SWARM_SUBNET="172.21.0.0/16" EXTERNAL_IP="<your_external_ip>" BRIDGE_IFACE="br-abc123" # Replace with your bridge interface name # Delete any existing MASQUERADE rule for the subnet sudo iptables -t nat -D POSTROUTING -s $SWARM_SUBNET -j MASQUERADE 2>/dev/null # Add SNAT rule if it doesn't already exist sudo iptables -t nat -C POSTROUTING -s $SWARM_SUBNET ! -o $BRIDGE_IFACE -j SNAT --to-source $EXTERNAL_IP 2>/dev/null if [ $? -ne 0 ]; then sudo iptables -t nat -A POSTROUTING -s $SWARM_SUBNET ! -o $BRIDGE_IFACE -j SNAT --to-source $EXTERNAL_IP fi - Make the script executable:
chmod +x swarm_snat_fix.sh - Set up a cron job or systemd service to run the script every minute (or on Docker daemon restarts) to keep the rules intact.
- Create a script
内容的提问来源于stack exchange,提问作者DarkW

