Linux network namespace с bridge
Что такое network namespace в Linux?
Network namespace в Linux - это механизм, который позволяет создавать изолированные сетевые окружения внутри одной операционной системы. У каждого namespace - свои сетевые интерфейсы, IP-адреса, таблицы маршрутизации и правила firewall.
Bridge, в свою очередь, - это сетевое устройство, которое соединяет несколько сетевых интерфейсов и позволяет им общаться друг с другом. Он работает на канальном уровне (Layer 2) модели OSI.
В этой статье разберём три сценария использования namespace:
- Прямое взаимодействие одного namespace с другим на том же хосте.
- Общение между одним и несколькими namespace через Linux bridge - так коммуникацию организовать проще.
- Выходим наружу! Namespace взаимодействует с внешним миром через Linux bridge.

Как организовать прямое взаимодействие между двумя namespace на одном хосте

Чтобы настроить network namespace с bridge в Linux, выполните следующие шаги.
Создаём namespace
ip netns add dev ip netns add prod # показать список namespace ip netns show
Создаём виртуальную пару Ethernet (veth)
Теперь создадим виртуальный Ethernet-кабель для соединения namespace:
ip link add veth-dev type veth peer veth-prod
Подключаем veth к namespace
ip link set veth-dev netns dev ip link set veth-prod netns prod
Почти готово. Осталось назначить IP-адреса в одной сети (/24) внутри каждого namespace:
ip netns exec dev ip addr add 192.168.10.1/24 dev veth-dev ip netns exec dev ip link set veth-dev up ip netns exec prod ip addr add 192.168.10.2/24 dev veth-prod ip netns exec prod ip link set veth-prod up
Проверяем связь
Пингуем один namespace из другого:
ip netns exec dev ping 192.168.10.2 ip netns exec prod ping 192.168.10.1
Ниже - сводный скрипт, который создаёт два namespace, соединяет их и проверяет связь:
#!/bin/bash set euxo -pipefail ip netns add dev ip netns add prod # показать namespace ip netns show ip link add veth-dev type veth peer name veth-prod ip link set veth-dev netns dev ip link set veth-prod netns prod ip -n dev addr add 192.168.10.1/24 dev veth-dev ip -n prod addr add 192.168.10.2/24 dev veth-prod ip -n dev link set veth-dev up ip -n prod link set veth-prod up ip netns exec prod ping 192.168.10.1 # Очистка ip netns delete dev ip netns delete prod
Пример вывода
Ниже - пример вывода, показывающий, что пакеты успешно передаются между двумя namespace:
root@ip-172-31-86-219:~$ sudo ip netns exec prod ping 192.168.10.1 PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data. 64 bytes from 192.168.10.1: icmp_seq=1 ttl=64 time=0.022 ms 64 bytes from 192.168.10.1: icmp_seq=2 ttl=64 time=0.032 ms 64 bytes from 192.168.10.1: icmp_seq=3 ttl=64 time=0.033 ms 64 bytes from 192.168.10.1: icmp_seq=4 ttl=64 time=0.034 ms
Создаём network namespace с bridge в Linux

Давайте теперь соберём схему с bridge, чтобы несколько namespace могли общаться через общий L2-сегмент.
Создаём namespace
ip netns add dev ip netns add prod
Создаём bridge
Используя network namespace и bridge, можно строить изолированные сетевые окружения в Linux и управлять их связностью так, как нужно.
Здесь команда ip link set dev v-net-0 up поднимает устройство bridge.
ip link add v-net-0 type bridge ip link set dev v-net-0 up
Проверим, что bridge создан.
Проверка через bridge-utils
apt install bridge-utils brctl show
Пример вывода:
root@ip-172-31-86-219:~# brctl show bridge name bridge id STP enabled interfaces v-net-0 8000.4248a9c73e1f no
Подключаем namespace к bridge
Теперь создадим veth-пары, чтобы подключить dev и prod к bridge v-net-0.
Создаём линк между namespace dev и bridge
ip link add veth-dev type veth peer name veth-dev-br
Создаём линк между namespace prod и bridge
ip link add veth-prod type veth peer name veth-prod-br
Настраиваем стороны линков
Для namespace dev
ip link set veth-dev netns dev ip link set veth-dev-br master v-net-0
Для namespace prod
ip link set veth-prod netns prod ip link set veth-prod-br master v-net-0
Назначаем IP-адреса
ip -n dev addr add 192.168.10.1/24 dev veth-dev ip -n prod addr add 192.168.10.2/24 dev veth-prod
Поднимаем интерфейсы
Со стороны namespace:
ip -n dev link set veth-dev up ip -n prod link set veth-prod up
Со стороны bridge:
ip link set veth-dev-br up ip link set veth-prod-br up
Теперь можно проверить связность между namespace:
ip netns exec dev ping 192.168.10.2
Полный скрипт
#!/bin/bash set euxo -pipefail ip netns add dev ip netns add prod # show namespace ip netns show ip link add v-net-0 type bridge ip link set dev v-net-0 up ip link add veth-dev type veth peer name veth-dev-br ip link add veth-prod type veth peer name veth-prod-br ip link set veth-dev netns dev ip link set veth-dev-br master v-net-0 ip link set veth-prod netns prod ip link set veth-prod-br master v-net-0 ip -n dev addr add 192.168.20.1/24 dev veth-dev ip -n prod addr add 192.168.20.2/24 dev veth-prod ip -n dev link set veth-dev up ip -n prod link set veth-prod up ip link set veth-dev-br up ip link set veth-prod-br up # Cleanup ip netns delete dev ip netns delete prod ip link set dev v-net-0 down brctl delbr v-net-0
Теперь у вас есть network namespace с bridge. Любые сетевые интерфейсы, добавленные в bridge, смогут общаться друг с другом.
Чтобы настроить IP-адреса, маршрутизацию или правила файрвола внутри namespace, используйте ip netns exec для выполнения команд в его контексте.
Выходим наружу! Namespace общается с внешним миром через Linux bridge

До этого момента мы всё время общались внутри одной VM - machine1.
Но рано или поздно namespace понадобится доступ наружу. Например, prod/dev в machine1 хотят достучаться до machine2.
В чём проблема?
В VM у нас есть две сети:
- Сеть внутри namespace
- Физическая сеть VM (инфраструктурная сеть)
В примере используется простая схема с двумя namespace в подсети 192.168.10.0/24, но на практике это могут быть несколько подсетей и множество namespace.В таких случаях чаще всего используют NAT.
Почему? Потому что маршрутизаторы вне VM не знают о сети namespace (192.168.10.0/24). И весь трафик с этих адресов просто будет отброшен.
Поэтому сеть namespace (192.168.10.0/24) нужно транслировать в инфраструктурную сеть VM - например, 10.10.10.0/24.
Разберём всё на нашем же примере.
Воссоздаём схему с двумя namespace и bridge
Всё это выполняется в одной VM - machine1:
ip netns add dev ip netns add prod # show namespace ip netns show ip link add v-net-0 type bridge ip link set dev v-net-0 up ip link add veth-dev type veth peer name veth-dev-br ip link add veth-prod type veth peer name veth-prod-br ip link set veth-dev netns dev ip link set veth-dev-br master v-net-0 ip link set veth-prod netns prod ip link set veth-prod-br master v-net-0 ip -n dev addr add 192.168.10.1/24 dev veth-dev ip -n prod addr add 192.168.10.2/24 dev veth-prod ip -n dev link set veth-dev up ip -n prod link set veth-prod up ip link set veth-dev-br up ip link set veth-prod-br up
Пробуем достучаться до machine2
Попробуем пропинговать machine2 (IP 10.10.10.5) из namespace dev:
ip netns exec dev ping 10.10.10.5
Результат:
ping: connect: Network is unreachable
Это ожидаемо - у namespace нет маршрута в сеть 10.10.10.0/24.
Проверим таблицу маршрутизации:
apt install net-tools ip netns exec dev route -n
Вывод:
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.10.0 0.0.0.0 255.255.255.0 U 0 0 0 veth-dev
Видим только локальную сеть namespace.
Добавляем gateway
Чтобы добавить маршрут, сначала нужно назначить gateway для подсети 192.168.10.0/24.
В нашем случае gateway задаём на Linux bridge (v-net-0) - туда приходят оба veth-интерфейса из dev и prod.
ip addr add 192.168.10.10/24 dev v-net-0
Теперь добавим маршрут в namespace dev:
ip -n dev route add 10.10.10.0/24 via 192.168.10.10
Проверяем маршруты
ip netns exec dev route -n
Вывод:
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.10.10.0 192.168.10.10 255.255.255.0 UG 0 0 0 veth-dev 192.168.10.0 0.0.0.0 255.255.255.0 U 0 0 0 veth-dev
Пробуем снова:
ip netns exec dev ping 10.10.10.5
Теперь поведение другое. Ping всё равно не проходит, но ошибка уже не Network is unreachable.
Это означает, что namespace успешно отправляет пакет через veth-dev к нужной сети, однако проблема возникает уже дальше по цепочке.
На этом этапе пакет выходит из namespace и попадает на Linux bridge.
Bridge теперь выступает в роли gateway между сетью namespace и сетью machine1 (10.10.10.0/24).
То есть echo request уходит с 192.168.10.1 (IP namespace dev) на 10.10.10.5 (IP machine2).
Именно поэтому здесь и нужен NAT (о котором говорили в начале раздела).
Включаем NAT
Для NAT используется netfilter - часть сетевого стека Linux, которая позволяет фильтровать и модифицировать пакеты, а также выполнять трансляцию адресов и портов. Настраивается это через iptables.
В Linux есть 4 типа таблиц:
- Filter table - таблица по умолчанию. Если явно не указать таблицу, используется именно она.
- NAT table - используется для трансляции адресов и портов.
- Mangle table - для специфической модификации пакетов (например, изменение QoS-битов в TCP-заголовке).
- Raw table - для настройки исключений в обработке.
Добавляем правило NAT
Настроим правило в таблице nat:
iptables --table nat -A POSTROUTING -s 192.168.10.0/24 -j MASQUERADE
Обязательно убедитесь, что включён IPv4 forwarding:
echo 1 > /proc/sys/net/ipv4/ip_forward
Теперь проверяем:
ip netns exec dev ping 10.10.10.5 -c4
Вывод:
PING 10.10.10.5 (10.10.10.5) 56(84) bytes of data. 64 bytes from 10.10.10.5: icmp_seq=1 ttl=62 time=0.585 ms 64 bytes from 10.10.10.5: icmp_seq=2 ttl=62 time=0.651 ms 64 bytes from 10.10.10.5: icmp_seq=3 ttl=62 time=0.662 ms 64 bytes from 10.10.10.5: icmp_seq=4 ttl=62 time=0.838 ms ^C --- 100.26.188.252 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 4077ms rtt min/avg/max/mdev = 0.585/0.684/0.838/0.083 ms
Если вы пингуете machine2, убедитесь, что в его security group во входящих правилах открыт ICMP (с machine1 или отовсюду).
Проверим, что NAT действительно работает
Мы добились связи между namespace dev на machine1 и machine2.
Но сможет ли namespace выйти вообще в любую внешнюю сеть?
Попробуем:
ip netns exec dev ping 8.8.8.8 -c4
Результат:
connect: Network is unreachable
Почему? Потому что в namespace dev нет маршрута в эту сеть.
Можно добавлять маршрут под каждую конкретную сеть, но это неудобно. Проще добавить default route.
Добавляем default route
ip -n dev route add default via 192.168.10.10
Проверяем таблицу маршрутизации:
ip netns exec dev route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.10.10 0.0.0.0 UG 0 0 0 veth-dev 10.10.10.0 192.168.10.10 255.255.248.0 UG 0 0 0 veth-dev 192.168.10.0 0.0.0.0 255.255.255.0 U 0 0 0 veth-dev
Теперь снова пробуем:
ip netns exec dev ping 8.8.8.8 -c4 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=107 time=0.612 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=107 time=0.679 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=107 time=0.752 ms 64 bytes from 8.8.8.8: icmp_seq=4 ttl=107 time=0.684 ms
Теперь всё работает - благодаря default route и включённому NAT.
Если нужно, чтобы prod namespace тоже мог пинговать machine2 или любые другие внешние адреса, его нужно настроить аналогично dev.