Leiten Sie den Host-Port an den Docker-Container weiter

166

Ist es möglich, dass ein Docker-Containerzugriffsport vom Host geöffnet wird? Konkret habe ich MongoDB und RabbitMQ auf dem Host ausgeführt und möchte einen Prozess in einem Docker-Container ausführen, um die Warteschlange abzuhören und (optional) in die Datenbank zu schreiben.

Ich weiß, dass ich einen Port vom Container an den Host weiterleiten kann (über die Option -p) und über den Docker-Container eine Verbindung zur Außenwelt (dh zum Internet) herstellen kann, möchte jedoch die Ports RabbitMQ und MongoDB nicht verfügbar machen vom Gastgeber nach außen.

EDIT: einige Klarstellung:

Starting Nmap 5.21 ( http://nmap.org ) at 2013-07-22 22:39 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00027s latency).
PORT     STATE SERVICE
6311/tcp open  unknown

joelkuiper@vps20528 ~ % docker run -i -t base /bin/bash
root@f043b4b235a7:/# apt-get install nmap
root@f043b4b235a7:/# nmap 172.16.42.1 -p 6311 # IP found via docker inspect -> gateway

Starting Nmap 6.00 ( http://nmap.org ) at 2013-07-22 20:43 UTC
Nmap scan report for 172.16.42.1
Host is up (0.000060s latency).
PORT     STATE    SERVICE
6311/tcp filtered unknown
MAC Address: E2:69:9C:11:42:65 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 13.31 seconds

Ich musste diesen Trick ausführen, um eine Internetverbindung mit dem Container herzustellen: Meine Firewall blockiert Netzwerkverbindungen vom Docker-Container nach außen

BEARBEITEN : Schließlich habe ich eine benutzerdefinierte Brücke mithilfe von Rohrleitungen erstellt und die Dienste die IP-Adressen der Brücke abhören lassen. Ich habe mich für diesen Ansatz entschieden, anstatt MongoDB und RabbitMQ auf der Docker-Bridge abhören zu lassen, da dies mehr Flexibilität bietet.

JoelKuiper
quelle

Antworten:

53

Ihr Docker-Host stellt einen Adapter für alle Container bereit. Angenommen, Sie sind auf dem neuesten Ubuntu, können Sie ausführen

ip addr

Auf diese Weise erhalten Sie eine Liste der Netzwerkadapter, von denen einer ungefähr so ​​aussieht

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 22:23:6b:28:6b:e0 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
inet6 fe80::a402:65ff:fe86:bba6/64 scope link
   valid_lft forever preferred_lft forever

Sie müssen Kaninchen / Mongo anweisen, sich an diese IP zu binden (172.17.42.1). Danach sollten Sie in der Lage sein, Verbindungen zu 172.17.42.1 aus Ihren Containern heraus zu öffnen.

Seldo
quelle
35
Woher weiß der Container, an welche IP Anforderungen gesendet werden sollen? Ich kann den Wert fest codieren (172.17.42.1 hier und auf meinem Prüfstand, aber stimmt das immer?), Aber das scheint gegen die Docker-Prinzipien der Arbeit mit jedem Host zu verstoßen!
JP.
2
@Seldo: Muss diese Schnittstelle konfiguriert werden, um angezeigt zu werden? Ich benutze Docker 1.7.1 und habe nur lound eth0.
Mknecht
8
Ist das irgendwie möglich, wenn der Host nur 127.0.0.1 hört?
HansHarhoff
5
"Sie müssen rabbit / mongo anweisen, sich an diese IP zu binden (172.17.42.1). Danach sollten Sie in der Lage sein, Verbindungen zu 172.17.42.1 aus Ihren Containern heraus zu öffnen." Wäre schön, wenn Sie erklären würden, wie das geht
Novaterata
1
Kann jemand, wie @Novaterata erwähnte, diesen Prozess erklären?
Keskinsaf
121

Ein einfacher, aber relativ unsicherer Weg wäre, die --net=hostOption zu nutzen docker run.

Diese Option bewirkt, dass der Container den Netzwerkstapel des Hosts verwendet. Anschließend können Sie eine Verbindung zu Diensten herstellen, die auf dem Host ausgeführt werden, indem Sie einfach "localhost" als Hostnamen verwenden.

Dies ist einfacher zu konfigurieren, da Sie den Dienst nicht so konfigurieren müssen, dass Verbindungen von der IP-Adresse Ihres Docker-Containers akzeptiert werden, und Sie müssen dem Docker-Container nicht nur eine bestimmte IP-Adresse oder einen bestimmten Hostnamen mitteilen, zu der bzw. dem eine Verbindung hergestellt werden soll ein Hafen.

Sie können es beispielsweise testen, indem Sie den folgenden Befehl ausführen, der davon ausgeht, dass Ihr Image aufgerufen wird my_image, Ihr Image das telnetDienstprogramm enthält und der Dienst, zu dem Sie eine Verbindung herstellen möchten, sich an Port 25 befindet:

docker run --rm -i -t --net=host my_image telnet localhost 25

Wenn Sie dies in Betracht ziehen, lesen Sie bitte die Sicherheitshinweise auf dieser Seite:

https://docs.docker.com/articles/networking/

Es sagt:

--net = host - Weist Docker an, das Platzieren des Containers in einem separaten Netzwerkstapel zu überspringen. Im Wesentlichen weist diese Auswahl Docker an, das Netzwerk des Containers nicht zu containerisieren! Während Containerprozesse weiterhin auf ihre eigenen Dateisystem-, Prozesslisten- und Ressourcenbeschränkungen beschränkt sind, zeigt Ihnen ein schneller Befehl ip addr, dass sie netzwerkmäßig „außerhalb“ im Docker-Haupthost leben und vollen Zugriff auf die Netzwerkschnittstellen haben . Beachten Sie, dass der Container dadurch den Host-Netzwerkstapel nicht neu konfigurieren kann - dies würde erfordern --privileged = true -, aber Containerprozesse können wie jeder andere Root-Prozess Ports mit niedriger Nummer öffnen. Außerdem kann der Container auf lokale Netzwerkdienste wie den D-Bus zugreifen. Dies kann dazu führen, dass Prozesse im Container unerwartete Dinge wie den Neustart Ihres Computers ausführen können.

David Grayson
quelle
12
Für alle, die Docker unter Linux nicht verwenden (z. B. Virtualisierung), funktioniert dies nicht, da der Host die enthaltende VM und nicht das eigentliche Host-Betriebssystem ist.
Sebastian Graf
13
Insbesondere unter MacOS ist dies nicht möglich (ohne einige Problemumgehungen
pje
15
Funktioniert unter MacOS --net=hostnicht, wenn Ihr Containerprozess mithilfe von eine Verbindung zu Ihrem Hostcomputer herstellen kann localhost. Stattdessen haben Sie Ihre Container nur Hostnamen auf die speziellen MacOS verbinden docker.for.mac.host.internalstatt localhost. Es sind keine zusätzlichen Parameter erforderlich, docker rundamit dies funktioniert. Sie können dies als env var übergeben, -ewenn Sie Ihre Containerplattform agnostisch halten möchten. Auf diese Weise können Sie eine Verbindung zu dem in env var genannten Host herstellen und docker.for.mac.host.internalMacOS und localhostLinux weitergeben.
TUL
18
Der neueste Hostname für Mac ist host.docker.internal, siehe doc
xysun
Das Gleiche gilt für Windows - docker run --rm -it --net=host postgres bashdannpsql -h host.docker.internal -U postgres
Leo Cavalcante
12

Sie können auch einen SSH-Tunnel erstellen.

docker-compose.yml::

---

version: '2'

services:
  kibana:
    image: "kibana:4.5.1"
    links:
      - elasticsearch
    volumes:
      - ./config/kibana:/opt/kibana/config:ro

  elasticsearch:
    build:
      context: .
      dockerfile: ./docker/Dockerfile.tunnel
    entrypoint: ssh
    command: "-N elasticsearch -L 0.0.0.0:9200:localhost:9200"

docker/Dockerfile.tunnel::

FROM buildpack-deps:jessie

RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive \
    apt-get -y install ssh && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

COPY ./config/ssh/id_rsa /root/.ssh/id_rsa
COPY ./config/ssh/config /root/.ssh/config
COPY ./config/ssh/known_hosts /root/.ssh/known_hosts
RUN chmod 600 /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/config && \
    chown $USER:$USER -R /root/.ssh

config/ssh/config::

# Elasticsearch Server
Host elasticsearch
    HostName jump.host.czerasz.com
    User czerasz
    ForwardAgent yes
    IdentityFile ~/.ssh/id_rsa

Auf diese Weise elasticsearchverfügt der über einen Tunnel zum Server mit dem ausgeführten Dienst (Elasticsearch, MongoDB, PostgreSQL) und macht Port 9200 mit diesem Dienst verfügbar.

czerasz
quelle
8
Sie fügen den privaten Schlüssel im Docker-Image ein. Geheimnisse sollten niemals in ein Docker-Image gelangen.
Teoh Han Hui
2
Dies ist die bislang einzige vernünftige Lösung.
Helvete
5

Ich hatte ein ähnliches Problem beim Zugriff auf einen LDAP-Server von einem Docker-Container aus. Ich habe eine feste IP für den Container festgelegt und eine Firewall-Regel hinzugefügt.

docker-compose.yml:

version: '2'
services:
  containerName:
    image: dockerImageName:latest
    extra_hosts:
      - "dockerhost:192.168.50.1"
    networks:
      my_net:
        ipv4_address: 192.168.50.2
networks:
  my_net:
    ipam:
      config:
      - subnet: 192.168.50.0/24

iptables-Regel:

iptables -A INPUT -j ACCEPT -p tcp -s 192.168.50.2 -d $192.168.50.1 --dport portnumberOnHost

Innerhalb des Containerzugangs dockerhost:portnumberOnHost

Arigion
quelle
3

Wenn MongoDB und RabbitMQ auf dem Host ausgeführt werden, sollte der Port bereits verfügbar sein, da er sich nicht in Docker befindet.

Sie benötigen die -pOption nicht , um Ports vom Container zum Host verfügbar zu machen. Standardmäßig sind alle Ports verfügbar. Mit dieser -pOption können Sie einen Port vom Container zur Außenseite des Hosts freigeben.

Also, meine Vermutung ist, dass Sie überhaupt nicht brauchen -pund es sollte gut funktionieren :)

knarren
quelle
1
Ich wusste das, aber es scheint, dass mir ein paar Informationen fehlen: siehe die letzte Bearbeitung, da ich die Ports auf dem Host nicht erreichen kann.
JoelKuiper
2
Sie müssen rabbitmq und mongodb einrichten, um auch auf der Bridge und nicht nur auf Ihrer Hauptnetzwerkschnittstelle zu lauschen.
Knarren
13
@creack wie bringt man rabbitmq und mongodb dazu, auf der brücke zuzuhören?
Ryan Walls