Jak przypisać mapowanie portów do istniejącego kontenera Docker?

436

Nie jestem pewien, czy coś tu źle zrozumiałem, ale wydaje się, że można ustawić mapowanie portów tylko poprzez utworzenie nowego kontenera z obrazu. Czy istnieje sposób przypisania mapowania portów do istniejącego kontenera Docker?

thasmo
źródło
3
Korzystanie z iptables może działać w ten sposób: Odsłanianie portu na kontenerze Docker Live
Choldrim
2
Podejrzewam, że jest to zgodne z projektem. Docker próbuje zmusić cię do „powtarzalności”, a kontener jest rodzajem „systemu zapisu”. Wszystko, co robisz jako krok, który nie wpływa na pojemnik, byłoby łatwym do stracenia krokiem ręcznym. Powiedział inaczej: chcesz, aby Twój kontener reprezentował całą konfigurację niezbędną do działania. Jeśli więc chcesz otworzyć nowy port, musisz utworzyć nowy kontener.
Lance Kind,
2
Stare pytanie i nie odpowiadam na to pytanie, ale chciałbym powiedzieć, że być może ty i ludzie popierający to pytanie i odpowiedzi mogliście całkowicie nie zrozumieć pojęcia dokera. Docker są przeznaczone do aplikacji bezstanowych, które mogą wielokrotnie skalować w górę lub w dół. Nigdy nie należy utrwalać czegoś w kontenerze dla środowiska produkcyjnego, którego nie można odtworzyć, jeśli trzeba utrwalić, zmapuj katalogi. Docker nie jest czymś w rodzaju „light vm”, być może to, czego szukasz, to linuxcontainers.org, lxd opiera się na koncepcji docker, ale z myślą o „light vm”.
Edgar Carvalho
na wypadek, gdyby to pomogło, można użyć narzędzia „Kitematic”, aby dodać mapowanie portów do już działających kontenerów. Powinno to oznaczać, że musi istnieć polecenie dokera, aby zrobić dokładnie to samo, ale z odrobiną googlingu :) Powodzenia
Yaffah

Odpowiedzi:

298

Możesz zmienić mapowanie portów, bezpośrednio edytując hostconfig.jsonplik na /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json

Możesz określić [hash_of_the_container] za pomocą docker inspect <container_name>polecenia, a wartością pola „Id” jest skrót.

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

Dzięki temu nie musisz tworzyć obrazu z takim podejściem. Możesz także zmienić tutaj flagę restartu.

PS Możesz odwiedzić https://docs.docker.com/engine/admin/, aby dowiedzieć się, jak poprawnie zrestartować silnik dokera zgodnie z maszyną hosta. Kiedyś sudo systemctl restart docker, aby ponownie uruchomić Döcker silnik, który jest uruchomiony na Ubuntu 16.04

holdfenytolvaj
źródło
17
Kiedy doker zatrzymuje się, wydaje się, że nadpisuje twoje zmiany, więc 2. zatrzymaj dokerię, 3. zmień plik, 4. uruchom silnik
dokera
5
Próbowałem powyższego i działa. Aby uzyskać więcej informacji, zobacz: mybrainimage.wordpress.com/2017/02/05/…
rohitmohta
11
Ważne jest, aby zatrzymać pojemnik, należy wyłączyć silnik i zmiany zarówno Döcker hostconfig.jsoni config.v2.jsondo tej pracy. Użyj linku podanego przez @rohitmohta, aby zobaczyć szczegóły.
Kalpak Gadre
5
pracował dla mnie, tylko jedna rzecz, jeśli używasz aplikacji dokera na Macu, postępuj zgodnie z instrukcjami tutaj, aby dostać się do folderu / var / lib / docker / container: stackoverflow.com/a/41226917/2048266 , po prostu uruchom screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/ttyPo uruchomieniu tty możesz przejdź do / var / lib /
docker
14
w przypadku systemu Windows, czy ktoś może udostępnić mi lokalizację folderu conatiners.?
Vijay
463

Interesuje mnie również ten problem.

Jak wspomniano w @Thasmo , przekierowanie portów można określić TYLKO za pomocą polecenia docker run(i docker create).
Inne polecenia, docker startnie ma -popcji i docker portwyświetla tylko bieżące przekazywanie.

Aby dodać przekierowanie portów, zawsze wykonuję następujące kroki,

  1. przestań działać pojemnik

    docker stop test01
    
  2. zatwierdzić kontener

    docker commit test01 test02
    

    UWAGA: Powyższe test02jest nowym obrazem, który tworzę z test01kontenera.

  3. ponownie uruchomić z zatwierdzonego obrazu

    docker run -p 8080:8080 -td test02
    

Gdzie pierwszy 8080 to port lokalny, a drugi 8080 to port kontenerowy.

Fujimoto Youichi
źródło
15
Co jeśli chcę zachować nazwę test01?
user69715,
12
Czy ktoś wie, czy istnieje problem z Dockerem, który pozwala na specyfikację portu (--publish) z docker start?
Elijah Lynn
8
A co dzieje się z woluminami w tym scenariuszu?
Andrew Savinykh
78
To okropne rozwiązanie, nie mam pojęcia, jak udało mu się zdobyć 250 głosów pozytywnych. Być może ci, którzy byli uprzywilejowani, nie wiedzieli, jaki bałagan powoduje to rozwiązanie. Tak, to jest okropne i równa się uruchomieniu nowego kontenera działającego na innym porcie.
Arrrr
25
@Arrrr Być może chcesz zostawić lepszą odpowiedź? Jestem pewien, że wszyscy bylibyśmy wdzięczni, gdybyś powiedział nam o wiele lepszy sposób na zrobienie tego.
crockeea,
40

Jeśli przez „istniejące” masz na myśli „uruchamianie”, nie jest możliwe (obecnie) dodanie mapowania portów.

Możesz jednak dynamicznie dodawać nowy interfejs sieciowy, np. Pipework , jeśli chcesz udostępnić usługę w działającym kontenerze bez jej zatrzymywania / restartowania.

jpetazzo
źródło
4
To powinna być najlepsza odpowiedź. Zwięzłe i odnosi się do pytania OP, którego nikt inny nie robi! Czasami wynik ujemny jest wynikiem!
Częściowe zachmurzenie
19

Nie jestem pewien, czy możesz zastosować mapowanie portów działającego kontenera. Możesz zastosować przekierowanie portów podczas uruchamiania kontenera, który różni się od tworzenia nowego kontenera.

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

zacznie działać kontener. W tym samouczku opisano przekierowanie portów.

rajalokan
źródło
2
Tak, wydaje się, że można ustawić tylko opcje takie jak mapowanie portów podczas tworzenia kontenera.
thasmo
20
Do Twojej wiadomości, ta odpowiedź nie jest całkowicie poprawna. docker runtworzy i uruchamia nowy kontener. Jest to równoważne z działaniem, docker createpo którym następuje docker start.
Trevor Sullivan
19

Wydaje się, że edycja pliku hostconfig.json nie działa teraz. Kończy się to tylko ujawnieniem tego portu, ale nie opublikowaniem go na hoście. Zatwierdzanie i odtwarzanie kontenerów nie jest dla mnie najlepszym podejściem. Nikt nie wspomniał docker network?

Najlepszym rozwiązaniem byłoby użycie odwróconego proxy w tej samej sieci

  1. Utwórz nową sieć, jeśli poprzedniego kontenera nie ma w żadnej z nazwanych.

    docker network create my_network

  2. Dołącz istniejący kontener do utworzonej sieci

    docker network connect my_network my_existing_container

  3. Uruchom odwróconą usługę proxy (np. Nginx), publikując potrzebne porty, dołączając do tej samej sieci

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

    Opcjonalnie usuń default.conf z nginx

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

  4. Utwórz nową konfigurację 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;
        }
    }
    

    Skopiuj config do kontenera nginx.

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

  5. Uruchom ponownie nginx

    docker restart nginx

Zalety : Aby opublikować nowe porty, możesz bezpiecznie zatrzymać / zaktualizować / odtworzyć kontener nginx, jak chcesz, bez dotykania kontenera biznesowego. Jeśli potrzebujesz zerowego czasu przestoju dla nginx, możesz dodać więcej odwróconych usług proxy dołączających do tej samej sieci. Poza tym kontener może dołączyć do więcej niż jednej sieci.

Edytować:

Aby odwrócić usługi proxy inne niż HTTP, plik konfiguracyjny jest nieco inny. Oto prosty przykład:

upstream my_service {
    server my_existing_container:9000;
}

server {
    listen 9000;
    proxy_pass my_service;
}
Sean C.
źródło
1
To niesamowite i praktyczne, ale w przypadku systemów korporacyjnych takie podejście wydaje się zaciemniać. O wiele lepiej jest pozwolić, aby pojedynczy system kontrolował przepływ pracy.
Afshin,
1
@Afshin Cóż, w przypadku systemów lub projektów korporacyjnych uważam, że to rozwiązanie jest lepsze niż odtwarzanie (powoduje przestoje) lub włamanie się do pliku hostconfig.json (przynajmniej nie oficjalnie wprowadzonego). Dodatkowy kontener po prostu odsłania wewnętrzny port kontenera firmy, zamiast wprowadzać w nim zmiany.
Sean C.
1
Niesamowite podejście. Musiałem inaczej skonfigurować nginx, aby mój kontener działał za serwerem proxy, ale wydaje się, że to właściwy sposób na robienie rzeczy. Działa również w przypadku wdrażania niebiesko-zielonego.
Brooks DuBois
18

W przykładzie Fujimoto Youichi test01jest kontenerem, a test02obrazem.

Zanim to docker runzrobisz, możesz usunąć oryginalny pojemnik, a następnie ponownie przypisać kontenerowi tę samą nazwę:

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

(Używanie -Pdo wystawiania portów losowym portom zamiast ręcznego przypisywania).

Luca
źródło
12
Proszę bądź świadom. utracisz wszystkie swoje dane, w zależności od aplikacji w środku.
Barry
14

Jeśli uruchomisz docker run <NAME>, pojawi się nowy obraz, który najprawdopodobniej nie jest tym, czego chcesz.

Jeśli chcesz zmienić bieżący obraz, wykonaj następujące czynności:

docker ps -a

Weź identyfikator docelowego kontenera i przejdź do:

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

Zatrzymaj pojemnik:

docker stop <NAME>

Zmień pliki

vi config.v2.json

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

I zmień plik

vi hostconfig.json

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

Uruchom ponownie dokera i powinno działać.

doker-noob
źródło
2
Nie działało to dla mnie w wersji Docker 17.09.0-ce. Po uruchomieniu pliki konfiguracyjne kontenera zostały zastąpione starymi wartościami.
thegeko
3
uruchom ponownie usługę dokowania w systemie hosta @thegeko
yurenchen
1
to działa! tks! 1. zatrzymaj kontener, 2. zmień pliki, 3. uruchom doker ponownie, 4. uruchom ponownie kontener
datdinhquoc
12

Odwrotnie, jeśli nie czujesz się dobrze z konfiguracją głębokości Docker, IPtables będzie twoim przyjacielem.

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}

To tylko sztuczka, a nie zalecany sposób, który działa w moim scenariuszu, ponieważ nie mogłem zatrzymać kontenera, mam nadzieję, że również ci pomoże.

Mansur Ali
źródło
to świetna odpowiedź! Dziękuję Ci! Jeśli chcę map DOCKER_PORTdo MACHINE_PORT, które elementy powinny zostać zmienione?
Ciprian Tomoiagă
Uwaga doker nie będzie wiedział o dodaniu tego podręcznika. Wpisy SO nie są usuwane, gdy później ponownie uruchomisz usługę z dokerem prawidłowo odsłaniającym porty. Więc jeśli coś się zmieni, koniecznie sprawdź dokładnie iptables. Zwłaszcza szukaj zduplikowanych wpisów!
Anthony
8

używamy przydatnych narzędzi, takich jak ssh, aby łatwo to osiągnąć.

Korzystałem z hosta Ubuntu i obrazu dokera opartego na ubuntu.

  1. Wewnątrz dokera zainstalowano klienta openssh.
  2. Zewnętrzny doker (host) ma zainstalowany serwer openssh-server.

gdy trzeba zmapować nowy port,

w oknie dokowanym uruchom następujące polecenie

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

172.17.0.1 to adres IP interfejsu dokera (można go uzyskać, uruchamiając go ifconfig docker0 | grep "inet addr" | cut -f2 -d":" | cut -f1 -d" "na hoście).

tutaj miałem lokalny port 8888 zmapowany z powrotem na hosty 8888. Możesz zmienić port w razie potrzeby.

jeśli potrzebujesz jeszcze jednego portu, możesz zabić ssh i dodać do niego jeszcze jedną linię -R za pomocą nowego portu.

Testowałem to z netcat.

melchi
źródło
2
  1. Zatrzymaj silnik dokera i ten kontener.
  2. Przejdź do /var/lib/docker/containers/${container_id}katalogu i edytujhostconfig.json
  3. Edytować PortBindings.HostPort , że chcesz zmienić.
  4. Uruchom silnik dokera i kontener.
ezileli
źródło
-1

Dla użytkowników Windows i Mac istnieje inny dość łatwy i przyjazny sposób na zmianę portu mapowania:

  1. pobierz kitematic

  2. przejdź do strony ustawień kontenera, na karcie porty, możesz bezpośrednio zmodyfikować tam opublikowany port.

  3. uruchom pojemnik ponownie

Jan
źródło
2
Próbowałem tego podejścia. Kinematic zastosował mapowanie portów. Jednak, aby je zastosować, odtworzył mój pojemnik z oryginalnego obrazu. Jeśli więc boisz się utraty zmian wprowadzonych w samym kontenerze, nie używaj tej metody.
VeganHunter
1
Wolałem to, rozumiem, że nie odpowiada na pytanie i tworzy nowy pojemnik. Ale przynajmniej działa, a ten wynik SO pojawił się podczas mojego wyszukiwania. +1
2b77bee6-5445-4c77-b1eb-4df3e5
-7

Krótka odpowiedź: Nie można przypisać mapowania portów do istniejącego kontenera Docker

Potrzebujesz nowego pojemnika ... poradzisz sobie z tym.

Stephen
źródło
4
Nie ma potrzeby takiego nastawienia. Również w tej odpowiedzi brakuje szczegółów.
lovefaithswing
1
Nie potrzeba szczegółów. Ton ma kluczowe znaczenie dla przekazania oszczędzającej czas odpowiedzi i efemerycznego charakteru pojemników.
Stephen
-11

Jeśli chcesz po prostu zmienić port działającego kontenera, wykonaj następujące czynności:

  1. zatrzymać istniejący kontener

    sudo docker stop NAME

  2. teraz uruchom ponownie z nowym mapowaniem portów

    sudo docker run -d -p 81:80 NAZWA

natomiast:

„-d” do tła / demona dokera

„-p” włącza mapowanie portów

Zewnętrzny („odsłonięty”) port „81”, którego używasz do uzyskiwania dostępu za pomocą przeglądarki

Port nasłuchiwania wewnętrznego kontenera dokującego „80”

Vlad Gulin
źródło
4
To jest po prostu złe. W docker runpoleceniu NAMEznajduje się nazwa obrazu, z którego ma być uruchamiany kontener, natomiast w docker stoppoleceniu NAMEokreśla nazwę kontenera, który ma się zatrzymać.
jonatan
1
„Uruchom dokera” utworzy nowy kontener. Nie może używać tej samej nazwy kontenera co ta, która została zatrzymana, ponieważ możesz mieć tylko jeden kontener o tej nazwie. Musisz więc zrobić: „docker stop NAME”, kontener docker rm NAME, a następnie „docker run -d -p 81:80 NAME”, jak to napisałeś.
Lance Kind,