So I have a Nginx running inside a docker container, I have a mysql running on localhost, I want to connect to the MySql from within my Nginx. The MySql is running on localhost and not exposing a port to the outside world, so its bound on localhost, not bound on the ip address of the machine.
Is there any way to connect to this MySql or any other program on localhost from within this docker container?
I disagree with the answer from Thomasleveil.
Making mysql bind to 172.17.42.1 will prevent other programs using the database on the host to reach it. This will only work if all your database users are dockerized.
Making mysql bind to 0.0.0.0 will open the db to outside world, which is not only a very bad thing to do, but also contrary to what the original question author wants to do. He explicitly says "The MySql is running on localhost and not exposing a port to the outside world, so its bound on localhost"
To answer the comment from ivant
This is not possible. The mysql/mariadb documentation explicitly says it is not possible to bind to several interfaces. You can only bind to 0, 1, or all interfaces.
As a conclusion, I have NOT found any way to reach the (localhost only) database on the host from a docker container. That definitely seems like a very very common pattern, but I don't know how to do it.
until host.docker.internal is working for every platform you can use my container acting as a NAT gateway without any manually setup https://github.com/qoomon/docker-host
Edit: If you are using Docker-for-mac or Docker-for-Windows 18.03+, just connect to your mysql service using the host
host.docker.internal
.As of Docker 18.04, this does not work on Docker-for-Linux. However, using a container as described in qoomon's answer you can get it to work.
TLDR
Use
--network="host"
in yourdocker run
command, then127.0.0.1
in your docker container will point to your docker host.Note on docker container networking modes
Docker offers different networking modes when running containers. Depending on the mode you choose you would connect to your MySQL database running on the docker host differently.
docker run --network="bridge" (default)
Docker creates a bridge named
docker0
by default. Both the docker host and the docker containers have an IP address on that bridge.on the Docker host, type
sudo ip addr show docker0
you will have an output looking like:So here my docker host has the IP address
172.17.42.1
on thedocker0
network interface.Now start a new container and get a shell on it:
docker run --rm -it ubuntu:trusty bash
and within the container typeip addr show eth0
to discover how its main network interface is set up:Here my container has the IP address
172.17.1.192
. Now look at the routing table:So the IP Address of the docker host
172.17.42.1
is set as the default route and is accessible from your container.docker run --network="host"
Alternatively you can run a docker container with network settings set to
host
. Such a container will share the network stack with the docker host and from the container point of view,localhost
(or127.0.0.1
) will refer to the docker host.Be aware that any port opened in your docker container would be opened on the docker host. And this without requiring the
-p
or-P
docker run
option.IP config on my docker host:
and from a docker container in host mode:
As you can see both the docker host and docker container share the exact same network interface and as such have the same IP address.
Connecting to MySQL from containers
bridge mode
To access MySQL running on the docker host from containers in bridge mode, you need to make sure the MySQL service is listening for connections on the
172.17.42.1
IP address.To do so, make sure you have either
bind-address = 172.17.42.1
orbind-address = 0.0.0.0
in your MySQL config file (my.cnf).If you need to set an environment variable with the IP address of the gateway, you can run the following code in a container :
then in your application, use the
DOCKER_HOST_IP
environment variable to open the connection to MySQL.Note: if you use
bind-address = 0.0.0.0
your MySQL server will listen for connections on all network interfaces. That means your MySQL server could be reached from the Internet ; make sure to setup firewall rules accordingly.Note 2: if you use
bind-address = 172.17.42.1
your MySQL server won't listen for connections made to127.0.0.1
. Processes running on the docker host that would want to connect to MySQL would have to use the172.17.42.1
IP address.host mode
To access MySQL running on the docker host from containers in host mode, you can keep
bind-address = 127.0.0.1
in your MySQL configuration and all you need to do is to connect to127.0.0.1
from your containers:note: Do use
mysql -h 127.0.0.1
and notmysql -h localhost
; otherwise the MySQL client would try to connect using a unix socket.Solution for Linux (kernel >=3.6).
Ok, your localhost server has default docker interface docker0 with ip address 172.17.0.1. Your container started with default network settings --net="bridge".
$ sysctl -w net.ipv4.conf.docker0.route_localnet=1
$ 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
CREATE USER 'user'@'%' IDENTIFIED BY 'password';
From the kernel documentation:
None of the answers worked for me when using Docker Toolbox on Windows 10 Home, but 10.0.2.2 did, since it uses VirtualBox which exposes the host to the VM on this address.
This worked for me on an NGINX/PHP-FPM stack without touching any code or networking where the app's just expecting to be able to connect to
localhost
Mount
mysqld.sock
from the host to inside the container.Find the location of the mysql.sock file on the host running mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'
Mount that file to where it's expected in the docker:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock
Possible locations of mysqld.sock: