« Architectures Orientées Micro-Services » : différence entre les versions
Aucun résumé des modifications |
|||
(35 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
//page WIP// |
|||
Dans ce projet, nous avons étudié les architectures micro-services que ce soit niveau [https://mbaron.developpez.com/cours/microservices/introduction-generalites/ théorique], ou niveau pratique (via [https://www.docker.com/ Docker]). |
Dans ce projet, nous avons étudié les architectures micro-services que ce soit niveau [https://mbaron.developpez.com/cours/microservices/introduction-generalites/ théorique], ou niveau pratique (via [https://www.docker.com/ Docker]). |
||
= |
= Dans la théorie = |
||
=== Introduction === |
=== Introduction === |
||
Ligne 11 : | Ligne 9 : | ||
Lors de leur invention, cela fut une révolution dans la création des services, les rendant plus rapides et plus économes à grande échelle que les architectures orientées services. |
Lors de leur invention, cela fut une révolution dans la création des services, les rendant plus rapides et plus économes à grande échelle que les architectures orientées services. |
||
=== Architecture logicielle === |
|||
=== Comment marche cette architecture ? === |
|||
*<i>Voir "[https://fr.wikipedia.org/wiki/Architecture_logicielle Architecture Logicielle]" sur wikipédia.</i> |
|||
Cette architecture se base sur l'architecture du Web, dans le sens où il n'y a pas de serveur centralisé. Chaque micro-service est un serveur, que l'on nomme conteneur, et ces conteneurs communiquent entre-eux, afin d'aboutir à ce que l'on recherche. |
|||
Une architecture logicielle décrit l'organisation globale d'un réseau, que ce soit les échanges ou la taille des entités. |
|||
Exemple : |
|||
(| |
|||
=== Architecture orientée micro-services === |
|||
Monolithique: |
|||
<i>insérer schéma arch oms</i> |
|||
Une architecture orientée micro-services se base sur l'architecture du Web, dans le sens où il n'y a pas de serveur centralisé. Chaque micro-service est un serveur, que l'on nomme conteneur, et ces conteneurs communiquent entre-eux, afin d'aboutir à ce que l'on recherche. |
|||
Cette architecture permet un travail à équipe réduite, car l'on assigne une équipe à un micro-service, qui ne nécessite pas de connaître tous les langages, mais uniquement les langages du micro-service sur lequel elle travaille. |
Cette architecture permet un travail à équipe réduite, car l'on assigne une équipe à un micro-service, qui ne nécessite pas de connaître tous les langages, mais uniquement les langages du micro-service sur lequel elle travaille. |
||
Ligne 24 : | Ligne 23 : | ||
De plus, une mise à jour d'une fonctionnalité ne nécessite que la mise à jour du conteneur en question, et non de toute l’infrastructure comme sur une architecture monolithique. |
De plus, une mise à jour d'une fonctionnalité ne nécessite que la mise à jour du conteneur en question, et non de toute l’infrastructure comme sur une architecture monolithique. |
||
Enfin, si une surcharge se produit sur un micro-service car beaucoup d'utilisateurs le demande, |
Enfin, si une surcharge se produit sur un micro-service car beaucoup d'utilisateurs le demande, l'application peut dupliquer ce service sans modifier l'architecture, car les conteneurs prennent source sur le même micro-service et donc gardent en mémoire les conteneurs où les informations sont stockées. |
||
=== Utilisation en entreprise === |
|||
=== Dans quelles types d'entreprises est-elle utilisée ? === |
|||
*Entreprises de vente de masse ([https://www.amazon.fr/ Amazon]) |
*Entreprises de vente de masse ([https://www.amazon.fr/ Amazon]) |
||
*Sites de Streaming Vidéo ou Audio ([https://www.netflix.com/fr/ Netflix] ou [https://www.deezer.com/fr/ Deezer]) |
*Sites de Streaming Vidéo ou Audio ([https://www.netflix.com/fr/ Netflix] ou [https://www.deezer.com/fr/ Deezer]) |
||
*Sites d'information utilisateur dans le domaine du transport (comme la [https://www.sncf.com/fr SNCF] ou [https://www.airfrance.fr/ Air France] |
*Sites d'information utilisateur dans le domaine du transport (comme la [https://www.sncf.com/fr SNCF] ou [https://www.airfrance.fr/ Air France]) |
||
*Applications qui vendent des services en général (comme [https://www.uber.com/fr/fr/ Uber] ou [https://maps.google.fr/ Google Maps]) |
*Applications qui vendent des services en général (comme [https://www.uber.com/fr/fr/ Uber] ou [https://maps.google.fr/ Google Maps]) |
||
=== Comparatif avec les |
=== Comparatif avec les architectures les plus communes === |
||
Ligne 64 : | Ligne 63 : | ||
|} |
|} |
||
= Côté Pratique (Docker) = |
|||
{| class="wikitable plainrowheaders" style="text-align: center; margin:auto; margin:auto;" |
|||
!Monolithique |
|||
!Micro-services |
|||
|- |
|||
|[[Fichier:monolit.png|400px]] |
|||
|[[Fichier:OMS.png|400px]] |
|||
|- |
|||
|} |
|||
= Dans la Pratique (Docker) = |
|||
=== Prérequis === |
|||
*Avoir un système d'exploitation linux (soit une [https://www.oracle.com/virtualization/technologies/vm/downloads/virtualbox-downloads.html machine virtuelle] avec [http://releases.ubuntu.com/ ubuntu] de préférence, soit physique) |
|||
*Avoir des connaissances de base en [https://www.tutorialspoint.com/unix/index.htm bash] et en [https://www.python.org/ python] |
|||
=== Installation === |
=== Installation === |
||
Pour installer Docker, il faut : |
|||
#Ouvrir le terminal de commandes |
|||
#Entrer cette commande : <pre>sudo apt-get update && sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</pre> |
|||
=== Installer un conteneur depuis DockerHub === |
=== Installer un conteneur depuis DockerHub === |
||
=== Créer un conteneur === |
|||
Pour installer un conteneur depuis DockerHub sur notre machine via Docker, il faut : |
|||
#Ouvrir le terminal de commandes |
|||
#Entrer la commande suivante : <pre>docker pull NOM_DU_CONTENEUR</pre> |
|||
Exemple : |
|||
<pre> docker pull romain22222/friendlyhello:Test</pre> permet de télécharger le conteneur romain22222/friendlyhello:Test |
|||
=== Utiliser un conteneur === |
=== Utiliser un conteneur === |
||
#Ouvrir le terminal de commandes |
|||
#Entrer la commande suivante : <pre>docker run -d -p NumPort NOM_IMAGE</pre> |
|||
Ici, <code>run</code> permet de lancer un conteneur à partir d'une image. |
|||
<code>-d</code> permet de faire tourner le conteneur en arrière plan. |
|||
<code>-p NumPort</code> permet de définir le port de votre machine sur lequel le conteneur est relié. Le port est de la forme #A:#B où #A correspond au port de la machine, et #B le port que Docker écoute. |
|||
=== Créer un conteneur === |
|||
Pour créer un conteneur, il faut : |
|||
#Choisir un dossier ou l'on va créer l'image pour ce conteneur |
|||
#Créer un fichier nommé <code>Dockerfile</code> (Voir comment créer un fichier Dockerfile en-dessous) |
|||
#Créer votre projet dans le dossier |
|||
#Ajouter un fichier requirements.txt dans lequel vous devez mettre tous les librairies non-natives pour python (au moins mettre Redis et Flask) |
|||
#Sauvegarder vos fichiers |
|||
#Lancer la commande suivante : <pre>docker build -t NOM_DU_CONTENEUR CHEMIN</pre>, où <code>-t</code> permet de spécifier le nom du conteneur (par défaut, le conteneur aura un nom aléatoire de la forme adjective_knownScientist, exemple : bold_einstein) |
|||
Exemple de fichier Dockerfile : |
|||
<pre> |
|||
FROM ubuntu:16.04 |
|||
RUN apt-get update -y && \ |
|||
apt-get install -y python3-pip python3-dev |
|||
COPY ./requirements.txt /app/requirements.txt |
|||
WORKDIR /app |
|||
RUN pip3 install -r requirements.txt |
|||
COPY . /app |
|||
ENTRYPOINT [ "python3" ] |
|||
CMD [ "app.py" ]</pre> |
|||
*<code>FROM NOM_IMAGE_BASE</code> permet de partir d'une image docker existante (sur la machine ou sur dockerhub) |
|||
*<code>RUN COMMANDE</code> permet de faire les mises à jour nécessaires et les installations hors python afin de faire tourner le conteneur |
|||
*<code>COPY CHEMIN1 CHEMIN2</code> fait une copie d'un fichier ou dossier vers un autre emplacement |
|||
*<code>WORKDIR CHEMIN</code> donne le nom du chemin où va travailler la machine |
|||
*<code>EXPOSE NOM_PORT</code> permet d'ouvrir un port de votre machine afin que le conteneur puisse communiquer (généralement 5000 pour Docker) |
|||
*<code>ENTRYPOINT [ "PREFIX" ]</code> permet d'exécuter les prochaines CMD avec le préfix en argument |
|||
*<code> CMD [ "NOM_FICHIER_PRINCIPAL.py" ]</code> fait tourner python3 avec le fichier de lancement de votre conteneur. |
|||
---- |
|||
Exemple de fichier python pour une page web : |
|||
<pre> |
|||
#!/bin/env python3 |
|||
from flask import Flask |
|||
from redis import Redis, RedisError |
|||
import os |
|||
import socket |
|||
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) |
|||
#définition de l'application |
|||
app = Flask(__name__) |
|||
@app.route('/') |
|||
def hello(): |
|||
try: |
|||
visits = redis.incr("counter") |
|||
except RedisError: |
|||
visits = "<i>Erreur<i>" |
|||
html = "<h3>Hello {name}!<h3>" \ |
|||
"<b>Hostname:</b> {hostname}<br/>" \ |
|||
"<b>Visits:</b> {visits}" |
|||
html+="<ul>" |
|||
for i in range(10): |
|||
html+="<li>{patate} "+str((i/5)**2)+"</li>" |
|||
html+=("</ul>") |
|||
return html.format(name=os.getenv("NAME","world"),hostname=socket.gethostname(),visits=visits,patate="test") |
|||
#lancement de l'application |
|||
if __name__ == "__main__": |
|||
app.run(host='0.0.0.0',port=5000, debug=False) |
|||
#host = adresse d'écoute (si 0.0.0.0, écoute tous les canaux) |
|||
#port = port de connexion sur la machine hôte (laisser à 5000 pour les premiers tests) |
|||
#debug = permet d'activer ou non le mode debug |
|||
</pre> |
|||
=== Publier une image === |
|||
Pour publier une image sur DockerHub, il faut tout d'abord : |
|||
*Créer un compte sur DockerHub et s'y connecter via le terminal |
|||
*Mettre en route l'image sur un conteneur sur la machine |
|||
Suite à cela, la commande à entrer est la suivante : <pre>docker push NOM_IMAGE</pre> |
|||
Il y a cependant une restriction pour le nom de l'image, il doit être de la forme <code>VotrePseudoDocker/NomImage:Tag</code> '''sans''' majuscules. |
|||
=== Faire communiquer deux conteneurs === |
=== Faire communiquer deux conteneurs === |
||
Pour faire communiquer deux conteneurs afin d'échanger des informations (comme un texte, un identifiant, etc.), il faut tout d'abord créer un réseau afin de relier les deux conteneurs. |
|||
Pour cela, il faut entrer la commande suivante : <pre>docker network create --driver bridge NOM_RESEAU</pre> où <code>--driver bridge</code> permet de calquer le réseau sur le driver nommé bridge |
|||
Ensuite, pour connecter un conteneur au réseau, il faut entrer <pre>docker network connect NOM_RESEAU NOM_CONTENEUR</pre> |
|||
A cause d'un crash prématuré de la machine virtuelle, nous n'avons pas pu finir cette partie. |
|||
=== Commandes utiles === |
=== Commandes utiles === |
||
*<code>docker login</code> permet de se connecter à DockerHub via le terminal (il faut se créer un compte au préalable sur le site [https://hub.docker.com/ DockerHub]) |
|||
*<code>docker ps</code> permet de lister les conteneurs créés sur la machine (mettre -la va lister tous les conteneurs ayant existés au moins une fois sur la machine). |
|||
*<code>docker images</code> permet de lister les images qui ont été utilisés sur la machine et celles qui sont en cours d'utilisation par les conteneurs allumés. |
|||
*<code>docker rename OLD_NAME NEW_NAME</code> permet de renommer une image docker. |
|||
*<code>docker tag image NomImage:NewTag</code> permet de changer le tag d'une image docker (par défaut le tag est <code>latest</code>) |
|||
*<code>docker rm NOM_CONTENEUR</code> permet de supprimer un conteneur (il faut que le conteneur soit à l'arrêt pour effectuer la commande) |
|||
*<code>docker system prune</code> supprime les images, les conteneurs et réseaux non-utilisés de la machine. |
|||
*<code>docker stop NOM_CONTENEUR</code> permet d'arrêter un conteneur. |
|||
*<code>docker run -t NOM_CONTENEUR --network NOM_RESEAU NOM_IMAGE</code> permet de démarrer un conteneur et de le connecter sur le réseau en argument. |
|||
*<code>docker network stop NOM_RESEAU</code> arrête le réseau en argument. |
|||
*<code>docker network disconnect NOM_RESEAU NOM_CONTENEUR</code> déconnecte un conteneur d'un réseau. |
|||
*<code>docker network rm NOM_RESEAU</code> supprime un réseau de la machine. |
|||
*<code>docker network inspect NOM_RESEAU</code> affiche les caractéristiques d'un réseau docker, dont les conteneurs connectés dessus ou encore son adresse ip. |
|||
*<code>docker network ls</code> liste les réseaux accessibles via la machine (par défaut, il y a docker0,host et bridge. |
|||
=== Problèmes rencontrés === |
|||
Durant ce projet, des problèmes sont survenus : |
|||
*Si vous rencontrez un manque d'autorisation, rajoutez <code>sudo</code> devant vos commandes pour que docker ait les autorisations nécessaires. |
|||
*Si vous n'arrivez pas à ouvrir la page, essayez les choses suivantes : |
|||
**Echangez les ports dans votre commande <code>docker run</code> |
|||
**Vérifier que vous avez rentré la bonne adresse dans la barre de recherche |
|||
= Liens utiles = |
= Liens utiles = |
||
*[https://mbaron.developpez.com/cours/microservices/introduction-generalites/ Diaporama de cours sur les architectures micro-services] |
|||
[] |
|||
*[https://www.docker.com/ Docker Site officiel] |
|||
[] |
|||
*[https://www.youtube.com/watch?v=YFl2mCHdv24 lien vers une vidéo (pour le php) d'un tutoriel pour Docker] |
|||
[] |
|||
*[https://docs.docker.com/ Documentation Docker Complète] |
|||
*[http://www.alain-andre.fr/docker/ruby/2016/11/08/faire-communiquer-des-conteneurs-docker.html Communication entre conteneurs basique] |
Dernière version du 14 mai 2020 à 13:29
Dans ce projet, nous avons étudié les architectures micro-services que ce soit niveau théorique, ou niveau pratique (via Docker).
Dans la théorie
Introduction
Le terme d'architectures micro-services est apparu aux alentours de 2011 lors d'un workshop sur les différentes architectures logicielles.
Lors de leur invention, cela fut une révolution dans la création des services, les rendant plus rapides et plus économes à grande échelle que les architectures orientées services.
Architecture logicielle
- Voir "Architecture Logicielle" sur wikipédia.
Une architecture logicielle décrit l'organisation globale d'un réseau, que ce soit les échanges ou la taille des entités.
Architecture orientée micro-services
Une architecture orientée micro-services se base sur l'architecture du Web, dans le sens où il n'y a pas de serveur centralisé. Chaque micro-service est un serveur, que l'on nomme conteneur, et ces conteneurs communiquent entre-eux, afin d'aboutir à ce que l'on recherche.
Cette architecture permet un travail à équipe réduite, car l'on assigne une équipe à un micro-service, qui ne nécessite pas de connaître tous les langages, mais uniquement les langages du micro-service sur lequel elle travaille.
De plus, une mise à jour d'une fonctionnalité ne nécessite que la mise à jour du conteneur en question, et non de toute l’infrastructure comme sur une architecture monolithique.
Enfin, si une surcharge se produit sur un micro-service car beaucoup d'utilisateurs le demande, l'application peut dupliquer ce service sans modifier l'architecture, car les conteneurs prennent source sur le même micro-service et donc gardent en mémoire les conteneurs où les informations sont stockées.
Utilisation en entreprise
- Entreprises de vente de masse (Amazon)
- Sites de Streaming Vidéo ou Audio (Netflix ou Deezer)
- Sites d'information utilisateur dans le domaine du transport (comme la SNCF ou Air France)
- Applications qui vendent des services en général (comme Uber ou Google Maps)
Comparatif avec les architectures les plus communes
Architectures | Monolithique | Orientée Services | Orientée Micro-Services |
---|---|---|---|
Forme | Une seule grosse application contenant toutes les fonctions | Une application par type de fonction | Une application par fonction |
Nombres de langages | Un seul pour toute l'application afin de faciliter la communication | Un nombre défini lors de la création du réseau | Autant de langages que l'on veut |
Moyen de communication | Par les données | Par les services | Par les services |
Force du couplage | Fort | Moyen | Faible |
Monolithique | Micro-services |
---|---|
Dans la Pratique (Docker)
Prérequis
- Avoir un système d'exploitation linux (soit une machine virtuelle avec ubuntu de préférence, soit physique)
- Avoir des connaissances de base en bash et en python
Installation
Pour installer Docker, il faut :
- Ouvrir le terminal de commandes
- Entrer cette commande :
sudo apt-get update && sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Installer un conteneur depuis DockerHub
Pour installer un conteneur depuis DockerHub sur notre machine via Docker, il faut :
- Ouvrir le terminal de commandes
- Entrer la commande suivante :
docker pull NOM_DU_CONTENEUR
Exemple :
docker pull romain22222/friendlyhello:Test
permet de télécharger le conteneur romain22222/friendlyhello:Test
Utiliser un conteneur
- Ouvrir le terminal de commandes
- Entrer la commande suivante :
docker run -d -p NumPort NOM_IMAGE
Ici, run
permet de lancer un conteneur à partir d'une image.
-d
permet de faire tourner le conteneur en arrière plan.
-p NumPort
permet de définir le port de votre machine sur lequel le conteneur est relié. Le port est de la forme #A:#B où #A correspond au port de la machine, et #B le port que Docker écoute.
Créer un conteneur
Pour créer un conteneur, il faut :
- Choisir un dossier ou l'on va créer l'image pour ce conteneur
- Créer un fichier nommé
Dockerfile
(Voir comment créer un fichier Dockerfile en-dessous) - Créer votre projet dans le dossier
- Ajouter un fichier requirements.txt dans lequel vous devez mettre tous les librairies non-natives pour python (au moins mettre Redis et Flask)
- Sauvegarder vos fichiers
- Lancer la commande suivante :
docker build -t NOM_DU_CONTENEUR CHEMIN
, où-t
permet de spécifier le nom du conteneur (par défaut, le conteneur aura un nom aléatoire de la forme adjective_knownScientist, exemple : bold_einstein)
Exemple de fichier Dockerfile :
FROM ubuntu:16.04 RUN apt-get update -y && \ apt-get install -y python3-pip python3-dev COPY ./requirements.txt /app/requirements.txt WORKDIR /app RUN pip3 install -r requirements.txt COPY . /app ENTRYPOINT [ "python3" ] CMD [ "app.py" ]
FROM NOM_IMAGE_BASE
permet de partir d'une image docker existante (sur la machine ou sur dockerhub)RUN COMMANDE
permet de faire les mises à jour nécessaires et les installations hors python afin de faire tourner le conteneurCOPY CHEMIN1 CHEMIN2
fait une copie d'un fichier ou dossier vers un autre emplacementWORKDIR CHEMIN
donne le nom du chemin où va travailler la machineEXPOSE NOM_PORT
permet d'ouvrir un port de votre machine afin que le conteneur puisse communiquer (généralement 5000 pour Docker)ENTRYPOINT [ "PREFIX" ]
permet d'exécuter les prochaines CMD avec le préfix en argumentCMD [ "NOM_FICHIER_PRINCIPAL.py" ]
fait tourner python3 avec le fichier de lancement de votre conteneur.
Exemple de fichier python pour une page web :
#!/bin/env python3 from flask import Flask from redis import Redis, RedisError import os import socket redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) #définition de l'application app = Flask(__name__) @app.route('/') def hello(): try: visits = redis.incr("counter") except RedisError: visits = "<i>Erreur<i>" html = "<h3>Hello {name}!<h3>" \ "<b>Hostname:</b> {hostname}<br/>" \ "<b>Visits:</b> {visits}" html+="<ul>" for i in range(10): html+="<li>{patate} "+str((i/5)**2)+"</li>" html+=("</ul>") return html.format(name=os.getenv("NAME","world"),hostname=socket.gethostname(),visits=visits,patate="test") #lancement de l'application if __name__ == "__main__": app.run(host='0.0.0.0',port=5000, debug=False) #host = adresse d'écoute (si 0.0.0.0, écoute tous les canaux) #port = port de connexion sur la machine hôte (laisser à 5000 pour les premiers tests) #debug = permet d'activer ou non le mode debug
Publier une image
Pour publier une image sur DockerHub, il faut tout d'abord :
- Créer un compte sur DockerHub et s'y connecter via le terminal
- Mettre en route l'image sur un conteneur sur la machine
Suite à cela, la commande à entrer est la suivante :
docker push NOM_IMAGE
Il y a cependant une restriction pour le nom de l'image, il doit être de la forme VotrePseudoDocker/NomImage:Tag
sans majuscules.
Faire communiquer deux conteneurs
Pour faire communiquer deux conteneurs afin d'échanger des informations (comme un texte, un identifiant, etc.), il faut tout d'abord créer un réseau afin de relier les deux conteneurs.
Pour cela, il faut entrer la commande suivante :
docker network create --driver bridge NOM_RESEAU
où --driver bridge
permet de calquer le réseau sur le driver nommé bridge
Ensuite, pour connecter un conteneur au réseau, il faut entrer
docker network connect NOM_RESEAU NOM_CONTENEUR
A cause d'un crash prématuré de la machine virtuelle, nous n'avons pas pu finir cette partie.
Commandes utiles
docker login
permet de se connecter à DockerHub via le terminal (il faut se créer un compte au préalable sur le site DockerHub)
docker ps
permet de lister les conteneurs créés sur la machine (mettre -la va lister tous les conteneurs ayant existés au moins une fois sur la machine).docker images
permet de lister les images qui ont été utilisés sur la machine et celles qui sont en cours d'utilisation par les conteneurs allumés.
docker rename OLD_NAME NEW_NAME
permet de renommer une image docker.docker tag image NomImage:NewTag
permet de changer le tag d'une image docker (par défaut le tag estlatest
)
docker rm NOM_CONTENEUR
permet de supprimer un conteneur (il faut que le conteneur soit à l'arrêt pour effectuer la commande)docker system prune
supprime les images, les conteneurs et réseaux non-utilisés de la machine.docker stop NOM_CONTENEUR
permet d'arrêter un conteneur.
docker run -t NOM_CONTENEUR --network NOM_RESEAU NOM_IMAGE
permet de démarrer un conteneur et de le connecter sur le réseau en argument.docker network stop NOM_RESEAU
arrête le réseau en argument.docker network disconnect NOM_RESEAU NOM_CONTENEUR
déconnecte un conteneur d'un réseau.docker network rm NOM_RESEAU
supprime un réseau de la machine.docker network inspect NOM_RESEAU
affiche les caractéristiques d'un réseau docker, dont les conteneurs connectés dessus ou encore son adresse ip.docker network ls
liste les réseaux accessibles via la machine (par défaut, il y a docker0,host et bridge.
Problèmes rencontrés
Durant ce projet, des problèmes sont survenus :
- Si vous rencontrez un manque d'autorisation, rajoutez
sudo
devant vos commandes pour que docker ait les autorisations nécessaires. - Si vous n'arrivez pas à ouvrir la page, essayez les choses suivantes :
- Echangez les ports dans votre commande
docker run
- Vérifier que vous avez rentré la bonne adresse dans la barre de recherche
- Echangez les ports dans votre commande