Een poort blootleggen op een live Docker-container

Ik probeer een Docker-container te maken die fungeert als een volledige virtuele machine. Ik weet dat ik de EXPOSE-instructie in een Dockerfile kan gebruiken om een ​​poort bloot te leggen, en ik kan de vlag -pmet docker rungebruiken om poorten toe te wijzen, maar zodra een container is actief is, is er een commando om extra poorten live te openen/toewijzen?

Stel bijvoorbeeld dat ik een Docker-container heb waarop sshd wordt uitgevoerd. Iemand anders die de container ssh gebruikt, is in en installeert httpd. Is er een manier om poort 80 op de container bloot te leggen en toe te wijzen aan poort 8080 op de host, zodat mensen de webserver in de container kunnen bezoeken zonder deze opnieuw te hoeven opstarten?


Antwoord 1, autoriteit 100%

Je kunt dit niet doen via Docker, maar je hebt wel toegang tot de niet-blootgestelde poort van de container vanaf de hostcomputer.

Als je een container hebt met iets dat op poort 8000 draait, kun je

wget http://container_ip:8000

Voer de 2 opdrachten uit om het IP-adres van de container te krijgen:

docker ps
docker inspect container_name | grep IPAddress

Intern werkt Docker om iptables aan te roepen wanneer u een afbeelding uitvoert, dus misschien werkt een variatie hierop.

Om poort 8000 van de container bloot te leggen op poort 8001 van uw localhost:

iptables -t nat -A  DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000

Een manier waarop u dit kunt oplossen, is door een andere container in te stellen met de gewenste poorttoewijzing en de uitvoer van de opdracht iptables-savete vergelijken (hoewel ik enkele van de andere opties die ervoor zorgen dat het verkeer via de docker-proxy gaat).

OPMERKING: dit ondermijnt Docker, dus moet worden gedaan met het besef dat het blauwe rook kan veroorzaken.

OF

Een ander alternatief is om te kijken naar de (nieuwe? post 0.6.6?) -P optie – die willekeurige hostpoorten zal gebruiken, en die vervolgens te verbinden.

OF

Met 0.6.5 zou je de LINKs-functie kunnen gebruiken om een ​​nieuwe container te openen die met de bestaande praat, met wat extra relais naar de -p-vlaggen van die container? (Ik heb nog geen LINKs gebruikt.)

OF

Met docker 0.11? u kunt docker run --net host ..gebruiken om uw container rechtstreeks aan de netwerkinterfaces van de host te koppelen (dwz net heeft geen namespace) en dus allepoorten die u opent in de container is zichtbaar.


Antwoord 2, autoriteit 39%

Dit is wat ik zou doen:

  • Commiteer de live container.
  • Voer de container opnieuw uit met de nieuwe afbeelding, met de poorten open (ik raad aan om een ​​gedeeld volume te koppelen en ook de ssh-poort te openen)
sudo docker ps 
sudo docker commit <containerid> <foo/live>
sudo docker run -i -p 22 -p 8000:80 -m /data:/data -t <foo/live> /bin/bash

Antwoord 3, autoriteit 18%

Hoewel u een nieuwe poort van een bestaandecontainer niet kunt vrijgeven, kunt u wel een nieuwe container starten in hetzelfde Docker-netwerk en ervoor zorgen dat het verkeer naar de oorspronkelijke container wordt doorgestuurd.

# docker run \
  --rm \
  -p $PORT:1234 \
  verb/socat \
    TCP-LISTEN:1234,fork \
    TCP-CONNECT:$TARGET_CONTAINER_IP:$TARGET_CONTAINER_PORT

Uitgewerkt voorbeeld

Lanceer een webservice die luistert op poort 80, maar nietde interne poort 80 vrijgeeft (oeps!):

# docker run -ti mkodockx/docker-pastebin   # Forgot to expose PORT 80!

Vind het IP-adres van het Docker-netwerk:

# docker inspect 63256f72142a | grep IPAddress
                    "IPAddress": "172.17.0.2",

Lanceer verb/socatmet poort 8080 zichtbaar en zorg ervoor dat het TCP-verkeer doorstuurt naar poort 80 van dat IP-adres:

# docker run --rm -p 8080:1234 verb/socat TCP-LISTEN:1234,fork TCP-CONNECT:172.17.0.2:80

Je hebt nu toegang tot pastebin op http://localhost:8080/, en je verzoeken gaan naar socat:1234die het doorstuurt naar pastebin:80, en het antwoord volgt hetzelfde pad in omgekeerde volgorde.


Antwoord 4, autoriteit 10%

IPtables-hacks werken niet, althans niet op Docker 1.4.1.

De beste manier zou zijn om een ​​andere container te draaien met de blootgestelde poort en door te sturen met socat. Dit is wat ik heb gedaan om (tijdelijk) verbinding te maken met de database met SQLPlus:

docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus

Dockerbestand:

FROM debian:7
RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean
USER nobody
CMD socat -dddd TCP-LISTEN:1521,reuseaddr,fork TCP:db:1521

Antwoord 5, autoriteit 10%

Hier is nog een idee. Gebruik SSH om de poort door te sturen; dit heeft het voordeel dat het ook in OS X (en waarschijnlijk Windows) werkt wanneer uw Docker-host een VM is.

docker exec -it <containterid> ssh -R5432:localhost:5432 <user>@<hostip>

Antwoord 6, autoriteit 2%

Om toe te voegen aan de geaccepteerde antwoordiptables-oplossing, moest ik nog twee opdrachten uitvoeren op de host om deze voor de buitenwereld te openen.

HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https

Opmerking: ik opende poort https (443), het interne IP-adres van mijn docker was 172.17.0.2

Opmerking 2: Deze regels zijn tijdelijk en zullen alleen duren totdat de container opnieuw wordt opgestart


Antwoord 7, autoriteit 2%

Ik had met hetzelfde probleem te maken en kon het oplossen zonder een van mijn actieve containers te stoppen. Dit is een oplossing die up-to-date is vanaf februari 2016, met Docker 1.9.1. Hoe dan ook, dit antwoord is een gedetailleerde versie van het antwoord van @ricardo-branco, maar met meer diepgang voor nieuwe gebruikers.

In mijn scenario wilde ik tijdelijk verbinding maken met MySQL die in een container draait, en aangezien andere applicatiecontainers eraan zijn gekoppeld, was het stoppen, opnieuw configureren en opnieuw uitvoeren van de databasecontainer een niet-starter.

Omdat ik de MySQL-database extern wil benaderen (van Sequel Pro via SSH-tunneling), ga ik poort 33306op de hostcomputer gebruiken. (Niet 3306, voor het geval er een buitenste MySQL-instantie actief is.)

Ongeveer een uur tweaken van iptablesbleek vruchteloos, hoewel:

Stap voor stap, dit is wat ik deed:

mkdir db-expose-33306
cd db-expose-33306
vim Dockerfile

Bewerk dockerfileen plaats dit erin:

# Exposes port 3306 on linked "db" container, to be accessible at host:33306
FROM ubuntu:latest # (Recommended to use the same base as the DB container)
RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean
USER nobody
EXPOSE 33306
CMD socat -dddd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306

Maak vervolgens de afbeelding:

docker build -t your-namespace/db-expose-33306 .

Voer het vervolgens uit en link naar uw actieve container. (Gebruik -din plaats van -rmom het op de achtergrond te houden totdat het expliciet wordt gestopt en verwijderd. Ik wil in dit geval alleen dat het tijdelijk actief is.)

docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306  your-namespace/db-expose-33306

Antwoord 8

Je kunt SSH gebruiken om een ​​tunnel te maken en je container in je host zichtbaar te maken.

Je kunt het op beide manieren doen, van container tot host en van host tot container. Maar je hebt een SSH-tool zoals OpenSSH in beide nodig (client in de ene en server in de andere).

In de container kunt u bijvoorbeeld

$ yum install -y openssh openssh-server.x86_64
service sshd restart
Stopping sshd:                                             [FAILED]
Generating SSH2 RSA host key:                              [  OK  ]
Generating SSH1 RSA host key:                              [  OK  ]
Generating SSH2 DSA host key:                              [  OK  ]
Starting sshd:                                             [  OK  ]
$ passwd # You need to set a root password..

U kunt het IP-adres van de container vinden op deze regel (in de container):

$ ifconfig eth0 | grep "inet addr" | sed 's/^[^:]*:\([^ ]*\).*/\1/g'
172.17.0.2

Dan kun je in de host gewoon het volgende doen:

sudo ssh -NfL 80:0.0.0.0:80 [email protected]

Antwoord 9

Er is een handige HAProxy-wrapper.

docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_HOST=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy

Hiermee wordt een HAProxy gemaakt voor de doelcontainer. easy peasy.


Antwoord 10

Hier zijn enkele oplossingen:

https://forums .docker.com/t/how-to-expose-port-on-running-container/3252/12

De oplossing voor het toewijzen van poorten tijdens het uitvoeren van de container.

docker run -d –net=host myvnc

die de poort automatisch zal blootleggen en toewijzen aan uw host


Antwoord 11

Als geen antwoord voor iemand werkt, controleer dan of uw doelcontainer al in het docker-netwerk draait:

CONTAINER=my-target-container
docker inspect $CONTAINER | grep NetworkMode
        "NetworkMode": "my-network-name",

Bewaar het voor later in de variabele $NET_NAME:

NET_NAME=$(docker inspect --format '{{.HostConfig.NetworkMode}}' $CONTAINER)

Zo ja, dan moet u de proxycontainer in hetzelfde netwerk uitvoeren.

Zoek vervolgens de alias voor de container op:

docker inspect $CONTAINER | grep -A2 Aliases
                "Aliases": [
                    "my-alias",
                    "23ea4ea42e34a"

Bewaar het voor later in de variabele $ALIAS:

ALIAS=$(docker inspect --format '{{index .NetworkSettings.Networks "'$NET_NAME'" "Aliases" 0}}' $CONTAINER)

Voer nu socatuit in een container in het netwerk $NET_NAMEom te overbruggen naar de blootgestelde (maar niet gepubliceerde) poort van de $ALIASed container :

docker run \
    --detach --name my-new-proxy \
    --net $NET_NAME \
    --publish 8080:1234 \
    alpine/socat TCP-LISTEN:1234,fork TCP-CONNECT:$ALIAS:80

Antwoord 12

Op basis van Robms antwoordheb ik een Docker-image en een Bash-script gemaakt met de naam portcat.

Met portcatkunt u eenvoudig meerdere poorten toewijzen aan een bestaande Docker-container. Een voorbeeld met het (optionele) Bash-script:

curl -sL https://raw.githubusercontent.com/archan937/portcat/master/script/install | sudo bash
portcat my-awesome-container 3456 4444:8080

En daar ga je! Portcat brengt in kaart:

  • porteer 3456naar my-awesome-container:3456
  • porteer 4444naar my-awesome-container:8080

Houd er rekening mee dat het Bash-script optioneel is, de volgende commando’s:

ipAddress=$(docker inspect my-awesome-container | grep IPAddress | grep -o '[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}' | head -n 1)
docker run -p 3456:3456 -p 4444:4444 --name=alpine-portcat -it pmelegend/portcat:latest $ipAddress 3456 4444:8080

Ik hoop dat portcatvan pas zal komen voor jullie. Proost!


Antwoord 13

U kunt een overlay-netwerk gebruiken zoals Weave Net, dat een uniek IP-adres toewijst aan elke container en impliciet alle poorten bloot aan elk containerdeel van het netwerk.

Weave biedt ook hostnetwerkintegratie. Het is standaard uitgeschakeld, maar als u ook toegang wilt tot de IP-adressen van de container (en al zijn poorten) vanaf de host, kunt u eenvoudig weave exposeuitvoeren.

Volledige openbaarmaking: ik werk bij Weaveworks.


Antwoord 14

Lees eerst de reactie van Ricardo. Dit werkte voor mij.

Er bestaat echter een scenario waarin dit niet werkt als de actieve container is gestart met docker-compose. Dit komt omdat docker-compose (ik gebruik docker 1.17) een nieuw netwerk maakt. De manier om dit scenario aan te pakken zou zijn:

docker network ls

Voeg dan het volgende toe:

docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name


Antwoord 15

Het is niet mogelijk om live poorttoewijzing uit te voeren, maar er zijn meerdere manieren waarop u een Docker-container kunt geven wat neerkomt op een echte interface zoals een virtuele machine zou hebben.

Macvlan-interfaces

Docker bevat nu een Macvlan-netwerkstuurprogramma. Dit koppelt een Docker-netwerk aan een “echte” interface en stelt u in staat om die netwerkadressen rechtstreeks aan de container toe te wijzen (zoals een overbrugde modus voor virtuele machines).

docker network create \
    -d macvlan \
    --subnet=172.16.86.0/24 \
    --gateway=172.16.86.1  \
    -o parent=eth0 pub_net

pipeworkkan ook een echte interface toewijzenin een container of stel een subinterface inin oudere versies van Docker.

IP’s routeren

Als je controle hebt over het netwerk, kun je extra netwerken routerennaar je Docker-host voor gebruik in de containers.

Vervolgens wijst u dat netwerk toe aan de containers en stelt u uw Docker-host in om de pakketten via het docker-netwerk te routeren.

Gedeelde hostinterface

Met de optie --net hostkan de hostinterface worden gedeeld in een container, maar dit is waarschijnlijk geen goede instelling om meerdere containers op één host te draaien vanwege het gedeelde karakter.

Other episodes