Allow docker container to connect to a local/host postgres database
Docker for Mac solution
17.06 onwards
Thanks to @Birchlabs' comment, now it is tons easier with this special Mac-only DNS name available:
docker run -e DB_PORT=5432 -e DB_HOST=docker.for.mac.host.internal
From 17.12.0-cd-mac46, docker.for.mac.host.internal
should be used instead of docker.for.mac.localhost
. See release note for details.
Older version
@helmbert's answer well explains the issue. But Docker for Mac does not expose the bridge network, so I had to do this trick to workaround the limitation:
$ sudo ifconfig lo0 alias 10.200.10.1/24
Open /usr/local/var/postgres/pg_hba.conf
and add this line:
host all all 10.200.10.1/24 trust
Open /usr/local/var/postgres/postgresql.conf
and edit change listen_addresses
:
listen_addresses = '*'
Reload service and launch your container:
$ PGDATA=/usr/local/var/postgres pg_ctl reload
$ docker run -e DB_PORT=5432 -e DB_HOST=10.200.10.1 my_app
What this workaround does is basically same with @helmbert's answer, but uses an IP address that is attached to lo0
instead of docker0
network interface.
Simple Solution
The newest version of docker (18.03) offers a built in port forwarding solution. Inside your docker container simply have the db host set to host.docker.internal
. This will be forwarded to the host the docker container is running on.
Documentation for this is here: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host
TL;DR
- Use
172.17.0.0/16
as IP address range, not172.17.0.0/32
. - Don't use
localhost
to connect to the PostgreSQL database on your host, but the host's IP instead. To keep the container portable, start the container with the--add-host=database:<host-ip>
flag and usedatabase
as hostname for connecting to PostgreSQL. - Make sure PostgreSQL is configured to listen for connections on all IP addresses, not just on
localhost
. Look for the settinglisten_addresses
in PostgreSQL's configuration file, typically found in/etc/postgresql/9.3/main/postgresql.conf
(credits to @DazmoNorton).
Long version
172.17.0.0/32
is not a range of IP addresses, but a single address (namly 172.17.0.0
). No Docker container will ever get that address assigned, because it's the network address of the Docker bridge (docker0
) interface.
When Docker starts, it will create a new bridge network interface, that you can easily see when calling ip a
:
$ ip a
...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
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
As you can see, in my case, the docker0
interface has the IP address 172.17.42.1
with a netmask of /16
(or 255.255.0.0
). This means that the network address is 172.17.0.0/16
.
The IP address is randomly assigned, but without any additional configuration, it will always be in the 172.17.0.0/16
network. For each Docker container, a random address from that range will be assigned.
This means, if you want to grant access from all possible containers to your database, use 172.17.0.0/16
.