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
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
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:
postgresql.service file alone doesn’t actually make Postgresql obey the new
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
/etc/systemd/system/postgresql.service.d/override.conf [email protected]/override.conf
The reason for both
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.