Então eu tenho um Nginx correndo dentro de um container, eu tenho um mysql correndo no localhost, eu quero me conectar ao MySql de dentro do meu Nginx. O MySql está rodando no localhost e não expondo uma porta para o mundo exterior, então ele está ligado no localhost, não ligado no endereço ip da máquina.
Existe alguma forma de se ligar a este MySql ou a qualquer outro programa no localhost a partir deste contentor portuário?
Esta questão é diferente de "Como obter o endereço IP do host portuário de dentro de um container" portuário; devido ao fato de que o endereço IP do host portuário pode ser o IP público ou o IP privado na rede que pode ou não ser alcançável de dentro do container portuário (quero dizer IP público se hospedado na AWS ou algo assim). Mesmo que você tenha o endereço IP do host da doca não significa que você pode se conectar ao host da doca de dentro do container, dado que o endereço IP da sua rede Docker pode ser overlay, host, bridge, macvlan, nenhum, etc., o que restringe a capacidade de alcance desse endereço IP.
Edit: Se você estiver utilizando Docker-for-mac ou Docker-for-Windows 18.03+, basta conectar ao seu serviço mysql utilizando o host host.docker.internal
.
Como no Docker 18.09.3, isto não funciona no Docker-for-Linux. Um conserto foi submetido em 8 de março de 2019 e espera-se que seja fundido com a base de código. Até lá, uma solução alternativa é usar um container como descrito em qoomon's answer.
Utilize --network="host"
no seu comando docker run
, então 127.0.0.1
no seu container portuário apontará para o seu host portuário.
Nota: Este modo só funciona no Docker para Linux, segundo a documentação.
O Docker oferece diferentes modos de rede ao executar containers. Dependendo do modo que você escolher, você se conectaria ao seu banco de dados MySQL rodando na máquina docker de forma diferente.
Docker cria uma ponte chamada docker0
por padrão. Tanto o anfitrião da doca como os contentores da doca têm um endereço IP nessa ponte.
no host Docker, digite sudo ip address show docker0
você terá uma saída parecida:
[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
Então aqui meu host docker tem o endereço IP 172.17.42.1
na interface de rede docker0
.
Agora, ponha um novo contentor e ponha-lhe uma concha: docker run --rm -it ubuntu:trusty bash
e dentro do container tipo ip addr show eth0
para descobrir como sua interface de rede principal é 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 container tem o endereço IP 172.17.1.192
. Agora olhe para 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 portuário `172.17.42.1' é definido como a rota padrão e é acessível a partir do seu container.
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
Alternativamente, você pode executar um container docker com configurações de rede definidas como host
. Tal container irá compartilhar a pilha de rede com a máquina docker e do ponto de vista do container, localhost
(ou 127.0.0.1
) irá se referir à máquina docker.
Esteja ciente de que qualquer porta aberta em seu contêiner portuário seria aberta no hospedeiro da doca. E isto sem requerer a opção -p' ou
-P' `docker run'.
Configuração de IP no meu host portuário:
[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 contentor de doca em modo **apresentador***:
[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, tanto o host da doca quanto o container da doca compartilham exatamente a mesma interface de rede e como tal têm o mesmo endereço IP.
Para acessar o MySQL rodando no host da docker a partir de containers em modo bridge, você precisa ter certeza que o serviço MySQL está escutando conexões no endereço IP 172.17.42.1
.
Para fazer isso, certifique-se de ter bind-address = 172.17.42.1
ou bind-address = 0.0.0.0.0
no 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, você pode executar o seguinte código em um container :
export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')
então em sua aplicação, utilize a variável de ambiente DOCKER_HOST_IP
para abrir a conexão com o MySQL.
Nota: se você utilizar bind-address = 0.0.0.0.0
o seu servidor MySQL escutará as conexões em todas as interfaces de rede. Isso significa que o seu servidor MySQL pode ser alcançado a partir da Internet ; certifique-se de configurar as regras de firewall de acordo.
Nota 2: se você utilizar bind-address = 172.17.42.1
o seu servidor MySQL não ouvirá as conexões feitas para 127.0.0.1
. Os processos em execução na máquina docker que quereriam se conectar ao MySQL teriam que utilizar o endereço IP 172.17.42.1
.
Para acessar o MySQL rodando no host da docker a partir de containers em modo host, você pode manter bind-address = 127.0.0.1
na sua configuração do MySQL e tudo que você precisa fazer é se conectar a 127.0.0.1
a partir de seus containers:
[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>
note: Utilize mysql -h 127.0.0.1
e não mysql -h localhost
; caso contrário o cliente MySQL tentaria se conectar utilizando um soquete unix.
Isto funcionou para mim em uma pilha NGINX/PHP-FPM sem tocar em nenhum código ou rede onde o aplicativo está apenas esperando ser capaz de se conectar a "localhost".
Monte mysqld.sock
do hospedeiro para dentro do recipiente.
Encontre a localização do arquivo mysql.sock no host executando o mysql:
netstat -ln | awk '/mysql(.*)?\i.sock/ { print $9 }'
Monte esse ficheiro até onde é esperado no cais:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock
Possíveis localizações 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
Eu discordo da resposta de Thomasleveil.
Fazer o mysql ligar-se à 172.17.42.1 impedirá que outros programas usem o banco de dados no host para alcançá-lo. Isto só funcionará se todos os usuários da sua base de dados estiverem encaixados.
Fazer o mysql ligar-se ao 0.0.0.0 abrirá o db para o mundo exterior, o que não só é uma coisa muito ruim de se fazer, mas também é contrário ao que o autor da pergunta original quer fazer. Ele diz explicitamente "O MySql está rodando no localhost e não está expondo um porto para o mundo exterior, então ele está vinculado ao localhost".
Para responder ao comentário do ivant
"Porque não ligar mysql à docker0 também?"
Isto não é possível. A documentação do mysql/mariadb diz explicitamente que não é possível ligar-se a várias interfaces. Você só pode ligar-se a 0, 1, ou a todas as interfaces.
Como conclusão, NÃO encontrei nenhuma forma de chegar à base de dados (apenas localhost) no hospedeiro a partir de um contentor portuário. Isso definitivamente parece ser um padrão muito comum, mas eu não sei como fazer isso.