OpenVZ veth etcnet
Здесь приведена информация, добытая в глубинах различных источников, которую я собрал для попытки описать максимально просто и последовательно, что же нужно сделать, чтобы получить следующее.
Работа с интерфейсом veth, etcnet и скриптами openvz
Конфигурация veth интерфейса с помощью etcnet
В различной документации для настройки veth-интерфейса для контейнера openvz предлагается использовать вручную вводимые команды или их наборы, помещаемые в стартовые скрипты(например). При наличии Etcnet дублировать (часть настраивать с помощью него, а часть нет) настройку не удобно, поэтому тут я привожу вариант только с помощью etcnet.
1. включить форвардинг пакетов на ноде в файле /etc/net/sysctl.conf:
net.ipv4.ip_forward = 1
2. создать и стартовать контейнер, но не добавлять адрес с помощью vzctl set --ipadd (он добавит интерфейс типа venet)
vzctl start 101
3. добавить veth-интерфейс в контейнер (формат команды подходит для vzctl 3.0.22, варианты см. по ссылке «например» выше).
vzctl set 101 --netif_add eth0,,fe:ff:ff:ff:ff:ff --save
при этом vzctl запишет в конфиг vz строку такого вида:
NETIF="ifname=eth0,mac=00:18:51:62:4E:08,host_ifname=veth101.0,host_mac=00:18:51:21:5F:E4"
(если же vzctl выдает ругань вида "According to vps.basic CT<N> has no veth interface configured." - значит, вы уже настраивали контейнеры и надо на данный момент закомментировать EXTERNAL_SCRIPT в /etc/net/vznet.conf)
первый mac-адрес будет использоваться для интерфейса в контейнере (обычный eth0 или как было задано в команде добавления)), а второй — для интерфейса на ноде (у него будет имя veth<номер ve>.0). mac-адреса можно указать и вручну, а если нет — то они вычислятся автоматически. Конечно, они не должны быть одинаковыми с соседними онтерфейсами (и вообще ни с чем в сети).
4. создать на ноде папку по имени интерфейса в etc/net/ifaces, а в нее положить такие файлы:
- ipv4address:
0 dev veth101.0
- ipv4route:
10.1.10.10 dev veth101.0
- options:
TYPE=eth BOOTPROTO=static ONBOOT=yes USE_HOTPLUG=yes
- sysctl.conf:
proxy_arp=1 ipv4_forwarding=1
файл ipv4address запустит интерфейс, но не назначит ему адреса (адрес присуствует у части, которая внутри VE, а снаружи — нет). файл ipv4route пропишет маршрут для адреса VE на конкретный интерфейс на ноде. файл options содержит важную опцию USE_HOTPLUG, она позволяет запускать интерфейс только тогда, когда VE реально стартует, без нее при старте сети будет ругань на невозможность сконфигурировать отсутствующий интерфейс. файл sysctl.conf задает параметры sysctl для конкретного интерфейса, используя автодополнение
5. такой же файл sysctl.conf надо положить в каталог физического eth-интерфейса сервера (eth0, если вы не переименовали его).
- sysctl.conf:
proxy_arp=1 ipv4_forwarding=1
6. Теперь надо зайти в VE (например, vzctl enter 101) и настроить интерфейс там. Положить следующие файлы в каталог etc/net/ifaces/eth0/ (если при создании вы назвали его eth0):
- ipv4address:
10.1.10.10/16
- ipv4route:
default via 10.1.10.150 dev eth0
- options:
TYPE=eth BOOTPROTO=static ONBOOT=yes
Здесь 10.1.10.10 — это адрес, который присваивается интерфейсу внутри VE, а 10.1.10.150 — адрес, присвоенный физическому интерфейсу на ноде. Проблема: если в качестве маршрута указать default dev eth0, то в локальной сети (10.1.*) этот интерфейс доступен будет, но при попытке выйти за ее пределы (например, в интернет) - работать не будет, так как будет считать что абсолютно все адреса должны быть доступны через arp-запрос в локальной сети). Что в случае адресов из интернета, конечно, неверно.
Проверка результатов
Теперь можно проверить, что получилось:
Выключить VE
vzctl stop 101
Тут желательно уже раскомментировать EXTERNAL_SCRIPT в /etc/net/vznet.conf, и проверить наличие в /etc/vz/conf/101
CONFIG_CUSTOMIZED="yes" BRIDGEDEV="br0"
если вы включаете интерфейсы в бридж.
Включить VE
vzctl start 101
и проверить наличие интерфейса veth и маршрута:
ip a ifconfig route -n
например, оно может выглядеть так:
2: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo 14: extbi: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:19:99:01:4b:82 brd ff:ff:ff:ff:ff:ff inet 10.1.10.150/16 brd 10.1.255.255 scope global extbi 21: veth1040.0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue link/ether 00:18:51:21:5f:e4 brd ff:ff:ff:ff:ff:ff
extbi Link encap:Ethernet HWaddr 00:19:99:01:4B:82 inet addr:10.1.10.150 Bcast:10.1.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 veth1040.0 Link encap:Ethernet HWaddr 00:18:51:21:5F:E4 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
10.1.10.40 0.0.0.0 255.255.255.255 UH 0 0 0 veth1040.0 10.1.0.0 0.0.0.0 255.255.0.0 U 0 0 0 extbi
и при этом обязательно должны быть включены forwarding и proxy_arp на соотв. интерфейсах (п .3 и 4)
[node]# cat /proc/sys/net/ipv4/conf/extbi/proxy_arp 1 [node]# cat /proc/sys/net/ipv4/conf/veth1040.0/proxy_arp 1
аналогично с forwarding.
с другого компьютера сети можно запустить ping
$ ping 10.1.10.10 PING 10.1.10.10 (10.1.10.10) 56(84) bytes of data. 64 bytes from 10.1.10.10: icmp_seq=1 ttl=64 time=2.82 ms
при этом в arp-таблице ноды появится запись
#arp samba.local ether 00:18:51:62:4E:08 C veth101.0
Если же у вас не так — смотрите, где что перепутано или забыто ;)
Как добиться прохождения broadcast в VE с интерфейсом veth
Если вы сделали все вышеописанное, то у вас будут работать сервисы в контейнере, которые получают пакеты, адресованные непосредственно им. (Такие как FTP, DNS, LDAP и другие). Но они работали бы и с интерфейсом venet, а veth обычно настраивают тогда, когда хотят поместить в контейнер что-то, что получало бы пакеты типа broadcast, адресованные всей подсети. Но на данном этапе работать это не будет ;) Причина в том, что в такой конфигурации между контейнером и остальной сетью есть роутер (это HN). Это можно легко проверить:
# traceroute -n 10.1.10.40 traceroute to 10.1.10.40 (10.1.10.40), 30 hops max, 40 byte packets 1 10.1.10.150 (10.1.10.150) 0.149 ms 0.123 ms 0.119 ms 2 10.1.10.40 (10.1.10.40) 0.139 ms 0.116 ms 0.118 ms
Т.е. пакеты из наружной сети проходя сначала через HN, но broadcast-пакеты роутеры не передают. Поэтому если поместить в такой контейнер сервисы типа DHCP или Samba, то работать они будут некорректно: например, Samba сможет работать как WINS-сервер, регистрируя имена тех, кто прямо укажет у себя адрес WINS-сервера, но она не сможет ответить за широковещательный запрос о наличии в сети master browser. Поэтому остальные машины выберут master browser кого-то другого, а не этот Samba-сервер ;)
А вот чтобы все же такие рассылки проходили и в этот контейнер, нужно сделать следующее.
1. Создать интерфейс типа bridge, как описано в пункте 3.6 статьи Etcnet. Поместить в него только один интерфейс, который является физическим ethernet на HN. С ним позже будет связываться интерфейс типа veth, который расположен на HN.
2. Использовать статью (и в частности раздел) OpenVZ wiki , где описано какие внести изменения в файлы конфигурации контейнера на HN.
3. Использовать приведенный там скрипт vznetcfg.custom, поместив его куда-нибудь, например в /usr/local/sbin/. Но исправить путь brctl=/usr/sbin/brctl на /sbin.
для простоты скопирую его и тут:
#!/bin/bash # /usr/sbin/vznetaddbr # a script to add virtual network interfaces (veth's) in a CT to a bridge on CT0 CONFIGFILE=/etc/vz/conf/$VEID.conf . $CONFIGFILE VZHOSTIF=`echo $NETIF |sed 's/^.*host_ifname=\(.*\),.*$/\1/g'` if [ ! -n "$VZHOSTIF" ]; then echo "According to $CONFIGFILE CT$VEID has no veth interface configured." exit 1 fi if [ ! -n "$VZHOSTBR" ]; then echo "According to $CONFIGFILE CT$VEID has no bridge interface configured." exit 1 fi echo "Adding interface $VZHOSTIF to bridge $VZHOSTBR on CT0 for CT$VEID" /usr/sbin/brctl addif $VZHOSTBR $VZHOSTIF exit 0
Этот скрипт читает конфиг VE в /etc/vz/conf, где добавлены соотв. параметры. VZHOSTBR - это имя бриджа из п.1, а VZHOSTIF определится скриптом из строки конфига NETIF. Скрипт проверяет наличие нужных параметров и просто добавляет еще один интерфейс (а именно интерфейс вида veth<номер VE> в уже существующий к этому моменту бридж.
4. veth интерфейсы, попадающие в бридж, не требуют специальной записи в таблице роутинга на ноде. поэтому в файле ipv4route в соотв. папке /etc/net/ifaces/veth* можно закомментировать установку маршрута. (Или это обязательно требуется? проверьте).
Поменяйте таким образом конфигурацию всех VE и интерфейсами veth, и они окажутся в одном бридже, что позволит им беспрепятственно, без роутинга, общаться между собой.
Результат:
# brctl show bridge name bridge id STP enabled interfaces br0 8000.001851215fe4 yes extbi veth1010.0 veth1040.0
При старте сервера сначала стартует etcnet, который создает бридж с одним ethernet-интерфейсом хоста (в этом примере - extbi) и пропускает veth-интерфейсы еще не стартовавших контейнеров (они USE_HOTPLUG):
May 21 14:40:46 fujitsu network: Starting veth1010.0: May 21 14:40:46 fujitsu network: skipping hotplug iface 'veth1010.0' May 21 14:40:46 fujitsu network: SKIPPED
А позже при старте VE и поднимается интерфейс и добавляет себя в бридж:
May 21 14:40:49 fujitsu vzctl: Configure veth devices: veth1010.0 May 21 14:40:49 fujitsu vzctl: ifname=eth0 May 21 14:40:49 fujitsu vzctl: mac=00:18:51:AE:1F:20 May 21 14:40:49 fujitsu vzctl: host_ifname=veth1010.0 May 21 14:40:49 fujitsu vzctl: host_mac=00:18:51:75:1B:64 May 21 14:40:49 fujitsu vzctl: Adding interface veth1010.0 to the bridge br0.
Проблемы
1. Если пытаться полностью полагаться на etcnet, то можно попробовать использовать скрипт ifup-post в каталоге интерфейса для добавления его в бридж. Тогда VZHOSTBR и VZHOSTIF прописать явно, они будут для каждого свои. У меня не получилось, но я не все варианты попробовал ;)
2. Если на HN находятся одновременно интерфейсы типа veth и типа venet, то у меня терялась между ними связь после экспериментов с добавлением veth в бридж. Те, кто конфигурировал такое, обычно опасались смешивать интерфейсы разного типа. Но может быть и такое, что это просто временные проблемы ядра, а у вас заработает. Пробуйте.
3 Если у вас часть интерфейсов veth, а часть venet и вы хотите переделать venet в veth, то, удалив адрес с venet и пытаясь сконфигурировать veth в том контейнере получится такое:
# vzctl set 1030 --ipdel 10.1.10.30 --save Deleting IP address(es): 10.1.10.30 Saved parameters for VE 1030 # vzctl set 1030 --netif_add eth0,,,fe:ff:ff:ff:ff:ff --save Configure veth devices: veth1030.0 According to vps.basic CT1030 has no veth interface configured. /usr/sbin/vznetcfg exited with error Saved parameters for VE 1030
Проблема курицы и яйца - сконфигурирован внешний скрипт, который при выполнении берет параметры из строки в конфиге NETIF (см. выше). А ее там еще нет, потому что она как раз и пытается добавиться. В результате ничего не изменится (NETIF не будет сконфигурирован). Выход, например - временно отключить в /etc/vz/vznet.conf параметр EXTERNAL_SCRIPT (или доработать скрипт?)
Как в нормальной системе использовать мост (bridge) в VE
Предыдущие разделы очень сложны по набору информации, и понять, что же нужно выбрать, может быть затруднительно. Скажу коротко, что если вам нужны контейнеры с внешними адресами, то надо использовать bridge — это самый простой вариант, не имеющий большинства проблем.
Возможно, что в серверном дистрибутиве уже используется bridge для сети (создано устройство breth0). Если этого нет, то создаём по пункту 3.6 статьи Etcnet. Если коротко, то в физическом интерфейсе оставляем только файл options с содержимым примерно
TYPE=eth MODULE=r8169
а все остальные настройки переносим в /etc/net/ifaces/breth0, где в options пишем
TYPE=bri HOST='eth0'
И создаём brctl с содержимым
stp AUTO on
(не понял, насколько это нужно). Остальные настройки (ipv4address, ipv4route, resolv.conf) должны быть скопированы, и обычно не требуют изменения.
Также обязательно должен быть включен ip forwarding (net.ipv4.ip_forward = 1 в /etc/net/sysctl.conf).
Далее в /etc/vz/vznet.conf вносим строку EXTERNAL_SCRIPT="/usr/sbin/vznetaddbr"
Предварительно удалив из конфига контейнера (/etc/vz/conf/501.conf) строку NETIF, запускаем
vzctl set 501 --netif_add breth0,,,fe:ff:ff:ff:ff:ff,breth0 --save
для каждого контейнера, который мы хотим подключить к сетевому мосту.
Дальше только не забываем в каждом контейнере поменять сетевые настройки, поскольку сменится название интерфейса внутри (с eth0 на breth0), соответственно нужно переименовать каталог /etc/net/ifaces/eth0.
Больше ничего делать не нужно.
Проверяем, что всё получилось:
# brctl show bridge name bridge id STP enabled interfaces breth0 8000.00185167a3cb yes eth0 veth501.0
Запускаем контейнер:
# vzctl start 501 ... File resolv.conf was modified Configure veth devices: veth501.0 Adding interface veth501.0 to bridge breth0 on CT0 for CT501