Contactez-nous

Exposer les ports : Rappel et détails (--publish, --publish-all)

Maîtrisez l'exposition des ports de conteneurs Docker vers l'hôte avec les options --publish (-p) et --publish-all (-P) pour rendre vos services accessibles.

Pourquoi exposer les ports ? Le pont entre l'hôte et le conteneur

Comme nous l'avons vu, les conteneurs s'exécutent dans des espaces réseau isolés par défaut, notamment lorsqu'ils utilisent des réseaux de type `bridge`. Cela signifie qu'un service écoutant sur un port à l'intérieur d'un conteneur (par exemple, un serveur web sur le port 80) n'est pas directement accessible depuis la machine hôte ou depuis d'autres machines sur le réseau local.

Pour rendre ces services internes accessibles depuis l'extérieur de l'environnement réseau isolé du conteneur, Docker fournit un mécanisme appelé publication ou mappage de ports. Ce mécanisme crée une règle sur la machine hôte qui redirige le trafic arrivant sur un port spécifique de l'hôte vers le port correspondant à l'intérieur du conteneur.

Sans publication de ports, vos applications web, API, ou bases de données conteneurisées resteraient inaccessibles autrement que par d'autres conteneurs sur le même réseau Docker. Les commandes `docker run` offrent principalement deux options pour gérer cette publication : `--publish` (raccourci `-p`) pour un contrôle précis et `--publish-all` (raccourci `-P`) pour une publication automatique basée sur les informations de l'image.

Contrôle précis avec `-p` ou `--publish`

L'option `-p` (ou sa forme longue `--publish`) est la méthode la plus courante et la plus flexible pour exposer des ports. Elle vous permet de spécifier exactement quel port sur l'hôte doit être mappé à quel port à l'intérieur du conteneur, et éventuellement sur quelle interface réseau de l'hôte et pour quel protocole (TCP ou UDP).

La syntaxe de base est `hostPort:containerPort`. Par défaut, cela s'applique au protocole TCP et à toutes les interfaces réseau de l'hôte (`0.0.0.0`).

# Mappe le port 8080 de l'hôte au port 80 (TCP) du conteneur
docker run -d --name my-web-server -p 8080:80 nginx:latest

Avec ce mappage, accéder à `http://:8080` dans votre navigateur atteindra le serveur Nginx sur le port 80 à l'intérieur du conteneur.

Variantes de la syntaxe :

  • Spécifier l'IP hôte : `ip:hostPort:containerPort`. Lie le port uniquement à une interface réseau spécifique de l'hôte. Utile si votre hôte a plusieurs adresses IP.
    # Mappe le port 8080 de l'IP 192.168.1.100 au port 80 du conteneur
    docker run -d -p 192.168.1.100:8080:80 nginx
  • Spécifier le protocole : `hostPort:containerPort/udp` (ou `/tcp`).
    # Mappe le port 53 (UDP) de l'hôte au port 53 (UDP) du conteneur (ex: serveur DNS)
    docker run -d -p 53:53/udp my-dns-server
  • Port hôte aléatoire : `containerPort`. Si vous omettez le port hôte, Docker choisira automatiquement un port disponible dans la plage éphémère (généralement > 32768) sur l'hôte et le mappa au port spécifié du conteneur. Utile lorsque le port exact de l'hôte n'a pas d'importance.
    # Mappe le port 80 (TCP) du conteneur à un port aléatoire sur l'hôte
    docker run -d -p 80 nginx
    Vous pouvez voir le port attribué avec `docker port 80` ou `docker ps`.
  • Mapping de plages : `hostPortStart-hostPortEnd:containerPortStart-containerPortEnd` (moins fréquent).

Vous pouvez spécifier l'option `-p` plusieurs fois pour mapper différents ports ou protocoles :

docker run -d -p 8080:80 -p 443:443 my-secure-web-app

Techniquement, Docker utilise des mécanismes comme `iptables` ou `nftables` sur Linux, ou un proxy utilisateur (`docker-proxy`), pour implémenter ces redirections de trafic.

Publication automatique avec `-P` ou `--publish-all`

L'option `-P` (ou `--publish-all`) offre une approche plus automatisée mais moins contrôlée. Lorsque vous utilisez `-P`, Docker examine l'image du conteneur (et ses images parentes) pour trouver les ports qui ont été déclarés avec l'instruction `EXPOSE` dans le Dockerfile.

Rappelons que l'instruction `EXPOSE` dans un Dockerfile sert principalement de documentation pour indiquer quels ports le service à l'intérieur du conteneur est censé écouter. Elle n'effectue pas de publication elle-même. Cependant, l'option `-P` utilise cette information.

Pour chaque port déclaré via `EXPOSE`, `-P` va automatiquement le publier en le mappant à un port aléatoire disponible sur l'hôte (dans la plage éphémère), en respectant le protocole (TCP/UDP) éventuellement spécifié dans l'instruction `EXPOSE`.

Exemple : Supposons que le Dockerfile de l'image `my-custom-app` contienne `EXPOSE 8000` et `EXPOSE 9000/udp`.

docker run -d --name my-app-instance -P my-custom-app

Docker va alors mapper le port 8000 (TCP) du conteneur à un port TCP aléatoire de l'hôte, et le port 9000 (UDP) du conteneur à un port UDP aléatoire de l'hôte. Pour connaître les ports hôtes attribués, vous devez utiliser `docker ps` ou `docker port my-app-instance` :

docker ps
# Output (extrait) :
# PORTS
# 0.0.0.0:32768->8000/tcp, 0.0.0.0:32769->9000/udp

docker port my-app-instance
# Output :
# 8000/tcp -> 0.0.0.0:32768
# 9000/udp -> 0.0.0.0:32769

L'option `-P` est pratique pour rapidement rendre accessible un service dont on ne connaît pas forcément tous les ports exposés, ou lors de tests rapides où les numéros de port hôte importent peu. Cependant, pour des déploiements stables ou en production, l'imprévisibilité des ports hôtes la rend généralement moins adaptée que `-p`.

Choisir entre `-p` et `-P` : considérations et bonnes pratiques

Le choix entre `-p` et `-P` dépend principalement du niveau de contrôle dont vous avez besoin :

  • Utilisez `-p` / `--publish` lorsque :
    • Vous avez besoin de mapper un service à un port spécifique et prévisible sur l'hôte (ex: port 80 ou 443 pour un serveur web).
    • Vous ne voulez exposer qu'un sous-ensemble des ports potentiellement déclarés par `EXPOSE`.
    • Vous devez lier le port à une adresse IP spécifique de l'hôte.
    • Vous travaillez en production ou dans tout scénario nécessitant une configuration réseau stable et explicite. C'est la méthode recommandée dans la majorité des cas.
  • Utilisez `-P` / `--publish-all` lorsque :
    • Vous voulez rapidement exposer tous les ports déclarés par `EXPOSE` sans vous soucier des numéros de port spécifiques sur l'hôte.
    • Utile pour des tests, des démonstrations rapides, ou lorsque l'application consommatrice peut découvrir dynamiquement le port hôte attribué.
    • L'image utilisée documente correctement ses ports via `EXPOSE`.
Points importants à retenir :
  • Conflits de ports : Avec `-p`, si le port hôte spécifié est déjà utilisé par un autre processus (ou un autre conteneur mappé), le lancement du conteneur échouera. Avec `-P`, Docker choisit des ports aléatoires non utilisés, évitant ainsi les conflits.
  • Sécurité : N'exposez que les ports strictement nécessaires. Chaque port exposé augmente la surface d'attaque potentielle de votre application.
  • Communication inter-conteneurs : Rappelez-vous que la publication de ports (`-p` ou `-P`) est principalement destinée à l'accès depuis l'extérieur de l'environnement réseau Docker. Les conteneurs sur le même réseau défini par l'utilisateur n'ont généralement pas besoin de ports publiés pour communiquer entre eux ; ils utilisent leurs adresses IP internes et la résolution DNS par nom.
  • `EXPOSE` vs Publication : Ne confondez pas l'instruction `EXPOSE` dans un Dockerfile (documentation, indice pour `-P`) avec la publication effective via `-p` ou `-P` (création de règles réseau). Un port peut être exposé sans être publié, et inversement (bien que publier un port non exposé soit moins courant).

En maîtrisant les options `-p` et `-P`, vous contrôlez efficacement la manière dont vos services conteneurisés interagissent avec le monde extérieur, une étape cruciale dans le déploiement d'applications avec Docker.