В связи с исчерпанием доступных ipv4 адресов все более актуальной становится тема размещения виртуальных машин за NAT. Таким образом можно добиться сразу нескольких преимуществ:
1. Экономия средств за счет использования только одного публичного адреса для множества машин;
2. Сокрытие внутреннего устройства публично доступных сервисов (т. е. ваша инфраструктура будет невидима для мира).
Однако, как и у любой технологии, у данного метода есть недостатки.
Во-первых, это производительность. Это связано с тем, что:
1. NAT должен переписать отправителя / адресата пакета;
2. Передать пакет следующему узлу (пускай и внутреннему — на это также нужны вычислительные ресурсы).
Во-вторых, это усложнение инфраструктуры. К счастью, это не страшно, если вся внутренняя сеть находится на одной машине.
Итак, что необходимо сделать чтобы начать размещать контейнеры?
Инструкции на примере Debian Jessie, расчитаны на людей имеющих представление о том, что такое NAT. Помимо LXC, они применимы для любой системы виртуализации.
1. Создайте сетевой мост для контейнеров.
В файле /etc/network/interfaces
, пропишите интерфейс моста, чтобы в итоге файл приобрел примерно следующий вид:
auto lo iface lo inet loopback # The primary network interface allow-hotplug eth0 iface eth0 inet static address 12.13.14.15 netmask 255.255.255.0 gateway 12.13.14.1 dns-nameservers 8.8.8.8 8.8.4.4 auto br0 iface br0 inet static address 172.16.1.1 netmask 255.255.255.0 bridge_ports none dns-nameservers 8.8.8.8 8.8.4.4
Здесь:
lo — loopback интерфейс, у вас он уже есть.
eth0 — интерфейс с внешним статическим IP.
br0 — интерфейс сетевого моста, к которому будут подключены контейнеры. У контейнеров будет статический внутренний IP из сети 172.16.1.0/24
2. Разрешите перенаправление пакетов.
По умолчанию в большинстве дистрибутивов перенаправление пакетов выключено. Это означает, что если на интерфейс (допустим, у него будет адрес 192.168.1.20) придет пакет для другого IP (например 192.168.2.45), то он его отбросит. При включенном же перенаправлении, он его направит целевому узлу.
Для этого выполните следующие команды в терминале:
/etc/network/interfaces
root@sol:~# echo 1 > /proc/sys/net/ipv4/ip_forward
root@sol:~# echo «net.ipv4.ip_forward=1» > /etc/sysctl.d/99-ipfwd.conf
Первая команда включает перенаправление пакетов для текущей сессии, вторая — ставит его по умолчанию, чтобы настройки не слетели после перезагрузки.
3. Создайте правило iptables для NAT.
Если у вас статический адрес:
root@sol:~# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 12.13.14.15
Если у вас динамический адрес:
root@sol:~# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Оно означает, что всем пакетам выходящим из интерфейса eth0 будет присвоен адрес этого интерфейса. Разница в том, что второе правило автоматически подставляет внешний адрес, но это понижает производительность, поэтому для статических адресов первый вариант приоритетен. Таблица iptables POSTROUTING означает, что действие будет применено после того, как будет определен исходящий интерфейс. Иными словами, сперва будет определено, что этот пакет идет наружу, в другую сеть и только после этого будет переписан его отправитель. Пакеты внутри сети NAT изменяться не будут.
4. Пропишите настройки сети для контейнеров.
Эти настройки можно прописать сразу в /etc/lxc/default.conf:
lxc.network.type = veth lxc.network.link = br0 lxc.network.name = eth0 lxc.network.flags = up
Создайте контейнер:
root@sol:~# lxc-create -t debian -n cnt0
Настройки сети для контейнера (/var/lib/lxc/cnt0/config):
lxc.network.ipv4 = 172.16.1.13/24 172.16.1.255 lxc.network.ipv4.gateway = 172.16.1.1
5. Запустите контейнер и протестируйте на нем сеть.
root@sol:~# lxc-start -n earth root@sol:~# lxc-attach -n earth root@earth:~# ping 8.8.8.8 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=56 time=1.29 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=1.29 ms 64 bytes from 8.8.8.8: icmp_seq=3 ttl=56 time=1.37 ms 64 bytes from 8.8.8.8: icmp_seq=4 ttl=56 time=1.24 ms 64 bytes from 8.8.8.8: icmp_seq=5 ttl=56 time=1.25 ms ^C --- 8.8.8.8 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 4005ms rtt min/avg/max/mdev = 1.241/1.291/1.375/0.060 ms root@earth:~#
6. Создайте правила iptables для проброса портов.
Добавьте следующее правило в iptables:
root@sol:~# iptables -t nat -I PREROUTING 2 -i eth0 -p tcp -m multiport --dports=80,443 -j DNAT --to 172.16.1.13
Оно означает, что TCP-пакетам на порты 80 и 443, пришедшим на интерфейс eth0, адресат будет переписан на 172.16.1.13, после чего для них будут применены правила маршрутизации. Глазами ядра это выглядит следующим образом:
1. «О, пакет для меня (12.13.14.15) на 80 порт!»
2. «Переписываю ему адресата на 172.16.1.13.»
3. «Теперь это пакет для сети 172.16.1.1/24.»
4. «Эта сеть подключена ко мне через интерфейс br0. Туда его и отправлю.»
Аналогично и с другими портами, которые должны быть доступны извне.
7. Сохраните правила iptables.
Чтобы не потерять правила фаервола после плановой(?) перезагрузки сервера, необходимо их сохранить:
root@sol:~# iptables-save > /etc/iptables/rules.v4
Готово! Теперь вы можете создать практически неограниченное количество виртуалок для изоляции своих сервисов.
Кстати, примерно аналогичным образом, по умолчанию работает Docker.