Getting Docker containers talking to Postgresql on the host

January 22, 2016

I’ve been running Django projects in Docker containers over the last new months, as it gives a much clearer separation of app and host system than using virtualenvs alone. Whilst this improves deployment, it has caused me some issues with connections to Postgresql databases.

I am currently running Postgresql on the host machine, as performing WAL backups etc. of containerised Postgresql adds a layer of complexity not necessary for a side project. In order to facilitate containers connecting to the host Postgresql instance, I needed to make Postgresql listen on the docker0 interface as well as localhost. docker0 is firewalled to prevent external access.

I set Postgresql to listen on the docker0 IP address:

listen_addresses = 'localhost, 172.17.0.1'

I then allowed authenticated connections to be made from IP addresses in the docker0 subnet in pg_hba.conf.

host    all     all     172.17.0.0/24       md5

Postgresql will fail to start if the Docker daemon has not started before, because the docker0 interface will not yet exist. To get the ordering right, the systemd configuration needs some overrides.

Systemd unit files can be overridden by one of two methods, either copying and modifying the entire .service file to /etc/systemd/system/, or by using named directories in /etc/systemd/system/service-name.service.d/*. The former has the disadvantage that you completely step away from the vendor supported unit file and any provided updates, and the latter that the vendor supplied version in a future update may be incompatible with your changes. The choice is up to you. I went for the latter.

In the case of Postgresql, there are two existing files on Debian:

/lib/systemd/system/postgresql.service
/lib/systemd/system/postgresql@.service

The latter is a template file which, when expanded, becomes [email protected]: in my case this is [email protected].

Overriding the postgresql.service file alone doesn’t actually make Postgresql obey the new Requires= and After= declarations we are keen to make. For this to work, both needed to be overridden.

This is facilitated by adding:

[Unit]
Requires=docker.service
After=docker.service

To both:

/etc/systemd/system/postgresql.service.d/override.conf
[email protected]/override.conf

The reason for both Requires= and After= is made clear by the Systemd Unit docs:

Requires= If this unit gets activated, the units listed here will be activated as well. If one of the other units gets deactivated or its activation fails, this unit will be deactivated. … If a unit foo.service requires a unit bar.service as configured with Requires= and no ordering is configured with After= or Before=, then both units will be started simultaneously and without any delay between them if foo.service is activated.

Reloading the config sudo systemctl daemon-reload, should set everything up, and when the system restarts, Postgresql will not start unless Docker has. This ensures docker0 will always be available for postgres to listen on.

Header image modified from: cc_c0 @powerhouse_museum (contact)