По просьбе трудящихся.

Итак, задача:
Настроить среду lxc таким образом, чтобы хостовая система была доступна по сети, даже если произойдёт внутренний lxc-коллапс, не затрагивающий дисковую подсистему.

Цель:
Универсальная боевая среда для быстрого разворачивая контейнеров с боевой средой приложения.

 

Главная идея на сервере должен быть внутренняя виртуальная сеть, независимая от внешних сетевых интерфейсов, но с возможностью nat-а.

1. определяемся с сетью
Для простоты возьмём 10.100.0.0/24.

2. обеспечим NAT.
для этого надо настроить iptables - это правила для iptables-restore:

*nat
:PREROUTING ACCEPT [38663:3845667]
:INPUT ACCEPT [100:5401]
:OUTPUT ACCEPT [414:31440]
:POSTROUTING ACCEPT [2653:185786]
-A POSTROUTING -s 10.100.0.0/24 -j MASQUERADE
COMMIT

второе, надо обеспечить фарвардинг пакетов:

sysctl -w net.ipv4.ip_forward=1

либо соответствующая строка в /etc/sysctl.conf

3. надо настроить виртуальную сеть
Для этого нам понадобятся 2 интерфейса br0 и dummy0 (потому что lo нельзя сунуть в бридж)
Для поднятия dummy0 нам достаточно сказать

modprobe dummy

и интерфейс сразу же объявится, навешивать адрес на него не нужно, его задача быть гвоздиком, за который цепляется br0, не более того. Отмечу, что далеко не во всех дистрибутивах этот интерфейс и этот модуль грузится по умолчанию, где-то я даже видел dummy.ko в balcklist-е модулей ядра.

Для поднятия br0 нам понадобится, как ни странно, тоже сунуть модуль в ядро

modprobe bridge

но этого недостаточно, надо настроить адрес шлюза на этом интерфейсе

ip addr add 10.100.0.1 dev br0

Для фиксации изменений, надо консультироваться с сетевыми настройками конкретного дистрибутива (у меня не возникло проблем/не понадобились костыли при настройке debian, centos, slackware - всё производилось штатными средствами)
для slackware это правки в

/etc/rc.d/rc.modules

добавлено

/sbin/modprobe dummy

и в /etc/rc.d/rc.inet1.conf
вписаны такие настройки:

# Config information for eth1:
IFNAME[1]="dummy0"
IPADDR[1]=""
NETMASK[1]=""
USE_DHCP[1]=""
DHCP_HOSTNAME[1]=""

# Config information for eth2:
IFNAME[2]="br0"
BRNICS[2]="dummy0"
IPADDR[2]="10.100.0.1"
NETMASK[2]="255.255.255.0"
USE_DHCP[2]=""
DHCP_HOSTNAME[2]=""

4. надо настроить собственно контейнер.
В данном случае идеальный вариант - это развернуть ту же ось, что и на хосте, через соответствующий темплейт (как правило он идёт в комплекте с системой, исключением является пожалуй только slackware, во всяком случае в 14-й и 14.1 приходилось брать темплейт со стороны, в котором не работал slackpkg по причине отсутствия одного пакета в установленном чруте.

Основная идея заключается в том, чтоб не настраивать сеть силами механизмов контейнера, а развернуть её силами lxc - полный контроль, насколько это возможно.

Вот пример конфига контейнера (/var/lib/lxc/имя_контейнера/config)

lxc.arch = x86
lxc.utsname = SRV1
#lxc.start.auto = 1
lxc.rootfs = /var/lib/lxc/SRV1/rootfs
lxc.mount.entry = lxcpts dev/pts devpts defaults,newinstance 0 0
lxc.mount.entry = none proc proc defaults 0 0
lxc.mount.entry = none sys sysfs defaults 0 0
lxc.mount.entry = none run tmpfs defaults,mode=0755 0 0
lxc.network.type = veth
lxc.network.veth.pair = SRV1
lxc.network.flags = up
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.hwaddr = 00:00:00:00:00:17
lxc.network.ipv4 = 10.200.0.17/24
lxc.network.ipv4.gateway = 10.200.0.1
lxc.tty = 1
lxc.pts = 1024
lxc.autodev = 1
lxc.kmsg = 0
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm

# we don't trust even the root user in the container, better safe than sorry.
# comment out only if you know what you're doing.
#lxc.cap.drop = sys_module mknod mac_override mac_admin sys_time setfcap setpcap
#lxc.cap.drop = sys_module mknod mac_override mac_admin sys_time

# you can try also this alternative to the line above, whatever suits you better.
lxc.cap.drop=sys_admin

Важный момент в данном случае - это пожалуй "ручная" сеть а также название интерфейса, который будет воткнут в бридж (lxc.network.veth.pair) чтобы можно было увидеть в читаемом виде список активных интерфейсов в бридже (brctl show).

Также стоит отметить, что многие системы подразумевают что сеть настраивается внутри контейнера, силами механизмов управления сетью, встроенными в ось, запущенную в контейнере. Так что с некоторой вероятностью придётся патчить init-скрипты, или конфиги сервисов.

Добавлю также, что идеальной контейнеризованной системой является alpine linux - он очень компактный и контейнеры получаются почти невесомыми.

Стоит отметить, что хорошей идеей является заготовка одного "типичного" минимального контейнера впрок, чтобы потом не иметь граблей с настройкой всяких особенностей типа dns-серверов внутри контейнера - развернул и всё на месте.

Next Post