Conteneur LXC + NAT

le

Comme beaucoup je suis en transition de VServer vers LXC, et il y a une possibilité qui me manquait : pouvoir monter un réseau local sur l'hôte servant à relier les instances virtuelles ET n'étant relié à une interface de l'hôte que via un NAT (du masquerading pour être plus précis). Aucune documentation ne semble donner de solution et il m'a fallu pas mal de lecture entre les lignes pour y arriver.

Le tout a été réalisé sous Debian GNU/Linux, version 6.0 (aka Squeeze). J'ai donc commencé par créer un conteneur à l'aide de debootstrap ainsi :

# lxc-create -n jenkins -t squeeze

Le conteneur s'appelera donc "jenkins" (où je prévois d'y installer... Jenkins). Il faut utiliser le hack mentionné sur http://wiki.debian.org/LXC pour pouvoir créer un tel conteneur, sinon vous ne pourrez instancier que du "Lenny" obsolète !

Ensuite je modifie la configuration réseau générée dans le conteneur pour ne déclarer (en plus de la loopback) qu' une interface statique veth0 :

# vi /var/lib/lxc/jenkins/etc/network/interfaces
...
auto veth0
iface veth0 inet static
  address 192.168.1.1
  netmask 255.255.255.0
  gateway 192.168.1.254

En ce qui concerne la configuration du conteneur lui-même, la voici :

# vi /var/lib/lxc/jenkins/config :
...
lxc.network.type = veth
lxc.network.name = veth0
lxc.network.flags = up
lxc.network.link = br0
lxc.network.veth.pair = veth0-jenkins

Je choisis de nommer l'interface veth0 vue depuis l'invité afin qu'il soit bien clair que c'est une interface virtuelle, et veth0-jenkins vue depuis l'hôte - ce qui est beaucoup mieux que les noms aléatoires que génère LXC par défaut. L'option réseau veth.pair permet de brancher automatiquement l'interface côté hôte sur un bridge dès que le conteneur est démarré.

Il reste donc à configurer le réseau de l'hôte, en rajoutant du masquerading sur l'interface de "sortie" (appelée ici WAN) et un bridge pour concrétiser le LAN qui relie les invités :

# vi /etc/network/interfaces
...
auto _WAN_
iface _WAN_ ...
  ...
  up iptables -t nat -F POSTROUTING
  up iptables -t nat -A POSTROUTING -o _WAN_ -j MASQUERADE

auto br0
iface br0 inet static
  address 192.168.1.254
  netmask 255.255.255.0
  bridge_ports none

Et ne pas oublier d'activer le routage pour que les paquets transitent bien d'une interface à l'autre, ce qui se fait ainsi :

# vi /etc/sysctl.conf
...
net.ipv4.ip_forward=1

Enfin, pour s'assurer que notre conteneur est toujours là au prochain (re)boot :

# ln -s /var/lib/lxc/jenkins/config /etc/lxc/jenkins/conf
# vi /etc/default/lxc
RUN=yes
CONTAINERS="jenkins"

A ce stade j'aime bien rebooter pour m'assurer que tout se met bien en place automatiquement, mais c'est aussi rassurant de tester le tout avant de rebooter :

# sysctl net.ipv4.ip_forward=1
# iptables -t nat -F POSTROUTING
# iptables -t nat -A POSTROUTING -o _WAN_ -j MASQUERADE
# ifup br0
# lxc-start -n jenkins -d

Remarquez que je démarre le conteneur en me détachant de la console car il y a un bug qui empêche la séquence d'échappement C-a-q de quitter la console... Il suffit de s'y accrocher dans un second temps :

# lxc-console -n jenkins

A ce stade votre invité a le même mot de passe root que l'hôte, et normalement ceci fonctionne aussi (depuis l'hôte bien sûr) :

# ssh 192.168.1.1

Gotcha : assurez vous que /etc/resolv.conf est cohérent dans l'invité (il est copité depuis celui de l'hôte). Si par exemple votre hôte utilise 127.0.0.1, ça ne fonctionnera pas...


Partager cet article :