MaDoVi - Le wiki

Machines - Données - Virtualisation

Outils pour utilisateurs

Outils du site


services:virtu:tuto:lxc_tuto1

Virtualisation - Containers LXC

LXC (Linux Container) est un outil de virtualisation léger. Il permet de faire s'exécuter une distribution complète avec ses services et ses applications sur notre serveur, de façon isolée et sans ajout au système hôte susceptible d'en perturber le fonctionnement.

Dans le cadre du projet , on utilise cette technologie pour virtualiser un maximum de services: sauvegardes, bases de données, services web, vidéo, etc…
Vous pouvez bien sûr l'utiliser dans un autre contexte, moyennant sans doute quelques adaptations.

Pour toutes les manipulations à suivre, on se positionne en root via:

$ sudo -i
[sudo] Mot de passe de <moââ> : 
# 

Le prompt en # vous indique que vous avez des droits d'administrateur.

1. Installation

La commande d'installation est la suivante:

# apt-get install lxc debootstrap libpam-cgfs python3-lxc dnsmasq-base bridge-utils lxc-dev

avec:

  • lxc, debootstrap: briques de base
  • libpam-cgfs: pour les container «unprivileged»
  • python3-lxc: pour ce fabriquer des petits outils en Python
  • dnsmasq-base, bridge-utils: pour les aspects réseau des containers
  • lxc-dev: on pourrait en avoir besoin, en particulier avec l'utilisation d'ansible

2. Stockage

Ce point est important, en particulier lorsque l'OS du système est défini sur un espace réduit ou fragile (OS sur une clé USB par exemple, qui cumule: réduit et fragile).

En effet, LXC travaille par défaut dans des répertoires dans /var, à la racine du système. Dans ce contexte (/var sur clé système), il paraît nécessaire de modifier les emplacements utilisés et les faire pointer vers un disque dur.

Si vous n'êtes pas concernés (assez d'espace sur votre HDD système par exemple), vous pouvez ignorer les propositions ci-dessous.

2.1. Chemins standards

Les dossiers utilisés par LXC en standard sont les suivants:

  • /var/lib/lxc: emplacement par défaut pour les containers
  • /var/lib/lxcsnap: emplacement par défaut pour les snapshots
  • /var/cache/cache/lxc: emplacement par défaut du cache des images de containers

Pour les containers «non privilégiés» (i.e. associés à un utilisateur):

  • $HOME/.local/share/lxc: emplacement par défaut pour les containers non privilégiés
  • $HOME/.local/share/lxcsnap: emplacement par défaut pour les snapshots non privilégiés
  • $HOME/.cache/lxc: emplacement par défaut du cache pour les containers non privilégiés

☛ Le chemin par défaut des containers, aussi appelé lxcpath, peut être remplacé sur la ligne de commande avec l'option -P, ou bien une fois pour toutes en définissant lxc.lxcpath = /new/path dans le fichier /etc/lxc/lxc.conf (ou $HOME/.config/lxc/lxc.conf pour les containers non privilégiés).

☛ Le répertoire snapshot est toujours snap ajouté à lxcpath (il suit donc toujourslxcpath).

☛ Le cache des images est malheureusement codé en dur et ne peut pas être facilement déplacé sans dépendre de bind-mounts ou de liens symboliques.

☛ La configuration par défaut utilisée pour tous les containers au moment de la création est tirée de /etc/lxc/default.conf ($HOME/.config/lxc/default.conf pour les containers non privilégié).

☛ Les modèles ou templates – des scripts appelés lors de la création des containers – sont stockés dans /usr/share/lxc/templates.

Ainsi, par configuration quand on peut, ou en modifiant du code dans le cas contraire, on va faire pointer ces dossiers par défaut dans une zone du disque dur qu'on a réservée à la virtualisation: en conséquence, ce tutoriel Gestion d'un disque avec LVM est un préalable ici.

2.2. Chemins cibles

Le tutoriel cité au-dessus nous a permis de définir un point de montage /mnt/env-lxc, avec un Volume Logique LVM sous-jacent sur notre disque dédié /dev/sda de virtualisation.

Nous allons donc établir les «correspondances» ci-après, et décrire ensuite leur mise en œuvre:

Configuration des chemins
Containers «privilégié»
⇒ Fichier de config system: /etc/lxc/lxc.conf
⇒ Ficher de config container (par défaut): /etc/lxc/default.conf
Chemin d'origine Chemin cible Modalité de configuration
/var/lib/lxc /mnt/env-lxc/lxc via /etc/lxc/lxc.conf
/var/lib/lxcsnap /mnt/env-lxc/lxcsnap Implicite
/var/cache/lxc /mnt/env-lxc/cache Changer les scripts template ou lien symbolique :?:
Containers «non privilégié»
⇒ Fichier de config system: ~/.config/lxc/lxc.conf
⇒ Ficher de config container (par défaut): ~/.config/lxc/default.conf
Chemin d'origine Chemin cible Modalité de configuration
~/.local/share/lxc /mnt/raid_data/users/<user>/.local/share/lxc Définition d'un compte <user> et son $HOME.
Ouvrir éventuellement la possibilité pour les utilisateurs
de créer des CT (comptes utilisateurs sur le RAID) :?:
~/.local/share/lxcsnap /mnt/raid_data/users/<user>/.local/share/lxcsnap Implicite
~/.cache/lxc /mnt/raid_data/users/<user>/.cache/lxc Définition d'un compte <user> et son $HOME.

2.3. Configuration des chemins

  • Pour les containers «privilégiés»:

    1. Configuration du chemin des containers dans le fichier /etc/lxc/lxc.conf.
      /etc/lxc/lxc.conf
      # SI NON LVM : Chemin par défaut des containers "privilégiés" 
      lxc.lxcpath = /mnt/env-lxc/lxc
      # SI LVM: Virtual Group (VG) par défaut des containers "privilégiés"
      lxc.bdev.lvm.vg = VGVirtu
    2. Configuration du chemin des snapshots des containers: implicite, «hérité» du précédent.

    3. Configuration du chemin du cache des images des containers.
      Il est nécessaire ici de définir un lien symbolique. Pour ce faire, passer les commandes suivantes:
      # rm /var/cache/lxc
      # ln -s /mnt/env-lxc/cache/ /var/cache/lxc
      ## Vous assurer que c'est bon: lien symbolique 
      # ls -als /var/cache/lxc
      0 lrwxrwxrwx 1 root root 19 oct.  24 23:59 /var/cache/lxc -> /mnt/env-lxc/cache/
  • Pour les containers «non privilégiés»: Dans ce cas, les chemins sont dépendants de la localisation du compte de l'utilisateur. On va donc se servir du compte admin qu'on a déjà défini (mais n'importe quel compte utilisateur suffit). Le répertoire $HOME est localisé sur l'espace RAID dans /mnt/raid_data/users/admin.

    Ceci implique que les containers «non privilégiés» qui seront créés sous le compte admin vont se retrouver dans l'espace RAID. Mais uniquement s'ils sont créés en mode DIR.

    C'est pourquoi il est plus intéressant de créer systématiquement les containers en mode LVM (on verra comment plus tard), pour une certaine … cohérence d'ensemble.

    :!: On se logue en admin :!: et on passe donc les commandes suivantes pour définir tout ça:

    1. Création des répertoires LXC:
      $ mkdir -p ~/.local/share/lxc ~/.cache/lxc ~/.config/lxc
    2. Copie de la configuration du stockage:
      $ cp /etc/lxc/lxc.conf ~/.config/lxc/lxc.conf

      On édite le fichier et on le modifie en supprimant lxcpath: les containers en DIR iront par défaut sur le RAID dans /mnt/raid_data/users/admin/.local/share/lxc, ceux en LVM iront dans un LV sur le disque dédié à la virtualisation:

      $ nano ~/.config/lxc/lxc.conf
      # SI LVM: Virtual Group (VG) par défaut des containers "non privilégiés"
      lxc.bdev.lvm.vg = VGVirtu
    3. Copie de la configuration CT et faire de admin le propriétaire: on l'adaptera toute à l'heure aux CT «non privilégiés»…
      $ cp /etc/lxc/default.conf ~/.config/lxc/default.conf
      $ sudo chown admin:admin ~/.config/lxc/default.conf 

3. Réseau

Il n'est pas inutile de rappeler l'illustration suivante (issue du vieux tuto VHS):

Schématiquement, les containers LXC constituent entre-eux un réseau isolé de «machines» qui peuvent dialoguer sur leur propre réseau et avec l'extérieur de ce réseau.

Ce réseau peut être vu comme un «LAN LXC» avec les concept associés:

  1. les machines LXC disposent d'une adresse IPv4 sous la forme x.y.z.t
  2. ces adresses sont configurées sur la machine LXC elle-même ou via un serveur DHCP qui leur attribue
  3. il existe souvent sur un LAN un composant qui associe les noms réseau des machines et leur adresse IP: le DNS

Ces éléments se configurent…

3.1. Définitions

Ce Lien (un peu daté mais toujours d'actualité) expose les possibilités de «raccordement» réseau des containers LXC.

Parmi les options qu'il présente, on choisit ici l'option «veth».
Présentons le schéma ci-dessous, qu'on «explique» rapidement ensuite:

En vocabulaire de tous les jours, un pont est un passage entre deux rives; en matière d'informatique, un bridge est un lien entre deux interfaces réseau. …pfff m(

Sur ce schéma:

  • eth0 sont les interfaces réseau des containers LXC
  • veth– sont des interfaces virtuelles, «appairées» avec les eth0
  • dnsmasq est l'outil qu'on a installé, qui est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de routeurs et DHCP.
  • lxcbr0 et br0 sont des bridges qui permettent de faire le lien entre les interfaces, virtuelles des containers…
  • … et ens— qui constitue l'interface réseau physique de la machine hôte.

Le bridge lxcbr0 permet aux containers de «sortir» sur le réseau local (et par suite sur internet). Il est isolé en ce sens que:

  • les adresses des containers sont attribués «localement» par l'outil dnsmasq (en 10.0.3.x ici)
  • les flux entrants – depuis le réseau local ou même depuis internet – ne seront autorisés que via des ouvertures de ports sur l'hôte, en utilisant iptables et les «NATage» de ces ports (consiste à autoriser les flux entrants depuis tel port sur l'hôte à destination de tel port d'un container identifié par son adresse IP).

On ajoute br0: on veut s'accorder la possibilité de présenter nos containers comme des machines à part entière sur notre réseau local, de telle manière qu'ils obtiennent leur adresse IP depuis la box / le routeur de ce réseau, et qu'ils soient vus et accessibles sur ce réseau. C'est l'objet du bridge br0 qui permet le lien entre les interfaces réseau des container et l'interface réseau de l'hôte et qui permet de «court-circuiter» dnsmasq et de se raccorder directement à la box/routeur.

3.2. ''lxcbr0'', DHCP & DNS

dnsmasq est un outil (qu'on a installé ci-dessus) léger qui fait fonction à la fois de serveur d'adresses DHCP et de serveur de noms DNS.

Sa configuration, dans le cadre de LXC est définie dans le fichier /etc/default/lxc-net. Dans la livraison Debian de LXC, ce fichier est vide. Dans celle de Ubuntu, tout est «pré-rempli». On va donc se fabriquer le notre sur cette base :

/etc/default/lxc-net
# Laissez USE_LXC_BRIDGE à "true" si vous voulez utiliser lxcbr0 pour vos containers LXC
# Définissez sur "false" si vous utiliserez virbr0 ou un autre logiciel existant bridge,
# ou Mavlan, sur l'interface réseau de votre hôte.
USE_LXC_BRIDGE="true"
 
# Si vous changez le LXC_BRIDGE pour autre chose que lxcbr0, alors
# vous devrez également mettre à jour votre fichier /etc/lxc/default.conf ainsi 
# que le fichier de configuration (/var/lib/lxc/<container>/config) pour tous 
# les containers déjà créés en utilisant la configuration par défaut pour refléter
# le nouveau nom de la passerelle.
 
# Les paramètre ci-dessous sont les valeurs par défaut utilisées par dnsmaq.
# Décommentez-les et valorisez-les autrement si vous souhaitez les changer
#LXC_BRIDGE="lxcbr0"
#LXC_ADDR="10.0.3.1"
#LXC_NETMASK="255.255.255.0"
#LXC_NETWORK="10.0.3.0/24"
#LXC_DHCP_RANGE="10.0.3.2,10.0.3.254"
#LXC_DHCP_MAX="253"
 
# Dé-commentez la ligne suivante si vous voulez utiliser un fichier de configuration
# du dnsmasq pour lxcbr0
# Par exemple, vous pouvez utiliser 'dhcp-host=mail1,10.0.3.100' pour avoir
# le container 'mail1' qui obtient toujours l'adresse IP 10.0.3.100.
LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf
 
# Dé-commentez la ligne suivante si vous voulez que le dnsmasq de lxcbr0 résolve le
# domaine en ".lxc". Vous pouvez alors ajouter 'server=/lxc/10.0.3.1' à /etc/dnsmasq.conf
# après quoi'container1.lxc' sera résolu sur votre host.
LXC_DOMAIN="lxc"

Et donc en complément, on définit le fichier «DNS / DHCP» /etc/lxc/dnsmasq.conf (référencé dans le fichier ci-dessus) avec:

/etc/lxc/dnsmasq.conf
server=/lxc/10.0.3.1
 
# ===> N'ajoutez pas nécessairement les lignes ci-dessous: on pourra le faire au fur et à mesure des besoins
# Fixer toujours la même adresse à un container en fonction de son nom
# cid  1 ->  49: containers term
dhcp-host=lxc-term01,10.0.3.11
dhcp-host=lxc-term02,10.0.3.12
dhcp-host=lxc-term03,10.0.3.13
 
# cid  50 -> 99: containers web
dhcp-host=lxc-proxy,10.0.3.50
dhcp-host=lxc-web01,10.0.3.51
dhcp-host=lxc-web02,10.0.3.52
dhcp-host=lxc-web03,10.0.3.53
 
# cid 100 -> 149; containers gui
dhcp-host=lxc-gui01,10.0.3.101
dhcp-host=lxc-gui02,10.0.3.102
dhcp-host=lxc-gui03,10.0.3.103
 
# cid 150 -> 199; containers divers
dhcp-host=lxc-guac,10.0.3.151
dhcp-host=lxc-gitlab,10.0.3.152
dhcp-host=lxc-docker,10.0.3.153
dhcp-host=lxc-kodi, 10.0.3.154

Pour prendre en compte les changements, il s'agit de redémarrer le service réseau de LXC:

# systemctl restart lxc-net.service

3.3. ''br0'' - Lien direct

Il s'agit de définir le pont br0 sur l'hôte. Pour ce faire, on modifie le fichier de configuration des interfaces réseau /etc/network/interfaces comme suit:

/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
# Modif <machin> - 2019.09.14 == Configurer l'hôte comme bridge
#allow-hotplug enp3s0
#iface enp3s0 inet dhcp
auto br0
iface br0 inet dhcp
        bridge_ports enp3s0
        bridge_fd 0
        bridge_maxwait 0

Il est possible que l'interface physique «native» ne soit pas enp3s0 comme ici sur votre machine: il faudra adapter. La ligne iface enp3s0 inet dhcp qu'il faudra commenter doit être la bonne, identifiée à l'installation.

La commande suivante liste les interfaces réseau disponibles; elle peut vous aider à trouver le bon nom, en considérant les VHS avec deux cartes réseaux… :

ls /sys/class/net/

Passer la commande suivante pour prise en compte du changement:

# systemctl restart networking.service

3.4. Double DNS

Les containers peuvent s'adresser les uns aux autres par leur nom: lorsque dhclient à l'intérieur d'un container demande une adresse IP, il inclut également son nom d'hôte dans la requête. dnsmasq, agissant en tant que serveur DHCP et DNS simultanément, affecte une adresse IP au container et ajoute également une entrée à sa table DNS. Ainsi, chaque container est capable de résoudre l'adresse IP de tous les autres container de manière transparente via DNS.

L'hôte, par contre, n'est pas capable par défaut de résoudre les adresses IP des containers. Pour régler ce problème, nous devons utiliser le démon dnsmasq local comme serveur DNS primaire sur l'hôte.

Ajoutez la ligne suivante au fichier /etc/dhcp/dhclient.conf de l'hôte :

prepend domain-name-servers 10.0.3.1 ;

et redémarrez le service réseau:

# systemctl restart networking.service

Vour pourrez alors constater que le serveur dnsmasq apparaît dans la liste des serveurs DNS sur l'hôte:

$ cat /etc/resolv.conf
domain local
search local
nameserver 10.0.3.1
nameserver 192.168.1.1

Maintenant quand une application sur l'hôte appelle une machine par son nom, la requête DNS est d'abord envoyée au démon dnsmasq local. Si la requête est le nom d'un des containers, alors dnsmasq répondra avec son adresse IP par lui-même en utilisant sa table DNS locale. Pour tous les autres noms d'hôtes, il agit comme proxy DNS et envoie les requêtes au serveur DNS amont spécifié dans /etc/resolv.conf. Et il est assez «intelligent» pour ne pas envoyer des demandes récursivement à lui-même…

De cette façon, et depuis la console de l'hôte, les commandes suivantes ne vous «enverront pas balader»:

$ ping -c 4 lxc-proxy
$ ssh toto@lxc-term01.lxc

4. Containers

On va mettre en place ici les éléments de configuration, dont hériteront dès leur création l'ensemble des containers LXC.

4.1. CT «privilégiés»

Le fichier concerné est /etc/lxc/default.conf pour les containers privilégiés, dont le contenu lxc.network.type = empty est remplacer par:

/etc/lxc/default.conf
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
#lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx

4.1. CT «non privilégiés»

Si vos conteneurs LXC doivent contenir des serveurs / services sensibles aux attaques, vous ne voudriez pas qu'un serveur compromis compromette tout le reste du système. Ne pas donner les privilèges super-utilisateur au container permet de limiter ce risque. C'est le but des containers «non privilégiés» … qui sont un peu «velus» à configurer sous Debian.

On va le faire sans trop d'explication – pas sûr de tout comprendre moi-même :-\ – mais l'essentiel est que ça fonctionne au bout…

Rappel: :!: On est logé en admin :!:

  • Configuration du noyau pour autoriser des utilisateurs banalisés à manipuler des containers:
    $ sudo sh -c 'echo "kernel.unprivileged_userns_clone=1" > /etc/sysctl.d/80-lxc-userns.conf'

    Prise en compte sans redémarrer:

    $ sudo sysctl --system
  • On autorise admin à utiliser le bridge dédié LXC lxcbr0, mais aussi le bridge «direct» br0, pour 10 CT (en tout, c'est parfaitement arbitraire):
    $ sudo nano /etc/lxc/lxc-usernet
    admin veth lxcbr0  5
    admin veth br0     5
  • Maintenant, on récupère les subuids et subgids de notre utilisateur courant (le retour peut-être différent chez vous bien sûr):
    $ cat /etc/s*id | grep ^$USER
    admin:231072:65536
    admin:231072:65536
  • Il faut ajouter ces informations au fichier ~/.config/lxc/default.conf selon:
    ~/.config/lxc/default.conf
    lxc.net.0.type = veth
    lxc.net.0.link = lxcbr0
    #lxc.net.0.link = br0
    lxc.net.0.flags = up
    lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
     
    # Ajout {g,u}id pour containers "unprivileged"
    lxc.idmap = u 0 231072 65536
    lxc.idmap = g 0 231072 65536
  • Le web indique: «Dans certaines configurations, le container non privilégié lxc se plaindra de ne pas pouvoir fonctionner, et demandera d'ajouter des droits d'exécutions sur les dossiers .local et .local/share: Permission refusée - Impossible d'accéder à /home/$USER/.local. Veuillez lui accorder l'accès x, ou ajouter une ACL pour la racine du container.»

    Pour prévenir cette erreur, passer la commande (attention le paquet acl doit avoir été installé):
    $ sudo setfacl -m u:231072:x .local .local/share

    231072 correspond au uid de votre utilisateur (le même que plus haut)

  • autostart: Dans la configuration des containers, il existe des propriétés qui permettent de gérer leur lancement dès le démarrage de l'hôte. il s'agit de (voir les pages man):
    #lxc.group = onboot
    #lxc.group = bddserver
    lxc.start.auto = 1
    lxc.start.delay = 5
    lxc.start.order = 103 

    Pour des CT «privilégiés», il n'y a pas de problème particulier: il existe un service dans systemd appelé lxc-autostart qui s'occupe de cela. Lorsque systemd démarre le service LXC, lxc-autostart est appelé. Mais il est appelé en tant que root, donc même si vous avez “lxc.start.auto = 1” dans votre configuration, votre container «non privilégié» n'est pas lancé.
    La solution consiste à définir un «cron au reboot» associé à l'utilisateur propriétaire: En tant qu'utilisateur propriétaire des containers «non privilégié», lancez:

    admin@wasabi $ crontab -e

    et ajoutez la ligne suivante :

    @reboot lxc-autostart -g "onboot,"

    Ainsi, lxc-autostart sera lancé au démarrage avec l'utilisateur admin et pourra pointer les CT en démarrage automatique: Par exemple ici, dans l'ordre, ceux qui appartiennent au groupe onboot, puis ceux qui n'ont pas de groupe défini. Vous pouvez jongler avec les groupes de containers que vous aurez défini.


La configuration est maintenant terminée (le § suivant consiste à vérifier).

C'est sans doute le moment de re-démarrer la machine, histoire de bien prendre en compte tout cela:

$ sudo reboot

5. Vérifications

Pour vérifier l'ensemble de ces configurations – leur exactitude et leur bonne prise en compte par le système – on propose de réaliser les opérations et les contrôles qui suivent.

5.1. CT «privilégiés»

L'environnement nécessaire ici est celui de root.

Si vous n'y êtes pas, positionnez-vous avec des privilèges :

$ sudo -i
[sudo] Mot de passe de <moââ> : 
# 

5.1.1. Isolé / DIR

Ce qu'on va faire ici:

  • Créer un CT «privilégié», isolé sur le réseau en '10.0.3.x' dédié, stocké dans le dossier réservé aux CT, sur un modèle Debian
  • Faire un certain nombre de vérifications: où il est stocké, son adresse IP, etc…
  • On va y ajouter un serveur ssh et faire les manipulations nécessaires pour l'atteindre depuis un poste client sur le LAN
  • Pour terminer, on va le supprimer et vérifier que le ménage est fait…

On y va…

☛ On créé donc en tant que root (donc «privilégié») un CT nommé lxc-term01 d'après le template debian qu'on stocke sur l'espace de l'environnement LXC ( par défaut car pas de paramètre '-B':

# lxc-create -n lxc-term01 -t debian

L'outil va chercher ce qui va bien sur internet et construit une image minimale Debian, avec toutes les librairies et paquets utiles. La sortie à l'écran du processus de création est longue et doit ressembler et se terminer comme:

Cliquer pour voir/cacher le résultat

Cliquer pour voir/cacher le résultat

root@wasabi:~# lxc-create -n lxc-term01 -t debian
debootstrap est /usr/sbin/debootstrap
Checking cache download in /var/cache/lxc/debian/rootfs-stable-amd64 ... 
Downloading debian minimal ...
I: Target architecture can be executed
I: Retrieving InRelease 
I: Checking Release signature
I: Valid Release signature (key id 6D33866EDD8FFA41C0143AEDDCC9EFBF77E11517)
I: Retrieving Packages 
I: Validating Packages 
...
...
I: Validating util-linux 2.33.1-0.1
I: Retrieving liblzma5 5.2.4-1
I: Validating liblzma5 5.2.4-1
I: Retrieving zlib1g 1:1.2.11.dfsg-1
I: Validating zlib1g 1:1.2.11.dfsg-1
I: Chosen extractor for .deb packages: dpkg-deb
I: Extracting libacl1...
I: Extracting adduser...
I: Extracting apt...
...
...
I: Extracting util-linux...
I: Extracting liblzma5...
I: Extracting zlib1g...
I: Installing core packages...
I: Unpacking required packages...
I: Unpacking libacl1:amd64...
I: Unpacking adduser...
I: Unpacking apt...
...
...
I: Unpacking util-linux...
I: Unpacking liblzma5:amd64...
I: Unpacking zlib1g:amd64...
I: Configuring required packages...
I: Configuring debian-archive-keyring...
I: Configuring libaudit-common...
...
...
I: Configuring mount...
I: Configuring sysvinit-utils...
I: Configuring libc-bin...
I: Unpacking the base system...
I: Unpacking libdns-export1104...
I: Unpacking libisc-export1100:amd64...
...
...
I: Unpacking sensible-utils...
I: Unpacking libwrap0:amd64...
I: Unpacking ucf...
I: Configuring the base system...
I: Configuring lsb-base...
I: Configuring net-tools...
...
...
I: Configuring openssh-client...
I: Configuring openssh-sftp-server...
I: Configuring openssh-server...
I: Configuring libc-bin...
I: Configuring systemd...
I: Base system installed successfully.
Download complete.
Copying rootfs to /mnt/env-lxc/lxc/lxc-term01/rootfs...Generating locales (this might take a while)...
  fr_FR.UTF-8... done
  fr_FR.UTF-8... done
Generation complete.
update-rc.d: error: cannot find a LSB script for checkroot.sh
update-rc.d: error: cannot find a LSB script for umountfs
Failed to disable unit, unit hwclock.sh.service does not exist.
update-rc.d: error: cannot find a LSB script for hwclockfirst.sh
Creating SSH2 RSA key; this may take some time ...
2048 SHA256:vxn3Au37ElGjg9FFV6QwykaNmmbTw6JBAF5r3qcB6HY root@wasabi (RSA)
Creating SSH2 ECDSA key; this may take some time ...
256 SHA256:YZnTllCVeMNrrec6S7+7DKkSUcE9E053DFuV2xeeL0s root@wasabi (ECDSA)
Creating SSH2 ED25519 key; this may take some time ...
256 SHA256:F2ar5grOHeM90DvRpPifu7No+qJfRVuNaN+agaMCzzA root@wasabi (ED25519)
invoke-rc.d: could not determine current runlevel
invoke-rc.d: policy-rc.d denied execution of start.

Current default time zone: 'Etc/UTC'
Local time is now:      Tue Oct 29 19:25:30 UTC 2019.
Universal Time is now:  Tue Oct 29 19:25:30 UTC 2019.

Vous pourrez noter au passage que le serveur ssh est pré-installer dans ce modèle.

☛ On vérifie:

  • Le CT est bien construit dans notre environnement dédié à la virtualisation /mnt/env-lxc
  • Le cache est alimenté de l'image Debian qu'on a construit (utile pour un prochain CT de même modèle)
  • Le dossier lxc contient la config du container lxc-term01 (que vous pouvez consulter: cat /mnt/env-lxc/lxc/lxc-term01/config), le dossier rootfs contient l'arborescence d'un système linux

    root@wasabi:~# tree -L 3 /mnt/env-lxc/
    /mnt/env-lxc/
    ├── cache
    │   └── debian
    │       └── rootfs-stable-amd64
    ├── lost+found
    └── lxc
        └── lxc-term01
            ├── config
            └── rootfs
     
    7 directories, 1 file

☛ On ajoute … rien car pour notre exemple, le serveur ssh est déjà installé.

  • On liste les CT:
    # lxc-ls -f
    NAME       STATE   AUTOSTART GROUPS IPV4       IPV6 UNPRIVILEGED 
    lxc-term01 STOPPED 0         -      -          -    false        
  • On va le lancer…
    # lxc-start -n lxc-term01 -d 
  • … et vérifier son statut après un petit délai (le temps du démarrage et de l'affectation d'une @IP):
    root@wasabi:~# lxc-ls -f
    NAME       STATE   AUTOSTART GROUPS IPV4       IPV6 UNPRIVILEGED 
    lxc-term01 RUNNING 0         -      10.0.3.11  -    false        

    Notez son adresse IP: elle correspond bien à ce que l'on a configuré dans le serveur DHCP dnsmasq pour un CT nommé lxc-term01.

  • On va s'attacher au CT (ouvrir une console dessus) et constater que l'outil serveur ssh est déjà installé par défaut dans le modèle Debian qu'on utilise:
    # lxc-attach -n lxc-term01
    root@lxc-term01:~# dpkg-query -l | grep openssh
    ii  openssh-client           1:7.9p1-10                 amd64        secure shell (SSH) client, for secure access to remote machines
    ii  openssh-server           1:7.9p1-10                 amd64        secure shell (SSH) server, for secure access from remote machines
    ii  openssh-sftp-server      1:7.9p1-10                 amd64        secure shell (SSH) sftp server module, for SFTP access from remote machines
  • On fait une mise à jour et on vérifie que le port ssh est bien à l'écoute, et on sort du CT:
    root@lxc-term01:~# apt update && apt upgrade -y

    Il se trouve que, au moment de la manipulation, justement ssh avait besoin d'une mise à jour (c'est un «hasard»).

    root@lxc-term01:~# ss -l | grep ssh
    tcp   LISTEN 0      128                         0.0.0.0:ssh             0.0.0.0:*                                                                               
    tcp   LISTEN 0      128                            [::]:ssh                [::]:*                                                                               
  • Pour ce connecter en ssh il nous faut un compte dans le CT:
    root@lxc-term01:~# adduser toto
    Adding user `toto' ...
    Adding new group `toto' (1000) ...
    Adding new user `toto' (1000) with group `toto' ...
    Creating home directory `/home/toto' ...
    Copying files from `/etc/skel' ...
    Nouveau mot de passe : 
    Retapez le nouveau mot de passe : 
    passwd: password updated successfully
    Changing the user information for toto
    Enter the new value, or press ENTER for the default
    	Full Name []: 
    	Room Number []: 
    	Work Phone []: 
    	Home Phone []: 
    	Other []: 
    Is the information correct? [Y/n] y
  • On sort du CT:
    root@lxc-term01:~# exit
    exit
    root@wasabi:~# 

    On est donc revenu sur l'hôte (gardez en mémoire le mot de passe que vous avez donné à < toto >).

☛ Il s'agit maintenant d’ouvrir un port sur l'hôte qui va nous permettre d'atteindre le serveur ssh du CT. On utilise pour ce faire les éléments suivants, via la commande iptables:

Ouvrir & fermer et Voir les @:ports NATés:

Terminal
Ouvrir:
sudo iptables -t nat -A PREROUTING -p tcp -i <interface> --dport <portHost> -j DNAT --to-destination <@IP:Port Destination>
Exemple:
sudo iptables -t nat -A PREROUTING -p tcp -i br0 --dport 60080 -j DNAT --to-destination 10.0.3.59:80
 
Fermer:
sudo iptables -t nat -D PREROUTING -p tcp -i <interface> --dport <portHost> -j DNAT --to-destination <@IP:Port Destination>
Exemple:
sudo iptables -t nat -D PREROUTING -p tcp -i br0 --dport 60080 -j DNAT --to-destination 10.0.3.59:80
 
Liste:
sudo iptables -t nat -L
sudo iptables -t nat -S
  • Donc, on ouvre par exemple l'accès ssh du CT via le port 10221 de l'hôte:
    # iptables -t nat -A PREROUTING -p tcp -i br0 --dport 10221 -j DNAT --to-destination 10.0.3.11:22
  • Et, si tout va bien, on peut se connecter sur le compte < toto > de notre CT depuis un PC sur notre réseau local et qui dispose d'un client ssh (PutTTY sous Windows par exemple):
     ssh -p 10221 toto@wasabi

    -p permet de préciser le port NATé sur la machine serveur qui est ici < wasabi >. Vous devriez pouvoir voir ceci:

    cram28@paprika:~$ ssh -p 10221 toto@wasabi
    The authenticity of host '[wasabi]:10221 ([192.168.1.3]:10221)' can't be established.
    ECDSA key fingerprint is SHA256:YZnTllCVeMNrrec6S7+7DKkSUcE9E053DFuV2xeeL0s.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '[wasabi]:10221,[192.168.1.3]:10221' (ECDSA) to the list of known hosts.
    toto@wasabi's password: 
    Linux lxc-term01 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64
     
    The programs included with the Debian GNU/Linux system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.
     
    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    permitted by applicable law.
    toto@lxc-term01:~$ 

Notre test est parfaitement concluant…8-) On peut sortir du container avec exit.

☛ … reste à faire le ménage ;-). On va virer tout ça et s'assurer de ce qui reste

  • Virer le NAT (même s'il disparaitra tout seul au prochain reboot du serveur):
    # iptables -t nat -D PREROUTING -p tcp -i br0 --dport 10221 -j DNAT --to-destination 10.0.3.11:22
  • Arrêter le CT:
    # lxc-stop -n lxc-term01
  • Le détruire:
    # lxc-destroy -n lxc-term01
  • Vérifier ce qui reste:
    # tree -L 3 /mnt/env-lxc/
    /mnt/env-lxc/
    ├── cache
    │   └── debian
    │       └── rootfs-stable-amd64
    ├── lost+found
    └── lxc
     
    5 directories, 0 files

    Le cache est maintenu, le reste a bien disparu.

5.1.2. LAN / LVM

Ce qu'on va faire ici est quasiment le même chose, SAUF QUE:

  • On va démarrer ce CT «privilégié» avec le bridge br0 pour une connexion directement au réseau local et on va le définir dans un volume logique LVM avec un modèle Ubuntu.
  • Le reste des actions et vérifications sera identique
  • On va donc ici se contenter de lister les commandes et modifications

Ci-dessous les étapes:

  • On créé le container lxc-gitlab dans un volume logique LVM de même nom, sur un modèle Ubuntu. On notera que l'installation vous posera sans doute des questions, et que … Ubuntu est bien «une grosse vache» :!:
    # lxc-create -n lxc-gitlab -t ubuntu -B lvm --lvname lxc-gitlab

    Notez bien en fin d'installation:

      ##
      # The default user is 'ubuntu' with password 'ubuntu'!
      # Use the 'sudo' command to run tasks as root in the container.
      ##
  • On vérifie le cache, le fichier de config. et le répertoire rootfs vide (car est sensé être dans LVM):
    # tree -L 3 /mnt/env-lxc/
    /mnt/env-lxc/
    ├── cache
    │   ├── debian
    │   │   └── rootfs-stable-amd64
    │   └── xenial
    │       └── rootfs-amd64
    ├── lost+found
    └── lxc
        └── lxc-gitlab
            ├── config
            └── rootfs
     
    9 directories, 1 file

    On note que le cache est enrichi avec Ubuntu Xenial.

  • On peut vérifier que le LV correspondant est bien créé dans notre espace de virtualisation. Si l'on ne précise pas de taille pour le disque virtuel du CT, 1Go sont réservés:
    # lsblk -o name,model,type,size,fstype,state,mountpoint /dev/sda
    NAME                    MODEL          TYPE   SIZE FSTYPE      STATE   MOUNTPOINT
    sda                     Maxtor_6V250F0 disk 233,8G             running 
    └─sda1                                 part 233,8G LVM2_member         
      ├─VGVirtu-env--lxc                   lvm     10G ext4        running /mnt/env-lxc
      └─VGVirtu-lxc--gitlab                lvm      1G ext4        running 
  • On liste les CT:
    # lxc-ls -f
    NAME       STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED 
    lxc-gitlab STOPPED 0         -      -    -    false        
  • Il s'agit de modifier son mode raccordement réseau avant de le lancer. On souhaite ici ouvrir notre container sur le réseau local et la configuration par défaut le confine au sous-réseau dédié LXC. Il faut donc modifier cette configuration en choisissant le bridge br0 au lieu de lxcbr0 en inversant les lignes commentées dans le fichier de configuration du CT:
    # nano /mnt/env-lxc/lxc/lxc-gitlab/config
    ...
    # Network configuration
    lxc.net.0.type = veth
    #lxc.net.0.link = lxcbr0          # <== commenter
    lxc.net.0.link = br0              # <== dé-commenter
    lxc.net.0.flags = up
    lxc.net.0.hwaddr = 00:16:3e:6c:30:9b
    ...
  • On va le lancer, patienter un peu, et vérifier son status/adresse:
    # lxc-start -n lxc-gitlab -d
    # lxc-ls -f
    NAME       STATE   AUTOSTART GROUPS IPV4         IPV6 UNPRIVILEGED 
    lxc-gitlab RUNNING 0         -      192.168.1.13 -    false        

    Notez son adresse IP: elle correspond bien à une adresse du LAN (enfin selon votre réseau local) allouée par votre routeur.
    Vous pouvez donc également consulter l'interface de celui-ci, par exemple sur l'interface web d'un routeur Tomato où on retrouve bien «nos petits»: adresses MAC, IP, nom réseau de la machine:

  • Ce container embarque nativement un serveur ssh. On peut donc se connecter directement en ssh depuis un poste client sur le réseau:
    cram28@paprika:~$ ssh ubuntu@lxc-gitlab
    The authenticity of host 'lxc-gitlab (192.168.1.13)' can't be established.
    ECDSA key fingerprint is SHA256:GJfod5FsTPcwSVNqmTMBfYX1Le6tlHUOtxri1E4Vcoc.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added 'lxc-gitlab,192.168.1.13' (ECDSA) to the list of known hosts.
    ubuntu@lxc-gitlab's password: 
    Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.19.0-6-amd64 x86_64)
     
     * Documentation:  https://help.ubuntu.com
     * Management:     https://landscape.canonical.com
     * Support:        https://ubuntu.com/advantage
     
    The programs included with the Ubuntu system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.
     
    Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
    applicable law.
     
    To run a command as administrator (user "root"), use "sudo <command>".
    See "man sudo_root" for details.
     
    ubuntu@lxc-gitlab:~$  lsb_release -a
    No LSB modules are available.
    Distributor ID:	Ubuntu
    Description:	Ubuntu 16.04.6 LTS
    Release:	16.04
    Codename:	xenial
    ubuntu@lxc-gitlab:~$ 
  • Là encore, ça fonctionne ! Reste à faire le ménage
    • Arrêter le CT:
      # lxc-stop -n lxc-gitlab
    • Le détruire:
      # lxc-destroy -n lxc-gitlab
    • Vérifier ce qui reste:
      # tree -L 3 /mnt/env-lxc/
      /mnt/env-lxc/
      ├── cache
      │   ├── debian
      │   │   └── rootfs-stable-amd64
      │   └── xenial
      │       └── rootfs-amd64
      ├── lost+found
      └── lxc
       
      7 directories, 0 files

      Le cache est maintenu, le reste a bien disparu.

    • Vérifier les volumes logiques LVM: a pu…
      # lsblk -o name,model,type,size,fstype,state,mountpoint /dev/sda
      NAME                 MODEL          TYPE   SIZE FSTYPE      STATE   MOUNTPOINT
      sda                  Maxtor_6V250F0 disk 233,8G             running 
      └─sda1                              part 233,8G LVM2_member         
        └─VGVirtu-env--lxc                lvm     10G ext4        running /mnt/env-lxc

8-) Ça fonctionne…

Mais :!: ATTENTION :!:: c'est pour «la beauté du geste» car ouvrir sur le net un container privilégié, construit et lancé avec des droits root, n'est certainement pas une bonne idée (en tous les cas, pas tout nu comme cela…) !

5.2. CT «non privilégiés»

Les CT «privilégiés» sont manipulés depuis le compte root, depuis un autre compte via sudo éventuellement; les CT «non privilégiés» sont associés à un compte banalisé, comme on l'a vu dans leurs éléments de configuration (mapping {g,u}id notamment).

Donc on se connecte sur le serveur avec le compte admin qu'on a déjà défini, à partir duquel on travaille:

admin@wasabi:~$ 

On ne peut pas, depuis ce compte, créer directement un container «non privilégié» en mode LVM: Il faut des droits root pour créer le Volume Logique associé au CT, droits que notre utilisateur banalisé n'a pas.

Cette option – CT «non privilégié» + LVM – n'est certes pas impossible, mais il faut prévoir des choses avant en root et ce n'est pas le lieu ici… On va donc se contenter de vérifier les raccordements réseau isolé/exposé, en mode DIR, c'est à dire avec l'arborescence du CT dans le dossier de l'utilisateur.

Au passage, on va utilisé le modèle download qui permet d'aller chercher une image sur un serveur internet de la distribution qu'on veut mettre dans notre container (images a priori plus «fraîches»).
Et du coup, on va en profiter pour fignoler notre configuration. En effet, le template download télécharge l'image choisie dans un répertoire temporaire /tmp… sur la clé donc… Faut changer cela !

5.2.1. Complément config.

Le modèle de CT lxc-download utilise le dossier /tmp pour stocker temporairement des données de construction. Pour éviter cela:

  • On créé un répertoire cible tmp dans l'environnement de virtualisation LXC:
    $ sudo mkdir -p /mnt/env-lxc/tmp 
    $ sudo chmod 777 /mnt/env-lxc/tmp 
  • On fixe ce chemin dans le code du template concerné:
    $ sudo sed -i "s|^DOWNLOAD_TEMP=|DOWNLOAD_TEMP=\"/mnt/env-lxc/tmp\"|g" /usr/share/lxc/templates/lxc-download

Dorénavant, les données temporaires, lors de la construction des containers utilisant ce modèle, n'iront plus sur la clé système.

5.2.2. Isolé / DIR

Allez:

  • On crée un CT … CentOS, release 8, architecture amd64:
    $ lxc-create -t download -n lxc-web01 -- -d centos -r 8 -a amd64
    Downloading the image index
    Downloading the rootfs
    Downloading the metadata
    The image cache is now ready
    Unpacking the rootfs
     
    ---
    You just created a Centos 8 x86_64 (20191030_20:33) container.
  • On regarde les arborescences:
    • Pas de cache Centos dans l'environnement «privilégié»:
      $ sudo tree -L 3 /mnt/env-lxc/
      /mnt/env-lxc/
      ├── cache
      │   ├── debian
      │   │   └── rootfs-stable-amd64
      │   └── xenial
      │       └── rootfs-amd64
      ├── lost+found
      ├── lxc
      └── tmp
       
      8 directories, 0 files
    • En revanche, des chose dans le $HOME de notre utilisateur:
      $ tree -a -L 5
      .
      ├── .cache
      │   └── lxc
      │       └── download
      │           └── centos
      │               └── 8
      ├── .config
      │   └── lxc
      │       ├── default.conf
      │       └── lxc.conf
      ├── .local
      │   └── share
      │       ├── lxc
      │       │   └── lxc-web01
      │       │       ├── config
      │       │       └── rootfs
      ..
      ..
  • On lance le CT et on regarde l'adresse que dnsmasq lui attribue ( 10.0.3.51 ici pour un CT nommé lxc-web01 ):
    $ lxc-start -n lxc-web01 -d
    $ lxc-ls -f

5.2.3. Exposé / DIR

On va pas se refaire un CT… On va juste changer la façon dont lxc-web01 se connecte au réseau: passer de «réseau de containers» à «réseau local». Pour ce faire:

  • On stoppe le CT:
    $ lxc-stop -n lxc-web01
  • On modifie sa config en commentant lxcbr0 (bridge lxc) et activant br0 (bridge LAN):
    $ nano .local/share/lxc/lxc-web01/config
    ...
    # Network configuration
    lxc.net.0.type = veth
    #lxc.net.0.link = lxcbr0   # <== commenter
    lxc.net.0.link = br0       # <== activer
    ...
  • On relance et on regarde (en patientant un peu) l'adresse IP obtenue:
    $ lxc-start -n lxc-web01 -d
    $ lxc-info -n lxc-web01 -i
    IP:             192.168.1.41

Bon, la config est pas mal… 8-).


Au cours de la mise en œuvre des services dans le cadre de , on aura l'occasion d'utiliser des éléments de configuration, en particulier dans la configuration de tel ou tel container.

Il est important de noter que les modèles et les distributions choisis sont parfois «un peu vides» et qu'on obtient pas directement ce que l'on veut. Par exemple Fedora en release 31 ne contient pas de client DHCP, le container ne sait donc pas obtenir dynamiquement d'adresse réseau…

services/virtu/tuto/lxc_tuto1.txt · Dernière modification: 02/02/2020 23:46 de Cram28