Come posso assegnare un mapping delle porte a un contenitore Docker esistente?


436

Non sono sicuro di aver frainteso qualcosa qui, ma sembra che sia possibile impostare i mapping delle porte solo creando un nuovo contenitore da un'immagine. Esiste un modo per assegnare un mapping delle porte a un contenitore Docker esistente?


3
L'uso di iptables può funzionare come questa risposta Esporre una porta su un container Live Docker
Choldrim

2
Sospetto che ciò avvenga in base alla progettazione. Docker sta cercando di forzarti ad essere "ripetibile" e il contenitore è un tipo di "sistema di registrazione". Qualunque cosa tu faccia come passaggio che non influisce sul contenitore sarebbe un passaggio manuale facilmente perdibile. Detto in altro modo: vuoi che il tuo contenitore rappresenti tutta la configurazione necessaria per operare. Quindi, se si desidera aprire una nuova porta, è necessario creare un nuovo contenitore.
Lance Kind,

2
Vecchia domanda e non sto rispondendo, ma vorrei dire che forse tu e le persone che hanno sollevato questa domanda e le risposte potrebbero aver frainteso del tutto il concetto di docker. Le docker sono per applicazioni senza stato, che possono essere ingrandite o ridotte più volte. Non si dovrebbe mai persistere qualcosa all'interno del contenitore per un ambiente di produzione che non può essere ricreato, se è necessario persistere, mappare le directory. Docker non è qualcosa come un "light vm", forse quello che stai cercando è linuxcontainers.org, lxd è basato sul concetto di docker ma con un "light vm" in mente.
Edgar Carvalho,

nel caso in cui ciò possa essere d'aiuto, è possibile utilizzare lo strumento "Kitematic" per aggiungere il mapping delle porte ai container già in esecuzione. Ciò dovrebbe implicare che ci deve essere un comando docker per fare esattamente la stessa cosa ma con un po 'di google :) Buona fortuna
Yaffah,

Risposte:


298

È possibile modificare il mapping delle porte modificando direttamente il hostconfig.jsonfile in /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json

È possibile determinare [hash_of_the_container] tramite il docker inspect <container_name>comando e il valore del campo "Id" è l'hash.

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

Quindi non è necessario creare un'immagine con questo approccio. Puoi anche cambiare il flag di riavvio qui.

PS È possibile visitare https://docs.docker.com/engine/admin/ per informazioni su come riavviare correttamente il motore docker secondo il computer host. Ho usato sudo systemctl restart dockerper riavviare il mio motore docker che è in esecuzione su Ubuntu 16.04


17
Quando la finestra mobile si interrompe, sembra sovrascrivere le modifiche, quindi 2. ferma la finestra mobile, 3. modifica il file, 4. avvia il motore della finestra mobile
Tacsiazuma

5
Ho provato quanto sopra e funziona. Per maggiori dettagli vedi: mybrainimage.wordpress.com/2017/02/05/…
rohitmohta

11
È importante arrestare il container, arrestare il motore docker e cambiare entrambi hostconfig.jsone config.v2.jsonfar funzionare tutto questo. Usa il link fornito da @rohitmohta per vedere i dettagli.
Kalpak Gadre,

5
ha funzionato per me, solo una cosa se si utilizza l'app docker su Mac, seguire le istruzioni qui per accedere alla cartella / var / lib / docker / containers: stackoverflow.com/a/41226917/2048266 , in pratica eseguire screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/ttyUna volta che tty è in esecuzione è possibile vai a / var / lib / docker
nommer il

14
per Windows, qualcuno può condividere la posizione della cartella conatiners.
Vijay,

463

Sono anche interessato a questo problema.

Come menzionato @Thasmo , i port forwarding possono essere specificati SOLO con il comando docker run(e docker create).
Altri comandi, docker startnon ha -popzione e docker portvisualizza solo gli inoltri correnti.

Per aggiungere il port forwarding, seguo sempre questi passaggi,

  1. interrompere l' esecuzione del contenitore

    docker stop test01
    
  2. impegnare il contenitore

    docker commit test01 test02
    

    NOTA: quanto sopra test02è una nuova immagine che sto costruendo dal test01contenitore.

  3. ri correre dall'immagine Commited

    docker run -p 8080:8080 -td test02
    

Dove il primo 8080 è la porta locale e il secondo 8080 è la porta del contenitore.


15
Cosa succede se voglio mantenere il nome test01?
user69715

12
Qualcuno sa se c'è un problema aperto con Docker per consentire la specifica della porta (--publish) con docker start?
Elijah Lynn,

8
E cosa succede con i volumi in questo scenario?
Andrew Savinykh,

78
Questa è una soluzione terribile, non ho idea di come sia riuscito a guadagnare 250 voti. Forse quelli come votati non sapevano che tipo di casino causasse questa soluzione. Sì, è terribile ed equivale ad avviare un nuovo contenitore in esecuzione su una porta diversa.
Arrrr,

25
@Arrrr Forse ti piacerebbe lasciare una risposta migliore? Sono sicuro che apprezzeremmo tutti se ci dicessi il modo migliore per farlo.
crockeea,

40

Se per "esistente" intendi "in esecuzione", allora non è (attualmente) possibile aggiungere un mapping delle porte.

Tuttavia, è possibile aggiungere dinamicamente una nuova interfaccia di rete con ad esempio Pipework , se è necessario esporre un servizio in un container in esecuzione senza arrestarlo / riavviarlo.


4
Questa dovrebbe essere la risposta migliore. Succinto e affronta la domanda di OP che nessuno degli altri fa! A volte un risultato negativo è un risultato!
Parzialmente nuvoloso

19

Non sono sicuro se è possibile applicare il mapping delle porte a un contenitore in esecuzione. È possibile applicare il port forwarding mentre si esegue un contenitore diverso dalla creazione di un nuovo contenitore.

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

inizierà l'esecuzione del contenitore. Questo tutorial spiega il reindirizzamento delle porte.


2
Sì, quindi sembra che sia possibile impostare opzioni come il mapping delle porte alla creazione del contenitore.
thasmo,

20
Cordiali saluti questa risposta non è del tutto corretta. docker runcrea e avvia un nuovo contenitore. È equivalente a fare docker createseguito da docker start.
Trevor Sullivan,

19

La modifica di hostconfig.json sembra non funzionare ora. Termina solo con quella porta esposta ma non pubblicata per ospitare. Commettere e ricreare contenitori non è l'approccio migliore per me. Nessuno menzionato docker network?

La soluzione migliore sarebbe utilizzare il proxy inverso all'interno della stessa rete

  1. Crea una nuova rete se il tuo contenitore precedente non si trova in quelli con nome.

    docker network create my_network

  2. Unisci il tuo contenitore esistente alla rete creata

    docker network connect my_network my_existing_container

  3. Avvia un servizio proxy inverso (ad es. Nginx) pubblicando le porte necessarie, unendoti alla stessa rete

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

    Facoltativamente, rimuovere default.conf in nginx

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

  4. Crea una nuova configurazione 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;
        }
    }
    

    Copia la configurazione nel contenitore nginx.

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

  5. Riavvia nginx

    docker restart nginx

vantaggi : per pubblicare nuove porte, è possibile arrestare / aggiornare / ricreare in sicurezza il contenitore nginx come desiderato senza toccare il contenitore aziendale. Se è necessario zero tempi di inattività per nginx, è possibile aggiungere altri servizi proxy invertiti unendosi alla stessa rete. Inoltre, un contenitore può unire più di una rete.

Modificare:

Per invertire i servizi proxy non http, il file di configurazione è leggermente diverso. Qui c'è un semplice esempio:

upstream my_service {
    server my_existing_container:9000;
}

server {
    listen 9000;
    proxy_pass my_service;
}

1
È sorprendente e pratico, ma per i sistemi aziendali questo approccio sembra offuscare. È molto meglio lasciare che un singolo sistema controlli il flusso di lavoro.
Afshin

1
@Afshin Beh, per sistemi o progetti aziendali, penso che questa soluzione sia meglio che ricreare (causa tempi di inattività) o hackerare il file hostconfig.json (almeno non introdotto ufficialmente). Il container aggiuntivo espone semplicemente la porta interna del container aziendale, anziché apportare modifiche.
Sean C.

1
Approccio fantastico. Avevo bisogno di configurare nginx in modo diverso affinché il mio contenitore funzionasse dietro un proxy, ma sembra il modo corretto di fare le cose. Funziona anche per la distribuzione blu-verde.
Brooks DuBois,

18

Nell'esempio di Fujimoto Youichi test01è un contenitore, mentre test02è un'immagine.

Prima di fare docker run è possibile rimuovere il contenitore originale e quindi assegnare nuovamente al contenitore lo stesso nome:

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

(Utilizzo -Pper esporre le porte a porte casuali anziché assegnarle manualmente).


12
Si prega di essere consapevoli. perderai tutti i tuoi dati, a seconda dell'applicazione all'interno.
Barry,

14

Se corri docker run <NAME> , verrà generata una nuova immagine, che molto probabilmente non è ciò che desideri.

Se si desidera modificare un'immagine corrente, procedere come segue:

docker ps -a

Prendi l'id del tuo contenitore di destinazione e vai a:

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

Ferma il contenitore:

docker stop <NAME>

Cambia i file

vi config.v2.json

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

E cambia file

vi hostconfig.json

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

Riavvia la finestra mobile e dovrebbe funzionare.


2
Questo non ha funzionato per me sulla versione Docker 17.09.0-ce. Dopo aver avviato il file di configurazione del contenitore, i file sono stati sovrascritti ai vecchi valori.
thegeko,

3
riavviare il servizio docker nel sistema host @thegeko
yurenchen,

1
questo funziona! tks! 1.stop container, 2.change files, 3.restart docker, 4.start back container
datdinhquoc

12

Al contrario, se non ti senti a tuo agio con la configurazione della profondità Docker, IPtables sarebbe tuo amico.

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}

Questo è solo un trucco non un modo raccomandato che funziona con il mio scenario perché non sono riuscito a fermare il contenitore, spero che possa aiutarti anche tu.


questa è un'ottima risposta! Grazie! Se voglio mappare DOCKER_PORTa MACHINE_PORT, quali parti dovrebbe essere cambiato?
Ciprian Tomoiagă,

Nota: la finestra mobile non sarà a conoscenza di questa aggiunta manuale. Le voci SO non vengono rimosse quando si riavvia in seguito il servizio con la finestra mobile che espone correttamente le porte. Quindi, quando qualcosa cambia, assicurati di controllare iptables con molta attenzione. Soprattutto cercare voci duplicate!
Anthony

8

usiamo strumenti utili come ssh per farlo facilmente.

Stavo usando l'host di Ubuntu e l'immagine docker basata su Ubuntu.

  1. Nella finestra mobile interna è installato openssh-client.
  2. La finestra mobile esterna (host) ha installato il server openssh-server.

quando è necessario mappare una nuova porta,

all'interno della finestra mobile eseguire il comando seguente

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

172.17.0.1 era l'ip dell'interfaccia docker (puoi ottenerlo eseguendo ifconfig docker0 | grep "inet addr" | cut -f2 -d":" | cut -f1 -d" "sull'host).

qui avevo la porta 8888 locale mappata di nuovo agli host 8888. puoi cambiare la porta secondo necessità.

se hai bisogno di un'altra porta, puoi uccidere ssh e aggiungere un'altra linea di -R con la nuova porta.

Ho provato questo con netcat.


2
  1. Arrestare il motore docker e quel contenitore.
  2. Vai alla /var/lib/docker/containers/${container_id}directory e modificahostconfig.json
  3. Modifica PortBindings.HostPortche desideri il cambiamento.
  4. Avviare il motore e il contenitore della finestra mobile.

-1

Per utenti Windows e Mac, esiste un altro modo abbastanza semplice e amichevole per cambiare la porta di mappatura:

  1. scarica kitematic

  2. vai alla pagina delle impostazioni del contenitore, nella scheda porte, puoi direttamente modificare la porta pubblicata lì.

  3. riavviare il contenitore


2
Ho provato questo approccio. Kinematic ha effettivamente applicato le mappature delle porte. Tuttavia, per applicarli, ha ricreato il mio contenitore dall'immagine originale. Quindi, se hai paura di perdere le modifiche apportate nel contenitore stesso, non utilizzare questo metodo.
VeganHunter,

1
Ho preferito questo, ho capito che non risponde alla domanda e crea un nuovo contenitore. Ma almeno funziona e questo risultato SO è apparso durante la mia ricerca. +1
2b77bee6-5445-4c77-b1eb-4df3e5

-7

Risposta breve: non è possibile assegnare un mapping delle porte a un contenitore Docker esistente

Hai bisogno di un nuovo contenitore ... affrontalo.


4
Non è necessario l'atteggiamento. Anche questa risposta è completamente priva di dettagli.
lovefaithswing,

1
Non è necessario per i dettagli. Il tono è cruciale per trasmettere questa risposta che fa risparmiare tempo e la natura effimera dei contenitori.
Stephen

-11

Se vuoi semplicemente cambiare la porta del container in esecuzione, fai:

  1. interrompere il contenitore esistente

    sudo docker stop NAME

  2. ora riavviare con la nuova mappatura delle porte

    sudo docker run -d -p 81:80 NAME

mentre:

"-d" per mettere in background / deamon la finestra mobile

"-p" abilita il mapping delle porte

Porta "81" esterna (esposta) che usi per accedere con il tuo browser

Porta di ascolto del contenitore finestra mobile interna "80"


4
Questo è semplicemente sbagliato. Nel docker runcomando, NAMEè il nome dell'immagine per eseguire un contenitore da, mentre docker stopla NAMEsi riferisce al nome del contenitore di arresto.
jonatan

1
"docker run" creerà un nuovo contenitore. Non può utilizzare lo stesso nome contenitore di quello che è stato arrestato perché è possibile avere un solo contenitore con quel nome. Quindi dovresti fare: "docker stop NAME", contenitore docker rm NAME, quindi "docker run -d -p 81:80 NAME" come l'hai scritto.
Lance Kind,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.