Come accedere alla porta host dal contenitore della finestra mobile


281

Ho un container docker con jenkins. Come parte del processo di compilazione, devo accedere a un server Web che viene eseguito localmente sul computer host. Esiste un modo in cui il server Web host (che può essere configurato per essere eseguito su una porta) può essere esposto al contenitore jenkins?

EDIT: sto eseguendo docker nativamente su una macchina Linux.

AGGIORNARE:

Oltre alla risposta @larsks di seguito, per ottenere l'indirizzo IP dell'host IP dal computer host, faccio quanto segue:

ip addr show docker0 | grep -Po 'inet \K[\d.]+'

Usare un commento poiché questa è una risposta terribile, ma credo che in genere sia possibile accedervi il 172.17.1.78, a meno che non si tratti di una configurazione boot2docker.
CashIsClay

@CashIsClay L'ho provato e ho riscontrato ancora questo errorecurl: (7) Failed to connect to 172.17.1.78 port 7000: No route to host
Tri Nguyen,

Non hai specificato; stai eseguendo boot2docker o stai eseguendo Docker nativamente su Linux?
Larks

@larsks mi dispiace, ho appena aggiornato la domanda - la sto eseguendo nativamente su Linux.
Tri Nguyen,

Risposte:


206

Quando si esegue Docker in modo nativo su Linux, è possibile accedere ai servizi host utilizzando l'indirizzo IP docker0dell'interfaccia. Dall'interno del contenitore, questo sarà il percorso predefinito.

Ad esempio, sul mio sistema:

$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link 
       valid_lft forever preferred_lft forever

E dentro un contenitore:

# ip route show
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0  src 172.17.0.4 

È abbastanza facile estrarre questo indirizzo IP usando un semplice script shell:

#!/bin/sh

hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip

Potrebbe essere necessario modificare le iptablesregole sull'host per consentire le connessioni dai contenitori Docker. Qualcosa del genere farà il trucco:

# iptables -A INPUT -i docker0 -j ACCEPT

Ciò consentirebbe l'accesso a tutte le porte sull'host dai contenitori Docker. Nota che:

  • Le regole di iptables sono ordinate e questa regola può o meno fare la cosa giusta a seconda di quali altre regole la precedono.

  • sarai in grado di accedere solo ai servizi host che sono (a) in ascolto INADDR_ANY(aka 0.0.0.0) o che stanno ascoltando esplicitamente docker0sull'interfaccia.


1
Grazie. Ottenere l'indirizzo IP era tutto ciò che mi serviva, senza modificare iptables :)
Tri Nguyen,


7
Che ne dici di Docker per MAC? AFAIK non esiste una rete docker0 disponibile per "Docker per MAC". In tal caso, come posso collegarmi all'host dal contenitore?
Vijay,

17
Se si utilizza Docker per MAC versione 17.06 o successiva, utilizzare docker.for.mac.localhostinvece di localhosto 127.0.0.1. Ecco il doc .
merito

1
Ho usato il nome host del mio host invece di ottenere l'indirizzo IP (comando nome host sull'host)
Marek F

313

Per macOS e Windows

Docker v 18.03 e versioni successive (dal 21 marzo 2018)

Usa il tuo indirizzo IP interno o connettiti al nome DNS speciale host.docker.internalche si risolverà nell'indirizzo IP interno utilizzato dall'host.

Supporto Linux in sospeso https://github.com/docker/for-linux/issues/264

MacOS con versioni precedenti di Docker

Docker per Mac dalla 17.12 alla v 18.02

Come sopra ma usa docker.for.mac.host.internalinvece.

Docker per Mac dalla 17.06 alla v 17.11

Come sopra ma usa docker.for.mac.localhostinvece.

Docker per Mac 17.05 e versioni precedenti

Per accedere al computer host dal contenitore della finestra mobile è necessario collegare un alias IP all'interfaccia di rete. Puoi associare qualsiasi IP tu voglia, assicurati solo di non usarlo per nient'altro.

sudo ifconfig lo0 alias 123.123.123.123/24

Quindi assicurati che il tuo server stia ascoltando l'IP di cui sopra o 0.0.0.0. Se è in ascolto su localhost 127.0.0.1, non accetterà la connessione.

Quindi punta il contenitore della finestra mobile a questo IP e puoi accedere al computer host!

Per testare puoi eseguire qualcosa come curl -X GET 123.123.123.123:3000all'interno del contenitore.

L'alias verrà reimpostato ad ogni riavvio, quindi creare uno script di avvio, se necessario.

Soluzione e altra documentazione qui: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


Ho provato con successo questo. Non è necessario disattivare il firewall
alvaro g

15
Dal 17.06 in poi, rilasciato a giugno 2017, la loro raccomandazione è di connettersi allo speciale nome DNS solo per Mac docker.for.mac.localhostche si risolverà all'indirizzo IP interno utilizzato dall'host! ... l'ho provato e funziona davvero! :)
Kyr,

Risposta esatta per gli utenti Mac come me. Grazie. Una cosa che non capisco è perché dare ip route show | awk '/default/ {print $3}'un IP ed docker.for.mac.localhostè un altro.
dmmd

8
modificato in host.docker.internal docs.docker.com/docker-for-mac/networking/…
Snowball

1
Raccomandare l'uso host.docker.internalnel contenitore finestra mobile e di configurazione 127.0.0.1 host.docker.internalin hosts file.
Junlin,

85

Utilizzare --net="host"come docker runcomando, quindi localhostnel contenitore della finestra mobile verrà indicato l'host della finestra mobile.


15
Non funzionerà per quelli che usano Dpcker per Windows / Docker per Mac per quanto ne so a causa del fatto che i contenitori funzionano in ambienti virtualizzati: Hyper-V (Windows) / xhyve (Mac)
ninjaboy

6
QUESTO! Questa è la risposta!
user3751385,

15
Solo per la cronaca: all'interno di Docker Componse, network_mode: "host"
jbarros,

Questo non funziona per me su Docker per Mac versione 19.03.1 su client e server. Vorrei che funzionasse, ma non lo è.
argilla,

1
Anche se sono su Mac, funziona quando vuoi la comunicazione tra due contenitori docker e mentre trasformo tutte le applicazioni in un'immagine
docker,

27

Soluzione con docker-compose: per accedere al servizio basato su host è possibile utilizzare il network_modeparametro https://docs.docker.com/compose/compose-file/#network_mode

version: '3'
services:
  jenkins:
    network_mode: host

EDIT 2020-04-27: raccomandato per l'uso solo in ambiente di sviluppo locale.


Quindi come accedere a jenkins? Sembra che il port forwarding non funzioni se si utilizza la modalità di rete host
Jeff Tian

1
è una soluzione molto rischiosa e per niente raccomandata. NON dovremmo aprire la nostra rete host ai container se non esplicitamente necessario
Fatemeh Majd


12

Ho creato un contenitore docker per fare esattamente questo https://github.com/qoomon/docker-host

È quindi possibile utilizzare semplicemente il nome contenitore dns per accedere al sistema host, ad es curl http://dockerhost:9200


Questa è una soluzione intelligente. Sei a conoscenza di qualcosa che utilizza questo con molto traffico? Potrebbe esserci un sovraccarico per il proxy di tutto il traffico attraverso questo contenitore.
bcoughlan,

3
Sì, funziona abbastanza bene a malapena nessun sovraccarico perché funziona solo su un dispositivo loopback
qoomon

11

Abbiamo scoperto che una soluzione più semplice a tutta questa spazzatura di rete è quella di utilizzare solo il socket di dominio per il servizio. Se stai provando a connetterti all'host, monta semplicemente la presa come volume e sei sulla buona strada. Per postgresql, questo era semplice come:

docker run -v /var/run/postgresql:/var/run/postgresql

Quindi abbiamo appena impostato la nostra connessione al database per utilizzare il socket anziché la rete. Letteralmente così facile.


Questa è un'ottima soluzione Bel lavoro!
un secchione pagato

2
Cordiali saluti, abbiamo riscontrato un grosso problema con questo: Docker per Mac non supporta i socket come volumi montati. Questo è andato avanti fino a quando un Mac non l'ha provato. :(
mlissner,

Grazie! Ha funzionato come un fascino su Linux!
Marcelo Cardoso,

7

Ho esplorato le varie soluzioni e trovo che questa sia la soluzione meno complicata:

  1. Definire un indirizzo IP statico per l'IP del gateway bridge.
  2. Aggiungi l'IP del gateway come voce aggiuntiva nella extra_hostsdirettiva.

L'unico aspetto negativo è che se hai più reti o progetti che lo fanno, devi assicurarti che il loro intervallo di indirizzi IP non sia in conflitto.

Ecco un esempio di Docker Compose:

version: '2.3'

services:
  redis:
    image: "redis"
    extra_hosts:
      - "dockerhost:172.20.0.1"

networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

È quindi possibile accedere alle porte sull'host dall'interno del contenitore utilizzando il nome host "dockerhost".



3

È possibile accedere al server Web locale in esecuzione nel computer host in due modi.

  1. Approccio 1 con IP pubblico

    Utilizzare l'indirizzo IP pubblico della macchina host per accedere al server Web nel contenitore della finestra mobile Jenkins.

  2. Approccio 2 con la rete host

    Utilizzare "--net host" per aggiungere il contenitore della finestra mobile Jenkins sullo stack di rete dell'host. I contenitori distribuiti nello stack dell'host hanno accesso completo all'interfaccia host. È possibile accedere al server Web locale nel contenitore finestra mobile con un indirizzo IP privato del computer host.

NETWORK ID          NAME                      DRIVER              SCOPE
b3554ea51ca3        bridge                    bridge              local
2f0d6d6fdd88        host                      host                local
b9c2a4bc23b2        none                      null                local

Avviare un contenitore con la rete host Eg: docker run --net host -it ubuntued eseguire ifconfigper elencare tutti gli indirizzi IP di rete disponibili che sono raggiungibili dal contenitore docker.

Ad esempio: ho avviato un server nginx nel mio computer host locale e sono in grado di accedere agli URL del sito Web nginx dal contenitore della finestra mobile Ubuntu.

docker run --net host -it ubuntu

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a604f7af5e36        ubuntu              "/bin/bash"         22 seconds ago      Up 20 seconds                           ubuntu_server

Accesso al server Web Nginx (in esecuzione su una macchina host locale) dal contenitore docker Ubuntu con indirizzo IP di rete privata.

root@linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes

3

Per docker-composeutilizzare la rete bridge per creare una rete privata tra contenitori, la soluzione accettata utilizzando docker0non funziona perché l'interfaccia di uscita dai contenitori non è docker0ma è invece un ID di interfaccia generato casualmente, come:

$ ifconfig

br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.32.1  netmask 255.255.240.0  broadcast 192.168.47.255

Sfortunatamente quell'ID casuale non è prevedibile e cambierà ogni volta che compose deve ricreare la rete (ad es. Al riavvio dell'host). La mia soluzione a questo è quella di creare la rete privata in una sottorete conosciuta e configurare iptablesper accettare quell'intervallo:

Componi lo snippet di file:

version: "3.7"

services:
  mongodb:
    image: mongo:4.2.2
    networks:
    - mynet
    # rest of service config and other services removed for clarity

networks:
  mynet:
    name: mynet
    ipam:
      driver: default
      config:
      - subnet: "192.168.32.0/20"

È possibile modificare la sottorete se l'ambiente lo richiede. Ho scelto arbitrariamente 192.168.32.0/20usando docker network inspectper vedere cosa veniva creato per impostazione predefinita.

Configurare iptablessull'host per consentire la sottorete privata come sorgente:

$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT

Questa è la iptablesregola più semplice possibile . Potresti voler aggiungere altre restrizioni, ad esempio per porta di destinazione. Non dimenticare di persistere nelle regole di iptables quando sei felice che funzionino.

Questo approccio ha il vantaggio di essere ripetibile e quindi automatizzabile. Uso il templatemodulo di ansible per distribuire il mio file di composizione con sostituzione variabile e quindi uso i moduli iptablese shellper configurare e mantenere le regole del firewall, rispettivamente.


Ho visto più risposte suggerire iptables -A INPUT -i docker0 -j ACCEPT, ma ciò non mi ha aiutato, mentre i iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPTsuggerimenti qui risolti hanno risolto il mio problema.
Terry Brown,

1

Questa è una vecchia domanda e aveva molte risposte, ma nessuna di quelle si adattava abbastanza bene al mio contesto. Nel mio caso, i contenitori sono molto snelli e non contengono nessuno degli strumenti di rete necessari per estrarre l'indirizzo IP dell'host dall'interno del contenitore.

Inoltre, l' --net="host"approccio è un approccio molto approssimativo che non è applicabile quando si desidera avere una configurazione di rete ben isolata con diversi contenitori.

Quindi, il mio approccio è quello di estrarre l'indirizzo degli host sul lato host e quindi passarlo al contenitore con il --add-hostparametro:

$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name

oppure, salvare l'indirizzo IP dell'host in una variabile di ambiente e utilizzare la variabile in un secondo momento:

$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name

Quindi docker-hostviene aggiunto al file hosts del contenitore e puoi usarlo nelle stringhe di connessione al database o negli URL API.


0

Quando hai già creato due immagini della finestra mobile e vuoi mettere due contenitori per comunicare tra loro.

Per questo, puoi comodamente eseguire ogni container con il suo --name e usare il flag --link per abilitare la comunicazione tra di loro. Tuttavia, non si ottiene questo durante la compilazione della finestra mobile.

Quando ti trovi in ​​uno scenario come me, ed è tuo

docker build -t "centos7/someApp" someApp/ 

Ciò si interrompe quando ci provi

curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

e rimani bloccato su "curl / wget" non restituendo "route to host".

Il motivo è la sicurezza impostata dalla finestra mobile che, per impostazione predefinita, sta vietando la comunicazione da un contenitore verso l'host o altri contenitori in esecuzione sull'host. Questo è stato abbastanza sorprendente per me, devo dire, ti aspetteresti che l'ecosistema di macchine docker in esecuzione su una macchina locale possa accedervi perfettamente senza troppi ostacoli.

La spiegazione di ciò è descritta in dettaglio nella seguente documentazione.

http://www.dedoimedo.com/computers/docker-networking.html

Vengono fornite due soluzioni alternative che consentono di spostarsi riducendo la sicurezza della rete.

L'alternativa più semplice è solo disattivare il firewall o consentire tutto. Ciò significa eseguire il comando necessario, che potrebbe essere systemctl per arrestare firewalld, iptables -F o equivalente.

Spero che questa informazione ti aiuti.


3
Proprio come una nota, --linkora è deprecato
Mr.Brisris il

0

Per me (Windows 10, Docker Engine v19.03.8) era un mix di https://stackoverflow.com/a/43541732/7924573 e https://stackoverflow.com/a/50866007/7924573 .

  1. cambia l'host / ip in host.docker.internal
    ad es .: LOGGER_URL = " http: //host.docker.internal: 8085 / log "
  2. impostare network_mode su bridge (se si desidera mantenere il port forwarding; in caso contrario utilizzare host ):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge o in alternativa: utilizzare --net="bridge"se non si utilizza docker-compose (simile a https://stackoverflow.com/a/48806927/7924573 )
    Come sottolineato nelle risposte precedenti: questo dovrebbe essere usato solo in un ambiente di sviluppo locale .
    Per maggiori informazioni leggi: https://docs.docker.com/compose/compose-file/#network_mode e https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds
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.