Accéder au contenu principal

Comment exposer un port Docker

Apprenez à exposer et à publier efficacement des ports dans Docker pour permettre la communication entre vos conteneurs et le monde extérieur. Ce guide couvre tous les aspects de la configuration des fichiers Docker et des drapeaux d'exécution, de l'orchestration de Docker Compose et des techniques de dépannage.
Actualisé 3 juin 2025  · 11 min de lecture

Lorsque vous travaillez avec des conteneurs Docker, l'un des aspects les plus cruciaux que j'ai rencontré est de permettre la communication réseau entre les conteneurs et le monde extérieur. Sans une configuration adéquate des ports, les applications conteneurisées restent isolées et inaccessibles. Dans cet article, je vous guiderai à travers le processus d'exposition des ports Docker, une compétence fondamentale pour toute personne travaillant avec des applications conteneurisées.

Ce guide est spécialement conçu pour les développeurs de logiciels, les ingénieurs DevOps et les professionnels de l'informatique qui doivent rendre leurs applications conteneurisées accessibles aux utilisateurs, à d'autres services ou à des systèmes externes. Que vous déployiez un serveur web, une API ou une base de données dans un conteneur, il est essentiel de comprendre l'exposition aux ports pour construire des systèmes fonctionnels basés sur Docker.

À la fin de cet article, vous aurez une compréhension claire du fonctionnement du réseau Docker, des différentes méthodes d'exposition des ports et des techniques pratiques pour mettre en œuvre ces concepts dans vos propres projets.

Si vous ne connaissez pas Docker, envisagez de suivre l'un de nos cours, tels que Introduction à Docker, Conteneurisation et virtualisation avec Docker et Kubernetes, Docker intermédiaire ou Concepts de conteneurisation et de virtualisation.

Qu'est-ce que l'exposition d'un port dans Docker ?

Avant de plonger dans les détails techniques, il est important de comprendre ce que signifie l'exposition aux ports dans l'écosystème Docker.

Principes d'isolation des réseaux de conteneurs

Les conteneurs Docker sont conçus avec l'isolation comme principe de base. Cet isolement est assuré par des fonctions du noyau Linux telles que les espaces de noms et les cgroups. Les espaces de noms assurent l'isolation des processus, garantissant que les processus d'un conteneur ne peuvent pas voir ou interagir avec les processus d'autres conteneurs ou du système hôte. Les cgroups, quant à eux, contrôlent l'allocation des ressources, en limitant la quantité de CPU, de mémoire et d'autres ressources qu'un conteneur peut consommer.

Du point de vue du réseau, chaque conteneur reçoit son propre espace de noms réseau, avec une interface Ethernet virtuelle (paire veth). Cette interface se connecte par défaut à un réseau de pont Docker, ce qui permet la communication entre les conteneurs tout en maintenant l'isolation par rapport au réseau hôte. Imaginez que chaque conteneur dispose de sa propre adresse réseau privée, invisible au monde extérieur.

Dans sa configuration par défaut, un conteneur Docker est entièrement placé dans un bac à sable. Les services exécutés à l'intérieur peuvent communiquer entre eux, mais ils sont inaccessibles depuis l'extérieur du conteneur, même depuis la machine hôte. C'est là que l'exposition du port devient nécessaire.

Exposer ou publier : distinction sémantique

Lorsque vous travaillez avec la configuration des ports Docker, vous rencontrez deux concepts liés mais distincts : l'exposition et la publication des ports.

L'exposition des ports à l'adresse est avant tout une fonction de documentation. Lorsque vous exposez un port dans Docker, vous ajoutez essentiellement des métadonnées à votre image de conteneur, indiquant que l'application conteneurisée écoute sur des ports spécifiques. 

Cependant, l'exposition d'un port ne le rend pas réellement accessible depuis l'extérieur du conteneur. Il sert de documentation aux utilisateurs de votre image.

La publication de ports à l'adresse est ce qui rend vos services conteneurisés accessibles au monde extérieur. La publication crée une correspondance entre un port sur la machine hôte et un port à l'intérieur du conteneur. Lorsque vous publiez un port, Docker configure le réseau de l'hôte pour transférer le trafic du port de l'hôte spécifié vers le port du conteneur correspondant.

Voici quand utiliser chaque approche :

  • Utiliser exposer lorsque vous construisez des images destinées à être utilisées par d'autres utilisateurs de Docker, afin de documenter les ports utilisés par votre application.
  • Utiliser publier lorsque vous avez besoin que des systèmes externes (y compris l'hôte) accèdent aux services fonctionnant dans votre conteneur.
  • Utilisez les deux ensemble pour une documentation et des fonctionnalités complètes, en particulier dans les environnements de production.

Comment exposer les ports Docker

Maintenant que nous avons compris les concepts, examinons les aspects pratiques de l'exposition des ports Docker dans différents contextes.

Stratégies de déclaration des fichiers Docker

La façon la plus simple d'exposer un port est d'utiliser l'instruction EXPOSE dans votre fichier Docker. Il s'agit de déclarer les ports que le conteneur est censé utiliser.

FROM my-image:latest
EXPOSE 80
EXPOSE 443

Dans cet exemple, j'ai spécifié que le conteneur utilisera les ports 80 et 443, qui sont standard pour le trafic HTTP (Hypertext Transfer Protocol) et HTTPS (Hypertext Transfer Protocol Secure). Vous pouvez également les combiner en une seule instruction :

EXPOSE 80 443

Lorsque vous spécifiez les ports, il est bon d'inclure le protocole, TCP (Transmission Control Protocol) ou UDP (User Datagram Protocol) si votre application en utilise un spécifique :

EXPOSE 53/udp
EXPOSE 80/tcp

Si aucun protocole n'est spécifié, TCP est utilisé par défaut. Cela convient à la plupart des applications web, mais les services tels que le DNS (Domain Name System) ou les serveurs de jeux requièrent souvent l'UDP.

Du point de vue de la sécurité, je recommande de n'exposer que les ports dont votre application a réellement besoin. Chaque port exposé représente un vecteur d'attaque potentiel, de sorte que la minimisation du nombre de ports exposés suit le principe du moindre privilège.

Gestion des ports en cours d'exécution

Alors que l'instruction EXPOSE documente les ports utilisés par un conteneur, pour rendre ces ports accessibles à l'hôte ou à d'autres machines, vous devez les publier lors de l'exécution du conteneur.

Voici comment lier explicitement un port de conteneur à un port d'hôte spécifique :

docker run -p 8081:80 my-image

L'option -p (ou --publish) vous permet de lier un seul port ou une série de ports du conteneur à l'hôte.

Cette commande fait correspondre le port 80 à l'intérieur du conteneur au port 8081 sur l'hôte. Après avoir exécuté cette commande, vous pouvez accéder au serveur web en naviguant vers http://localhost:8081 dans votre navigateur.

Pour faciliter le développement, Docker propose l'option -P, P majuscule ou --publish-all, qui publie automatiquement tous les ports exposés vers des ports aléatoires à numéro élevé sur l'hôte :

docker run -P my-image

Pour savoir quels ports d'hôte ont été attribués, je peux utiliser la commande docker ps:

docker ps

Vous obtiendrez un résultat du type

CONTAINER ID   IMAGE  COMMAND    CREATED  STATUS  PORTS                                  NAMES
a7c53d9413bf   image  "/docker-.…"  10 s ago   Up 9 s    0.0.0.0:49153->80/tcp, :::49153->80/tcp   wizardl

Ici, le port 80 à l'intérieur du conteneur est mappé au port 49153 sur l'hôte.

Lorsque vous travaillez avec des services qui utilisent à la fois TCP et UDP sur le même port (comme les serveurs DNS), vous devez spécifier le protocole lors de la publication :

docker run -p 53:53/tcp -p 53:53/udp dns-server

Orchestration Docker Compose

Pour les applications multi-conteneurs, Docker Compose offre un moyen plus facile à gérer pour configurer le réseau et les ports.

Dans un fichier YAML de Docker Compose, vous pouvez spécifier des mappages de ports sous la clé ports pour chaque service :

services:
  web:
    image: my-image
    ports:
      - "8081:80"
      - "443:443"
  api:
    build: ./api
    ports:
      - "3000:3000"

Docker Compose fait une distinction importante entre ports et expose. La section ports crée des mappages de ports publiés accessibles de l'extérieur, tandis que expose ne met les ports à la disposition que des services liés au sein du même réseau Compose :

services:
  web:
    image: my-image
    ports:
      - "8081:80"
  database:
    image: postgres
    expose:
      - "5432"

Dans cet exemple, le service web est accessible depuis l'hôte sur le port 8081, mais la base de données PostgreSQL n'est accessible qu'aux autres services du fichier Compose, et non directement depuis l'hôte.

Pour des configurations flexibles, en particulier dans des environnements différents, je peux utiliser des variables d'environnement dans les mappages de ports :

services:
  web:
    image: my-image
    ports:
      - "${WEB_PORT:-8081}:80"

Cette syntaxe me permet de spécifier le port de l'hôte par le biais d'une variable d'environnement (WEB_PORT), qui prend par défaut la valeur 8081 si elle n'est pas définie.

Exposer les ports Docker - Exemple pratique

Voyons un exemple complet d'exposition de ports Docker pour une application web avec un backend de base de données.

Imaginez que nous construisions une application web simple composée d'un service API Python Flask et d'une base de données PostgreSQL. Le service API écoute sur le port 5000, et PostgreSQL utilise son port par défaut 5432.

Voici à quoi peut ressembler notre application Flask simple (app.py). Cette application créera une base de données myapp et récupérera les données du tableau items, une fois que ce tableau sera créé dans la base de données.

from flask import Flask, jsonify
import os
import psycopg2

app = Flask(__name__)

# Database connection parameters from environment variables
DB_HOST = os.environ.get('DB_HOST', 'db')
DB_NAME = os.environ.get('DB_NAME', 'myapp')
DB_USER = os.environ.get('DB_USER', 'postgres')
DB_PASS = os.environ.get('DB_PASSWORD', 'postgres')

@app.route('/')
def index():
    return jsonify({'message': 'API is running'})

@app.route('/items')
def get_items():
    # Connect to the PostgreSQL database
    conn = psycopg2.connect(
        host=DB_HOST,
        database=DB_NAME,
        user=DB_USER,
        password=DB_PASS
    )
    
    # Create a cursor and execute a query
    cur = conn.cursor()
    cur.execute('SELECT id, name FROM items')
    
    # Fetch results and format as list of dictionaries
    items = [{'id': row[0], 'name': row[1]} for row in cur.fetchall()]
    
    # Close connections
    cur.close()
    conn.close()
    
    return jsonify(items)

if __name__ == '__main__':
    # Run the Flask app, binding to all interfaces (important for Docker)
    app.run(host='0.0.0.0', port=5000)

Ensuite, je vais créer notre fichier requirements.txt:

flask
psycopg2-binary

Maintenant, je dois créer un fichier Docker pour notre service d'API Python :

FROM python:3.9-slim
WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose the port Flask runs on
EXPOSE 5000

# Command to run the application
CMD ["python", "app.py"]

Enfin, je vais créer un fichier Docker Compose pour orchestrer les deux services :

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      tags:
        - "my-custom-image:latest"
    container_name: my-custom-api
    ports:
      - "5000:5000"
    environment:
      - DB_HOST=db
      - DB_NAME=myapp
      - DB_USER=postgres
      - DB_PASSWORD=postgres
    depends_on:
      - db
  
  db:
    container_name: my-custom-db
    image: postgres:13
    expose:
      - "5432"
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Dans cette configuration :

  1. Le service API se construit à partir de notre fichier Docker et publie le port 5000, ce qui le rend accessible depuis la machine hôte.
  2. Le service PostgreSQL expose le port 5432 mais ne le publie pas, ce qui le rend accessible uniquement aux autres services du réseau Compose.
  3. Le service API peut accéder à la base de données en utilisant le nom d'hôte db (qui est le nom du service) et le port 5432.

Pour exécuter cette application, utilisez :

docker-compose up

Maintenant, je peux accéder à l'API à http://localhost:5000, mais l'instance PostgreSQL n'est pas directement accessible depuis l'extérieur du réseau Docker, ce qui est une bonne pratique de sécurité pour les services de base de données. Mais vous pouvez accéder à PostgreSQL depuis le conteneur en cours d'exécution :

docker compose exec db psql -U postgres -d myapp

Cette commande permet d'accéder au CLI de PostgreSQL, où je peux visualiser la base de données et créer un tableau items. Une fois créé, je peux visualiser les données dans http://localhost:5000/items

Comment exposer plusieurs ports Docker

Si mon application Python doit exposer plusieurs ports, je peux tous les spécifier dans le fichier Dockerfile :

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000 8081 9090
CMD ["python", "app.py"]

Ce fichier Docker expose :

  • Port 5000 pour l'application principale de Flask (actuellement active)
  • Port 8081 pour un éventuel tableau de bord de surveillance 
  • Port 9090 pour une future interface de débogage

Il est important de noter que bien que j'aie exposé les ports 8081 et 9090 dans le fichier Docker comme documentation, mon application Flask actuelle n'est configurée que pour écouter sur le port 5000. Les ports supplémentaires exposés indiquent où des fonctionnalités futures pourraient être mises en œuvre.

Comment publier les ports exposés

Pour publier les ports exposés dans un fichier Docker, j'utilise le drapeau -p ou -P lors de l'exécution du conteneur :

docker run -p 8081:5000  my-custom-image

Cela permet de faire correspondre le port 5000 dans le conteneur (qui est exposé dans le fichier Docker et où Flask est à l'écoute) au port 8081 sur l'hôte. Après avoir exécuté cette commande, je peux accéder à mon application Flask en naviguant vers http://localhost:8081 dans mon navigateur.

Je peux également utiliser l'option -P pour publier automatiquement tous les ports exposés sur des ports aléatoires de l'hôte :

docker run -P my-custom-image

Pour vérifier quels ports sont publiés, je peux utiliser :

docker ps

Pour des informations plus détaillées, je peux utiliser :

docker port [container_id]
5000/tcp -> 0.0.0.0:32768
8081/tcp -> 0.0.0.0:32769
9090/tcp -> 0.0.0.0:32770

Cette commande affiche tous les mappages de ports pour un conteneur spécifique. Par exemple, si mon application Flask n'écoute que sur le port 5000 mais que j'ai exposé plusieurs ports dans le fichier Docker, Docker port me montrera exactement quels ports hôtes sont mappés à quels ports de conteneurs. Ainsi, si le port 5000 a été mappé à 32768, je peux accéder à mon application Flask sous http://localhost:32768

Techniques de diagnostic et de dépannage

Même avec une configuration minutieuse, des problèmes peuvent survenir avec le mappage des ports Docker. Voici quelques techniques que j'utilise pour diagnostiquer et résoudre des problèmes courants.

Inspection de la cartographie portuaire

La première étape du diagnostic des problèmes liés aux ports consiste à vérifier que les mappages sont correctement configurés. J'utilise les commandes suivantes :

Liste de tous les conteneurs en cours d'exécution avec les correspondances de ports :

docker ps

Obtenez des informations détaillées sur un conteneur spécifique :

docker inspect [container_id]

Vérifier le mappage des ports pour un conteneur spécifique :

docker port [container_id]

La commande docker inspect fournit des informations détaillées, notamment sur les paramètres du réseau. Pour vous concentrer sur les détails liés au réseau, utilisez :

docker inspect --format='{{json .NetworkSettings.Ports}}' [container_id] | jq

Si vous devez effectuer une analyse plus approfondie du trafic, des outils tels que tcpdump et netstat peuvent s'avérer très utiles. Tout d'abord, assurez-vous qu'ils sont installés à l'intérieur du conteneur. Si le conteneur n'inclut pas déjà ces outils, vous pouvez les installer en exécutant la commande suivante :

docker exec -u root -it f5c6cac71492 bash -c "apt-get update && apt-get install -y net-tools tcpdump"

Pour visualiser les ports sur lesquels l'application écoute à l'intérieur du conteneur :

docker exec -it [container_id] netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.11:42265        0.0.0.0:*               LISTEN
udp        0      0 127.0.0.11:34267        0.0.0.0:*

Cela montre, par exemple, que l'application Flask est à l'écoute sur toutes les interfaces sur le port 5000.

Pour surveiller le trafic entrant et sortant sur l'interface réseau principale du conteneur (généralement eth0) :

docker exec -it [container_id] tcpdump -i eth0
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

Cette commande vous permet de suivre le trafic et d'identifier si les requêtes atteignent le conteneur ou si les paquets sont abandonnés ou mal acheminés.

Analyse des règles d'Iptables

Docker s'appuie sur iptables pour gérer la traduction d'adresses réseau (NAT) et contrôler le flux de trafic entre l'hôte et les conteneurs. Il insère automatiquement des règles pour transférer les ports de l'hôte vers les IP et les ports appropriés du conteneur, ce qui permet un accès transparent aux services conteneurisés.

Sur les hôtes Linux natifs, vous pouvez inspecter ces règles à l'aide de commandes telles que :

sudo iptables -t nat -L DOCKER -n -v

Cela montre comment Docker fait correspondre le trafic entrant sur des ports d'hôte spécifiques à des points d'extrémité de conteneur. En se basant sur le fichier Docker Compose de tout à l'heure, vous verrez les ports redirigés :

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
   50  3000 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
  100  6000 RETURN     all  --  br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0
  500 30000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:5000 to:172.18.0.2:5000
  400 24000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.18.0.2:5000
  300 18000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:9090 to:172.18.0.2:5000

Ici :

  • DNAT redirigent le trafic de l'hôte vers le conteneur.
  • RETURN garantissent le bon acheminement du trafic réseau interne de Docker.

Cependant, selon votre environnement (par exemple, Docker Desktop sur Windows ou WSL2), Docker peut gérer le transfert de port différemment, et les règles iptables peuvent ne pas être visibles ou modifiables depuis l'intérieur du système. Dans ce cas, vous pouvez vérifier le transfert de port à l'aide de la commande suivante :

sudo ss -tulnp
Netid    State       Recv-Q      Send-Q            Local Address:Port         Peer Address:Port 
tcp        LISTEN     0                 4096                                          *:5000           	        *:*           
tcp        LISTEN     0                 4096                          		   *:8081                               *:*    
tcp        LISTEN     0                 4096                          		   *:9090                              *:*    

Conseils de dépannage :

  • Confirmez le mappage des ports avec docker ps et docker port [container].
  • Vérifiez si le pare-feu du système hôte ou le logiciel de sécurité bloque les ports.
  • Utilisez les journaux des conteneurs et les outils réseau tels que netstat et tcpdump pour vérifier le comportement du réseau de votre application.

Conclusion

L'exposition des ports Docker est une compétence fondamentale qui comble le fossé entre l'isolation conteneurisée et la facilité d'utilisation pratique. Tout au long de cet article, j'ai expliqué le fonctionnement du modèle de réseau de Docker, la différence entre l'exposition et la publication de ports, et j'ai fourni des exemples pratiques pour divers scénarios.

Gardez à l'esprit les points suivants :

  • Utilisez EXPOSE dans les fichiers Docker pour documenter les ports utilisés par votre application.
  • Utilisez -p ou -P lors de l'exécution des conteneurs pour rendre ces ports accessibles de l'extérieur.
  • Tirez parti de Docker Compose pour gérer des applications multi-conteneurs complexes.
  • Utiliser des outils de diagnostic pour résoudre les problèmes lorsqu'ils surviennent.

La maîtrise de ces concepts et techniques vous permettra de concevoir des applications conteneurisées plus robustes qui communiquent efficacement à la fois en interne et avec le monde extérieur. Que vous développiez une simple application web ou une architecture microservices complexe, une bonne gestion des ports est essentielle pour réussir.

Alors que les conteneurs continuent de dominer les stratégies de déploiement d'applications modernes, la capacité à gérer en toute confiance le réseau et les ports Docker restera une compétence essentielle dans la boîte à outils de chaque développeur.

Pour continuer à apprendre, consultez les ressources suivantes :

Exposer un port Docker FAQs

Que signifie exposer un port dans Docker ?

Exposer un port dans Docker est un moyen de documenter les ports sur lesquels votre application conteneurisée écoute, mais cela ne rend pas le port accessible à l'extérieur du conteneur.

Comment rendre le port d'un conteneur Docker accessible depuis ma machine hôte ?

Vous publiez un port en utilisant le drapeau -p avec docker run ou la section ports dans Docker Compose, qui fait correspondre un port hôte au port du conteneur.

Quelle est la différence entre `EXPOSE` et `-p` dans Docker ?

EXPOSE est utilisé dans le fichier Docker pour déclarer les ports pour la documentation, tandis que -p publie et mappe ces ports pour l'accès externe.

Puis-je exposer plusieurs ports pour un seul conteneur Docker ?

Oui, vous pouvez exposer plusieurs ports en utilisant plusieurs instructions EXPOSE dans le fichier Docker ou en spécifiant plusieurs ports dans la section ports de Docker Compose.

Comment résoudre les problèmes de mappage de port Docker ?

Utilisez des commandes telles que docker ps, docker port, docker inspect, et des outils réseau à l'intérieur du conteneur (par exemple, netstat, tcpdump) pour vérifier les mappages de ports et le flux de trafic.


Benito Martin's photo
Author
Benito Martin
LinkedIn

En tant que fondateur de Martin Data Solutions et Data Scientist freelance, ingénieur ML et AI, j'apporte un portefeuille diversifié en régression, classification, NLP, LLM, RAG, réseaux neuronaux, méthodes d'ensemble et vision par ordinateur.

  • A développé avec succès plusieurs projets de ML de bout en bout, y compris le nettoyage des données, l'analyse, la modélisation et le déploiement sur AWS et GCP, en fournissant des solutions impactantes et évolutives.
  • Création d'applications web interactives et évolutives à l'aide de Streamlit et Gradio pour divers cas d'utilisation dans l'industrie.
  • Enseigne et encadre des étudiants en science des données et en analyse, en favorisant leur développement professionnel par le biais d'approches d'apprentissage personnalisées.
  • Conception du contenu des cours pour les applications de génération augmentée par récupération (RAG) adaptées aux exigences de l'entreprise.
  • Rédaction de blogs techniques à fort impact sur l'IA et le ML, couvrant des sujets tels que les MLOps, les bases de données vectorielles et les LLM, avec un engagement significatif.

Dans chaque projet que je prends en charge, je m'assure d'appliquer des pratiques actualisées en matière d'ingénierie logicielle et de DevOps, comme le CI/CD, le linting de code, le formatage, la surveillance des modèles, le suivi des expériences et la gestion robuste des erreurs. Je m'engage à fournir des solutions complètes, en transformant les connaissances sur les données en stratégies pratiques qui aident les entreprises à se développer et à tirer le meilleur parti de la science des données, de l'apprentissage automatique et de l'IA.

Sujets

Les meilleurs cours sur Docker

Cursus

Professional Data Engineer in Python

0 min
Dive deep into advanced skills and state-of-the-art tools revolutionizing data engineering roles today with our Professional Data Engineer track.
Afficher les détailsRight Arrow
Commencer le cours
Voir plusRight Arrow