📘 Montage de répertoires/fichiers dans un conteneur

1. Problématique

Comme expliqué dans le chapitre précédent, un conteneur est un environnement simplifié possédant notamment un système de fichiers. Par défaut, ce système de fichiers contient les données présentes dans l’image de conteneur utilisée comme base pour créer un conteneur (ce qui inclut généralement tous les fichiers du système d’exploitation utilisé comme base dans l’image).

Mais un logiciel déployé dans un conteneur va également :

  • utiliser des données de différentes formes : fichiers de configurations, données d’entrée pour un calcul ou un traitement, données à (re)distribuer, clés de chiffrement, etc.

  • produire des données de différentes formes : données persistées/stockées, résultats de calculs, etc.

Exemple 1. Données requises et produites par Simplestblog

Comme vu dans les chapitres précédents, un début de déploiement du logiciel Simplestblog à l’aide de deux conteneurs donnerait la situation suivante :

simplestblog with.drawio

On peut voir ici que :

  • Dans le conteneur pour Simplestblog, le processus a besoin de lire un fichier de configuration qui lui a été préparé.

  • Dans le conteneur pour la base de données, MariaDB, le processus a besoin de lire et écrire les fichiers où il stocke les tables de la base de données.

Exemple 2. Données requises et produites par Automatic-Image-Converter

Comme vu dans les chapitres précédents, un début de déploiement du logiciel Automatic-Image-Converter à l’aide d’un conteneur donnerait la situation suivante :

automatic image converter with.drawio

On peut voir ici que dans le conteneur prévu le processus Automatic-Image-Converter a besoin :

  • De lire le contenu du répertoire d’entrée dans lequel on lui dépose des photos à convertir,

  • D'écrire dans le répertoire de sortie les images produites suite aux opérations de conversion.

Pour fournir ou récupérer les données requises ou produites par un logiciel conteneurisé, une possibilité est d’utiliser la copie de fichiers vers (ou depuis) un conteneur, comme vu avec la commande podman container cp. Cependant, deux problèmes apparaissent avec cette manière de faire :

  • Cela nécessite un grand nombre d’actions manuelles tout au long de la vie d’un logiciel conteneurisé, pour lui fournir des fichiers lorsqu’il en a besoin, ou pour récupérer sans cesse des données qu’il aurait produites.

  • Les données d’un conteneur disparaissent dès la supression de ce dernier. Or, nous verrons qu’il est très courant − et même parfois souhaitable − de devoir supprimer un conteneur, par exemple effectuer une mise à jour logicielle à l’aide d’un conteneur "tout neuf". Et si les données de travail d’un conteneur n’ont pas été "rapatriées" avant la supression du conteneur, elles sont perdues !

Dans ce chapitre, pour résoudre ces deux problèmes, nous allons voir un nouveau méchanisme permettant de gérer les données d’un conteneur : le montage de répertoires/fichiers.

2. Caractère éphémère des données d’un conteneur

Avant d’étudier le principe du montage, creusons un peu une situation posée un peu plus haut : pourquoi arrive-t-il que l’on doive supprimer un conteneur ?

  • Mise à jour du système d’exploitation. Un conteneur est créé à partir d’une image de conteneur dans laquelle se trouve généralement un système d’exploitation (par exemple "Ubuntu 22.04"). Il peut arriver pour des raisons de sécurité ou pour des raisons techniques de nécessiter une version plus récente d’un système d’exploitation (par exemple "Ubuntu 224.04"), voire un système d’exploitation différent (par exemple "Fedora Server 42"). Dans ce cas, la seule solution est de créer un nouveau conteneur à partir d’une image qui contient le système d’exploitation souhaiter, puis de jeter l’ancien conteneur.

  • Mise à jour du logiciel déployé. Il est possible que le logiciel que l’on déploie soit déjà distribué à l’aide d’une image de conteneur pré-construite, et qu’on utilise cette image pour le déploiement. Dans ce cas, il est courant qu’une nouvelle image de conteneur soit distribuée pour chaque nouvelle version du logiciel. Ainsi, si on souhaite mettre à jour le logiciel, il faudra nécessaire créer un tout nouveau conteneur à partir de la nouvelle image de conteneur qui contient la nouvelle version du logiciel déployé, puis jeter l’ancien conteneur.

  • Remise à zéro. Parfois en s’exécutant un logiciel crée un certain nombre de fichiers temporaires, comme des fichiers de cache, qui peuvent s’accumuler dans le conteneur. On trouve également des situations où un logiciel se trompe et abime par erreur des parties importantes de son conteneur (suppression de fichiers importants, création d’un état corrompu, etc.). Des situations de ce type peuvent justifier de faire une complète "remise à zéro" en supprimant un conteneur et en le recréant à l’identique.

Pour être préparé à faire face à ce type de situations, il est d’usage de considérer un conteneur comme une entité éphémère et "jetable", qu’on est susceptible de supprimer et recréer à tout moment. Cette pratique courante est rendue possible par la combinaison de deux choses :

  • d’une part, la possibilité de créer une image de conteneur réutilisable, qui permet de recréer un nouveau conteneur avec presque aucun effort à partir d’une base figée − ce principe sera étudié en fin de semestre.

  • d’autre part, la possibilité de persister les données d’un conteneur à l’aide du montage de répertoires/fichiers, qui permet de ne pas perdre les données de travail d’un conteneur lors de sa suppression − ce principe est présenté dans la suite de ce chapitre.

3. Principe du montage de répertoire/fichier

Pour fournir des fichiers à un logiciel dans un conteneur, ou pour récupérer des fichiers produits par un logiciel dans un conteneur, il est possible de partager des fichiers entre l’environnement d’accueil et le conteneur par un montage de répertoire/fichier (en anglais bind mount).

3.1. Montage de répertoire

Voyons le principe d’un montage de répertoire :

  • Soit un répertoire host_data dans l’environnement d’accueil.

  • Lors de la création d’un conteneur, on prépare un répertoire vide container_data au sein du conteneur, et on active un montage du répertoire host_data (de l’environnement d’accueil) au sein du répertoire container_data (du conteneur).

  • Dès lors, ces deux répertoires sont liés et contiendront toujours exactement les même fichiers : tout fichier présent dans container_data (donc accessible depuis le conteneur) sera également présent dans host_data (donc accessible depuis l’environnement d’accueil), et inversement. Il en va de même pour toute suppression ou modification de fichier. En fait, host_data et container_data sont désormais le même répertoire (même avec des noms différents), accessible depuis deux environnements différents, à savoir l’environnement d’accueil et le conteneur.

Le montage de répertoire devient alors un puissant outil pour trois types de situations :

  • Confier des données à un conteneur: si depuis l’environnement d’accueil on dépose un fichier dans host_data (par exemple un fichier de configuration), alors ce fichier sera accessible et utilisable par un logiciel exécuté dans le conteneur.

  • Récupérer des données produites par un conteneur: si un logiciel dans le conteneur dépose un fichier dans container_data (par exemple le résultat d’un calcul), alors ce fichier sera directement accessible depuis l’environnement d’accueil.

  • Persister les données d’un conteneur: si le conteneur se retrouve supprimé (ce qui inclut le répertoire container_data), le répertoire host_data est lui préservé ainsi que tout son contenu.

montages.drawio
Figure 1. Montage de répertoires de l’environnement d’accueil dans plusieurs conteneurs

L’illustration ci-dessus présente trois conteneurs dans le même environnement d’accueil. On s’intéresse à trois répertoires de l’environnement d’accueil, à savoir /data/x, /data/y et /data/z. On souhaite que les conteneurs A et B puissent accéder à /data/x, que le conteneur B puisse accéder à /data/y, et que le conteneur C puisse accéder à /data/z. On choisit donc, lors de la création de ces conteneurs, de réaliser les montages (représentés par les traits pointillés avec des extrémités en losanges) : /data/x est monté à la fois au sein du répertoire /foo au sein du conteneur A, et au sein du répertoire /bar du conteneur B. On fait de même avec les autres répertoires et conteneurs : /data/y est monté dans /do dans le conteneur B, et /data/z est monté dans /wal dans le conteneur C.

Une fois ces montages en place, les situations suivantes deviennent possibles :

  • Si un fichier est déposé dans le répertoire /data/y de l’environnement d’accueil, alors ce fichier sera accessible depuis le répertoire /do du conteneur B.

  • Si un fichier est déposé dans le répertoire /do du conteneur B, alors ce fichier sera accessible depuis le répertoire /data/y de l’environnement d’accueil.

  • Si un fichier est déposé dans le répertoire /data/z de l’environnement d’accueil, alors ce fichier sera accessible depuis le répertoire /wal du conteneur B.

  • Si un fichier est déposé dans le répertoire /wal du conteneur C, alors ce fichier sera accessible depuis le répertoire /data/z de l’environnement d’accueil.

  • Si un fichier est déposé dans le répertoire /data/x de l’environnement d’accueil, alors ce fichier sera accessible :

    • depuis le répertoire /foo du conteneur A,

    • depuis le répertoire /bar du conteneur B.

  • Si un fichier est déposé dans le répertoire /foo du conteneur A, alors ce fichier sera accessible :

    • depuis le répertoire /data/x de l’environnement d’accueil,

    • depuis le répertoire /bar du conteneur B. -Si un fichier est déposé dans le répertoire /bar du conteneur B, alors ce fichier sera accessible :

    • depuis le répertoire /data/x de l’environnement d’accueil,

    • depuis le répertoire /foo du conteneur A.

Comme vu dans cette illustration, il est possible pour un même répertoire ou fichier de l’environnement d’accueil d’être simultanément monté dans plusieurs conteneurs. Cela peut par exemple servir à un conteneur de produire des fichiers qui sont ensuite récupérés par un second conteneur.
Exemple 3. Montage de répertoires pour Automatic-Image-Converter

Automatic-Image-Converter opère sur un répertoire d’entrée contenant les fichiers d’images à traiter, et un répertoire de sortie où enregistrer les images une fois converties. Ces deux répertoires doivent être accessibles depuis l’extérieur si on souhaite pouvoir confier de nouvelles images à l’application, et récupérer les résultats produits.

On choisit donc de préparer un conteneur pour lequel on effectue deux montages de répertoire :

  • Le répertoire /data/input_images de l’environnement d’accueil est monté dans le répertoire /inputs du conteneur,

  • Le répertoire /data/output_images de l’environnement d’accueil est monté dans le répertoire /outputs du conteneur.

On configure ensuite Automatic-Image-Converter pour utiliser /inputs comme répertoire d’entrée, et /outputs comme répertoire de sortie.

On obtient la situation suivante :

automatic image converter mount.drawio

Ainsi, de manière transparente, tout utilisateur ou logiciel qui dépose des fichiers dans le répertoire /data/input_images de l’environnement d’accueil pourra ensuite récupérer les images converties dans /data/output_images. Sans plus avoir besoin d’utiliser podman container cp, Automatic-Image-Converter n’est plus totalement isolé.

3.2. Montage de fichier

Voyons ensuite le principe d’un montage de fichier, très similaire au montage de répertoire  :

  • Soit un fichier host_file dans l’environnement d’accueil.

  • Lors de la création d’un conteneur, on active un montage du fichier host_file (de l’environnement d’accueil) sous la forme d’un fichier container_file (du conteneur).

  • Dès lors, ces deux fichiers sont liés et contiendront toujours exactement les même données. En fait, host_file et container_file sont désormais le même fichier, mais accessible depuis deux environnements différents, à savoir l’environnement d’accueil et le conteneur.

Le montage de fichier est très utile pour les mêmes trois types de situations que le montage de répertoire :

  • Confier des données à un conteneur: si depuis l’environnement d’accueil on prépare des données dans un fichier host_file (par exemple un fichier de configuration), alors ce fichier sera accessible et utilisable par un logiciel exécuté dans le conteneur.

  • Récupérer des données produites par un conteneur: si un logiciel dans le conteneur écrit des données dans le fichier container_file (par exemple le résultat d’un calcul), alors ce ces données seront accessibles depuis l’environnement d’accueil via le fichier host_file.

  • Persister les données d’un conteneur: si le conteneur se retrouve supprimé (ce qui inclut le fichier container_file), le fichier host_file est lui préservé ainsi que tout son contenu.

Exemple 4. Montage de fichier et répertoire pour Simplestblog

Simplestblog requiert un fichier de configuration pour fonctionner. On souhaite préparer ce fichier depuis l’environnement d’accueil, pouvoir facilement mettre à jour ce fichier dans le futur, et s’assurer que ce fichier soit préservé en sécurité.

On choisit donc de créer le conteneur de Simplestblog avec un montage de fichier :

  • Le fichier /data/simplestblog/test_config.py de l’environnement d’accueil est monté comme fichier /config.py dans le conteneur.

On configure ensuite Simplestblog pour utiliser /config.py comme fichier de configuration.

Ensuite, le système de base de données que nécessite Simplestblog, à savoir MariaDB, a besoin d’écrire et de lire le contenu de la base de données au sein d’un répertoire à l’emplacement /var/lib/mysql. On souhaite s’assurer que le contenu de la base de données soit préservé en sécurité.

On choisit donc de créer le conteneur de MariaDB avec un montage de répertoire :

  • Le répertoire /data/simplestblog/database_data de l’environnement d’accueil est monté comme répertoire /var/lib/mysql dans le conteneur.

On obtient la situation suivante :

simplestblog mount.drawio

Ainsi, de manière transparente :

  • Le fichier de configuration peut facilement être modifié directement depuis l’environnement d’accueil,

  • Le fichier de configuration sera préservé en cas de suppression de conteneur,

  • Les données de MariaDB seront préservées en cas de suppression de conteneur.

Le tout sans plus avoir besoin d’utiliser podman container cp.

4. Mise en œuvre d’un montage de répertoire/fichier avec Podman

Le montage d’un répertoire/fichier se fait lors de la création d’un conteneur (par exemple lors d’un appel à podman container run) à l’aide de l’option suivante :

--mount type=bind,source="<répertoire/fichier accueil>",target="<répertoire/fichier conteneur>"
Il ne faut surtout pas ici mettre d’espace avant ou après les caractères égal = et virgule , !

avec :

  • <répertoire/fichier accueil> : un chemin vers un répertoire/fichier au sein de l’environnement d’accueil,

  • <répertoire/fichier conteneur> : un chemin valide au sein du conteneur, au sein duquel sera monté le répertoire/fichier spécifié.

Même s’il existe plusieurs types de montages dans Podman, on ne verra dans ce cours que le montage de répertoire/fichier, qui se déclare toujours avec type=bind.
Exemple 5. Montages de répertoires avec Podman pour Automatic-Image-Converter

On souhaite créer un conteneur pour déployer Automatic-Image-Converter. Il nous faut pour cela faire en sorte que deux répertoires de l’environnement d’accueil soient montés au sein du conteneur : le répertoire d’entrée où sont déposées les images, et le répertoire de sortie où les conversions sont générées.

On suppose que le logiciel a déjà été préparé sous forme d’image de conteneur, et que l’image est disponible dans le registre de conteneurs du Gitlab Nantes Université sous le nom developpement_exploitation/resources/automatic-image-converter. Cette image fait certaines hypothèses : le répertoire d’entrée où déposer les images doit se trouver dans le conteneur à l’emplacement /inputs, le répertoire de sortie doit se trouver dans le conteneur à l’emplacement /outputs, le format de conversion est spécifié par la variable d’environnement FORMAT, et la durée entre deux passes de conversion est donnée en millisecondes par la variable d’environnement DURATION.

On souhaite que notre conteneur :

  • soit nommé aic,

  • soit en mode détaché,

  • soit automatiquement supprimé à la fin de son exécution,

  • possède un montage du répertoire de l’environnement d’accueil /data/input_images vers le répertoire /inputs du conteneur,

  • possède un montage du répertoire de l’environnement d’accueil /data/output_images vers le répertoire /outputs du conteneur,

  • spécifie un format de conversion PNG,

  • spécifie une durée entre deux passes qui soit de 5000 ms,

  • utilise la version 16 de l’image de conteneur.

On exécute donc la commande suivante :

$ podman container run --name aic \
                       --detach \
                       --rm \
                       --mount type=bind,source="/data/input_images",target="/inputs" \
                       --mount type=bind,source="/data/output_images",target="/outputs" \
                       --env FORMAT="png" \
                       --env DURATION="5000" \
                       docker-registry.univ-nantes.fr/gl/developpement_exploitation/resources/automatic-image-converter:16

Ainsi, toute image qu’on dépose dans l’environnement d’accueil à l’emplacement /data/input_images sera vue au sein du conteneur dans l’emplacement /inputs, puis sera traitée par la boucle d’exécution, et l’image convertie en PNG sera produite dans /outputs dans le conteneur, et apparaîtra donc dans l’emplacement /data/output_images de l’environnement d’accueil.

Exemple 6. Montages de répertoires et de fichiers avec Podman pour Simplestblog

On souhaite déployer Simplestblog à l’aide de conteneurs. Il nous faut pour cela créer deux conteneurs : Simplestblog d’une part, et une base de données compatible MySQL d’autre part.

Pour la base de données, on souhaite utiliser l’image MariaDB disponible sur le registre Docker Hub à l’emplacement mariadb.

On souhaite que notre conteneur MariaDB :

  • soit nommé simplestblog_db,

  • soit en mode détaché,

  • soit automatiquement supprimé à la fin de son exécution,

  • possède un montage du répertoire de l’environnement d’accueil /data/simplestblog/database_data vers le répertoire /var/lib/mysql du conteneur, de manière à persister le contenu de la base de données sur l’environnement d’accueil,

  • configure les variables d’environnement attendues par l’image MariaDB, c’est à dire :

    • MARIADB_ROOT_PASSWORD, le mot de passe administrateur de l’instance MariaDB, avec la valeur "my_very_very_secret_root_password",

    • MARIADB_DATABASE, le nom de la base de donnée pour Simplestblog, avec la valeur simplestblog

    • MARIADB_USER, le nom d’utilisateur du compte base de données, avec la valeur "simplestblog",

    • MARIADB_PASSWORD, le mot de passe pour le compte base de données, avec la valeur "my_very_secret_db_password",

  • utilise la version 11 de l’image de conteneur.

On exécute donc la commande suivante :

$ podman container run --name simplestblog_db \
             --detach \
             --rm \
             --mount type=bind,source="/data/simplestblog/database",target="/var/lib/mysql" \
             --env MARIADB_ROOT_PASSWORD="my_very_very_secret_root_password" \
             --env MARIADB_DATABASE="simplestblog" \
             --env MARIADB_USER="simplestblog" \
             --env MARIADB_PASSWORD="my_very_secret_db_password" \
             docker.io/mariadb:11

Ensuite, pour Simplestblog, on fait usage de l’image disponible dans le registre de conteneurs du Gitlab Nantes Université, accessible à l’emplacement developpement_exploitation/resources/simplestblog. On suppose qu’une image de conteneur a déjà été préparée pour Simplestblog, et que cette image fait l’hypothèse qu’un fichier de configuration doit se trouver à l’emplacement /config.py au sein du conteneur. Ce fichier doit notamment contenir les informations indiquant à Simplestblog comment se connecter à sa base de données.

On prépare le fichier configuration Simplestblog suivant, à l’emplacement /data/simplestblog/test_config.py dans l’environnement d’accueil :

SECRET_KEY = "my_very_secret_key"

DB_TYPE = "mysql"

MYSQL_DATABASE_USER = "simplestblog"
MYSQL_DATABASE_DB = "simplestblog"
MYSQL_DATABASE_PASSWORD = "my_very_secret_db_password"
MYSQL_DATABASE_HOST = "simplestblog_db"
MYSQL_DATABASE_PORT = "3306"

Le contenu de ce fichier de configuration est préparé de manière à être compatible avec le conteneur MariaDB préparé plus haut. Plus précisément on peut constater que :

  • MYSQL_DATABASE_USER correspond à MARIADB_USER dans la configuration du conteneur MariaDB,

  • MYSQL_DATABASE_DB correspond à MARIADB_DATABASE dans la configuration du conteneur MariaDB,

  • MYSQL_DATABASE_PASSWORD correspond à MARIADB_PASSWORD dans la configuration du conteneur MariaDB,

  • MYSQL_DATABASE_HOST correspond au nom du conteneur MariaDB, car le nom du conteneur est également un nom d’hôte permettant d’atteindre le dit conteneur au sein du réseau virtuel où il se trouve (à savoir le réseau simplestblog_network dans notre exemple).

  • MYSQL_DATABASE_PORT correspond au port sur lequel écoute le processus MariaDB (à savoir, par défaut, 3306)

Enfin on souhaite que notre conteneur Simplestblog :

  • soit nommé simplestblog_app,

  • soit en mode détaché,

  • soit automatiquement supprimé à la fin de son exécution,

  • possède un montage du fichier de l’environnement d’accueil /data/simplestblog/test_config.py vers le fichier /config.py du conteneur,

  • utilise la version 52 de l’image de conteneur.

On exécute donc la commande suivante :

$ podman container run --name simplestblog_app \
                       --detach \
                       --rm \
                       --mount type=bind,source="/data/simplestblog/test_config.py",target="/config.py" \
                       docker-registry.univ-nantes.fr/gl/developpement_exploitation/resources/simplestblog:60
Faire le déploiement avec les commandes proposées ici n’est pas suffisant, car il manque toujours la mise en place d’une communication entre les processus des deux conteneurs, ainsi que l’ouverture d’un port réseau permettant de se connecter à l’application web depuis le réseau de l’environnement d’accueil. Toutes ces notions de réseau seront introduites dans la suite du cours.
Et l’option --volume alors ?

Il existe dans Podman (et Docker) une option similaire à --mount appelée --volume, qui permet également de déclarer un montage au sein d’un conteneur. L’option --volume possède une syntaxe légèrement différente à --mount, et permet notamment de déclarer un montage de répertoire.

Par exemple le montage de répertoire suivant :

--mount type=bind,source="/data",target="/var/logs"

peut se déclarer de manière équivalente de la manière suivante avec --volume :

--volume /data:/var/logs

Cependant --volume possède plusieurs inconvénients :

  • Le nom de l’option est directement tiré du concept de volume, qui est une manière différente de persister les données d’un conteneur (non étudiée dans ce cours). Ainsi même si on utilise --volume pour déclarer un montage de répertoire, on crée une confusion sur le type de montage que l’on souhaite (volume ou montage de répertoire ?).

  • Si on se trompe et qu’on déclare un répertoire sans le préfixer d’un slash /, alors cela sera automatiquement interprété comme un montage de volume et non un montage de répertoire. Cette erreur est très vite arrivée !

  • La syntaxe de --volume est moins complète, moins expressive et plus implicite que --mount, notamment pour bien gérer d’autres types de montages.

Malgré ses inconvénients, et même si dans le cours on préférera l’option --mount, l’option --volume est encore très couramment utilisée aujourd’hui.

Lorsque Podman est utilisé dans un environnement d’accueil qui exécute le système de contrôle d’accès obligatoire SELinux, il est nécessaire d’indiquer à SELinux que le conteneur a bien le droit de manipuler un répertoire monté. Pour cela, il existe une option de montage :Z qui indique que SELinux doit être prévenu que le conteneur a bien le droit d’accéder au répertoire. Il existe également l’option :z qui indique que SELinux doit être prévenu que plusieurs conteneurs différents ont bien le droit d’accéder au répertoire.

Rassurez-vous, SELinux n’est pas activé en travaux pratiques, donc il n’est pas nécessaire de retenir cela !

5. Droits d’accès sur les fichiers créés dans un conteneur

Lorsqu’un logiciel exécuté dans un conteneur crée de nouveaux fichiers, il le fait par le biais d’un compte Linux virtuel qui est spécifique au conteneur. À cause de cela, il peut arriver que des fichiers soient créées dans un conteneur avec des droits d’accès étranges, notamment des droits d’accès qui empêchent votre propre compte Linux de lire, modifier ou supprimer ces fichiers depuis l’environnement d’accueil.

Si les fichiers créés par le conteneur n’ont pas vocation à sortir du conteneur, cela ne pose aucun problème. En revanche, si ces fichiers sont rendus disponibles dans l’environnement d’accueil par le biais d’un montage de répertoire, alors on peut se retrouver bien embêté à ne pas pouvoir supprimer, déplacer ou modifier ces fichiers !

Pourquoi cela arrive-t-il ?
Il n’est pas demandé de mémoriser ou de comprendre cet encart, c’est avant tout pour les curieux.

C’est assez difficile à expliquer sans rentrer dans certains détails sur le fonctionnement de Podman… mais essayons !

Dans un système Linux, chaque fichier possède un propriétaire, à savoir un compte Linux. Dans un conteneur Podman, un ensemble de comptes virtuels existent, et sont utilisés pour manipuler les fichiers. En toute logique, si un de ces comptes virtuels crée un fichier, alors ce fichier aura pour propriétaire ce compte virtuel.

Mais que se passe-t-il quand ce fichier créé est visible à la fois depuis le conteneur et depuis l’environnement d’accueil, par le biais d’un montage de répertoire ? Surtout, quel est alors le propriétaire du fichier, étant donné que le "vrai" propriétaire est un compte Linux virtuel qui n’existe que dans le conteneur ?

Pour résoudre cela, Podman effectue une association de chaque compte Linux virtuel du conteneur, à un compte Linux réel de l’environnement d’accueil. Ainsi, si un compte Linux X existe dans le conteneur, il sera associé à un compte Linux A de l’environnement d’accueil. On peut alors avoir le scénario suivant :

  • Un conteneur est créé avec le montage de répertoire suivant : le répertoire /data_hote de l’environnement d’accueil est monté dans le répertoire /data_conteneur du conteneur.

  • Ce conteneur possède un compte Linux virtuel appelé X. Le moteur de conteneurisation associe ce compte virtuel X à un compte réel A de l’environnement d’accueil.

  • Depuis le conteneur, un fichier est créé à l’emplacement /data_conteneur/nouveau_fichier à l’aide du compte virtuel X. Ainsi, du point de vue du conteneur, le fichier /data_conteneur/nouveau_fichier a X pour propriétaire.

  • Depuis l’environnement d’accueil, ce même fichier est visible à l’emplacement /data_hote/nouveau_fichier, non pas avec comme propriétaire X (compte qui n’existe pas dans l’environnement d’accueil), mais avec comme propriétaire A, à savoir le compte réel associé à X.

La conséquence de cette situation est que si le compte A de l’environnement d’accueil est différent du compte utilisateur Linux que l’on utilise, alors on ne possède pas l’autorisation de supprimer ou modifier /data_hote/nouveau_fichier, et on se retrouve bloqué. Il est alors nécessaire de "se faire passer pour A" afin de récupérer le droit d’agir sur ce fichier.

Pour résoudre une situation de ce type, Podman met à disposition la commande suivante qui permet de passer temporairement outre ce problème de droit d’accès :

$ podman unshare

Une fois cette commande effectuée, on possède alors temporairement le droit de modifier n’importe quel fichier créé par un compte virtuel d’un conteneur Podman. Cette commande est indispensable pour faire le ménage dans les montages de répertoires !.

Exemple 7. Supprimer les données créées par un conteneur MariaDB

On souhaite créer un conteneur MariaDB, permettant de stocker une base de données MySQL.

On prépare et on exécute la commande suivante :

$ podman container run --name my_db \
             --detach \
             --rm \
             --mount type=bind,source="/data/my_db",target="/var/lib/mysql" \
             --env MARIADB_ROOT_PASSWORD="my_very_very_secret_root_password" \
             docker.io/mariadb:11

On obtient ainsi une base de données MariaDB dont les données sont stockées dans l’environnement d’accueil à l’emplacement /data/my_db.

Plus tard, on stoppe ce conteneur :

$ podman container stop my_db

Et on souhaite supprimer les fichiers créées par MariaDB à l’emplacement /data/my_db :

$ rm -rf /data/my_db

Mais, patatras, on se retrouve face à une myriade d’erreurs "Permission non accordée" ! En effet, ces fichiers ont été créés dans le conteneur par un compte virtuel, et on ne possède donc pas le droit de les supprimer.

On demande donc les droits de modifier ces fichiers avec :

$ podman unshare

Puis on essaye à nouveau :

# rm -rf /data/my_db

Et cette fois-ci la suppression se fait sans problème.