273 votes

Transférer le port de l'hôte au conteneur docker

Est-il possible de faire en sorte qu'un conteneur Docker accède aux ports ouverts par l'hôte ? Concrètement, MongoDB et RabbitMQ fonctionnent sur l'hôte et j'aimerais exécuter un processus dans un conteneur Docker pour écouter la file d'attente et (éventuellement) écrire dans la base de données.

Je sais que je peux transférer un port du conteneur vers l'hôte (via l'option -p) et établir une connexion avec le monde extérieur (c'est-à-dire Internet) à partir du conteneur Docker, mais j'aimerais ne pas exposer les ports RabbitMQ et MongoDB de l'hôte au monde extérieur.

EDIT : quelques précisions :

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

J'ai dû faire cette astuce pour obtenir une connexion internet à l'intérieur du conteneur : Mon pare-feu bloque les connexions réseau du conteneur Docker vers l'extérieur.

EDIT : Finalement, j'ai opté pour la création d'un pont personnalisé à l'aide de tuyauterie et que les services écoutent sur les IP du pont. J'ai choisi cette approche plutôt que de faire écouter MongoDB et RabbitMQ sur le pont docker, car elle offre plus de flexibilité.

173voto

David Grayson Points 22459

Un moyen simple mais relativement peu sûr serait d'utiliser la fonction --net=host option pour docker run .

Cette option fait en sorte que le conteneur utilise la pile réseau de l'hôte. Vous pouvez alors vous connecter aux services exécutés sur l'hôte en utilisant simplement "localhost" comme nom d'hôte.

C'est plus facile à configurer car vous n'aurez pas à configurer le service pour qu'il accepte les connexions à partir de l'adresse IP de votre conteneur docker, et vous n'aurez pas à indiquer au conteneur docker une adresse IP ou un nom d'hôte spécifique auquel se connecter, juste un port.

Par exemple, vous pouvez le tester en exécutant la commande suivante, qui suppose que votre image s'appelle my_image votre image comprend le telnet et le service auquel vous voulez vous connecter est sur le port 25 :

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

Si vous envisagez de procéder de cette manière, veuillez consulter l'avertissement concernant la sécurité sur cette page :

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

C'est écrit :

--net=host -- Indique à Docker de ne pas placer le conteneur dans une pile réseau séparée. En substance, ce choix indique à Docker de ne pas conteneuriser la mise en réseau du conteneur ! Alors que les processus du conteneur seront toujours confinés à leur propre système de fichiers, à leur propre liste de processus et à leurs propres limites de ressources, une rapide commande ip addr vous montrera que, du point de vue réseau, ils vivent " à l'extérieur " de l'hôte principal de Docker et ont un accès complet à ses interfaces réseau. Notez que cela ne permet pas au conteneur de reconfigurer la pile réseau de l'hôte - cela nécessiterait --privileged=true - mais cela permet aux processus du conteneur d'ouvrir des ports à faible numérotation comme tout autre processus Root. Il permet également au conteneur d'accéder aux services réseau locaux comme D-bus. Cela peut conduire à ce que les processus du conteneur soient capables de faire des choses inattendues comme redémarrer votre ordinateur. Vous devez utiliser cette option avec prudence.

81voto

Seldo Points 4432

Votre hôte Docker expose un adaptateur à tous les conteneurs. En supposant que vous êtes sur un ubuntu récent, vous pouvez exécuter

ip addr

Vous obtiendrez une liste d'adaptateurs réseau, dont l'un ressemblera à ceci

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

Vous devrez indiquer à rabbit/mongo de se lier à cette IP (172.17.42.1). Après cela, vous devriez être en mesure d'ouvrir des connexions vers 172.17.42.1 à partir de vos conteneurs.

25voto

warvariuc Points 11787

Comme indiqué dans l'un des commentaires, cela fonctionne pour Mac (probablement pour Windows/Linux aussi) :

JE VEUX ME CONNECTER DEPUIS UN CONTENEUR À UN SERVICE SUR L'HÔTE.

L'hôte a une adresse IP changeante (ou aucune si vous n'avez pas d'accès au réseau). Nous vous recommandons de vous connecter au nom DNS spécial host.docker.internal qui se résout en l'adresse IP interne utilisée par l'hôte. Ceci est destiné au développement et ne fonctionnera pas dans un environnement de production en dehors de Docker Desktop pour Mac.

Vous pouvez également atteindre la passerelle en utilisant gateway.docker.internal .

Citation tirée de https://docs.docker.com/docker-for-mac/networking/

Cela a fonctionné pour moi sans utiliser --net=host .

14voto

czerasz Points 2135

Vous pouvez également créer un tunnel ssh.

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

De cette façon, le elasticsearch a un tunnel vers le serveur avec le service en cours d'exécution (Elasticsearch, MongoDB, PostgreSQL) et expose le port 9200 avec ce service.

14voto

b01 Points 1528

TLDR ;

Pour le développement local uniquement, procédez comme suit :

  1. Démarrez le service ou le tunnel SSH sur votre ordinateur portable/ordinateur/PC/Mac.
  2. Construire/exécuter votre image/conteneur Docker pour se connecter au nom d'hôte host.docker.internal:<hostPort>

Note : Il existe également gateway.docker.internal que je n'ai pas essayé.

END_TLDR ;

Par exemple, si vous utilisiez ceci dans votre conteneur :

PGPASSWORD=password psql -h localhost -p 5432 -d mydb -U myuser

changez-le en ceci :

PGPASSWORD=password psql -h host.docker.internal -p 5432 -d mydb -U myuser

Cela permet de se connecter comme par magie au service qui fonctionne sur ma machine hôte. Vous n'avez pas besoin d'utiliser --net=host o -p "hostPort:ContainerPort" o -P

Contexte

Pour plus de détails, voir : https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

Je l'ai utilisé avec un tunnel SSH vers une instance Postgres AWS RDS sous Windows 10. Je n'ai eu qu'à changer l'utilisation de localhost:containerPort dans le conteneur pour host.docker.internal:hostPort .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X