LINUX:Conteneur

De WIKI sur Linux (ADB)
Aller à la navigation Aller à la recherche

retour au menu de Linux


But

Un conteneur est une unité de logiciel qui fournit un mécanisme d'emballage qui abstrait le code et toutes ses dépendances pour rendre l'application ayant une construction rapidement et fiable. Ce logiciel s'exécute de façon isolée vis-à-vis des autres applications.

Nous aborderons les bases de ce concept. Nous l'utiliserons sur une machine utilisant l'OS Linux de la distribution Fedora. Les conteneurs utilisés dans les exemples mis en place, auront majoritairement une base Linux des distributions Debian ou Ubuntu.


Concept

Un conteneur travaille de façon analogue à une machine virtuelle mais plus légère. Conventionnellement il ne comprend qu'une application qui va travailler isolément des autres applications de la machine hôte (Linux Fedora). Il n'aura des interactions avec d'autres applications qu'au travers du réseau comme une machine indépendante.

Comparons un conteneur à une machine virtuelle (VM) qui tournent tous deux sur une machine hôte équipée de son propre OS et de logiciels propres. Un conteneur et une machine virtuelle s'exécute comme un parasite de la machine hôte.

Une machine virtuelle se base sur une partie des ressources matérielles de la machine hôte et accapare ces ressources. Il met en oeuvre l'ensemble des composants d'une machine: son OS qui va interagir avec ces ressources matérielles et tout le cortège des logiciels nécessaires à ses tâches. Cet OS peut être n'importe lequel indépendamment de celui de la machine hôte. Il aura besoin de ressources comme s'il tournait sur une machine physique indépendante. Par ce fait, il en découle une machine physique ayant des ressources très importantes. Le seul bénéfice, vis-à-vis des autres machines virtuelles tournant sur la même machine hôte, réside dans la mutualisation d'une partie de ses ressources avec les autres machines virtuelles pour autant que l'ensemble des ressources nécessaires ne dépassent pas les capacités de la machine hôte et selon ses besoins propres à un moment donné qui fluctuent en fonction des demandent qui lui sont demandées.

De son côté, un conteneur va se baser, non pas directement sur les ressources matérielles de la machine hôte mais sur l'OS (système opératoire) de la machine hôte. Il va donc contenir le nécessaire pour faire le logiciel ciblé et ses interactions avec le réseau afin d'interagir avec d'autres conteneurs et d'autres machines au travers la machine hôte. Il va se comporter comme une micro-machine isolée du reste du système de la machine hôte et des autres conteneurs tout en n'utilisant que le kernel ou noyau de la machine hôte qui elle gère les ressources matérielles de la machine physique. Par ce fait, le logiciel de ce conteneur ne pas interférer avec les autres logiciels tournant sur la même machine, hôte ou conteneurs. Et corolaire, les ressources utilisées sont très nettement moindres, tout en devant être compatibles avec l'OS de la machine hôte au travers de son kernel ou noyau.

Tous deux apportent une couche de sécurité supplémentaire à tout intrusion non désirée ou dégâts collatéraux vis-à-vis des autres applications tournant sur cette machine.


Installation

Comme les machines virtuelles, les conteneurs ont besoin de leur gestionnaire. Mais celui utilisé n'a pas besoin d'un service dédié au contraire de Docker. Nous utilisons "PodMan".

Nous l'installons grâce à la commande de ligne suivante:

dnf install podman toolbox


Cockpit

Le logiciel Cockpit possède un module permettant de gérer les conteneurs.

Nous allons l'ajouter via la commande de ligne suivante:

dnf install cockpit-podman


Si l'adresse IP de notre machine hôte est "192.168.1.66", on peut accéder à Cockpit via l'URL:

https://192.168.1.66:9090


Un écran d'authentification demande le nom d'utilisateur Linux de la machine hôte et son mot de passe.

Un conteneur est créé et utilisé via un nom d'utilisateur spécifique Linux sur la machine hôte. L'authentification doit se faire via ce nom d'utilisateur qui seul peut voir et gérer ce conteneur. Par exemple, un conteneur créé sous l'utilisateur "adminct" ne pourra pas être vu par l'utilisateur "root" via l'interface Web de Cockpit.

Dans l'interface qui s'ouvre, on choisit le point "Conteneurs Podman" dans le menu de gauche.


Mode Root et RootLess

Un conteneur peut être utilisé sous l'utilisateur "root" ou tout autre utilisateur de la machine hôte n'ayant pas des droits administrateur (RootLess). Le cycle de vie d'un conteneur est identique dans les deux cas. Il n'y aura que quelques particularités lors de l'exécution automatique des conteneurs.

En première partie, nous gérerons les conteneurs sous l'Utilisateur "root". Ensuite nous aborderons le cas d'utilisation sous un utilisateur non root (RootLess).

L'intérêt est d'ajouter une couche de protection. Si le conteneur est compromis, le pirate n'aura que les droits réduits de cet utilisateur.

On peut pousser plus loin en créant un conteneur par utilisateur afin de complexifier la sécurité. Chaque conteneur est sécurisé des autres.


Cycle de vie d'un conteneur

Il existe la possibilité de construire et d'exécuter, via la couche Systemd, de tout nouveau conteneur. Nous ne l'utiliserons pas car nous avons préféré décomposer toutes les étapes de vie d'un conteneur afin de mieux comprendre sa mise en place. L'utilisation via Systemd est adaptée pour une implémentation clé en main, standardisée sur un ensemble de machines.

De plus, nous n'aborderons pas la facette de création de nos propres environnements de conteneurs ou images. Il existe un grand nombre d'images pour les principales applications; il existe même de nombreuses versions pour une même application. Nous chercherons parmi elles.


Le cycle de vie d'un conteneur est le suivant, sur base d'un choix dune application précise:

  • Phase de création et d'utilisation:
    • On recherche le nom d'une image de l'application ciblée.
    • On récupère l'image choisie.
    • On crée un volume qui sera utilisé par notre conteneur; ce volume qui peut être un répertoire ou un fichier permet de personnaliser le conteneur, le conteneur lui-même étant volatile.
    • On crée un conteneur sur base de cette image; cette création est accompagnée d'un certain nombre de paramètres qui servent à adapter cette application à nos besoins.
    • On démarre le conteneur.
    • Au besoin, on adapte l'hôte afin de faciliter l'utilisation de cette application par les clients.
  • Phase d'élimination d'un conteneur:
    • On arrête le conteneur.
    • On efface le conteneur.
    • On efface les volumes de ce conteneur.
    • On efface l'image associée.
    • On élimine les adaptations faites au niveau de l'hôte.

Evidemment ce cycle peut se faire de façon partielle spécialement dans sa phase de recherche de la bonne configuration. Par exemple, si le paramétrage ne nous convient pas; on se limite à l'arrêt de ce conteneur et à sa destruction pour pouvoir recréer ce même conteneur avec d'autres options.


Découverte de notre premier conteneur

On va commencer par découvrir les principales étapes du cycle d'un conteneur. Nous avons opté pour la création d'un site Web statique. Nous utiliserons un serveur Web Apache: HTTPD. Nous utiliserons une image toute faite.

La très grande majorité des commandes de ligne se font avec le logiciel "podman" que nous avons installé en début d'article. Nous l'utilisons sous l'utilisateur "root".

Tout ce nous ferons par la suite sera enregistré dans le dossier "/var/lib/containers/storage".


Recherche d'une image

La première étape est la recherche une image. Une image est un paquet qui contient tout le nécessaire pour créer un conteneur.

Pour cette recherche, Linux Fedora possède une liste de sites où chercher les images. On peut en avoir une idée en consultant le site: https://hub.docker.com/

Pour effectuer cette recherche nous lançons la commande:

podman search httpd

qui donne la longue liste suivante:


NAME                                  DESCRIPTION
registry.fedoraproject.org/f29/httpd
docker.io/library/httpd               The Apache HTTP Server Project
docker.io/manageiq/httpd              Container with httpd, built on CentOS for Ma...
docker.io/paketobuildpacks/httpd
docker.io/vulhub/httpd
docker.io/openeuler/httpd
docker.io/dockerpinata/httpd
docker.io/centos/httpd
docker.io/jokerjack/httpd             base image:  buxybox, running httpd server,...
docker.io/manasip/httpd
docker.io/e2eteam/httpd
docker.io/6sycho/httpd                busybox httpd /docker run --name -d mageedu/...
docker.io/puyanhong/httpd             busybox httpd ,  docker run --name NAME -d p...
docker.io/wanliduxing/httpd           busybox httpd  docker run --name NAME -d  ma...
docker.io/ghtl/httpd                  busybox httpd  docker run --name NAME -d ght...
docker.io/litaotaodocker/httpd        busybox httpd docker run -name NAME -d litao...
docker.io/liubaoyu/httpd              busybox httpd     docker run --name NAME -d...
docker.io/ohcoder/httpd               busybox httpd  docker run --name NAME -d ohc...
docker.io/muda/httpd                  busybox httpd   docker run --name NAME -d ma...
docker.io/dockerptu/httpd             busybox httpd     'docker run --name NAME -d...
docker.io/lolhens/httpd               Apache httpd 2 Server
docker.io/vishakkv/httpd              spinup httpd in centos 7
docker.io/amd64/httpd                 The Apache HTTP Server Project
docker.io/tangxj/httpd                busybox-httpd,you should use this command: d...
docker.io/went2675/httpd              docker --name NAME -d went2675/httpd
docker.io/futdryt/httpd

Nous retiendrons la seconde, l'officielle: "docker.io/library/httpd" dont le détail peut être consulté à l'URL: https://hub.docker.com/_/httpd

Ce site vous explique comment l'utiliser.


Récupération de l'image

La seconde étape consiste à récupérer cette image avec la commande:

podman pull docker.io/library/httpd

Cette récupération consiste à récupérer le "blob" ou module principal et toutes ses dépendances.


Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
Copying blob c4a216db6600 done   |
Copying blob 26c307b5e35a done   |
Copying blob 4f4fb700ef54 done   |
Copying blob c271d17baba2 done   |
Copying blob 04951bf53bdd done   |
Copying blob 2c2b87df2933 done   |
Copying config 46ababc59d done   |
Writing manifest to image destination
46ababc59dbd026ab02d09961f28873185d8331b0939954aa24f57b55fca7244

La dernière ligne correspond à l'ID de l'image.


On peut lister les images déjà téléchargées:

podman image list

qui donne:


REPOSITORY               TAG         IMAGE ID      CREATED     SIZE
docker.io/library/httpd  latest      46ababc59dbd  8 days ago  120 MB


On peut lister les modules associés:

podman image tree docker.io/library/httpd

qui donne:


Image ID: 46ababc59dbd
Tags:     [docker.io/library/httpd:latest]
Size:     120.3MB
Image Layers
├── ID: 6f9432833129 Size: 81.05MB
├── ID: dd0da4e32c9e Size:  2.56kB
├── ID: 623762dd73ce Size: 1.024kB
├── ID: 4db9e02e6229 Size: 6.041MB
├── ID: c2b626d7d8f8 Size: 33.13MB
└── ID: 7f5555156aba Size: 3.584kB Top Layer of: [docker.io/library/httpd:latest]


On peut consulter ses caractéristiques:

podman image inspect docker.io/library/httpd

La partie suivante est intéressante:


...
         "Config": {
              "ExposedPorts": {
                   "80/tcp": {}
              },
              "Env": [
                   "PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                   "HTTPD_PREFIX=/usr/local/apache2",
                   "HTTPD_VERSION=2.4.68",
                   "HTTPD_SHA256=68c74d4df38c26bed4dfbdb8f3baf1eb532f3872357becc1bba5d136f6b63c06",
                   "HTTPD_PATCHES="
              ],
              "Cmd": [
                   "httpd-foreground"
              ],
              "WorkingDir": "/usr/local/apache2",
              "StopSignal": "SIGWINCH"
         },
...

Cette partie nous sera utile pour affiner la configuration de notre futur conteneur.


Si on ne veut plus de cette image, on peut l'éliminer:

podman image rm docker.io/library/httpd

Attention, il ne doit plus exister de conteneur associé.


Création d'un conteneur de base

Nous allons créer notre premier conteneur afin de l'explorer avant sa création définitive.

Cette commande est la suivante, réduite au minimal opérationnel:

podman create --name mysite --publish 8081:80 docker.io/library/httpd

Elle comporte bon nombre d'options; nous n'en avons retenu que deux:

  • name: nomme notre conteneur en plus de son ID, ce qui sera plus pratique pour l'utiliser.
  • publish: Il permet de faire apparaître le service qui tourne dans notre conteneur sur notre hôte. Dans le conteneur, le port 80/tcp est à l'écoute et sur la machine hôte, il apparaîtra selon le port tcp/8081. On pourrait en mode "root" utiliser le port tcp/80 au lieu de tcp/8081 mais si nous avons plusieurs conteneurs de sites Web, il ne peut n'y en avoir qu'un avec le port tcp/80. On verra plus loin comment contourner ce problème. Si tout va bien, la commande nous retourne l'ID du nouveau conteneur.

Le dernier argument reprend le nom de l'image.

Cette opération est analogue à une installation d'un nouveau système opératoire (OS) sur un disque dur à partie d'une image placée sur un média tel une clé USB.


On peut lister les conteneurs existants:

podman container list --all

L'option "--all" sert à tous les lister; si cette option n'est pas présente, seul les conteneurs actifs sont listés. Cette commande donne:


CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS      PORTS                 NAMES
83e0e2eda21b  docker.io/library/httpd:latest  httpd-foreground  29 minutes ago  Created     0.0.0.0:8081->80/tcp  mysite


Démarrage du conteneur

Maintenant que notre micro-machine est créée, on va la démarrer:

podman start mysite

ou

podman container start mysite


Conséquences de ce lancement

Notre commande du point précédent:

podman container list

permet de constater que notre conteneur a changé de statut:


CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS        PORTS                 NAMES
83e0e2eda21b  docker.io/library/httpd:latest  httpd-foreground  39 minutes ago  Up 2 minutes  0.0.0.0:8081->80/tcp  mysite


De même est apparu de nouveaux processus:

ps axfu

qui donne:


USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...
root      113754  0.0  0.0  10400  2712 ?        Ss   18:08   0:00  \_ /usr/bin/conmon --api-version 1 -c 83e0e2eda21bea8eded900a3e0c5e
root      113758  0.0  0.1   6224  4996 ?        Ss   18:08   0:00      \_ httpd -DFOREGROUND
33        113763  0.0  0.1 1210968 4404 ?        Sl   18:08   0:00          \_ httpd -DFOREGROUND
33        113764  0.0  0.1 1210968 4392 ?        Sl   18:08   0:00          \_ httpd -DFOREGROUND
33        113766  0.0  0.1 1210968 4396 ?        Sl   18:08   0:00          \_ httpd -DFOREGROUND

On remarque qu'un processus "conmon" est lancé qui exécute le micro-système opératoire (micro-OS) de notre conteneur "mysite" qui, à son tour, lance quatre autres processus, ici le serveur Web "httpd". On remarquera que le nom d'utilisateur n'est pas "apache" comme sur notre système hôte. Il est inconnu de notre hôte et est propre au conteneur "UID=33". Il correspond à l'utilisateur "www-data".


En corolaire, un nouveau port est à l'écoute "tcp/8081" comme attendu:

netstat -nltp

qui donne


Connexions Internet actives (seulement serveurs)
Proto Recv-Q Send-Q Adresse locale          Adresse distante        Etat        PID/Program name
...
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      113754/conmon
...


Le démarrage de ce conteneur s'accompagne de nouveaux interfaces réseaux liés à ce dernier:

ip address

qui donne:


1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host noprefixroute
      valid_lft forever preferred_lft forever
2: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
   link/ether 00:1c:c0:79:7c:12 brd ff:ff:ff:ff:ff:ff
   altname enx001cc0797c12
   inet 192.168.1.66/24 brd 192.168.1.255 scope global noprefixroute enp0s25
      valid_lft forever preferred_lft forever
3: podman0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
   link/ether fe:8d:8c:60:67:58 brd ff:ff:ff:ff:ff:ff
   inet 10.88.0.1/16 brd 10.88.255.255 scope global podman0
      valid_lft forever preferred_lft forever
   inet6 fe80::fc8d:8cff:fe60:6758/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
4: veth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master podman0 state UP group default qlen 1000
   link/ether fa:7c:b0:42:9b:fc brd ff:ff:ff:ff:ff:ff link-netns netns-47970c99-3958-82f8-8b6f-4cdd76dbbf4d
   inet6 fe80::acb4:d6ff:fe10:d1b0/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever

L'interface "podman0" correspond à notre hôte vu du côté du réseau des conteneurs avec l'adresse IPv4 "10.88.0.1/16". Le suivant correspond à notre conteneur. Si nous avions un second conteneur actif, on aurait un cinquième interface. On verra son adresse IPv4 en rentrant dans ce conteneur. Il appartiendra au réseau "10.88.0.0/16".


De même la table de routage est amandée:

ip route

qui donne:


default via 192.168.1.1 dev enp0s25 proto static metric 100
10.88.0.0/16 dev podman0 proto kernel scope link src 10.88.0.1
192.168.1.0/24 dev enp0s25 proto kernel scope link src 192.168.1.66 metric 100

Notre hôte avec l'adresse IPv4 "10.88.0.1" sert de route vers le réseau des conteneurs.


On peut également retrouver nombre d'informations en inspectant ce conteneur:

podman container inspect mysite


Site Web

C'est ne moment de tester notre site.

On lance dans notre navigateur Internet préféré, l'URL: http://192.168.1.66:8081/

On a la phrase suivante qui s'affiche:


It works!

Note: N'oubliez pas de désactiver le FireWall ou d'ouvrir le port tcp/8081.


Travailler dans le conteneur

Il est possible d'ouvrir une console dans ce conteneur:

podman exec -it mysite bash

ou:

podman container exec -it mysite bash

On lance l'interpréteur de commande "bash" en mode interactif (option: "-i") dans un terminal (option: "-t").

On a un prompt. En y lançant la commande:

cat /etc/os-release

on a:


PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.6
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

On remarque qu'on est en présence d'une distribution de Linux Debian.

On ressort avec:

exit


Mais on remarque vite qu'on est très limité dans les commandes. En effet, on a affaire à un OS minimum.

On va procéder à quelques installations. Notons que celles-ci disparaitront avec la destruction du conteneur.

Voici quelques commandes pour aider la consultation du réseau, des processus et de la navigation aisée (mc ou Midnight Commander):

podman exec -it mysite /usr/bin/apt -y update
podman exec -it mysite /usr/bin/apt -y upgrade
podman exec -it mysite /usr/bin/apt -y install mc net-tools procps iproute2 iputils-ping


On rentre à nouveau dans le conteneur.

Et on exécute:

ps axfu

qui donne:


USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         831  0.0  0.0   4328  3764 pts/0    Ss   17:20   0:00 bash
root         833  0.0  0.0   6400  3764 pts/0    R+   17:20   0:00  \_ ps axfu
root           1  0.0  0.1   6224  4996 ?        Ss   16:08   0:00 httpd -DFOREGROUND
www-data       3  0.0  0.1 1210968 4404 ?        Sl   16:08   0:00 httpd -DFOREGROUND
www-data       4  0.0  0.1 1211032 4992 ?        Sl   16:08   0:00 httpd -DFOREGROUND
www-data       6  0.0  0.1 1210976 4408 ?        Sl   16:08   0:00 httpd -DFOREGROUND

On remarque notre session "root" en mode terminal et le serveur Web "httpd".

Et pour le réseau:

 ip address

on a:


1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host proto kernel_lo
      valid_lft forever preferred_lft forever
2: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
   link/ether 86:15:1c:84:d9:d2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
   inet 10.88.0.2/16 brd 10.88.255.255 scope global eth0
      valid_lft forever preferred_lft forever
   inet6 fe80::8415:1cff:fe84:d9d2/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever

De même:

ip route

on a:


default via 10.88.0.1 dev eth0 proto static metric 100
10.88.0.0/16 dev eth0 proto kernel scope link src 10.88.0.2

Si maintenant on va dans le dossier suivant:

cd /usr/local/apache2/htdocs

on y trouve le fichier "index.html" qui contient le message affiché dans notre navigateur Internet.

Ces informations vont nous servir pour l'étape suivante. On peut sortir.


Arrêt du conteneur

Ce conteneur était conçu afin d'apprivoiser le concept de conteneur.

On va l'arrêter:

podman stop mysite

ou:

podman container stop mysite


Destruction du conteneur

On n'en a plus besoin, donc on l'efface:

podman container rm mysite

Le cycle de ce conteneur est terminé.


Note

Au lieu d'utiliser les commandes:

podman create ...
podman start ...

On peut les coupler avec la commande:

podman run -d ...

Ses arguments sont les mêmes que pour "podman create ..."

Si on ajoute l'option "-rm":

podman run -d -rm ...

La commande:

podman stop ...

sera équivalente à:

podman stop ...
podman container rm ...


Réseau

Le logiciel "podman" intègre une gestion de réseaux liés aux conteneurs. Intégré à l'installation, un réseau est créé: "podman". On a remarqué sa présence en consultant les interfaces réseaux suite à l'activation du conteneur "mysite": "podman0". Mais on peut en créer d'autres.

Pour voir la liste de ces réseaux, on exécute la commande:

podman network list

qui donne:


NETWORK ID    NAME        DRIVER
2f259bab93aa  podman      bridge

On peut voir le détail de ce réseau:

podman network inspect podman

qui donne:


[
    {
         "name": "podman",
         "id": "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9",
         "driver": "bridge",
         "network_interface": "podman0",
         "created": "2026-08-13T18:38:45.98474812+02:00",
         "subnets": [
              {
                   "subnet": "10.88.0.0/16",
                   "gateway": "10.88.0.1"
              }
         ],
         "ipv6_enabled": false,
         "internal": false,
         "dns_enabled": false,
         "ipam_options": {
              "driver": "host-local"
         },
         "containers": {
              "83e0e2eda21bea8eded900a3e0c5e53e8b584380f55c004ef2158b75d639be32": {
                   "name": "mysite",
                   "interfaces": {
                        "eth0": {
                             "subnets": [
                                  {
                                       "ipnet": "10.88.0.2/16",
                                       "gateway": "10.88.0.1"
                                  }
                             ],
                             "mac_address": "86:15:1c:84:d9:d2"
                        }
                   }
              }
         }
    }
]

Il est de type "pont" ou "bridge".

Cette commande est exécutée alors que le conteneur "mysite" était actif. On le voit dans la section "containers", les informations de celui que nous venons de lancer. Il a l'adresse IPv4 "10.88.0.2/16" et son routeur est celle de notre machine hôte "10.88.0.1".


Pour en créer un nouveau, on exécute la commande suivante:

podman network create --subnet 172.30.1.0/24 mynetwork

Ce réseau se nomme "mynetwork" et couvre l'adressage "172.30.1.0/24".

On peut l'éliminer comme suit:

podman network rm mynetwork


Il est à remarquer que le réseau "podman" est présent pour tout utilisateur. Par contre, ceux créés ne sont accessibles que par l'utilisateur qui l'a créé.


Volume

Un conteneur comprend un ensemble de fichiers et de répertoires découlant du déploiement de son image. Mais si on le détruit tout disparaît même le paramétrage ou les mises à jour. Par exemple, quand on utilise un logiciel tel WordPress, on ajoute des documents, des pages,... et le paramétrage est stocké dans une base de données. Et le tout est inaccessible directement.

La solution est la création d'un volume. Ce volume peut comprendre un fichier ou toute une arborescence de fichiers et répertoires. Ce volume sera lié à un endroit particulier du conteneur lors de sa création et remplacera ce qui existait dans le conteneur.

Il y a divers intérêts:

  • Le contenu du volume est directement visible et gérable par le conteneur et l'hôte.
  • Dans le cas de la destruction du conteneur, le contenu du volume n'est pas détruit et peu donc être réutilisé par un autre conteneur ou récupéré.

Par contre,

  • le contenu de ce volume est géré et utilisé par le conteneur et donc il faut que les droits et privilèges soient ceux du conteneur et les utilisateurs et les groupes du conteneur sont différents de l'hôte. Il faut faire très attention à ce point au risque que les services fournis par les conteneurs ne soient pas au rendez-vous.


Pour créer un conteneur nommé, par exemple, "htmlasbl", on lance la commande:

podman volume create htmlasbl

Le dossier correspondant est créé: "/var/lib/containers/storage/volumes/htmlasbl". On peut placer, modifier, consulter,... tout fichier ou répertoire à l'intérieur du sous-dossier "_data".


On peut lister tous les volumes existant avec la commande:

podman volume list

qui donne:


DRIVER      VOLUME NAME
local       htmlasbl


Et son détail:

podman volume inspect htmlasbl

qui donne:


[
    {
         "Name": "htmlasbl",
         "Driver": "local",
         "Mountpoint": "/var/lib/containers/storage/volumes/htmlasbl/_data",
         "CreatedAt": "2026-08-14T13:49:56.862714111+02:00",
         "Labels": {},
         "Scope": "local",
         "Options": {},
         "MountCount": 0,
         "NeedsCopyUp": true,
         "NeedsChown": true,
         "LockNumber": 1
    }
]


On peut le détruire par la commande:

podman volume rm htmlasbl


Démarrage automatique des conteneurs

Si on redémarre notre hôte, tous les conteneurs actifs sont arrêtés mais ne redémarrent pas.

Pour pallier à ce problème, on doit activer un service spécifique et on l'active ensuite:

systemctl enable podman-restart.service
systemctl start  podman-restart.service

De plus il faut ajouter l'option "--restart=always" lors de la création des conteneurs concernés.


Création des conteneurs

Nous allons créer cinq conteneurs dans le but de présenter quelques cas simples.


Conteneur sur base de l'image "httpd"

Maintenant qu'on a découvert les bases d'un conteneur, on va affiner notre paramétrage.

Pour ce premier cas, on a pour but créer un conteneur pour un site Web statique existant sur base d'une image "httpd". Le détail peut être consulté à l'URL: https://hub.docker.com/_/httpd

On commence par créer un volume où on placera le contenu de notre site:

podman volume create htmlasbl


En second, on crée un conteneur sur base de notre image "docker.io/library/httpd".


podman create \
  --name myasbl \
  --restart=always \
  --hostname ctasbl.home.dom \
  --network podman:ip=10.88.0.11 \
  --publish 127.0.0.1:8081:80 \
  --volume htmlasbl:/usr/local/apache2/htdocs \
  docker.io/library/httpd

On a ajouté diverses options dont quelques-unes découlent de notre connaissances acquises aux points précédents/

  • On nomme ce conteneur ("name"): "myasbl".
  • L'option "--restart=always" enclenche le démarrage automatique du conteneur lors du redémarrage de l'hôte comme vu plus tôt.
  • On donne un nom de machine ("hostname") au conteneur plutôt qu'un nom aléatoire: "ctasbl.home.dom", ce qui évite un message d'erreur du processus "httpd".
  • L'option "network" nous sert à imposer l'adresse IPv4 du conteneur à "10.88.0.11" sur base du réseau "podman" vu plus haut.
  • On publie le port tcp/80 du service HTTPD du conteneur au niveau de l'hôte: "tcp/127.0.0.1:8081". On remarque que ce service ne sera accessible que par l'hôte en local. On verra plus loin l'intégration de plusieurs services Web, visibles par tous.
  • On a remarqué plus haut que le contenu du site se trouvait au niveau du conteneur dans le répertoire "/usr/local/apache2/htdocs". On va lier ce dossier au volume créé ci-dessus.


On peut lancer le conteneur:

podman start myasbl

En consultant le contenu du dossier "/var/lib/containers/storage/volumes/htmlasbl/_data", on y retrouve notre fichier "index.html" dont voici ses droits sous l'hôte:

ls -ln

qui donne:


total 4
-rw-r--r-- 1 501 50 191  7 nov  2025 index.html

On peut copier les fichiers et répertoires de notre site à la place de ce fichier. On adapte les droits d'accès et surtout le propriétaire:

chown -R 501:50 *


On peut tester localement ce site:

curl http://localhost:8081

ou

lynx http://localhost:8081


On peut également visualiser le journal du conteneur:

podman logs myasbl

qui donne:


[Fri Aug 14 12:00:18.868366 2026] [mpm_event:notice] [pid 1:tid 1] AH00489: Apache/2.4.68 (Unix) configured -- resuming normal operations
[Fri Aug 14 12:00:18.877689 2026] [core:notice] [pid 1:tid 1] AH00094: Command line: 'httpd -D FOREGROUND'
10.88.0.1 - - [14/Aug/2026:12:59:33 +0000] "GET / HTTP/1.1" 200 2554

On remarque l'accès au site avec la commande "curl" en dernière ligne.


Conteneur sur base de l'image "mariadb"

Le second projet consiste à installer un site Web basé sur WordPress.

Mais pour cela, il nous faut une base de données de type MySql. En l'occurrence, nous recherchons une image "mariadb". Nous avons mis notre dévolu sur l'image "docker.io/library/mariadb:latest". Le détail peut être consulté à l'URL: https://hub.docker.com/_/mariadb


On commence par créer un volume où on placera le contenu de la base de données:

podman volume create dbmariadb


En second, on crée un conteneur sur base de notre image "docker.io/library/mariadb".


podman create \
  --name mymariadb \
  --restart=always \
  --hostname ctmariadb.home.dom \
  --network podman:ip=10.88.0.13 \
  --publish 3307:3306 \
  --env MARIADB_ROOT_PASSWORD='SpediaPwRoot' \
  --env MARIADB_DATABASE='dbwp' \
  --env MARIADB_USER='userwp' \
  --env MARIADB_PASSWORD='SuiteInconnue72' \
  --volume dbmariadb:/var/lib/mysql \
  docker.io/library/mariadb:latest

On a ajouté diverses options dont quelques-unes découlent de notre connaissances acquises aux points précédents:

  • On nomme ce conteneur ("name"): "mymariadb".
  • L'option "--restart=always" enclenche le démarrage automatique du conteneur lors du redémarrage de l'hôte comme vu plus tôt.
  • On donne un nom de machine ("hostname") au conteneur plutôt qu'un nom aléatoire: "ctmariadb.home.dom".
  • L'option "network" nous sert à imposer l'adresse IPv4 du conteneur à "10.88.0.13" sur base du réseau "podman" vu plus haut.
  • On publie le port tcp/3306 du service MARIADB du conteneur au niveau de l'hôte: "tcp/3307". On a changé au niveau de l'hôte le n° du port afin qu'on puisse à l'avenir créer d'autres conteneurs de base de données. On n'a pas limité son accès au port local de l'hôte car il sera accédé par un autre conteneur. Au niveau du FireWall de l'hôte, il n'est pas nécessaire d'ouvrir ce port car tout se passera au travers l'interface "lo" et d'un trafic interne qui est normalement ouvert.
  • La base de données sera placée dans un volume créé ci-dessus et lié au niveau du conteneur dans le répertoire "/var/lib/mysql".
  • Ensuite nous avons à notre disposition diverses variables d'environnement qui vont servir à créer la base de données et le schéma qui contiendra les données du site de WordPress.
    • MARIADB_ROOT_PASSWORD: pour le mot de passe de l'utilisateur "root" de la base de données MariaDB.
    • MARIADB_DATABASE: pour le nom du schéma qui contiendra les données du site de WordPress
    • MARIADB_USER: pour le nom d'utilisateur ayant le droit d'accès au schéma "dbwp"
    • MARIADB_PASSWORD: pour le mot de passe de l'utilisateur "userwp"


On peut lancer le conteneur:

podman start mymariadb

On verra le volume créé se remplir par les fichiers de la base de données MariaDb et le répertoire pour le schéma "dbwp".


On peut également visualiser le journal du conteneur:

podman logs mymariadb


Conteneur sur base de l'image "wordpress"

Le second projet consiste à installer un site Web basé sur WordPress. Un conteneur pour la base de données MariaDb vient d'être installé.

Nous avons mis notre dévolu sur l'image "docker.io/library/wordpress:latest". Le détail peut être consulté à l'URL: https://hub.docker.com/_/wordpress


On commence par créer un volume où on placera le contenu du site WordPress:

podman volume create htmlwp


En second, on crée un conteneur sur base de notre image "docker.io/library/wordpress".


podman create \
  --name mywp \
  --restart=always \
  --hostname ctwp.home.dom \
  --network podman:ip=10.88.0.12 \
  --publish 127.0.0.1:8082:80 \
  --env WORDPRESS_DB_HOST=192.168.1.66:3307 \
  --env WORDPRESS_DB_NAME=dbwp \
  --env WORDPRESS_DB_USER=userwp \
  --env WORDPRESS_DB_PASSWORD=SuiteInconnue72 \
  --volume htmlwp:/var/www/html \
  docker.io/library/wordpress:latest

On a ajouté diverses options dont quelques-unes découlent de nos connaissances acquises aux points précédents:

  • On nomme ce conteneur ("name"): "mywp".
  • L'option "--restart=always" enclenche le démarrage automatique du conteneur lors du redémarrage de l'hôte comme vu plus tôt.
  • On donne un nom de machine ("hostname") au conteneur plutôt qu'un nom aléatoire: "ctwp.home.dom".
  • L'option "network" nous sert à imposer l'adresse IPv4 du conteneur à "10.88.0.12" sur base du réseau "podman" vu plus haut.
  • On publie le port tcp/80 du service HTTPD du conteneur au niveau de l'hôte: "tcp/127.0.0.1:8082". On remarque que ce service ne sera accessible que par l'hôte en local. On verra plus loin l'intégration de plusieurs services Web, visibles par tous.
  • Le contenu du site se trouve au niveau du conteneur dans le répertoire "/var/www/html". On va lier ce dossier au volume créé ci-dessus.
  • Ensuite nous avons à notre disposition diverses variables d'environnement qui vont servir à créer la base de données et le schéma qui contiendra les données du site de WordPress.
    • WORDPRESS_DB_NAME: pour le nom du schéma qui contiendra les données du site de WordPress
    • WORDPRESS_DB_USER: pour le nom d'utilisateur ayant le droit d'accès au schéma "dbwp"
    • WORDPRESS_DB_PASSWORD: pour le mot de passe de l'utilisateur "userwp"
    • WORDPRESS_DB_HOST: pour l'adresse IP et le port pour accéder à la base de données. Il y a trois moyens d'accès:
      • 10.88.0.13:3306: cette adresse correspond à celle du conteneur "mymariadb" qui écoute sur le port tcp/3306.
      • 192.168.1.66:3307 et 10.88.0.1:3307: ces adresses correspondent à l'hôte qui a deux adresses IPv4, l'un vers notre réseau physique et l'autre vers le réseau des conteneurs. Il écoute lui par contre sur le port tcp/3307.


On peut lancer le conteneur:

podman start mywp

On verra le volume créé se remplir par les fichiers du site de WordPress. Quand on ajoutera des médias, on les verra apparaître dans le dossier "/var/lib/containers/storage/volumes/htmlwp/_data/wp-content/uploads".


On pourrait tester localement ce site:

lynx http://localhost:8082

Lors du premier démarrage, on demande la langue, le nom du site et un nom d'utilisateur et son mot de passe.


On peut également visualiser le journal du conteneur:

podman logs mywp


Note: Il est à remarquer qu'un conteneur ne peut interagir avec un autre conteneur que s'ils sont tous deux créés par le même utilisateur. C'est le cas des conteneurs "mywp" et "mymariadb".


Conteneur sur base de l'image "phpmyadmin"

Le troisième projet consiste à installer un site Web qui va gérer la base de données. Un conteneur pour la base de données MariaDb vient d'être installé. Le gestionnaire sera basé sur le logiciel bien connu "phpmyadmin".

Nous avons mis notre dévolu sur l'image "docker.io/library/phpmyadmin:latest". Le détail peut être consulté à l'URL: https://hub.docker.com/_/phpmyadmin


On crée un conteneur sur base de notre image "docker.io/library/phpmyadmin".


podman create \
  --name myphpmyadmin \
  --restart=always \
  --hostname ctphpmyadmin.home.dom \
  --network podman:ip=10.88.0.14 \
  --publish 127.0.0.1:8083:80 \
  --env PMA_HOST=192.168.1.66:3307 \
  docker.io/library/phpmyadmin:latest

On a ajouté diverses options dont quelques-unes découlent de nos connaissances acquises aux points précédents:

  • On nomme ce conteneur ("name"): "myphpmyadmin".
  • L'option "--restart=always" enclenche le démarrage automatique du conteneur lors du redémarrage de l'hôte comme vu plus tôt.
  • On donne un nom de machine ("hostname") au conteneur plutôt qu'un nom aléatoire: "ctphpmyadmin.home.dom".
  • L'option "network" nous sert à imposer l'adresse IPv4 du conteneur à "10.88.0.14" sur base du réseau "podman" vu plus haut.
  • On publie le port tcp/80 du service HTTPD du conteneur au niveau de l'hôte: "tcp/127.0.0.1:8083". On remarque que ce service ne sera accessible que par l'hôte en local. On verra plus loin l'intégration de plusieurs services Web, visibles par tous.
  • Ensuite nous avons à notre disposition diverses variables d'environnement qui vont servir à définir le conteneur contenant la base de données.
    • PMA_HOST: pour l'adresse IP et le port pour accéder à la base de données. Il y a trois moyens d'accès:
      • 10.88.0.13:3306: cette adresse correspond à celle du conteneur "mymariadb" qui écoute sur le port tcp/3306.
      • 192.168.1.66:3307 et 10.88.0.1:3307: ces adresses correspondent à l'hôte qui a deux adresses IPv4, l'un vers notre réseau physique et l'autre vers le réseau des conteneurs. Il écoute lui par contre sur le port tcp/3307.
    • PMA_ARBITRARY: en alternative à la désignation d'un conteneur de base de données, on peut mettre cette variable à 1 (PMA_ARBITRARY=1) afin de pouvoir préciser librement l'adresse et le port du conteneur cible.

Note: Pour s'authentifier, on utilise l'utilisateur de la base de données "root" dont on a défini le mot de passe lors de la création du conteneur "mymariadb" grâce à la variable d'environnement: "MARIADB_ROOT_PASSWORD".


On peut lancer le conteneur:

podman start myphpmyadmin


On pourrait tester localement ce site:

lynx http://localhost:8083

Lors du premier démarrage, on demande la langue, le nom du site et un nom d'utilisateur et son mot de passe.


On peut également visualiser le journal du conteneur:

podman logs myphpmyadmin


Note: Il est à remarquer qu'un conteneur ne peut interagir avec un autre conteneur que s'ils sont tous deux créés par le même utilisateur. C'est le cas des conteneurs "muphpmyadmin" et "mymariadb".


Conteneur sur base de l'image "portainer"

Une alternative à Cockpit qui est propre à RedHat, est l'utilisation d'un conteneur particulier qui présente les mêmes fonctionnalités et informations. Il se présente sous forme d'un interface Web. Nous avons mis notre dévolu sur l'image "portainer/portainer-ce:lts". Les instructions pour l'installation se trouvent sur le site du concepteur à l'URL: https://docs.portainer.io/start/install-ce/server/podman/linux

On commence par activer un service:

systemctl enable podman.socket
systemctl start podman.socket

Ensuite il faut créer un volume où seront placés les paramètres:

podman volume create portainer_data

En troisième, on crée un conteneur sur base de notre image "portainer/portainer-ce:lts".


podman create \
  --name portainer \
  --restart=always \
  --hostname ctportainer.home.dom \
  --network podman:ip=10.88.0.15 \
  --publish 127.0.0.1:9000:9000 \
  --privileged \
  --volume /run/podman/podman.sock:/var/run/docker.sock \
  --volume portainer_data:/data \
  docker.io/portainer/portainer-ce:lts \
  --no-setup-token

On a ajouté diverses options dont quelques-unes découlent de notre connaissances acquises aux points précédents:

  • On nomme ce conteneur ("name"): "myportainer".
  • L'option "--restart=always" enclenche le démarrage automatique du conteneur lors du redémarrage de l'hôte comme vu plus tôt.
  • On donne un nom de machine ("hostname") au conteneur plutôt qu'un nom aléatoire: "ctportainer.home.dom".
  • L'option "network" nous sert à imposer l'adresse IPv4 du conteneur à "10.88.0.15" sur base du réseau "podman" vu plus haut.
  • On publie le port tcp/9000 du service du conteneur au niveau de l'hôte: "tcp/127.0.0.1:9000". On remarque que ce service ne sera accessible que par l'hôte en local. On verra plus loin l'intégration de plusieurs services Web, visibles par tous.
  • Les paramètres se trouvent au niveau du conteneur dans le répertoire "/data". On va lier ce dossier au volume créé ci-dessus. On lie aussi le socket enclenché.
  • Lors de l'initialisation de l'authentification, il est normalement demandé un jeton que l'on trouve dans le journal du conteneur mais ce jeton a une durée de vie réduite et pour éviter son utilisation, on le désactive.


On peut lancer le conteneur:

podman start myportainer

Lors du premier contact avec cette application en mode Web, on demande de donner un mot de passe à l'utilisateur "admin" et de procurer un autre nom d'utilisateur en alternative.


Il est important de rappeler que Portainer comme Cockpit ne peuvent voir que les conteneurs créés sous un même utilisateur:

  • Cockpit selon l'utilisateur authentifié, ne verra que les conteneurs créés par cet utilisateur;
  • Portainer créé par un utilisateur ne verra que les conteneurs créés par ce même utilisateur.


Service HTTPD de l'hôte

Nous sommes en présence de trois services Web avec des ports différents: 9000, 8081 et 8082 mais qui ne sont accessibles que par l'hôte.

Pour les rassembler sous un même port tcp/80 classique, on va faire appel pour chacun à un nom de machine virtuelle et à une approche "proxy" et son inverse.

On crée un fichier "/etc/httpd/conf/proxy.conf" dont voici le contenu:


<VirtualHost *:80>
  ServerName asbl.home.dom
  ProxyRequests Off
  ProxyPass / http://127.0.0.1:8081/
  ProxyPassReverse / http://127.0.0.1:8081/
  ProxyPreserveHost On
</VirtualHost>
 
<VirtualHost *:80>
  ServerName wp.home.dom
  ProxyRequests Off
  ProxyPass / http://127.0.0.1:8082/
  ProxyPassReverse / http://127.0.0.1:8082/
  ProxyPreserveHost On
<VirtualHost>
 
<VirtualHost *:80>
  ServerName phpmyadmin.home.dom
  ProxyRequests Off
  ProxyPass / http://127.0.0.1:8083/
  ProxyPassReverse / http://127.0.0.1:8083/
  ProxyPreserveHost On
<VirtualHost>
 
<VirtualHost *:80>
  ServerName portainer.home.dom
  ProxyRequests Off
  ProxyPass / http://127.0.0.1:9000/
  ProxyPassReverse / http://127.0.0.1:9000/
  ProxyPreserveHost On
</VirtualHost>

On ajoute en fin du fichier "/etc/httpd/conf/httpd.conf" l'appel à ce fichier:


...
Include conf/proxy.conf

On relance le service HTTPD:

systemctl restart httpd.service

Cette configuration est basique et locales. On peut facilement l'adapter pour un accès Internet avec un cryptage via des certificats.

Ces trois noms de machines virtuelles sont soit ajoutés dans votre serveur DNS local, privé. A défaut, on ajoute leurs références dans le fichiers "hosts" des clients. Dans les machines Linux, il se trouve dans le répertoire "/etc" et sous MS Windows, "C:\windows\system32\drivers\etc".

Voici la ligne à ajouter dans notre cas dans le fichier "hosts":


192.168.1.66 portainer.home.dom wp.home.dom asbl.home.dom phpmyadmin.home.dom

Dès lors on peut y accéder via les URLs:

http://asbl.home.dom
http://wp.home.dom
http://phpmyadmin.home.dom
http://portainer.home.dom


RootLess

Jusqu'à maintenant, nous avons travaillé sous l'utilisateur "root" qui a tous les droits. Pour une question de sécurité, il est conseillé de travailler sous un utilisateur classique ayant moins de droits. Mais dans cet environnement, il est nécessaire d'effectuer quelques adaptations.


Utilisateur

Nous allons ajouter un nouvel utilisateur que nous nommons "admincl":

adduser admincl

Cet utilisateur a dans notre cas l'UID de 1001 et le GID de 1001. Nous n'avons pas utilisé l'utilisateur ayant l'UID de 1000 et le GID de 1001 car avec ces ID, classiquement, c'est le premier utilisateur créé lors de l'installation du système qui peut accéder aux droits élevés via la commande "sudo".

Nous avons gardé son répertoire personne:: "/home/adminct"


Répertoires

La structure reprenant les images, volumes, conteneurs,... ont changés de place:

  • Sous l'utilisateur "root", elle se trouve dans "/var/lib/containers/storage",
  • Sous tout autre utilisateur, elle se trouve dans son espace: "~/.local/share/containers/storage" ou /home/adminct/.local/share/containers/storage" pour notre utilisateur "adminct".


Démarrage automatique des conteneurs

Nous sommes en présence d'un utilisateur classique et le démarrage automatique des conteneurs doit être déclenché de façon spécifique.

La commande suivante règle la première partie du problème:

systemctl --user enable podman-restart.service
systemctl --user start  podman-restart.service

Le script de lancement "podman-restart.service" ne se met pas dans le répertoire "/etc/systemd/system/default.target.wants" mais dans l'espace de l'utilisateur: "/home/adminct/.config/systemd/user/default.target.wants"


Le second problème à résoudre est le suivant. Si on active un conteneur est activé sous cet utilisateur, il démarre bien mais dès qu'on clôture la session de cet utilisateur, ce conteneur s'arrête. De même, un démarrage de l'hôte ne lance pas ce conteneur.

En fait, il faut avoir un privilège spécial que l'utilisateur "root" a. Il permet d'activer le "Systemd" de l'utilisateur perpétuellement.

Pour l'activer, on exécute la commande suivante:

loginctl enable-linger adminct

ou si on est sous la session de cet utilisateur:

loginctl enable-linger 

Le fichier "/var/lib/systemd/linger/adminct" correspondant est créé.

Pour le désactiver, on utilise la commande inverse:

loginctl disable-linger adminct


Conteneurs

L'utilisation de la commande "podman" la même que sous l'utilisation sous l'utilisateur "root".

Nous avons rencontré deux cas liés:

  • au conteneur "portainer" que nous allons traiter ci-dessous et
  • à la gestion du réseau des conteneurs.

Le conteneur "portainer" fait appel à un socket activé par Systemd. Cette commande doit être adaptée au contexte de l'utilisateur classique:

systemctl --user enable podman-restart.service
systemctl --user start podman-restart.service

En liaison, dans la commande de création de ce conteneur, le volume faisant référence à ce "socket" a changé de place vers: "/run/user/1001/podman/podman.sock:/var/run/docker.sock". On y remarque l'UID de notre utilisateur "adminct", à adaper selon l'utilisateur.

La commande devient:


podman create \
  --name portainer \
  --restart=always \
  --hostname ctportainer.home.dom \
  --network podman:ip=10.88.0.15 \
  --publish 127.0.0.1:9000:9000 \
  --privileged \
  --volume /run/user/1001/podman/podman.sock:/var/run/docker.sock \
  --volume portainer_data:/data \
  docker.io/portainer/portainer-ce:lts \
  --no-setup-token


Réseau PASTA

Lors de mon premier contact avec l'environnement d'un utilisateur classique, la gestion du réseau est fort différente.

En fait, un utilisateur classique ne peut créer ou gérer la couche réseau; il faut donc passer par quelques artifices. Les problèmes sont apparus suite à l'interaction en conteneurs; c'est le cas du conteneur "mywp" qui veut se connecter à la base de données du conteneur "mymariadb"; idem pour le conteneur "myphpmyadmin".


En première approche, je n'ai pas utilisé l'option "--network" dans la commande "podman create ...".

Dans ce cas, le système charge le processus "pasta" de régler ce problème.

Dans le conteneur qui est isolé du reste, l'adressage réseau de l'hôte est simplement recopiée dans celle du conteneur. Inévitablement tout administrateur réseau trouverait cela étrange et source de conflits. Si on se connecte dans ces conteneurs, on le visualise avec les commandes "ifconfig" ou "ip address".

Mais en correspondance, l'adresse IPv4 de l'hôte du côté du réseau des conteneurs prend la valeur "169.254.1.2" et le nom de machine "host.containers.internal". Or ce type d'adresse est de type "Local-Link". Elle se présente quand une machine ne disposant pas d'un adresse IPv4, en demande une à un serveur DHCP; s'il n'en obtient pas, il génère sa propre adresse de ce type. Elle a comme restriction d'être locale et non routable.

Pour résoudre ce problème qui se présente pour nos conteneurs "mywp" et "myphpmyadmin" voulant accéder au conteneur "mymariadb", on doit adapter les variables d'environnement:

  • pour le conteneur "mywp", on met:
--env WORDPRESS_DB_HOST=host.containers.internal:3307 \

ou

--env WORDPRESS_DB_HOST=169.254.1.2:3307 \
  • pour le conteneur "myphpmyadmin", on met:
--env PMA_HOST=host.containers.internal:3307 \

ou

--env PMA_HOST=169.254.1.2:3307 \

Si on se connecte dans ces conteneurs, on retrouve cette déclarative dans le fichier "/etc/hosts".


Réseau PODMAN

Pour résoudre ce problème, on fait appel au réseau "podman" ou à tout autre réseau créé via la commande "podman network create ...".

A toute création de tout nouveau conteneur, on fait appel à l'option "network" en spécifiant le nom du réseau à utiliser, par exemple:

--network podman

et on se retrouve dans la situation de l'utilisateur "root" pour la couche réseau.

Mais elle devient une pseudo-couche réseau. Il faut utiliser une commande spéciale au niveau de l'hôte pour la visualiser, par exemple:

  • pour l'adressage IP, on lance la commande:
podman unshare --rootless-netns ip address

au lieu de:

ip address
  • pour la table de routage, on lance la commande:
podman unshare --rootless-netns ip route

au lieu de:

ip route

Par exemple, si on lance seul le conteneur "myasbl", on a pour l'adressage:


1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host proto kernel_lo
      valid_lft forever preferred_lft forever
2: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
   link/ether f2:4e:6b:f0:ae:93 brd ff:ff:ff:ff:ff:ff
   inet 192.168.1.66/24 brd 192.168.1.255 scope global noprefixroute enp0s25
      valid_lft forever preferred_lft forever
   inet6 fe80::f04e:6bff:fef0:ae93/64 scope link nodad proto kernel_ll
      valid_lft forever preferred_lft forever
3: podman0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc noqueue state UP group default qlen 1000
   link/ether 0e:b2:40:0b:a0:34 brd ff:ff:ff:ff:ff:ff
   inet 10.88.0.1/16 brd 10.88.255.255 scope global podman0
      valid_lft forever preferred_lft forever
   inet6 fe80::cb2:40ff:fe0b:a034/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
4: veth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc noqueue master podman0 state UP group default qlen 1000
   link/ether 86:ed:1d:90:7b:df brd ff:ff:ff:ff:ff:ff link-netnsid 0
   inet6 fe80::84ed:1dff:fe90:7bdf/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever

et pour la table de routage:


default via 192.168.1.1 dev enp0s25 proto static metric 100
10.88.0.0/16 dev podman0 proto kernel scope link src 10.88.0.1
192.168.1.0/24 dev enp0s25 proto kernel scope link metric 100


En conclusion, on garde les commandes de création de conteneurs identiques à celles utilisées pour l'utilisateur "root" et nos problèmes d'interconnexions entre conteneurs sont résolus et on évite de processus "pasta".




retour au menu de Linux