One of the biggest benefits of using docker for me has been the fact that it makes developing code with databases much simpler.
Whenever I’m building an app, I tend to use postgres as the database. Pre-docker, this meant installing postgres locally on my machine, running the server, creating the database, adding the required users and persmissions and finally running the app locally to test and develop. I’ve spent hours going through this.
Post-docker, things became much much simpler, especially with docker-compose. With docker-compose now I can have a postgres server up and running and configured as I want within 5-10min and I don’t have to worry about installing it and running it on my machine anymore. This is was magical. I could now focus spending my time on more important things. Like looking at cat gifs.
Today however, wasn’t one of those days :(
Scouring the internet for the initial config to go on, I wrote my docker-compose.yml as shown.
services: postgres: image: postgres restart: always ports: - "5432:5432" environment: - POSTGRES_PASSWORD=pass - POSTGRES_USER=user - POSTGRES_DB=db server: build: ./ ports: - "8000:8000" depends_on: - postgres networks: - default
And used the following string for the postgres connection in the app
Only to be met with the unexpected error, when running both the containers
server_1 | 2020/12/13 19:42:16 couldn't get driver: failed to connect to `host=127.0.0.1 user=postgres database=postgres`: dial error (dial tcp 127.0.0.1:5432: connect: connection refused) server_1 | exit status 1
And while I’ve done this a couple of times before I couldn’t wrap my head around why this error was popping up.
Step 1: Typo
Without much resolute my first instinct was to check for typos, after cross-verifying, I found everything to be ok.
Step 2: Brute force
Not particularly proud of this, but I did try swapping 127.0.0.1 with localhost to get the same error. Hint: I was spot on as to where the error was, but just totally wrong about how to go about it.
Step 3: Bash
This I like. To diagnose the problem, I ran
❯ docker-compose exec server bash. This dropped me right into the shell of the server app. From here these are the following debugging steps I followed
- Install psql client
- Try to manually connect using the psql client. This failed.
- Check if the port is being used using netstat. No, it wasn’t.
- Realize that this is a network issue. Ahaa!
Docker Compose Network
Putting it shortly, docker compose isolates each of the containers network. This is done by adding them to the
<myapp>_default which is a newly created network, where
<myapp> is the name of the directory. Under this each of the containers is added via it’s name. In our case that would be
server. These are like DNS A-records, which means using
postgres would resolve to the IP of the postgres container and so on. Each of the container can use these names to connect to the other containers.
Now that we know the exact problem, all we need to do is change our host in the postgres connection string to
Another way is to add
network_mode: bridge to each container to put them all under the same network. While this is a topic in itself, this bridges the network between the two containers so that they co-exist on the same network.