LXC: Virtualisierung, die Zweite

Diesmal verwende ich LXC (Linux Container) zur Virtualisierung. Es ist zwar keine vollwertige Virtualisierung wie KVM, dafür aber wesentlich ressourcenschonender da sich der Gast mit dem Host den selben Kernel teilt. Zudem ist das Setup um einiges einfacher als bei QEMU/KVM. Unter anderem wurde LXC von frühen Docker Versionen eingesetzt.
Immer noch ist das Ziel, verschiedene Dienste isoliert voneinander laufen zu lassen, diese müssen unter einer öffentlichen IPv4 via NAT/Portweiterleitung erreichbar sein, darüber hinaus soll jeder Container über ein eigenes IPv6/64 Subnet verfügen. In dieser Übergangszeit auf IPv6 im Dual-Stack Betrieb, sozusagen.

Zuerst einmal geht's mit den erforderlichen Paketen los:
Unter Debian 8 sind das
bridge-utils lxc radvd resolvconf

Darauf folgend die Netzwerkkonfiguration, bei online.net werden alle IP-Adressen über DHCP bezogen.

Netzwerkkonfiguration #1 - Host
/etc/network/interfaces
## This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet dhcp
dns-nameservers 8.8.8.8 8.8.4.4

iface eth0 inet6 static
address 2001:xxx:xxxx💯:
netmask 56
pre-up dhclient -cf /etc/dhcp/dhclient6.conf -pf /run/dhclient6.eth0.pid -6 -P eth0
pre-down dhclient -x -pf /run/dhclient6.eth0.pid
dns-nameservers 2001:4860:4860::8888 2001:4860:4860::8844

# VM IPv4 NAT & IPv6
auto veth0
iface veth0 inet static
address 172.16.0.1
netmask 255.255.255.0
bridge_ports none

iface veth0 inet6 static
address 2001:xxx:xxxx:101::
netmask 64



/etc/dhcp/dhclient6.conf für online.net
interface "eth0" {
    send dhcp6.client-id DUID;
    request;
}


Systemkonfiguration:
update-rc.d radvd defaults;

echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf;
echo net.ipv6.conf.all.forwarding=1 >> /etc/sysctl.conf;
echo net.ipv6.conf.all.accept_ra=2 >> /etc/sysctl.conf;
echo net.ipv6.conf.eth0.accept_ra=2 >> /etc/sysctl.conf;
echo net.ipv6.bindv6only=1 >> /etc/sysctl.conf;

echo 'LXC_AUTO="false"' > /etc/default/lxc;
echo -e "lxc.network.type=veth\nlxc.network.link=veth0" > /etc/lxc/default.conf;
echo -e "interface veth0\n{\n AdvSendAdvert on;\n AdvManagedFlag off;\n AdvOtherConfigFlag off;\n};" > /etc/radvd.conf;


Um diese Änderungen anzuwenden, ist ein reboot erforderlich.

Die Installation des Gastsystem ist ähnlich schnell erledigt wie mit GRML, denn lxc-create nutzt genauso debootstrap.
Ein Debian8 System wird wie folgt installiert:
LANG=C SUITE=jessie MIRROR=http://httpredir.debian.org/debian lxc-create -n testvm -t debian


Netzwerkkonfiguration #2 - Container Config
nano /var/lib/lxc/testvm/config wird hinzugefügt:
# autostart network
lxc.network.flags = up
# IPv4 address
lxc.network.ipv4 = 172.16.0.2/24
lxc.network.ipv4.gateway = 172.16.0.1
# IPv6 address
lxc.network.ipv6 = 2001:xxx:xxxx:101::1/64
# For the autostart of the container
lxc.start.auto = 1
# Delay before starting next container
lxc.start.delay = 5
# falls noch nicht vorhanden
lxc.network.type = veth
lxc.network.link = veth0


Netzwerkkonfiguration #3 - im Container
nano /var/lib/lxc/testvm/rootfs/etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 172.16.0.2
    gateway 172.16.0.1
    netmask 255.255.255.0

iface eth0 inet6 static
    address 2001:xxx:xxxx:101::1
    netmask 64


Netzwerkkonfiguration #4 - NAT IPv4 Host<->VM
Internetzugriff der VMs über IPv4:

#iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -o eth0 -j SNAT --to-source public_ipv4_address


Weiterleitung öffentliche IPv4:Port zur VM

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 172.16.0.2:Port


Ein LXC-Container ist wirklich nur ein minimalstes Minimalsystem. Kein wget, kein ping. Werden die Standardpakete einer Debian Minimalinstallation, z.B. wie sie in einer Installation via netinstall enthalten sind, benötigt, so können diese mit

aptitude install ~pstandard ~pimportant ~prequired #(+300MB!)

nachinstalliert werden.

Gestartet wird ein LXC-Container mit
lxc-start -dn testvm,
eine Konsole erhält man mit
lxc-attach -n testvm,
Statusübersicht
lxc-ls --fancy

Fazit
Automatisiert man die 3 obigen Schritte, lxc-create mit fortlaufender IP an den passenden Stellen, so ist ein neuer LXC Container innerhalb von nur 45 Sekunden einsatzbereit.

Demnächst geht es weiter mit Ressourcenlimitierung der LXC-Container.

Update 24.01.2016:
Damit der Container nicht nach 30 Minuten sämtliche IPv6 Konnektivität nach außen verliert, musste ich in der radvd.conf
AdvDefaultLifetime 1080 (Defaultwert) auf AdvDefaultLifetime 999999999 ändern.


Update 03.02.2016:
UDP Port 546 (DHCP v6 Client) darf nicht blockiert werden...

Update 20.06.2016:
ICMPv6 muss zwingend auf die Whitelist. Ansonsten werden die Router Advertisements geblockt.

Quellen
Dual-Stacked LXC Container (NAT+IPv6) on Ubuntu 14.04 für Dedibox SC gen2
radvd
IPv6 Subnet Calculator