Docker Network — Réseaux et Isolation
Configuration complète des réseaux Docker, équipements physiques (FortiGate, Cisco) et isolation VLAN CPE.
Réseaux Docker principaux
rgz_rgz-net (Réseau principal)
Type: Bridge network
CIDR: 172.23.0.0/16 (prefix rgz_ ajouté par Docker Compose)
⚠️ LL#72 Important: Le vrai nom du réseau est rgz_rgz-net, pas rgz-net
# Vérifier le nom réel
docker network ls | grep rgz
# Inspecter le réseau
docker network inspect rgz_rgz-netServices connectés (22 services):
Core (14):
rgz-api:172.23.0.10
rgz-db:172.23.0.11
rgz-redis:172.23.0.12
rgz-radius:172.23.0.13
rgz-gateway:172.23.0.14 (+ host network)
rgz-dns:172.23.0.15
rgz-beat:172.23.0.16
rgz-portal:172.23.0.17
rgz-web:172.23.0.18
rgz-kea:172.23.0.19
rgz-ids:172.23.0.20
rgz-nginx:172.23.0.21
rgz-wireguard:172.23.0.22
rgz-canary:172.23.0.23
Monitoring (8):
rgz-prometheus:172.23.0.30
rgz-grafana:172.23.0.31
rgz-alertmanager:172.23.0.32
rgz-elasticsearch:172.23.0.33
rgz-kibana:172.23.0.34
rgz-logstash:172.23.0.35
rgz-netflow:172.23.0.36
rgz-docs:172.23.0.37Isolation: Services internes uniquement (pas d'accès direct depuis Internet)
DNS interne: Docker embedded DNS resolver (127.0.0.11:53)
# Dans un container
nslookup rgz-api
# Résout: 172.23.0.10
# Ou via Docker DNS
ping rgz-postgres # ✅ Workstraefik-public (Réseau externe)
Type: Bridge external (partagé entre docker-compose files)
CIDR: 10.0.9.0/24
Services connectés: Traefik + services exposés (API, web, portal, grafana, docs)
Role: Reverse proxy HTTPS vers Internet
# Créer réseau (une fois)
docker network create traefik-public --driver bridge
# Services exposés
docker network inspect traefik-publicDocker Compose expose services:
networks:
traefik-public:
external: true
services:
rgz-api:
networks:
- rgz-net # réseau privé core
- traefik-public # réseau public Traefik
ports:
- "8000:8000" # accessible localhost:8000 (dev)Host network mode (rgz-gateway seulement)
Type: host
Raison: NET_ADMIN capability + nftables rules
# rgz-gateway doit être sur host network
networks:
- host
# JAMAIS sur rgz-net (nftables ne fonctionne pas en réseau bridge)Accès:
# Service sur host network = directement accessible
nft list tables # Depuis l'hôte
curl 127.0.0.1:8080 # Port sur hôteConfiguration IP fixes
Chaque service a une IP fixe statique pour fiabilité:
# docker-compose.core.yml
version: '3.8'
networks:
rgz-net:
driver: bridge
ipam:
config:
- subnet: 172.23.0.0/16
services:
rgz-api:
networks:
rgz-net:
ipv4_address: 172.23.0.10
rgz-db:
networks:
rgz-net:
ipv4_address: 172.23.0.11
# ... etcPourquoi IPs fixes?
✅ Healthchecks fiables (pas de DNS résolution)
✅ Configuration statique dans configs (Prometheus scrape)
✅ RADIUS NAS-Identifier validation
✅ Firewall rules nftables
Architecture réseau physique (FortiGate + Cisco)
Le réseau physique en amont de la stack Docker repose sur deux équipements :
┌──────────────────────────────────────────────────────────────────┐
│ INTERNET (ISP) │
└───────────┬──────────────────────────────────────────────────────┘
│
┌───────────▼──────────────────────────────────────────────────────┐
│ 🛡️ FortiGate Firewall │
│ ├─ VLAN Gateway (termine VLANs 100-499) │
│ ├─ NAT : 10.(100+n).0.0/24 → IP publique │
│ ├─ ACL : deny inter-VLAN, allow VLAN→Internet │
│ ├─ RADIUS NAS : Access-Request → rgz-radius (1812/udp) │
│ ├─ DHCP relay → rgz-kea (67/udp) │
│ ├─ NetFlow v5 → rgz-netflow (2055/udp) │
│ ├─ Syslog → Logstash → Elasticsearch │
│ └─ SNMP v3 → Prometheus │
└───────────┬──────────────────────────────────────────────────────┘
│ Trunk 802.1Q (VLANs 100-499 tagués)
│
┌───────────▼──────────────────────────────────────────────────────┐
│ 🔌 Cisco L2/L3 Switches │
│ ├─ Ports trunk → FortiGate (tous VLANs) │
│ ├─ Ports access → CPE (1 VLAN par revendeur) │
│ ├─ PoE : alimentation CPE via câble Ethernet │
│ ├─ Spanning Tree RSTP │
│ └─ SNMP v3 → Prometheus │
└───────────┬──────────────────────────────────────────────────────┘
│ Câbles Ethernet PoE
│
┌───────────▼──────────────────────────────────────────────────────┐
│ 📡 CPE LiteBeam 5AC (160+ antennes terrain) │
│ ├─ SSID : "ACCESS [NomRevendeur]" │
│ ├─ VLAN : port access sur Cisco (ex: VLAN 142) │
│ └─ Abonnés WiFi → DHCP → portail captif → Internet │
└──────────────────────────────────────────────────────────────────┘Isolation VLAN CPE
Schéma complet (couche physique + Docker) :
┌────────────────────────────────────────┐
│ ABONNÉ WiFi (smartphone/laptop) │
│ MAC aléatoire (iOS 14+/Android 10+) │
└────────┬───────────────────────────────┘
│ Connexion WiFi
│
┌────▼────────────────────────────────┐
│ CPE LiteBeam 5AC │
│ SSID: "ACCESS [Revendeur]" │
│ → Trafic abonné vers switch │
└────┬────────────────────────────────┘
│ Ethernet PoE (untagged)
│
┌────▼────────────────────────────────┐
│ Cisco Switch (port access) │
│ ↓ Tag VLAN (100+n) sur le port │
│ ↓ Forward via trunk 802.1Q │
└────┬────────────────────────────────┘
│ Trunk 802.1Q (tagged VLAN n)
│
┌────▼────────────────────────────────┐
│ FortiGate (VLAN Gateway) │
│ ↓ Termine VLAN n │
│ ↓ ACL: deny inter-VLAN │
│ ↓ DHCP relay → rgz-kea │
│ ↓ RADIUS NAS → rgz-radius │
│ ↓ NAT → Internet │
└────┬────────────────────────────────┘
│ DHCP relay
│
┌────▼────────────────────────────────┐
│ rgz-kea (DHCP Server) │
│ ↓ Identifie VLAN via Option 82 │
│ ↓ Alloue IP par VLAN │
│ IP: 10.(100+n).0.x/24 │
│ GW: 10.(100+n).0.1 (FortiGate) │
└────┬────────────────────────────────┘
│ Trafic data
│
┌────▼────────────────────────────────┐
│ FortiGate NAT │
│ → rgz-gateway (QoS HTB/fq_codel) │
│ → rgz-ids (Suricata IDS/IPS) │
│ → Internet │
└────┬────────────────────────────────┘
│ Trafic isolé par VLAN
│ Pas d'accès inter-revendeur
↓
InternetAllocation VLAN
| V1 Revendeur | VLAN ID | Subnet | Gateway | CPE IPs |
|---|---|---|---|---|
| Tech Connect | 100 | 10.100.0.0/24 | 10.100.0.1 | 10.100.0.2-254 |
| WIFI Zone A | 101 | 10.101.0.0/24 | 10.101.0.1 | 10.101.0.2-254 |
| WIFI Zone B | 102 | 10.102.0.0/24 | 10.102.0.1 | 10.102.0.2-254 |
| ... | ... | ... | ... | ... |
| Dernier V1 | 499 | 10.499.0.0/24 | 10.499.0.1 | 10.499.0.2-254 |
Total: 400 VLANs (100-499) pour 400 V1 revendeurs
Kea DHCP configuration
# /config/kea/kea-dhcp4.conf
subnet 10.100.0.0 netmask 255.255.255.0 {
option routers 10.100.0.1;
option domain-name-servers 172.23.0.15; # rgz-dns
pool {
range 10.100.0.10 10.100.0.250;
option routers 10.100.0.1;
}
# Identifier = NAS-ID via Option 82
subnet-id 0; # VLAN 100
}
subnet 10.101.0.0 netmask 255.255.255.0 {
# ... même structure
subnet-id 1; # VLAN 101
}
# ... jusqu'à VLAN 499Option 82 (Remote-ID) — Identifie le revendeur:
DHCP Request:
Client MAC: AA:BB:CC:DD:EE:FF
Option 82: Remote-ID = "access_tech_connect" (NAS-ID from API)
Kea mapping:
NAS-ID "access_tech_connect" → VLAN 100 → subnet 10.100.0.0/24
Result:
IP allocation: 10.100.0.x/24
Gateway: 10.100.0.1 (rgz-gateway)nftables firewall par VLAN
# /scripts/gateway/rgz-main.nft
table inet rgz_filter {
chain forward {
type filter hook forward priority 0; policy drop;
# Accepter VLAN internes (100-499)
iifname "vlan100" oifname "vlan100" accept
iifname "vlan100" oifname "eth0" accept
iifname "eth0" oifname "vlan100" accept
iifname "vlan101" oifname "vlan101" accept
iifname "vlan101" oifname "eth0" accept
iifname "eth0" oifname "vlan101" accept
# ... répéter pour vlan100-499
# Inter-VLAN: DROP (isolation)
iifname "vlan*" oifname "vlan*" drop
# Logging (optionnel)
counter log prefix "rejected: "
}
chain nat {
type nat hook postrouting priority 100;
# SNAT: 10.x.0.0/24 → publique IP
oifname "eth0" ip saddr 10.100.0.0/24 snat to <server_ip>
oifname "eth0" ip saddr 10.101.0.0/24 snat to <server_ip>
# ... etc
}
}VLAN tagging — Cisco + FortiGate (production)
En production, le VLAN tagging est géré par les équipements physiques :
Cisco Switch FortiGate
├─ Port 1 (access VLAN 100) → interface vlan100 (10.100.0.1/24)
├─ Port 2 (access VLAN 101) → interface vlan101 (10.101.0.1/24)
├─ Port 3 (access VLAN 102) → interface vlan102 (10.102.0.1/24)
├─ ... → ...
└─ Trunk (all VLANs) ──────→ Trunk port (tagged 100-499)Configuration Cisco (exemple) :
interface GigabitEthernet0/1
switchport mode access
switchport access vlan 100
description "CPE Tech Connect"
interface GigabitEthernet0/24
switchport mode trunk
switchport trunk allowed vlan 100-499
description "Trunk vers FortiGate"Configuration FortiGate (exemple) :
config system interface
edit "vlan100"
set vdom "root"
set ip 10.100.0.1 255.255.255.0
set interface "port1"
set vlanid 100
next
endVLAN tagging fallback (driver Linux vlan)
En dev/test sans FortiGate/Cisco, les VLANs peuvent être créés en logiciel :
# Créer VLANs Linux (dev uniquement)
ip link add link eth0 name vlan100 type vlan id 100
ip addr add 10.100.0.1/24 dev vlan100
ip link set vlan100 up# docker-compose.core.yml (dev)
services:
rgz-gateway:
cap_add:
- NET_ADMIN
networks:
- hostRésolution DNS interne
Docker embedded resolver:
# Depuis container rgz-api
cat /etc/resolv.conf
# nameserver 127.0.0.11:53
# Requête DNS
nslookup rgz-db
# Server: 127.0.0.11
# Address: 172.23.0.11
# Service discovery automatique
# rgz-db resolves to IP de rgz-db containerHealthcheck utilise DNS:
healthcheck:
test: ["CMD", "curl", "-f", "http://rgz-api:8000/health"]
# ✅ Résout rgz-api → 172.23.0.10Isolation réseau (LL#40 warning)
⚠️ JAMAIS nft flush ruleset sur Docker:
# ❌ DANGEREUX
nft flush ruleset
# Résultat: Docker chains disparaissent → perte connectivité réseau
# ✅ CORRECT: Supprimer sélectivement
nft delete table inet rgz_filter 2>/dev/null || trueRaison: Docker crée des tables nftables par défaut:
# Tables Docker
nft list tables
# inet firewalld (ou inet filter si iptables-nft)
# inet docker-ingress
# ... autres
# Flush supprime TOUTES les tables
# Y compris Docker infrastructureNetwork policies
| Service | Inbound | Outbound | Notes |
|---|---|---|---|
| rgz-api | 8000/tcp (rgz-net) | rgz-db, rgz-redis, external | JSON responses |
| rgz-db | 5432/tcp (rgz-net) | none | Read-only replication |
| rgz-redis | 6379/tcp (rgz-net) | none | No persistence |
| rgz-radius | 1812/udp, 1813/udp (ext) | rgz-api, rgz-db | Auth + acct |
| rgz-gateway | all (host) | all (host) | Firewall |
| rgz-dns | 53/udp (ext+rgz-net) | external | Recursive |
| rgz-portal | 80/tcp (rgz-net) | rgz-api | Proxy |
| rgz-web | 3000/tcp (rgz-net) | rgz-api | API calls |
Debugging réseau
# Lister tous les réseaux
docker network ls
# Inspecter réseau
docker network inspect rgz_rgz-net
# Services sur réseau
docker network inspect rgz_rgz-net | grep -A 2 "\"Containers\""
# Tester connectivité container → container
docker exec rgz-api ping rgz-db
# PING rgz-db (172.23.0.11): 56 data bytes
# Vérifier DNS résolution
docker exec rgz-api nslookup rgz-redis
# Address: 172.23.0.12
# Vérifier nftables (sur host)
sudo nft list tables
sudo nft list table inet rgz_filter
# Vérifier VLAN tagging
ip link show
# vlan100@eth0: <...>
# vlan101@eth0: <...>
# Vérifier DHCP (sur rgz-gateway)
docker exec rgz-gateway cat /var/lib/dhcp/dhcpd.leasesMonitoring réseau
Prometheus metrics:
# Container networking
container_network_receive_bytes_total{container_id="...", interface="eth0"}
container_network_transmit_bytes_total
# Docker bridge
docker_network_upGrafana dashboard:
- Network I/O (bits/sec)
- Dropped packets
- Connection count (netstat)
- VLAN isolation validation
Configuration yaml (référence)
# docker-compose.core.yml
version: '3.8'
networks:
rgz-net:
name: rgz_rgz-net
driver: bridge
driver_opts:
com.docker.network.bridge.name: docker_rgz
com.docker.driver.mtu: 1500
ipam:
driver: default
config:
- subnet: 172.23.0.0/16
gateway: 172.23.0.1
traefik-public:
external: true
name: traefik-public
services:
rgz-api:
networks:
rgz-net:
ipv4_address: 172.23.0.10
traefik-public:
ipv4_address: 10.0.9.10
ports:
- "127.0.0.1:8000:8000" # localhost only
labels:
traefik.http.routers.api.rule: "Host(`api-rgz.duckdns.org`)"
rgz-gateway:
network_mode: host # Special case
cap_add:
- NET_ADMINÉtapes suivantes
- Ports Reference — Tous les ports
- Dataflow — Flux de données
- Dependencies — Graph 81 outils