Comment attribuer un mappage de port à un conteneur Docker existant?

437

Je ne sais pas si j'ai mal compris quelque chose ici, mais il semble qu'il ne soit possible de définir des mappages de ports qu'en créant un nouveau conteneur à partir d'une image. Existe-t-il un moyen d'affecter un mappage de port à un conteneur Docker existant?

thasmo
la source
3
L'utilisation d'iptables peut fonctionner comme cette réponse. Exposer un port sur un conteneur Docker Live
Choldrim
2
Je soupçonne que c'est par conception. Docker essaie de vous forcer à être «répétable» et le conteneur est un type de «système d'enregistrement». Tout ce que vous faites comme étape qui n'affecte pas le conteneur serait une étape manuelle facilement perdue. Autrement dit: vous voulez que votre conteneur représente toute la configuration nécessaire au fonctionnement. Donc, si vous souhaitez ouvrir un nouveau port, vous devez créer un nouveau conteneur.
Lance Kind
2
Vieille question et je n'y réponds pas, mais je voudrais dire que peut-être que vous et les personnes ayant mis à jour cette question et vos réponses ont peut-être complètement mal compris le concept de docker. Docker est destiné aux applications sans état, qui peuvent augmenter ou diminuer plusieurs fois. Vous ne devez jamais persister quelque chose à l'intérieur du conteneur pour un environnement de production qui ne peut pas être recréé, si vous devez persister, mappez les répertoires. Docker n'est pas quelque chose comme un "light vm", peut-être que ce que vous cherchez est linuxcontainers.org, lxd est basé sur le concept de docker mais avec un "light vm" en tête.
Edgar Carvalho
juste au cas où cela pourrait aider, il est possible d'utiliser l'outil "Kitematic" pour ajouter le mappage de port aux conteneurs déjà en cours d'exécution. Cela devrait impliquer qu'il doit y avoir une commande docker pour faire exactement la même chose mais avec un peu de recherche sur Google :) Bonne chance
Yaffah

Réponses:

298

Vous pouvez modifier le mappage de port en modifiant directement le hostconfig.jsonfichier à /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json

Vous pouvez déterminer le [hash_of_the_container] via la docker inspect <container_name>commande et la valeur du champ "Id" est le hachage.

1) stop the container 
2) stop docker service (per Tacsiazuma's comment)
3) change the file
4) restart your docker engine (to flush/clear config caches)
5) start the container

Vous n'avez donc pas besoin de créer une image avec cette approche. Vous pouvez également modifier l'indicateur de redémarrage ici.

PS Vous pouvez visiter https://docs.docker.com/engine/admin/ pour savoir comment redémarrer correctement votre moteur docker selon votre machine hôte. J'ai utilisé sudo systemctl restart dockerpour redémarrer mon moteur docker qui fonctionne sur Ubuntu 16.04

holdfenytolvaj
la source
17
Lorsque le docker s'arrête, il semble écraser vos modifications, donc 2. arrêtez le docker, 3. changez le fichier, 4. démarrez le moteur du docker
Tacsiazuma
5
J'ai essayé ce qui précède et cela fonctionne. Pour plus de détails, voir: mybrainimage.wordpress.com/2017/02/05/…
rohitmohta
11
Il est important d'arrêter le conteneur, d'arrêter le moteur docker et de changer les deux hostconfig.jsonet config.v2.jsonde faire en sorte que cela fonctionne. Utilisez le lien fourni par @rohitmohta pour voir les détails.
Kalpak Gadre
5
a fonctionné pour moi, une seule chose si vous utilisez l'application docker sur mac, suivez les instructions ici pour accéder au dossier / var / lib / docker / containers: stackoverflow.com/a/41226917/2048266 , exécutez essentiellement screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/ttyUne fois que vous obtenez le tty en cours d'exécution, vous pouvez accédez à / var / lib / docker
nommer
14
pour Windows, quelqu'un peut-il me partager l'emplacement du dossier conatiners.?
Vijay
463

Je suis également intéressé par ce problème.

Comme @Thasmo l'a mentionné, les transferts de port peuvent être spécifiés UNIQUEMENT avec la commande docker run(et docker create).
Les autres commandes docker startn'ont pas d' -poption et docker portn'affiche que les renvois en cours.

Pour ajouter des transferts de port, je suis toujours ces étapes,

  1. arrêter l' exécution du conteneur

    docker stop test01
    
  2. valider le conteneur

    docker commit test01 test02
    

    REMARQUE: ce qui précède test02est une nouvelle image que je construis à partir du test01conteneur.

  3. re- initiée à partir de l'image commited

    docker run -p 8080:8080 -td test02
    

Où le premier 8080 est le port local et le second 8080 est le port à conteneurs.

Fujimoto Youichi
la source
15
Et si je veux conserver le nom test01?
user69715
12
Quelqu'un sait-il s'il existe un problème ouvert avec Docker pour autoriser la spécification de port (--publish) avec docker start?
Elijah Lynn
8
Et que se passe-t-il avec les volumes dans ce scénario?
Andrew Savinykh
78
C'est une solution terrible, je ne sais pas comment il a réussi à gagner 250 votes positifs. Peut-être que les votants ne savaient pas quel genre de gâchis cette solution provoque. Oui, c'est terrible, et c'est égal à démarrer un nouveau conteneur fonctionnant sur un port différent.
Arrrr
25
@Arrrr Peut-être aimeriez-vous laisser une meilleure réponse? Je suis sûr que nous apprécierions tous que vous nous disiez la meilleure façon de procéder.
crockeea
40

Si par "existant" vous voulez dire "en cours d'exécution", il n'est pas (actuellement) possible d'ajouter un mappage de port.

Vous pouvez cependant ajouter dynamiquement une nouvelle interface réseau avec par exemple Pipework , si vous avez besoin d'exposer un service dans un conteneur en cours d'exécution sans l'arrêter / le redémarrer.

jpetazzo
la source
4
Cela devrait être la meilleure réponse. Succinct et il répond à la question d'OP qu'aucune des autres ne fait! Parfois, un résultat négatif est un résultat!
Partiellement nuageux
19

Je ne sais pas si vous pouvez appliquer le mappage de port à un conteneur en cours d'exécution. Vous pouvez appliquer la redirection de port lors de l'exécution d'un conteneur qui est différent de la création d'un nouveau conteneur.

$ docker run -p <public_port>:<private_port> -d <image>  

commencera à exécuter le conteneur. Ce didacticiel explique la redirection de port.

rajalokan
la source
2
Oui, il semble donc qu'il ne soit possible de définir des options comme le mappage de port lors de la création du conteneur.
thasmo
20
Pour info cette réponse n'est pas tout à fait correcte. docker runcrée et démarre un nouveau conteneur. C'est équivalent à faire docker createsuivi de docker start.
Trevor Sullivan
19

La modification de hostconfig.json ne semble pas fonctionner maintenant. Il se termine uniquement lorsque ce port est exposé mais pas publié sur l'hôte. Engager et recréer des conteneurs n'est pas la meilleure approche pour moi. Personne n'a mentionné docker network?

La meilleure solution serait d'utiliser un proxy inversé au sein du même réseau

  1. Créez un nouveau réseau si votre conteneur précédent ne figure dans aucun conteneur nommé.

    docker network create my_network

  2. Joignez votre conteneur existant au réseau créé

    docker network connect my_network my_existing_container

  3. Démarrez un service proxy inversé (par exemple nginx) publiant les ports dont vous avez besoin, rejoignant le même réseau

    docker run -d --name nginx --network my_network -p 9000:9000 nginx

    Supprimez éventuellement le fichier default.conf dans nginx

    docker exec nginx rm /etc/nginx/conf.d/default.conf

  4. Créer une nouvelle configuration nginx

    server
    {
        listen 9000;
    
        location / {
            proxy_pass http://my_existing_container:9000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
    

    Copiez la configuration dans le conteneur nginx.

    docker cp ./my_conf.conf nginx:/etc/nginx/conf.d/my_conf.conf

  5. Redémarrez nginx

    docker restart nginx

Avantages : Pour publier de nouveaux ports, vous pouvez arrêter / mettre à jour / recréer en toute sécurité le conteneur nginx comme vous le souhaitez sans toucher au conteneur métier. Si vous n'avez besoin d'aucun temps d'arrêt pour nginx, il est possible d'ajouter plus de services proxy inversés rejoignant le même réseau. En outre, un conteneur peut rejoindre plusieurs réseaux.

Éditer:

Pour inverser les services proxy non http, le fichier de configuration est un peu différent. Voici un exemple simple:

upstream my_service {
    server my_existing_container:9000;
}

server {
    listen 9000;
    proxy_pass my_service;
}
Sean C.
la source
1
C'est incroyable et pratique, mais pour les systèmes d'entreprise, cette approche semble obscurcir. Il est préférable de laisser un seul système contrôler le flux de travail.
Afshin
1
@Afshin Eh bien pour les systèmes ou projets d'entreprise, je pense que cette solution est meilleure que de recréer (cause des temps d'arrêt) ou de pirater le fichier hostconfig.json (du moins pas officiellement introduit). Le conteneur supplémentaire expose simplement le port interne du conteneur de votre entreprise, plutôt que d'y apporter des modifications.
Sean C.
1
Super approche. J'avais besoin de configurer nginx différemment pour que mon conteneur fonctionne derrière un proxy, mais cela semble être la bonne façon de faire les choses. Fonctionne également pour le déploiement bleu-vert.
Brooks DuBois
18

Dans l'exemple de Fujimoto Youichi test01est un conteneur, tandis test02qu'une image.

Avant de le faire, docker runvous pouvez supprimer le conteneur d'origine, puis attribuer de nouveau le même nom au conteneur:

$ docker stop container01
$ docker commit container01 image01
$ docker rm container01
$ docker run -d -P --name container01 image01

(Utilisation -Ppour exposer des ports à des ports aléatoires plutôt que de les attribuer manuellement).

Luca
la source
12
Fait attention. vous PERDREZ toutes vos données, selon l'application à l'intérieur.
Barry
14

Si vous l'exécutez docker run <NAME>, une nouvelle image apparaîtra, ce qui n'est probablement pas ce que vous voulez.

Si vous souhaitez modifier une image actuelle, procédez comme suit:

docker ps -a

Prenez l'id de votre conteneur cible et accédez à:

cd /var/lib/docker/containers/<conainerID><and then some:)>

Arrêtez le conteneur:

docker stop <NAME>

Changer les fichiers

vi config.v2.json

"Config": {
    ....
    "ExposedPorts": {
        "80/tcp": {},
        "8888/tcp": {}
    },
    ....
},
"NetworkSettings": {
....
"Ports": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],

Et changer de fichier

vi hostconfig.json

"PortBindings": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],
     "8888/tcp": [
         {
             "HostIp": "",
             "HostPort": "8888"
         } 
     ]
 }

Redémarrez votre docker et cela devrait fonctionner.

docker-noob
la source
2
Cela ne fonctionnait pas pour moi sur Docker version 17.09.0-ce. Après avoir commencé, les fichiers de configuration du conteneur ont été remplacés par les anciennes valeurs.
thegeko
3
redémarrer le service docker dans le système hôte @thegeko
yurenchen
1
cela marche! tks! Conteneur 1.stop, fichiers 2.change, docker 3.restart, conteneur back
4.start
12

Si vous n'êtes pas à l'aise avec la configuration de profondeur Docker, IPtables serait votre ami.

iptables -t nat -A DOCKER -p tcp --dport ${YOURPORT} -j DNAT --to-destination ${CONTAINERIP}:${YOURPORT}

iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source ${CONTAINERIP} --destination ${CONTAINERIP} --dport ${YOURPORT}

iptables -A DOCKER -j ACCEPT -p tcp --destination ${CONTAINERIP} --dport ${YOURPORT}

C'est juste une astuce et non une manière recommandée, cela fonctionne avec mon scénario, car je ne pouvais pas arrêter le conteneur, j'espère qu'il vous aidera également.

Mansur Ali
la source
C'est une excellente réponse ! Je vous remercie! Si je veux mapper DOCKER_PORTvers MACHINE_PORT, quelles parties doivent être modifiées?
Ciprian Tomoiagă
Notez que docker ne connaîtra pas cet ajout manuel. Les entrées SO ne sont pas supprimées lorsque vous redémarrez ultérieurement le service avec le docker exposant correctement les ports. Donc, lorsque quelque chose change, assurez-vous de vérifier très attentivement iptables. Recherchez particulièrement les entrées en double!
anthony
8

nous utilisons des outils pratiques comme ssh pour y parvenir facilement.

J'utilisais l'hôte ubuntu et l'image de docker basée sur ubuntu.

  1. Dans Docker, le client openssh est installé.
  2. Le docker extérieur (hôte) a un serveur openssh-server installé.

lorsqu'un nouveau port doit être tracé,

à l'intérieur du docker exécutez la commande suivante

ssh -R8888:localhost:8888 <username>@172.17.0.1

172.17.0.1 était l'ip de l'interface docker (vous pouvez l'obtenir en exécutant ifconfig docker0 | grep "inet addr" | cut -f2 -d":" | cut -f1 -d" "sur l'hôte).

ici, j'avais le port 8888 local mappé sur les hôtes 8888. vous pouvez changer le port si nécessaire.

si vous avez besoin d'un port supplémentaire, vous pouvez tuer le ssh et y ajouter une ligne de -R supplémentaire avec le nouveau port.

J'ai testé cela avec netcat.

melchi
la source
2
  1. Arrêtez le moteur docker et ce conteneur.
  2. Accédez au /var/lib/docker/containers/${container_id}répertoire et modifiezhostconfig.json
  3. Modifiez PortBindings.HostPortque vous souhaitez la modification.
  4. Démarrez le moteur docker et le conteneur.
ezileli
la source
-1

Pour les utilisateurs Windows et Mac, il existe un autre moyen assez simple et convivial de modifier le port de mappage:

  1. télécharger kitematic

  2. allez sur la page des paramètres du conteneur, sur l'onglet ports, vous pouvez directement y modifier le port publié.

  3. redémarrer le conteneur

John
la source
2
J'ai essayé cette approche. Kinematic a effectivement appliqué les mappages de ports. Cependant pour les appliquer, il a recréé mon conteneur à partir de l'image d'origine. Donc, si vous avez peur de perdre les modifications apportées au conteneur lui-même, n'utilisez pas cette méthode.
VeganHunter
1
J'ai préféré cela, je comprends que cela ne répond pas à la question, et cela crée un nouveau conteneur. Mais au moins cela fonctionne, et ce résultat SO est apparu lors de ma recherche. +1
2b77bee6-5445-4c77-b1eb-4df3e5
-7

Réponse courte: vous ne pouvez pas affecter un mappage de port à un conteneur Docker existant

Vous avez besoin d'un nouveau conteneur ... traitez-le.

Stephen
la source
4
Pas besoin d'attitude. De plus, cette réponse manque complètement de détails.
lovefaithswing
1
Pas besoin de détails. Le ton est crucial pour transmettre cette réponse qui fait gagner du temps et la nature éphémère des conteneurs.
stephen
-11

Si vous souhaitez simplement modifier le port du conteneur en cours d'exécution, vous devez:

  1. arrêter le conteneur existant

    sudo docker stop NAME

  2. maintenant, redémarrez avec le nouveau mappage de port

    sudo docker run -d -p 81:80 NOM

tandis que:

"-d" à l'arrière-plan / démon du docker

"-p" active le mappage de port

"81" port externe (exposé) que vous utilisez pour accéder avec votre navigateur

Port d'écoute de conteneur docker interne "80"

Vlad Gulin
la source
4
C'est tout simplement faux. Dans la docker runcommande, NAMEest le nom de l'image à partir de laquelle exécuter un conteneur, tandis que dans docker stople NAMEfait référence au nom du conteneur à arrêter.
jonatan
1
"docker run" créera un nouveau conteneur. Il ne peut pas utiliser le même nom de conteneur que celui qui a été arrêté car vous ne pouvez avoir qu'un seul conteneur avec ce nom. Vous devez donc faire: "docker stop NAME", docker container rm NAME, puis "docker run -d -p 81:80 NAME" comme vous l'avez écrit.
Lance Kind