More often than not, we end up spending a lot of time & effort on installing and re-installing software & tools on our computers. Docker helps in providing us with a way to reduce this pain of installing software and fighting issues while doing so. Some understanding of how docker works is needed to achieve this, so we’ll briefly discuss Docker before getting into the actual implementation.
What is Docker and how to install it?
Docker is a very popular open-source project based on Linux containers. It helps in decoupling any application from the infrastructure by packing all application system requirements into a container. This means that we can pack all the requirements to run Postgres on our machines into one package called a container & run it without bothering about any system-specific requirements. Tons of docs and articles can be found for docker for those who want to know more about it, but an ideal starting place would be here and instructions on how to install docker can be found here.
Pull the Postgres docker image
A docker image is a template that contains instructions to create a container that can be run on a docker platform. It is a convenient way to package up applications & their direct requirements which can then be shared across and run in an isolated manner.
In order to pull the latest stable release of Postgres, run
docker pull postgres
This will pull the image from the official Postgres docker hub repository. In case a specific version of Postgres is needed, one can provide the appropriate image tag name to the above command like so
docker pull postgres:[tag_name]
Where should the data be stored?
If we need to store the data generated by the Postgres instance running inside a container beyond its lifecycle, we need to map a local mount point as a data volume to a path inside the container. In simpler terms, we are letting the container know that instead of storing the data inside the container, it can use another path in the outside world to store it (considering the container as isolated). This way, the data is persisted even after the container has been killed & when a new container is run, it can pick up right where the last one left it. We can use any directory (making sure it is not used by anything else), but instead, I will be using this command, which creates all the directories under $HOME
which is /Users/[logged_in_user]
in your terminal.
HINT: Both read/write permissions might be needed for this directory
mkdir -p $HOME/docker/volumes/postgres
Running the container
This command will start running the container & add a local mount point as a data volume to a path inside the container.
docker run --rm --name pg-docker -e POSTGRES_PASSWORD=root -d -p 5432:5432 -v $HOME/docker/volumes/postgres:/var/lib/postgresql/data postgres:[tag_name]
What does this command do?
docker run
: runs the image as a container--rm
: option to remove container & its filesystem after it has been exited--name
: is followed by the name which we want to provide to the container. No two containers cannot have the same name, so its useful to pass--rm
-e
: expose an environment variable. Here were are settingPOSTGRES_PASSWORD
which is specific to the image. It sets the superuser password for the Postgres instance. More environment variables can be set and details can be found here-d
: run in a detached mode which means the container would be run in the background-p
: port binding 5432 to localhost:5432 within the container. This enables the outside world to connect to the container (the Postgres instance in this case)-v
: define the local mount point. Here we are mounting$HOME/docker/volumes/postgres
on our machines to/var/lib/postgres/data
inside the container (the postgres instance) which ensures data persistence outside the container filesystem
More details on the options for this command can be found here
Connect to the Postgres instance inside a container
Once the container is up and running, we can run
docker exec -it pg-docker psql -U postgres
What does this command do?
docker exec
: this runs a new command inside a running container-it
:i
stands for interactive which keeps the standard input open even when the process is not attached.-t
stands fortty
which allocated a pseudo-TTYpg-docker
: name of the running container (pg-docker in this case)psql -U postgres
: the actual command which is being run inside the container. This tries to connect to the Postgres instance using psql with username Postgres
More details on the options for this command can be found here
Some more info
- Use
docker images
to find the Postgres image which was pulled usingdocker pull
along with the tag details as well as some more information - Use
docker ps -a
to find the details of all containers. This can be run afterdocker run
to check if the container is up & running successfully. More info here - Use
docker stop [container_name]
to stop a container anddocker rm [container_name]
to remove a container (options can be used to stop & remove) - If you are using zsh shell, you can make use of aliasing to form custom shorthands for the commands discussed above.