Some PostgreSQL Docker image tips
I have been playing a little with the official Postgres Docker image. I had two main goals:
- Connect client containers to the running PostgreSQL container using modern docker network functionality instead of the deprecated Docker link feature. The image’s current documentation only uses link in the examples.
- Store the database data in a Docker volume so that it can survive the deletion of the database container, and can be attached to a new container created from the same PostgreSQL image.
First I created a volume for the data:
docker volume create pgdatavol
Then I created a network:
docker network create simple-network
Why not simply run the container in the default network? Because, as stated in the documentation:
Docker does not support automatic service discovery on the default bridge network. If you want containers to be able to resolve IP addresses by container name, you should use user-defined networks instead.
I launched the PostgreSQL containter like this:
docker run --name some-postgres -d --rm -p 127.0.0.1::5432 --network=simple-network --network-alias=pgmachine -v pgdatavol:/var/lib/postgresql/data -e POSTGRES_PASSWORD='somepasswdhere' postgres
- -d starts the container in detached mode. (But you can use docker logs some-postgres to check the server logs.)
- -rm ensures that the container is deleted when the container is killed or the server exits.
- -p 127.0.0.1::5432 publishes the exposed 5432 port of the container in the Docker host’s loopback interface. If I had used -P the port would have been open in all the host’s interfaces. I didn’t specify a host port, so docker port some-postgres was necessary to identify it. That said, I access the database from a container in the same bridge network, and not directly from the host, so publishing the port was unnecessary.
- — network-alias=pgmachine provides another name (besides the one given with — name) for containers in the network to locate the database container. The following passage in the documentation is interesting:
How can Docker supply each container with a hostname and DNS configuration, without having to build a custom image with the hostname written inside? Its trick is to overlay three crucial /etc files inside the container with virtual files where it can write fresh information. You can see this by running mount inside a container
Having launched the database container, I ran psql in another container spawned from the same image:
docker run -it --rm --network=simple-network postgres psql -h some-postgres -U postgres
- -it starts the container in interactive mode.
Putting the data in a separate volume seems to work, and I assume it can be faster that working in the container’s filesystem.
One thing I noticed is that if the volume already contains data, the parameter
-e POSTGRES_PASSWORD='somepasswdhere'
is ignored when you spawn a new container from the PostgreSQL image. The container keeps using the initial password in that case, I suppose because it finds the already existing configuration.