28/03/2020

lxc

Installation

Creation d’un container

apt install lxc

Verifier la config

lxc-checkconfig

Pour créer un conteneur :

lxc-create -t download -n [name]

Si vous aussi vous avez une erreur GPG

ERROR: Unable to fetch GPG key from keyserver.

Vous pouvez ignorer la valisation avec la commande (C’est pas ouf mais j’ai la flemme):

lxc-create -t download -n [name] --  --no-validate

Lister les conteneurs :

lxc-ls -f

Lancer un container :

lxc-start -n [name]

Stopper un container

lxc-stop -n [name] 

Rentrer dans le container :

lxc-attach -n [name] 

Configuration réseau

Pour l’instant votre conteneur n’a pas accès à internet, il faut lui attribuer une ip. Pour avoir accès à internet, les conteneurs doivent se connecter à une interface bridge sur l’hôte. Celle-ci peut avoir été créée par le paquetage (Ubuntu, paquetage lxc-net), alors on peu la créer manuellement. Pour la créer manuellement faut continuer le tuto ;)

brctl show : permet d’obtenir la liste des interfaces bridges sur l’hôte. La commande est accessible via le paquet bridge-utils

On veut obtenir ceci :

  [routeur physique]
  [   192.168.0.1  ]
           |
         eth0
      192.168.0.2
           |
        laptop
           |
        lxcbr0
       10.0.30.1
       /      \
containr0    containr1
10.0.30.2    10.0.30.3

Pour arriver à ce resultat il faut que ton pc reagisse comme un routeur. Pour savoir s’il est déjà, tape cette commande si ça renvoie … = 1 c’est bon

sysctl net.ipv4.ip_forward

Sinon

sysctl -w net.ipv4.ip_forward=1

et pour faire de façon permanent, modifiez le fichier /etc/sysctl.conf :

net.ipv4.ip_forward = 1

Ou lancer la commande :

sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf

et lance la commande :

sysctl -p /etc/sysctl.conf

Configurer votre brige

Maintenant il faut créer l’interface bridge et on lui assigne une ip :

brctl addbr lxcbr0
ip addr add 10.0.30.1 brd + dev lxcbr0

Il faut rendre le bridge persistant au démarage. Sur debian on fait :

Pour créer une interface, il faut créer un fichier avec la configuration de l’interface dans le repertoire /etc/network/interfaces.d. Normalement le fichier /etc/network/interfaces fait le lien avec ce repertoire (include). Vérifier au cas où par exemple sur certaines version le fichier doit porter l’extension .cfg

Créer un fichier /etc/network/interfaces.d/lxcbr0 qui contient :

auto lxcbr0
iface lxcbr0 inet static
    bridge_ports none
    address 10.0.30.1
    netmask 255.255.255.0

Si vous n’avez pas de repertoire interfaces.d, installez net-tools

apt install ifupdown net-tools

On peut ensuite contrôler l’interface avec les scripts ifup et ifdown:

ifup lxcbr0
ifdown lxcbr0

Si ya pas de fichier /etc/network/interfaces reinstall ifupdown

apt autoremove --purge ifupdown && apt install ifupdown

Pour voir l’etat du bridge, tapez la commande

brctl show

Normalement vous avez votre bridge ;)

Ubuntu

Sur ubuntu, le bridge est déjà configuré avec lxc-net. La configuration de lxc est dans /etc/default/lxc. et elle est override par /etc/default/lxc-net.

LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.33.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.33.0/24"
#LXC_DHCP_RANGE="10.0.3.2,10.0.3.254"
#LXC_DHCP_MAX="253"

Sur le fichier de config vous pouvez changer la config réseau de lxc et activer ou pas le DHCP

systemctl restart lxc

Configurer votre container

Votre container de situe dans le dossier /var/lib/lxc/[name]

Dans ce repertoire vous trouverez le rootfs qui est le dossier de votre container, et le fichier config. Vous l’aurez compris c’est dans ce fichier que nous allons spécifier la configuration réseau de votre container.

Je vous met ici un exemple de configuration d’un de mes container, à vous de prendre ce que vous souhaitez

!!! Attention !!! quand vous modifiez votre fichier de config il est fortement recommandé de le stopper.

Il est important de changer l’adresse MAC pour chaque container sinon vous aurez des problèmes par la suite.

Parameters passed to the template: --release buster
# Template script checksum (SHA-1): b290eda01b21f9818fcf1402b2749c4c218500ed
# For additional config options, please look at lxc.container.conf(5)

# Uncomment the following line to support nesting containers:
#lxc.include = /usr/share/lxc/config/nesting.conf
# (Be aware this has security implications)

lxc.net.0.type = veth
lxc.net.0.hwaddr = 00:16:3e:d2:3e:5f
lxc.net.0.flags = up
lxc.net.0.name = eth1
# ip du container
lxc.net.0.ipv4.address = 10.0.30.4/24
# L'interface bridge est le link
lxc.net.0.link = lxcbr0

lxc.rootfs.path = /var/lib/lxc/nextcloud/rootfs
lxc.net.0.ipv4.gateway = 10.0.30.1

# Common configuration
lxc.include = /usr/share/lxc/config/common.conf

# Container specific configuration
lxc.tty.max = 4
lxc.uts.name = nextcloud
lxc.arch = amd64
lxc.apparmor.profile = unconfined

lxc.start.auto = 1

memory.limit_in_bytes=512M

documentation : https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html

Ancienne version

lxc.network.type = veth
lxc.network.hwaddr = 00:16:3e:d2:3e:5f
lxc.network.flags = up
lxc.network.name = eth1
# ip du container
lxc.network.ipv4.address = 10.0.30.4/24
# L'interface bridge est le link
lxc.network.link = lxcbr0

Votre configuration sera valide quand vous pourrez lancer votre container et en tappant la commande

ip a

Vous verrez aparaitre l’ip que vous lui avez renseigné. Mais à cette étape vos containers ne peuvent pas encore se connecter à “l’internet des objects”

Regle IPTABLE

Pour pourvoir se connecter à internet depuis vos containers, il faut rajouter cette rêgle iptables sur la machine hôte :

apt install iptables
iptables -t nat -A POSTROUTING -s 10.0.30.0/24 -j MASQUERADE

Pour voir la liste des rêgles iptables, tapez la commande

iptables -L -t nat

Attention, les rêgles iptables ne sont pas permanente, il faudra la remettre au à chaque redemarrage de la machine hôte. Cependant il existe un moyen de les rendre permanente :

apt install iptables-persistent

Les sauvegardes sont dans les fichiers : /etc/iptables/rules.v4, /etc/iptables/rules.v6

La commande iptables-save exporte la config iptables. Il faut juste rediriger la sortie dans les sauvegardes :

iptables-save > /etc/iptables/rules.v4
iptables-save > /etc/iptables/rules.v6
Supprimer toutes les rêgles iptables :
iptables -F POSTROUTING
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X

Le dns

Sur votre containers se trouve souvent dans le fichier /etc/resolv.conf la configuration dns. Vous devez mettre la même que la machine hôte ou cas spécifique votre propre dns.

Pour ovh c’est

nameserver 127.0.0.1
nameserver 213.186.33.99
search ovh.net

Tester les erreurs

Pour voir les logs du container :

journalctl -f

Pour voir les requete sur le bridge tapez sur la machine hote

tcpdump -i lxcbr0 -v

Déplacer un container sur une autre machine

Déplacer un container c’est déplacer le rootfs vers une autre machine possédant une installation de lxc. Il faudra sur cette autre machine recréer le fichier de config.

Première méthode (envoyer une archive)

lxc-stop -n $NAME
cd /var/lib/lxc/$NAME/
tar --numeric-owner -czvf container_fs.tar.gz ./*
The --numeric-owner flag is very important! Without it, the container may not boot because the uid/gids get mangled in the extracted filesystem. When tar creates an archive, it preserves user / group ownership information. By default, when extracting, tar tries to resolve the archive user/group ownership names with the ids on the system running tar. This is intended to ensure that user ownership is resolved on the new system, in case the UID numeric values differ between systems.

This is bad for an LXC filesystem because the numeric uid/gid ownership is intended to be preserved for the whole filesystem. If it gets resolved to a different value, bad things happen.
rsync -avh container_fs.tar.gz user@newserver:/var/lib/lxc/
mkdir /var/lib/lxc/$NAME/
cd /var/lib/lxc/$NAME/
tar --numeric-owner -xzvf container_fs.tar.gz .

If you’re using an overlay backed container, you’ll also need to migrate the container this new one is based off of. Lastly, you might see a few warnings about skipped socket files:

tar: /var/lib/lxc/$NAME/rootfs/dev/log: socket ignored

I’ve ignored this error, and haven’t had any issues with any of the containers I manage. If you have further issues, add your error messages to the original post and I’ll elaborate.


Deuxième méthode (plus pratique)

rsync -arAXDx --numeric-ids --delete --progress root@arkalo.ovh:/var/lib/lxc/gitea/rootfs/ /home/omer/Documents/backup/

Normalement c’est bon mais j’ai eu un bug avec mariadb :

● mariadb.service - MariaDB 10.3.15 database server
   Loaded: loaded (/etc/systemd/system/mariadb.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Tue 2019-08-13 08:55:56 UTC; 8s ago
     Docs: man:mysqld(8)
           https://mariadb.com/kb/en/library/systemd/
  Process: 88 ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld (code=exited, status=226/NAMESPACE)

Aug 13 08:55:56 gitea systemd[1]: Starting MariaDB 10.3.15 database server...
Aug 13 08:55:56 gitea systemd[88]: mariadb.service: Failed to set up mount namespacing: Permission denied
Aug 13 08:55:56 gitea systemd[88]: mariadb.service: Failed at step NAMESPACE spawning /usr/bin/install: Permission denied
Aug 13 08:55:56 gitea systemd[1]: mariadb.service: Control process exited, code=exited, status=226/NAMESPACE
Aug 13 08:55:56 gitea systemd[1]: mariadb.service: Failed with result 'exit-code'.
Aug 13 08:55:56 gitea systemd[1]: Failed to start MariaDB 10.3.15 database server.

Your workaround is working but it seems that removing only these 3 lines is sufficient:

vim /etc/systemd/system/mariadb.service
ProtectSystem=full
PrivateDevices=true
ProtectHome=true

source : http://debian.2.n7.nabble.com/Bug-920643-mariadb-server-10-3-mariadb-won-t-start-when-running-inside-an-lxc-container-when-runningg-td4460471.html#a4488757

Faire une snapshot

lxc-snapshot -n [containername] [snapshot-name]

Renommer un container

hostnamectl set-hostname [hostname]

Après avoir changer le hostname, n’oubliez pas le mettre à jour le fichier /etc/hosts au niveau du 127.0.1.1

bugs :

apt install -y dbus

Modifier le fichier /etc/hostname and reboot

Configurer la date

dpkg-reconfigure tzdata
/bin/ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime

Enlever les recommandations apt

En gros sur debian 10 apt install plein de truc en plus quand vous faites un apt install et c’est chiant.

cat > /etc/apt/apt.conf.d/01norecommend << EOF
APT::Install-Recommends "0";
APT::Install-Suggests "0";
EOF

Redirection de port

Vous l’aurez remarqué, quand on fait tourner une application sur le port 80, elle n’est pas disponible en publique (avec votre adresse publique). Vous avez 2 solutions :

  1. Votre application est une application web, il faut créer un reverse proxy sur la machine hôte

Voir tuto nginx

  1. Ouvrir le port sur la machine hôte avec iptables

Par exemple pour ssh, vous voulez vous connecter en ssh directement dans le container :

Il faut avoir au préalable

iptables -t nat -A PREROUTING -p tcp --dport [port d'entrée] -j DNAT --to [ip container]:22

ex :

iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to 10.0.30.7:22

Pour se connecter, il faut lancer :

ssh omer@[adresse publique] -p [port d'entrée]

Attention je le rappel les rêgles iptables ne sont pas permannent et je sais plus comment on fait pour les rendre permannente OK !

Gestion des utilisateurs

Cette partie est plus propre à linux qu’a lxc mais j’arrete pas d’oublier les commandes ça me casse les c******* !!! Alors je le met ici.

  1. Ensuite créer un utilisateur dans le container :
useradd -s /bin/bash -m [username]
  1. lui attribuer un password
passwd [username]
  1. On lui ajouter des droit sudo
usermod -aG sudo omer

Sur debian sudo n’est pas installé

apt install sudo
  1. Installer openssh pour l’utilisateur
su [username]
sudo apt install openssh-server

Ya un petit soucis avec les utiliateurs dans un container lxc. Quand on se connecte en lxc-attach et su [username], on ne met pas de mot de passe. Le petit soucis c’est que quand on fait sudo … on a cette erreur :

sudo: no tty present and no askpass program specified

J’ai pas trop de solution pour le moment, il faut soit se connecter en ssh direct avec l’user ou ajouter cette ligne :

visudo
[username] ALL=(ALL) NOPASSWD:ALL

Pour faire plus propre, le mieux c’est de créer un fichier /etc/sudoer.d/[username] avec cette ligne dedans et decomenter cette ligne dans le visudo :

includedir /etc/sudoers.d/

Alors très important, quand vous modifiez le fichier sudoer, faites le toujours en passant par la commande visudo. Cette commande fait une verification de votre modification avant de valider. Car en cas d’erreur de syntaxe c’est la merdouille.

Inotify

Alors une erreurs que j’ai rencontré sur linux c’est les inotify. En gros à force de créer des containers vous tomberez surement sur cette erreur : failed to create inotify: Too many op en files. Ce message signifi que la limite à été atteinte.

Le mécanisme inotify permet de mettre ce que l’on appel un watch descriptor sur un fichier, qui enverra des notifications au système lorsque des événements sur le fichier.

Pour connaitre ces limites, tapez la commande :

sysctl fs.inotify.max_user_instances

Pour modifier cette valeur de façon permaenente il faut modifier le fichier /etc/sysctl.conf

Par defaut j’était à 128.

fs.inotify.max_queued_events=1048576
fs.inotify.max_user_instances=1048576
fs.inotify.max_user_watches=1048576
sysctl --system

Superviser

Il est possible de récupérer des données sur les conteneur tel que la consommationo CPU. Ces données se situe sur la machine hote dans le repertoire /sys/fs/cgroup/cpuacct/lxc/

Exemple :

Le cpu se situe dans le fichier : /sys/fs/cgroup/cpuacct/lxc/discord/cpuacct.usage

Ram utilisé en nanoseconde depuis que le container est lancé