De dentro de um contêiner do Docker, como eu me conecto ao host local da máquina?

1451

Então, eu tenho um Nginx rodando dentro de um contêiner de docker, eu tenho um mysql rodando no localhost, eu quero me conectar ao MySql de dentro do meu Nginx. O MySql está sendo executado no host local e não está expondo uma porta para o mundo externo; portanto, está ligado ao host local, não ao endereço IP da máquina.

Existe alguma maneira de conectar-se a este MySql ou a qualquer outro programa no host local a partir deste contêiner do docker?

Esta pergunta é diferente de "Como obter o endereço IP do host da estação de encaixe dentro de um contêiner de estação de encaixe" devido ao fato de que o endereço IP do host da estação de encaixe pode ser o IP público ou o IP privado na rede que pode ou pode não pode ser acessado a partir do contêiner do docker (quero dizer, IP público se hospedado na AWS ou algo assim). Mesmo se você tiver o endereço IP do host do docker, isso não significa que você pode se conectar ao host do docker de dentro do contêiner, pois o endereço IP da rede do Docker pode ser sobreposto, host, ponte, macvlan, nenhum, etc., o que restringe a acessibilidade de esse endereço IP.

Phil
fonte
Por que não vincular o mysql ao docker0 também?
ivant
2
Para máquina Windows: - $ docker run -d --name MyWebServer -P httpd
Lokesh S
1
Sem network: hostvocê não pode voltar de um contêiner para o host. Hospedar apenas para contêiner. Essa é a principal ideologia por trás dos contêineres. Eles são isolados por razões de estabilidade e segurança.
FreeSoftwareServers

Respostas:

1970

Edit: Se você estiver usando o Docker-for-mac ou o Docker-for-Windows 18.03+, conecte-se ao seu serviço mysql usando o host host.docker.internal(em vez da 127.0.0.1string de conexão).

A partir do Docker 18.09.3, isso não funciona no Docker para Linux. Uma correção foi enviada em 8 de março de 2019 e, esperamos, será mesclada à base de código. Até então, uma solução alternativa é usar um contêiner conforme descrito na resposta do qoomon .

2020-01: foram feitos alguns progressos . Se tudo correr bem, isso deve ocorrer no Docker 20.04


TLDR

Use --network="host"em seu docker runcomando e, 127.0.0.1em seguida, em seu contêiner de docker apontará para o host do docker.

Nota: Este modo funciona apenas no Docker for Linux, de acordo com a documentação .


Nota sobre os modos de rede do contêiner do docker

O Docker oferece diferentes modos de rede ao executar contêineres. Dependendo do modo escolhido, você se conectaria ao banco de dados MySQL em execução no host do docker de maneira diferente.

docker run --network = "bridge" (padrão)

O Docker cria uma ponte denominada docker0por padrão. O host da docker e os contêineres têm um endereço IP nessa ponte.

no host do Docker, digite que sudo ip addr show docker0você terá uma saída semelhante a:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::5484:7aff:fefe:9799/64 scope link
       valid_lft forever preferred_lft forever

Portanto, aqui meu host docker tem o endereço IP 172.17.42.1na docker0interface de rede.

Agora inicie um novo contêiner e obtenha um shell: docker run --rm -it ubuntu:trusty bashe dentro do tipo de contêiner ip addr show eth0para descobrir como sua interface de rede principal está configurada:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.1.192/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
       valid_lft forever preferred_lft forever

Aqui meu contêiner tem o endereço IP 172.17.1.192. Agora veja a tabela de roteamento:

root@e77f6a1b3740:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

Portanto, o endereço IP do host da janela de encaixe 172.17.42.1é definido como a rota padrão e é acessível a partir do seu contêiner.

root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms

docker run --network = "host"

Como alternativa, você pode executar um contêiner de docker com as configurações de rede definidas comohost . Esse contêiner compartilhará a pilha de rede com o host do docker e, do ponto de vista do container, localhost(ou 127.0.0.1) fará referência ao host do docker.

Esteja ciente de que qualquer porta aberta no contêiner do docker seria aberta no host do docker. E isso sem exigir a opção -pou-P docker run .

Configuração de IP no meu host docker:

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

e de um contêiner de docker no modo host :

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

Como você pode ver, o host e o contêiner de docker compartilham exatamente a mesma interface de rede e, como tal, têm o mesmo endereço IP.


Conectando ao MySQL a partir de contêineres

Modo Ponte

Para acessar o MySQL em execução no host docker a partir de contêineres no modo bridge , é necessário garantir que o serviço MySQL esteja escutando as conexões no 172.17.42.1endereço IP.

Para fazer isso, verifique se você possui bind-address = 172.17.42.1ou está bind-address = 0.0.0.0no seu arquivo de configuração do MySQL (my.cnf).

Se você precisar definir uma variável de ambiente com o endereço IP do gateway, poderá executar o seguinte código em um contêiner:

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

depois, no seu aplicativo, use a DOCKER_HOST_IPvariável de ambiente para abrir a conexão com o MySQL.

Nota: se você usar bind-address = 0.0.0.0o servidor MySQL, escutará as conexões em todas as interfaces de rede. Isso significa que seu servidor MySQL pode ser acessado da Internet; certifique-se de configurar as regras do firewall de acordo.

Nota 2: se você usar bind-address = 172.17.42.1o servidor MySQL, não ouvirá as conexões feitas 127.0.0.1. Os processos em execução no host do docker que desejariam se conectar ao MySQL precisariam usar o 172.17.42.1endereço IP.

modo host

Para acessar o MySQL em execução no host docker a partir de contêineres no modo host , você pode manter bind-address = 127.0.0.1sua configuração do MySQL e tudo que você precisa fazer é conectar-se a 127.0.0.1partir de seus contêineres:

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

nota: use mysql -h 127.0.0.1e não mysql -h localhost; caso contrário, o cliente MySQL tentaria se conectar usando um soquete unix.

Thomasleveil
fonte
8
Obrigado por uma resposta tão detalhada! Pelo que reuni, usar o modo host é a única maneira de obter essa funcionalidade através do host local. Eu não tentei, mas suponho que você possa criar uma rede separada para conectar contêineres através de sua própria ponte, oferecendo a eles um 'localhost' comum.
Ben
26
Nota para usuários do OSX: faça login na sua máquina virtual do docker primeiro (boot2docker), usando "docker-machine ssh default" e execute "sudo ip addr show docker0". Continue com as instruções de Thomas a partir daí.
Charlie Dalsass #
30
Estou executando o Docker para Mac e não há mais 172.17.42.1, não há mais docker0. Era 172.17.0.1 como gateway, e não pode nem mesmotelnet 172.17.0.1 3306
zx1986
26
Você pode montar o soquete mysql no contêiner em vez de fazer uma rede como -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockesta.
chx 2/09/16
8
Alguém pode resolver a situação ao executar o Docker no Mac e não usar o boot2docker, como tal, não há interface docker0?
TheJKFever
350

Para macOS e Windows

Docker v 18.03 e superior (desde 21 de março de 2018)

Use seu endereço IP interno ou conecte-se ao nome DNS especial host.docker.internalque resolverá o endereço IP interno usado pelo host.

Suporte para Linux pendente https://github.com/docker/for-linux/issues/264

MacOS com versões anteriores do Docker

Docker para Mac v 17.12 a v 18.02

O mesmo que acima, mas use em seu docker.for.mac.host.internallugar.

Docker para Mac v 17.06 a 17.11

O mesmo que acima, mas use em seu docker.for.mac.localhostlugar.

Docker para Mac 17.05 e abaixo

Para acessar a máquina host a partir do contêiner do docker, você deve anexar um alias de IP à sua interface de rede. Você pode vincular o IP que desejar, apenas certifique-se de não usá-lo com mais nada.

sudo ifconfig lo0 alias 123.123.123.123/24

Em seguida, verifique se o servidor está ouvindo o IP mencionado acima ou 0.0.0.0. Se estiver ouvindo no host local 127.0.0.1, não aceitará a conexão.

Em seguida, basta apontar o contêiner do docker para esse IP e você poderá acessar a máquina host!

Para testar, você pode executar algo como curl -X GET 123.123.123.123:3000dentro do contêiner.

O alias será redefinido a cada reinicialização, portanto, crie um script de inicialização, se necessário.

Solução e mais documentação aqui: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

Janne Annala
fonte
5
brilhante e obrigado, isso funcionou para mim dentro do contêiner. mysql -uroot -hdocker.for.mac.localhost
Richard Frank
1
docker.for.mac.localhost É exatamente o que eu estava procurando. Mas isso é sujo como o inferno ao mesmo tempo. No docker, seria de esperar que o hook docker.for.mac.localhost fosse um nome interno do docker genérico válido para qualquer sistema operacional, não apenas para o Mac. Mas, para fins de desenvolvimento, isso é bom o suficiente.
precisa saber é o seguinte
Como acesso uma porta que está exposta em, digamos, 9093. Estou tentando telnet docker.for.mac.localhost 9093. É inacessível, mas se eu executar ping docker.for.mac.localhost, é alcançável. Estou perdendo alguma coisa aqui?
Achilleus
1
O nome DNS docker.for.mac.host.internal deve ser usado em vez do docker.for.mac.localhost (ainda válido) para a resolução do host dos contêineres, pois existe uma RFC que proíbe o uso de subdomínios do localhost. Consulte tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya
Isso não funciona para mim. Quando eu docker run -e HOSTNAME= docker.for.mac.host.internal , o contêiner é criado, mas nada acontece. Eu tenho que então crtl + C. Com --net=host -e HOSTNAME=localhostpelo menos o contêiner é executado e reclama que não consegue encontrar o serviço que preciso (MySQL db).
Jorge Orpinel 11/0318
83

Estou fazendo um hack semelhante às postagens acima para obter o IP local para mapear para um nome alternativo (DNS) no contêiner. O principal problema é obter dinamicamente com um script simples que funcione no Linux e no OSX o endereço IP do host . Eu fiz esse script que funciona nos dois ambientes (mesmo na distribuição Linux com o "$LANG" != "en_*"configurado):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

Portanto, usando o Docker Compose, a configuração completa será:

Script de inicialização (docker-run.sh) :

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-compose.yml :

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

Mude http://localhostpara http://dockerhostno seu código.

Para um guia mais avançado de como personalizar o DOCKERHOSTscript, dê uma olhada nesta postagem com uma explicação de como ele funciona.

Mariano Ruiz
fonte
1
Dependendo do seu caso de uso, você pode simplesmente usar o DOCKERHOSTvalor aqui em vez de "localhost" ou 0.0.0.0 em qualquer serviço que seu contêiner de docker precise conectar localmente.
Enderland 15/03
2
Eu ligeiramente modificada a sua solução para ser compatível com redes personalizadas: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') Onde <NETWORK-NAME> poderia ser ponte ou o nome da rede, conforme definido pela janela de encaixe-compose (geralmente path-name - network_name ).
precisa saber é o seguinte
1
Você precisa adicionar um comentário: use dockerhostcomo host para conexão db (normalmente substitua por localhostno arquivo de configuração).
Justin
solução estranho, mas é o único que o trabalho make xdebug sob janela de encaixe com cli php
Eddie
Acl parou de funcionar após esta solução em haproxy. Alguma idéia do porquê?
HyukHyukBoi 28/01
41

Isso funcionou para mim em uma pilha NGINX / PHP-FPM sem tocar em nenhum código ou rede em que o aplicativo apenas espera poder se conectar a localhost

Monte mysqld.sockdo host para dentro do contêiner.

Encontre a localização do arquivo mysql.sock no host executando o mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Monte esse arquivo no local esperado na janela de encaixe:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Localizações possíveis do mysqld.sock:

/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock 
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP
user833482
fonte
2
Esta é uma solução muito mais limpa, não expondo o Mysql para o exterior (se não estiver usando um firewall).
user1226868
5
Os soquetes não escalam tão bem quanto o TCP porque bloqueiam com mais frequência e podem causar um comportamento estranho. Use TCP sempre que possível.
Joel E Salas
3
@JoelESalas Você tem uma fonte para essa reivindicação?
Privado
Eu descobri que essa é a solução mais fácil. Polegares para cima user833482! Você deve contribuir com mais frequência para o StackOverflow.
Privado
2
@ JoelESalas Eu acho que você está enganado. A biblioteca do cliente mysql ainda usa soquetes unix por padrão ao conectar-se ao localhost, em vez de realmente fazer uma conexão ao localhost. Um soquete unix evita a sobrecarga da pilha e roteamento TCP e deve ser executado mais rapidamente.
M Conrad
25

Até que host.docker.internalesteja funcionando para todas as plataformas, você pode usar meu contêiner atuando como um gateway NAT sem nenhuma configuração manual:

https://github.com/qoomon/docker-host

qoomon
fonte
5
Posso confirmar que isso não funciona no Docker for Windows 19.03.2 com contêiner do Windows.
KMC
alguma idéia de como consertar isso? (Eu não sou um usuário do Windows)
qoomon 18/09/19
Se o seu ambiente não bloquear a porta que o mysql usa, você pode consultar o servidor pelo nome do computador em que está hospedado. Portanto, na cadeia de conexão, use o nome do seu computador como um nome de servidor.
KMC
24

Solução para Linux (kernel> = 3.6).

Ok, seu servidor localhost possui a interface padrão do docker docker0 com o endereço IP 172.17.0.1 . Seu contêiner começou com as configurações de rede padrão --net = "bridge" .

  1. Habilite route_localnet para a interface docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Adicione estas regras ao iptables:
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. Crie usuário mysql com acesso de '%' que significa - de qualquer pessoa, excluindo localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Altere no seu script o endereço do servidor mysql para 172.17.0.1


Na documentação do kernel :

route_localnet - BOOLEAN: Não considere endereços de loopback como origem ou destino marciano durante o roteamento. Isso permite o uso de 127/8 para propósitos de roteamento local ( padrão FALSE ).

Ray D
fonte
1
Qual é o objetivo do segundo comando iptable? Eu posso entender que o primeiro é reescrever todos os destinos tcp que correspondem a 172.17.0.1:3306 a 127.0.0.1:3306, mas por que o segundo comando iptable é necessário?
Patrick
17

Solução para Windows 10

Docker Community Edition 17.06.0-ce-win18 28/06/2017 (estável)

Você pode usar o nome DNS do host docker.for.win.localhostpara resolver o IP interno. (Aviso algumas fontes mencionadas, windowsmas deve ser win)

Visão geral
Eu precisava fazer algo semelhante, que é conectar do meu contêiner Docker ao meu host local, que estava executando o Azure Storage Emulatore CosmosDB Emulator.

Por Azure Storage Emulatorpadrão, ouve 127.0.0.1 , enquanto você pode alterar o IP também, eu estava procurando uma solução que funcionasse com as configurações padrão.

Isso também funciona para conectar do meu contêiner do Docker ao SQL Servere IIS, ambos em execução localmente no meu host com configurações de porta padrão.

Ralph Willgoss
fonte
13

Muito simples e rápido, verifique o IP do seu host com ifconfig (linux) ou ipconfig (windows) e crie um

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

Dessa forma, seu contêiner poderá acessar seu host. Ao acessar seu banco de dados, lembre-se de usar o nome que você especificou anteriormente, neste caso "dockerhost" e a porta do host em que o banco de dados está sendo executado

Felipe Toledo
fonte
No HaProxy, esta solução parou de funcionar com as ACLs por algum motivo, apenas a configuração padrão está funcionando.
HyukHyukBoi 28/01
1
A única solução que funciona em um sistema Linux. +1
Rafik Farhad
11

Nenhuma das respostas funcionou para mim ao usar o Docker Toolbox no Windows 10 Home, mas o 10.0.2.2 funcionou, pois usa o VirtualBox, que expõe o host à VM nesse endereço.

Elad
fonte
2
Funciona. Mesmo não sendo necessário especificar --network = host. parece 10.0.2.2 é definido como um IP padrão para o host. Obrigado.
TheManish 27/03/19
Mas, posso usar esse IP estático para todas as versões do Windows e Mac ?, como posso lidar com ele em várias plataformas via script?
151291 31/03
Isso funcionou para mim. Basta executar o ipconfig no seu host (windows) e obter o endereço IP emEthernet adapter vEthernet (DockerNAT)
Kihats
10

Para aqueles no Windows, supondo que você esteja usando o driver de rede em ponte, convém ligar especificamente o MySQL ao endereço IP da interface de rede hyper-v.

Isso é feito através do arquivo de configuração na pasta C: \ ProgramData \ MySQL normalmente oculta.

A ligação a 0.0.0.0 não funcionará. O endereço necessário também é mostrado na configuração do docker e, no meu caso, foi 10.0.75.1.

Casey
fonte
3
Você merece uma medalha! Estou trabalhando nisso há dois dias. Obrigado pela ajuda!
Michael
1
Eu também estava trabalhando nisso por dois dias inteiros. Este é o único lugar na web que eu encontrei mencionado. A Microsoft fica completamente calada quanto a isso quando se trata de se conectar ao MSSQL a partir de um contêiner do Docker. Isso faz você pensar se eles já conseguiram trabalhar por conta própria!
Contango
8

Edit: Acabei criando um protótipo do conceito no GitHub. Confira: https://github.com/sivabudh/system-in-a-box


Primeiro, minha resposta é voltada para 2 grupos de pessoas: aqueles que usam um Mac e aqueles que usam o Linux.

O modo de rede host não funciona em um Mac. Você deve usar um alias de IP, consulte: https://stackoverflow.com/a/43541681/2713729

O que é um modo de rede host? Vejo: https://docs.docker.com/engine/reference/run/#/network-settings

Em segundo lugar, para aqueles que usam o Linux (minha experiência direta foi com o Ubuntu 14.04 LTS e estou atualizando para 16.04 LTS em produção em breve), sim , é possível conectar o serviço em execução em um contêiner do Docker aolocalhost serviços em execução no Host Docker (por exemplo, seu laptop).

Quão?

A chave é quando você executa o contêiner do Docker, é necessário executá-lo com o modo host . O comando fica assim:

docker run --network="host" -id <Docker image ID>

Quando você faz um ifconfig(precisará do apt-get install net-toolsseu contêiner para ifconfigser chamado) dentro do contêiner, verá que as interfaces de rede são iguais às do host do Docker (por exemplo, seu laptop).

É importante notar que eu sou um usuário de Mac, mas eu executo o Ubuntu no Parallels, portanto, usar um Mac não é uma desvantagem. ;-)

E é assim que você conecta o contêiner NGINX ao MySQL em execução no localhost.

sivabudh
fonte
1
É importante observar que o modo host oferece melhor desempenho, pois usa a pilha de rede do SO.
Sivabudh
2
Muito bom ponto lá. Embora seja possível conectar-se de um contêiner a um serviço host com anexação de IP não utilizada docs.docker.com/docker-for-mac/networking . Não é uma solução agradável ... mas funciona.
Xavier Huppé
Coisas boas aqui. Uma vez dentro do contêiner com --network="host", como se conectar ao host mysql, por exemplo?
Michael
1
@Buccleuch Basta usar localhost. Confira meu código-fonte do GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Procure 'HOST', você verá 127.0.0.1 para conectar-se ao Postgresql.
sivabudh
Consegui acessar os bancos de dados mysql do host montando o volume conforme @ user833482 e depois de instalar o mysql-client e o servidor no contêiner do docker, é claro.
Michael
7

Solução mais simples para Mac OSX

Basta usar o endereço IP do seu Mac. No Mac, execute isso para obter o endereço IP e usá-lo dentro do contêiner:

$ ifconfig | grep 'inet 192'| awk '{ print $2}'

Enquanto o servidor em execução localmente no seu Mac ou em outro contêiner de docker estiver escutando 0.0.0.0, o contêiner de docking poderá entrar em contato com esse endereço.

Se você quiser acessar outro contêiner de docker que esteja escutando no 0.0.0.0, poderá usar 172.17.0.1

dansalmo
fonte
1
O Docker para Mac expõe o docker.for.mac.host.internalnome do host agora.
Matt
5

Esta não é uma resposta para a pergunta real. Foi assim que resolvi um problema semelhante. A solução vem totalmente de: Definir rede de contêiner Docker para que os contêineres possam se comunicar . Agradecimentos a Nic Raboy

Deixando isso aqui para outras pessoas que desejam fazer chamadas REST entre um contêiner e outro. Responde à pergunta: o que usar no lugar do host local em um ambiente de docker?

Saiba como é a sua rede docker network ls

Crie uma nova rede docker network create -d my-net

Iniciar o primeiro contêiner docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Confira as configurações de rede para o primeiro contêiner docker inspect first_container. "Redes": deve ter 'my-net'

Iniciar o segundo contêiner docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Confira as configurações de rede para o segundo contêiner docker inspect second_container. "Redes": deve ter 'my-net'

ssh em seu segundo contêiner docker exec -it second_container shou docker exec -it second_container bash.

Dentro do segundo contêiner, você pode executar ping no primeiro contêiner ping first_container. Além disso, suas chamadas de código, como http://localhost:5000podem ser substituídas porhttp://first_container:5000

Shirish Hirekodi
fonte
Exatamente o que eu estava procurando. Obrigado: D
Simar Singh
5

Para Windows,

Alterei o URL do banco de dados na configuração do Spring: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Então construa a imagem e execute. Funcionou para mim.

Praveenkumar Beedanal
fonte
interessante ....
Phil
para mim não funciona. Eu tenho mac e tentando de um contêiner php para se conectar ao localhost mysql. Qualquer ideia ?
A. Zalonis 19/04
4

Discordo da resposta de Thomasleveil.

Fazer o mysql se ligar a 172.17.42.1 impedirá que outros programas usem o banco de dados no host para alcançá-lo. Isso funcionará apenas se todos os usuários do seu banco de dados estiverem em dockerized.

Fazer o mysql ligar para 0.0.0.0 abrirá o banco de dados para o mundo exterior, o que não é apenas uma coisa muito ruim a ser feita, mas também é contrário ao que o autor da pergunta original deseja fazer. Ele diz explicitamente "O MySql está sendo executado no host local e não está expondo uma porta para o mundo exterior, portanto, está ligado ao host local"

Para responder ao comentário de ivant

"Por que não vincular o mysql ao docker0 também?"

Isso não é possível. A documentação do mysql / mariadb diz explicitamente que não é possível ligar a várias interfaces. Você só pode vincular a 0, 1 ou todas as interfaces.

Como conclusão, NÃO encontrei nenhuma maneira de acessar o banco de dados (somente localhost) no host a partir de um contêiner de docker. Definitivamente, parece um padrão muito, mas não sei como fazê-lo.

orzel
fonte
4
do host do docker, você ainda pode se conectar ao servidor MySQL usando o 172.17.42.1endereço Mas a sua nota está certa em contrário. Aso, eu editei a minha resposta com o hostmodo de rede que permite manter o servidor MySQL obrigado a 127.0.0.1, permitindo que os recipientes se conectar a ele
Thomasleveil
não, como eu disse, você não pode se conectar ao 172.17.42.1 se o mysql estiver vinculado ao localhost.
orzel
4
"Fazer o mysql se vincular à 172.17.42.1 impedirá que outros programas usem o banco de dados no host para alcançá-lo." - isso não é verdade. Outros programas podem usar o mysql, eles apenas precisam se conectar ao 172.17.42.1 em vez do localhost / 127.0.0.1.
0x89
A solução para o problema nesta resposta geralmente é conectar o servidor MySQL 0.0.0.0e, em seguida, configurar um firewall para que o banco de dados não seja acessível pela Internet.
halfer
4

Aqui está a minha solução: funciona para o meu caso

  • configure o servidor mysql local para acesso público por comentário #bind-address = 127.0.0.1 em /etc/mysql/mysql.conf.d

  • reinicie o servidor mysql sudo /etc/init.d/mysql restart

  • execute o seguinte comando para abrir o acesso root do usuário a qualquer host mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • crie um script sh: run_docker.sh

    #! bin / bash

    HOSTIP = `ip -4 addr show scope global dev eth0 | grep inet | awk '{print \ $ 2}' | corte -d / -f 1`


      janela de encaixe run -it -d --name web-app \
                  --add-host = local: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = demo \
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • executar com docker-compositor

    versão: '2.1'

    Serviços:
    tomcatwar: extra_hosts: - "local: 10.1.2.232" imagem: sopheamak / springboot_docker_mysql
    portas: - 8080: 8080 meio Ambiente: - DATABASE_HOST = local - DATABASE_USER = root - DATABASE_PASSWORD = raiz - DATABASE_NAME = demo - DATABASE_PORT = 3306

sopheamak
fonte
4

Várias soluções vêm à mente:

  1. Mova suas dependências primeiro para contêineres
  2. Torne seus outros serviços acessíveis externamente e conecte-se a eles com esse IP externo
  3. Execute seus contêineres sem isolamento de rede
  4. Evite conectar-se pela rede, use um soquete montado como volume

A razão pela qual isso não funciona imediatamente é que os contêineres são executados com seu próprio namespace de rede por padrão. Isso significa que o host local (ou 127.0.0.1 apontando para a interface de loopback) é exclusivo por contêiner. Conectar-se a isso se conectará ao próprio contêiner, e não aos serviços executados fora da janela de encaixe ou dentro de outro contêiner.

Opção 1 : Se sua dependência puder ser movida para um contêiner, eu faria isso primeiro. Isso torna sua pilha de aplicativos portátil, enquanto outros tentam executar seu contêiner em seu próprio ambiente. E você ainda pode publicar a porta no seu host para onde outros serviços que não foram migrados ainda possam alcançá-la. Você pode até publicar a porta na interface host local no host do docker para evitar que seja acessível externamente com uma sintaxe como: -p 127.0.0.1:3306:3306para a porta publicada.

Opção 2 : Existem várias maneiras de detectar o endereço IP do host de dentro do contêiner, mas cada um tem um número limitado de cenários em que eles trabalham (por exemplo, exigindo o Docker para Mac). A opção mais portátil é injetar o IP do host no contêiner com algo como uma variável de ambiente ou arquivo de configuração, por exemplo:

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

Isso exige que seu serviço esteja atendendo a essa interface externa, o que pode ser uma preocupação de segurança. Para outros métodos para obter o endereço IP do host de dentro do contêiner, consulte esta postagem .

Opção 3 : Executando sem isolamento de rede, ou seja, executando com --net host, significa que seu aplicativo está sendo executado no espaço para nome da rede host. Isso é menos isolamento para o contêiner e significa que você não pode acessar outros contêineres através de uma rede de docker compartilhada com DNS (em vez disso, é necessário usar portas publicadas para acessar outros aplicativos em contêiner). Porém, para aplicativos que precisam acessar outros serviços no host que estão apenas ouvindo no 127.0.0.1host, essa pode ser a opção mais fácil.

Opção 4 : Vários serviços também permitem acesso através de um soquete baseado em sistema de arquivos. Esse soquete pode ser montado no contêiner como um volume montado em ligação, permitindo acessar o serviço host sem passar pela rede. Para acessar o mecanismo da janela de encaixe, você costuma ver exemplos de montagem /var/run/docker.sockno contêiner (fornecendo acesso raiz ao contêiner ao host). Com o mysql, você pode tentar algo como -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.socke conectar-se ao localhostqual o mysql se converte usando o soquete.

BMitch
fonte
3

Você pode obter o IP do host usando imagem alpina

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

Isso seria mais consistente, pois você sempre usa alpine para executar o comando.

Semelhante à resposta de Mariano, você pode usar o mesmo comando para definir uma variável de ambiente

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up
hasnat
fonte
3

Para Linux, onde você não pode alterar a interface à qual o serviço localhost se liga

Existem dois problemas que precisamos resolver

  1. Obtendo o IP do host
  2. Disponibilizando nosso serviço de host local para o Docker

O primeiro problema pode ser resolvido usando a imagem docker-host do qoomon , conforme fornecido por outras respostas.

Você precisará adicionar esse contêiner à mesma rede de pontes que seu outro contêiner para poder acessá-lo. Abra um terminal dentro do seu contêiner e garanta que você pode executar ping dockerhost.

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

Agora, o problema mais difícil é tornar o serviço acessível ao docker.

Podemos usar o telnet para verificar se podemos acessar uma porta no host (pode ser necessário instalar isso).

O problema é que nosso contêiner poderá acessar apenas serviços vinculados a todas as interfaces, como SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

Mas os serviços vinculados apenas ao host local serão inacessíveis:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

A solução adequada aqui seria vincular o serviço à rede de pontes dos estivadores. No entanto, esta resposta assume que não é possível alterar isso. Então, vamos usariptables .

Primeiro, precisamos encontrar o nome da rede de ponte com a qual o docker está usando ifconfig. Se você estiver usando uma ponte sem nome, será apenas isso docker0. No entanto, se você estiver usando uma rede nomeada, terá uma ponte começando com br-essa janela de encaixe. O meu ébr-5cd80298d6f4 .

Depois de termos o nome dessa ponte, precisamos permitir o roteamento dessa ponte para o host local. Isso está desativado por padrão por motivos de segurança:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

Agora, para configurar nossa iptablesregra. Como nosso contêiner só pode acessar portas na rede de ponte do docker, vamos fingir que nosso serviço está realmente vinculado a uma porta nessa rede.

Para isso, encaminharemos todas as solicitações <docker_bridge>:portparalocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

Por exemplo, para o meu serviço na porta 1025

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

Agora você deve conseguir acessar seu serviço a partir do contêiner:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready
JShorthouse
fonte
1
É o mesmo que o @ ray-d mencionou acima, mas é bem explicado. Obrigado! Além disso, ao usar o docker-compose, eu também precisei adicionar uma regra DNAT na cadeia PREROUTING para todos os pacotes que chegam na interface docker0: porque o docker-compose parece estar usando o docker0 durante as compilações (não durante as execuções, surpreendentemente): sysctl -w net.ipv4.conf.docker0.route_localnet=1eiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd 26/03
3

Você precisa conhecer o gateway ! Minha solução com o servidor local foi expô-lo 0.0.0.0:8000, executar o docker com sub - rede e executar o contêiner como:

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

Então, agora você pode acessar seu loopback através http://172.35.0.1:8000

kirill .z
fonte
3

Tente o seguinte:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

Para obter 192.168.1.202 , usaifconfig

Isso funcionou para mim. Espero que esta ajuda!

Binh Ho
fonte
2

Os CGroups e Namespaces estão desempenhando papel importante no ecossistema de contêineres.

O espaço para nome fornece uma camada de isolamento. Cada contêiner é executado em um espaço para nome separado e seu acesso é limitado a esse espaço para nome. O Cgroups controla a utilização de recursos de cada contêiner, enquanto o Namespace controla o que um processo pode ver e acessar o respectivo recurso.

Aqui está o entendimento básico da abordagem da solução que você pode seguir,

Usar espaço para nome de rede

Quando um contêiner aparece fora da imagem, uma interface de rede é definida e criada. Isso fornece ao endereço e interface IP exclusivos do contêiner.

$ docker run -it alpine ifconfig

Ao alterar o espaço de nome para host, as redes de cotainers não permanecem isoladas em sua interface, o processo terá acesso à interface de rede das máquinas host.

$ docker run -it --net=host alpine ifconfig

Se o processo ouvir nas portas, elas serão ouvidas na interface do host e mapeadas para o contêiner.

Usar o espaço para nome do PID A alteração do espaço para nome do Pid permite que um contêiner interaja com outro processo além do seu escopo normal.

Este contêiner será executado em seu próprio espaço para nome.

$ docker run -it alpine ps aux

Alterando o espaço para nome para o host, o contêiner também pode ver todos os outros processos em execução no sistema.

$ docker run -it --pid=host alpine ps aux

Compartilhando espaço para nome

Essa é uma prática recomendada para fazer isso na produção, pois você está quebrando o modelo de segurança do contêiner que pode abrir vulnerabilidades e facilitar o acesso ao interceptador. Isso é apenas para ferramentas de depuração e para subestimar as brechas na segurança do contêiner.

O primeiro contêiner é o servidor nginx. Isso criará um novo espaço para nome de rede e processo. Este contêiner se ligará à porta 80 da interface de rede recém-criada.

$ docker run -d --name http nginx:alpine

Outro contêiner agora pode reutilizar esse espaço para nome,

$ docker run --net=container:http mohan08p/curl curl -s localhost

Além disso, esse contêiner pode ver a interface com os processos em um contêiner compartilhado.

$ docker run --pid=container:http alpine ps aux

Isso permitirá que você conceda mais privilégios aos contêineres sem alterar ou reiniciar o aplicativo. Da mesma forma, você pode se conectar ao mysql no host, executar e depurar seu aplicativo. Mas, não é recomendável seguir por esse caminho. Espero que ajude.

mohan08p
fonte
1

Para máquinas Windows: -

Execute o comando abaixo para Expor a porta do Docker aleatoriamente durante o tempo de construção

$docker run -d --name MyWebServer -P mediawiki

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Na lista de contêineres acima, você pode ver a porta atribuída como 32768. Tente acessar

localhost:32768 

Você pode ver a página mediawiki

Lokesh S
fonte
5
Embora essa resposta possa fornecer informações úteis para alguns usuários, é o contrário ! Trata-se de acessar um serviço em execução no contêiner a partir da máquina host. A questão, no entanto, era sobre acessar um serviço em execução no host a partir do contêiner.
Einjohn # 9/19
1

Até que a correção não seja mesclada na masterramificação, para que o IP do host seja executado apenas dentro do contêiner:

ip -4 route list match 0/0 | cut -d' ' -f3

(como sugerido por @Mahoney aqui ).

patryk.beza
fonte
1

Eu o resolvi criando um usuário no MySQL para o ip do contêiner:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

Em seguida, no recipiente: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name

Leandro
fonte
Esta é a solução mais simples. Funcionou para mim e me referi a muitos
Sopia Alfred
-1

A maneira como faço isso é passar o IP do host como variável de ambiente para o contêiner. O contêiner acessa o host por essa variável.

F. Kam
fonte
Você pode ilustrar como você faz isso? Eu tentei essa abordagem, mas não
obtive
`docker run -i -t -e HOST = 10.145.2.123 raiz do ubuntu @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Tentando 10.145.2.123 ... Conectado a 10.145.2.123. O caractere de escape é '^]'. SSH-2.0-OpenSSH_7.4`
F. Kam