5. Rôle serveur de conteneurs

5.1. Configuration de l'interface du serveur

Une fois la machine virtuelle serveur de conteneurs lancée, les premières étapes consistent à lui attribuer un nouveau nom et à configurer les interfaces réseau pour joindre le routeur voisin et l'Internet.

Q16.

Comment changer le nom de la machine virtuelle ?

Il faut créer le fichier /etc/hostname avec le nom d'hôte voulu.

echo hosting | sudo tee /etc/hostname
sudo reboot

Q17.

Comment appliquer les configurations réseau IPv4 et IPv6 à partir de l'unique interface de la machine d'hébergement ?

Consulter la documentation de Netplan pour obtenir les informations sur la configuration des interfaces réseau à l'adresse Netplan documentation.

Il existe plusieurs possibilités pour configurer une interface réseau. Dans le contexte de ces manipulations, on utilise Netplan dans le but de séparer la partie déclarative du moteur de configuration.

C'est systemd-networkd qui joue le rôle de moteur de configuration sur les machines virtuelles utilisées avec ces manipulations.

La configuration de base fournie avec l'image maître suppose que l'interface obtienne un bail DHCP pour la partie IPv4 et une configuration automatique via SLAAC pour la partie IPv6. Cette configuration par défaut doit être éditée et remplacée.

  • L'interface réseau appartient un seul et unique domaine de diffusion : le VLAN 440 dans le contexte de cette maquette.

  • On fait le choix d'attribuer des adresses statiques à l'interface enp0s1 pour être en mesure de tester le routage et la traduction d'adresses sources au niveau du routeur. Ainsi, on ne dépend pas du service dnsmasq pour les tests de communication.

Voici une copie du fichier /etc/netplan/enp0s1.yaml de la maquette.

cat << EOF | sudo tee /etc/netplan/enp0s1.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s1:
      dhcp4: false
      dhcp6: false
      accept-ra: true
      addresses:
        - 192.0.2.2/24
        - fda0:7a62:1b8::2/64
      routes:
        - to: default
          via: 192.0.2.1
        - to: "::/0"
          via: fe80::baad:caff:fefe:5
          on-link: true
      nameservers:
        addresses:
          - 172.16.0.2
          - 2001:678:3fc:3::2
EOF

Bien sûr, il ne faut pas oublier d'appliquer les paramètre de configuration de l'interface.

sudo netplan apply

Q18.

Comment valider la configuration réseau du serveur de conteneurs ?

Lancer une série de tests ICMP IPv4 et IPv6.

On reprend les tests usuels avec les commandes ping et host.

etu@server:~$ ping -q -c2 9.9.9.9
PING 9.9.9.9 (9.9.9.9) 56(84) bytes of data.

--- 9.9.9.9 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 19.433/19.586/19.740/0.153 ms
etu@server:~$ ping -q -c2 2620:fe::fe
PING 2620:fe::fe(2620:fe::fe) 56 data bytes

--- 2620:fe::fe ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 42.983/43.114/43.246/0.131 ms
etu@server:~$ host kernel.org
kernel.org has address 139.178.84.217
kernel.org has IPv6 address 2604:1380:4641:c500::1
kernel.org mail is handled by 10 smtp1.kernel.org.
kernel.org mail is handled by 10 smtp3.kernel.org.
kernel.org mail is handled by 10 smtp2.kernel.org.

5.2. Installation du gestionnaire de conteneurs Incus

Sur l'hôte qui tient le rôle de serveur d'hébergement, la gestion des conteneurs est confiée à Incus.

Selon l'exergue du site, Incus est un gestionnaire de conteneurs et de machines virtuelles puissant, sûr et moderne.

Dans le contexte de ces manipulations, c'est la variété des modes d'interconnexion réseau offerte par Incus qui est le point le plus déterminant. Ici on utilise le mode macvlan qui raccorde les conteneurs au même domaine de diffusion que la machine hôte. C'est le mode de raccordement le plus simple. Cependant, il n'autorise pas les communications entre les conteneurs du fait de l'isolation des espaces de noms.

Q19.

Comment installer le gestionnaire de conteneurs Incus ?

Lancer une recherche dans la liste des paquets Debian.

Le paquet s'appelle tout simplement incus.

apt search ^incus
sudo apt -y install incus

Q20.

Comment faire pour que l'utilisateur normal etu devienne administrateur et gestionnaire des conteneurs ?

Rechercher le nom du groupe système correspondant à l'utilisation des outils Incus.

Il faut que l'utilisateur normal appartienne au groupes systèmes incus et incus-admin pour qu'il ait tous les droits sur la gestion des conteneurs.

grep incus /etc/group
incus:x:990:
incus-admin:x:989:
sudo adduser etu incus
sudo adduser etu incus-admin
[Avertissement] Avertissement

Attention ! Il faut se déconnecter/reconnecter pour bénéficier de la nouvelle attribution de groupe. On peut utiliser les commandes groups ou id pour vérifier le résultat.

groups
etu adm sudo users incus-admin incus

5.3. Configuration du gestionnaire de conteneurs Incus

Q21.

Quelle est l'instruction de configuration initiale du gestionnaire Incus ?

Utiliser l'aide de la commande incus.

C'est l'instruction incus admin init qui nous intéresse.

Voici une copie d'écran de son exécution.

incus admin init
Would you like to use clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Would you like to create a new local network bridge? (yes/no) [default=yes]: no
Would you like to use an existing bridge or host interface? (yes/no) [default=no]: yes
Name of the existing bridge or host interface: enp0s1
Would you like the server to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]:
Would you like a YAML "init" preseed to be printed? (yes/no) [default=no]:

Q22.

Quelle est l'instruction qui permet d'afficher le profil par défaut des conteneurs ?

Rechercher dans les options de la commande incus profile.

Voici un exemple d'exécution.

incus profile show default
config: {}
description: Default Incus profile
devices:
  eth0:
    name: eth0
    nictype: macvlan
    parent: enp0s1
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default
used_by: []
project: default

L'affichage de ce profil par défaut permet de vérifier que tous les paramètres voulus sont correctement positionnés.

Q23.

Quelle est l'instruction de création et de lancement de nouveaux conteneurs ?

Rechercher dans les options de la commande incus.

Tester son exécution avec un conteneur de type debian/trixie.

Voici un exemple d'exécution pour 3 nouveaux conteneurs.

for i in {0..2}; do incus launch images:debian/trixie c$i; done
Launching c0
Launching c1
Launching c2
incus ls
+------+---------+--------------------+-------------------------------------------+-----------+-----------+
| NAME |  STATE  |        IPV4        |                   IPV6                    |   TYPE    | SNAPSHOTS |
+------+---------+--------------------+-------------------------------------------+-----------+-----------+
| c0   | RUNNING | 192.0.2.52 (eth0)  | fda0:7a62:1b8:0:216:3eff:febd:a233 (eth0) | CONTAINER | 0         |
+------+---------+--------------------+-------------------------------------------+-----------+-----------+
| c1   | RUNNING | 192.0.2.133 (eth0) | fda0:7a62:1b8:0:216:3eff:fe8e:cc62 (eth0) | CONTAINER | 0         |
+------+---------+--------------------+-------------------------------------------+-----------+-----------+
| c2   | RUNNING | 192.0.2.187 (eth0) | fda0:7a62:1b8:0:216:3eff:fe7d:6898 (eth0) | CONTAINER | 0         |
+------+---------+--------------------+-------------------------------------------+-----------+-----------+

La copie d'écran ci-dessus montre que l'adressage automatique des conteneurs depuis le routeur a fonctionné.

Q24.

Comment tester les communications réseau depuis chaque conteneur ?

Rechercher dans les options de la commande incus celle qui permet de lancer un traitement dans le conteneur.

C'est la commande incus exec qui correspond à notre besoin. Voici une exemple de boucle qui permet de lancer les tests ICMP IPv4 et IPv6 dans les 3 conteneurs actifs.

for i in {0..2}
do
    echo ">>>>>>>>>>>>>>>>> c$i"
    incus exec c$i -- ping -qc2 9.9.9.9
    incus exec c$i -- ping -qc2 2620:fe::fe
done
PING 9.9.9.9 (9.9.9.9) 56(84) bytes of data.

--- 9.9.9.9 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 27.887/28.676/29.465/0.789 ms
PING 2620:fe::fe (2620:fe::fe) 56 data bytes

--- 2620:fe::fe ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 41.727/48.212/54.697/6.485 ms
>>>>>>>>>>>>>>>>> c1
PING 9.9.9.9 (9.9.9.9) 56(84) bytes of data.

--- 9.9.9.9 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 28.179/34.740/41.302/6.561 ms
PING 2620:fe::fe (2620:fe::fe) 56 data bytes

--- 2620:fe::fe ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 40.002/40.529/41.057/0.527 ms
>>>>>>>>>>>>>>>>> c2
PING 9.9.9.9 (9.9.9.9) 56(84) bytes of data.

--- 9.9.9.9 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 28.539/35.408/42.278/6.869 ms
PING 2620:fe::fe (2620:fe::fe) 56 data bytes

--- 2620:fe::fe ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 40.428/47.517/54.606/7.089 ms

Q25.

Comment exécuter des jeux d'instructions dans les conteneurs depuis le serveur d'hébergement ?

On entre ici dans le domaine de l'automatisation à l'aide de scripts Bash. Même si l'ambition reste très modeste, on peut développer un script qui utilise la liste des conteneurs actifs pour lancer une suite de traitements dans ces mêmes conteneurs.

Comme les conteneurs Incus appartiennent à la famille des conteneurs système, ils disposent d'une arborescence complète et d'une gestion de paquets. Allons y pour une mise à jour des paquets de chaque conteneur actif.

Voici un exemple de code qui stocke les commandes à lancer dans un tableau et qui les exécute sur chacun des conteneurs actifs.

#!/bin/bash

cmds=(
  "apt -y update"
  "apt -y full-upgrade"
  "apt -y clean"
  "apt -y autopurge"
)

clist=$(incus list status=running -c n -f compact | grep -v NAME | tr '\n' ' ' | tr -s ' ')

for c in $clist; do
  echo ">>>>>>>>>>>>>>>>> $c"
  for cmd in "${cmds[@]}"; do
    eval "incus exec $c -- $cmd"
  done
done

exit 0

Si ce script est enregistré dans le fichier run-commands-in-containers.sh, on peut lancer les traitements comme dans l'exemple ci-dessous.

bash run-commands-in-containers.sh
>>>>>>>>>>>>>>>>> c0
Hit:1 http://deb.debian.org/debian trixie InRelease
Hit:2 http://deb.debian.org/debian trixie-updates InRelease
Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
All packages are up to date.
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0
>>>>>>>>>>>>>>>>> c1
Hit:1 http://deb.debian.org/debian trixie InRelease
Hit:2 http://deb.debian.org/debian trixie-updates InRelease
Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
All packages are up to date.
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0
>>>>>>>>>>>>>>>>> c2
Hit:1 http://deb.debian.org/debian trixie InRelease
Hit:2 http://deb.debian.org/debian trixie-updates InRelease
Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
All packages are up to date.
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 0

Pour compléter, voici une seconde version du script qui utilise les arguments de la ligne de commande pour remplir le tableau des commandes à exécuter.

#!/bin/bash

cmds=("$@")

clist=$(incus list status=running -c n -f compact | grep -v NAME | tr '\n' ' ' | tr -s ' ')

for c in $clist; do
  echo ">>>>>>>>>>>>>>>>> $c"
  for cmd in "${cmds[@]}"; do
    eval "incus exec $c -- $cmd"
  done
done

Q26.

Comment passer d'un adressage automatique à un adressage statique pour chaque conteneur ?

Comme la gestion de la configuration des interfaces est assurée par systemd-networkd, il faut s'intéresser à la syntaxe du fichier /etc/systemd/network/eth0.network de chaque conteneur.

Cette question est un prétexte pour utiliser le transfert de fichier depuis le serveur d'hébergement vers les conteneurs.

Voici une liste des actions à réaliser sur tous les conteneurs actifs.

  1. Installer le paquet netplan.io

  2. Générer le fichier de déclaration YAML des paramètres de configuration réseau des interfaces eth0

  3. Transférer le fichier de déclaration YAML dans le dossier /etc/netplan/

  4. Effacer le fichier /etc/systemd/network/eth0.network

  5. Appliquer la nouvelle configuration réseau

Pour connaître les paramètres de configuration réseau d'une interface de conteneur, on peut extraire le fichier /etc/systemd/network/eth0.network et consulter son contenu.

incus file pull c0/etc/systemd/network/eth0.network .
cat eth0.network
[Match]
Name=eth0

[Network]
DHCP=true

[DHCPv4]
UseDomains=true

[DHCP]
ClientIdentifier=mac

On vérifie ainsi que la configuration réseau issue de la source de tirage des conteneurs implique un adressage automatique au moins en IPv4. On propose donc de remplacer cet adressage automatique par un adressage statique.

Voici une proposition de script qui traite chacun des points définis dans la question.

#!/bin/bash

# Préparation -> générer la liste des conteneurs actifs
clist=$(incus list status=running -c n -f compact | grep -v NAME | tr '\n' ' ' | tr -s ' ')

# Étape 1 -> installer le paquet netplan.io
. run-commands-in-containers.sh "apt -y install netplan.io"

addr_idx=0
for c in $clist; do
  echo ">>>>>>>>>>>>>>>>> $c"

# Étape 2 -> générer le fichier de configuration réseau YAML
$(cat << EOF > eth0.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: false
      dhcp6: false
      accept-ra: true
      addresses:
        - 192.0.2.$((addr_idx + 10))/24
        - fda0:7a62:1b8::$(printf "%x" $((addr_idx + 10)))/64
      routes:
        - to: default
          via: 192.0.2.1
        - to: "::/0"
          via: fe80::baad:caff:fefe:5
          on-link: true
      nameservers:
        addresses:
          - 172.16.0.2
          - 2001:678:3fc:3::2
EOF
)

# Étape 3 -> transférer le fichier de déclaration YAML
  incus file push eth0.yaml $c/etc/netplan/eth0.yaml

# Étape 4 -> effacer le fichier /etc/systemd/network/eth0.network
  incus exec $c -- rm /etc/systemd/network/eth0.network

# Étape 5 -> appliquer la nouvelle configuration
  incus exec $c -- netplan apply

  ((addr_idx++))
done

exit 0

Si le code du script ci-dessus est placé dans un fichier appelé set-static-addressing.sh, on peut l'exécuter directement et relever les résultats.

bash set-static-addressing.sh
incus restart --all
incus ls
+------+---------+-------------------+-------------------------------------------+-----------+-----------+
| NAME |  STATE  |       IPV4        |                   IPV6                    |   TYPE    | SNAPSHOTS |
+------+---------+-------------------+-------------------------------------------+-----------+-----------+
| c0   | RUNNING | 192.0.2.10 (eth0) | fda0:7a62:1b8::a (eth0)                   | CONTAINER | 0         |
|      |         |                   | fda0:7a62:1b8:0:216:3eff:febd:a233 (eth0) |           |           |
+------+---------+-------------------+-------------------------------------------+-----------+-----------+
| c1   | RUNNING | 192.0.2.11 (eth0) | fda0:7a62:1b8::b (eth0)                   | CONTAINER | 0         |
|      |         |                   | fda0:7a62:1b8:0:216:3eff:fe8e:cc62 (eth0) |           |           |
+------+---------+-------------------+-------------------------------------------+-----------+-----------+
| c2   | RUNNING | 192.0.2.12 (eth0) | fda0:7a62:1b8::c (eth0)                   | CONTAINER | 0         |
|      |         |                   | fda0:7a62:1b8:0:216:3eff:fe7d:6898 (eth0) |           |           |
+------+---------+-------------------+-------------------------------------------+-----------+-----------+