How to use PostGIS in Podman

Running containers with PostGIS and pgAdmin in an easier and more secure way than using Docker.

Some years ago, I blogged about how to run PostGIS and pgAdmin in Docker containers, with a follow-up on PostGIS with Docker Compose. With Podman, we got a great Docker alternative: It is more secure (no deamon running with superuser privileges), completely open source (not true for some parts of Docker), the commands and options are almost the same (podman run instead of docker run etc.), you can still use the images from Docker Hub … And best of all, the concept of pods makes our life easier. Nowadays, this might be the easiest way to set up the latest versions of PostGIS and pgAdmin on Linux (avoiding dependency hell).

PostGIS and pgAdmin in Podman Desktop

Pods are a group of containers that behave like if they are all running on the same host (a concept from Kubernetes). With Docker, it was tricky to get the Database, pgAdmin and ogr2ogr or QGIS talking to each other, everything was routed over the network, with every container having its own IP address.

Podman is in the repo of most Linux distros and simple to install. It is also available for Windows and Mac. Optionally, you can add Podman Desktop as a GUI.

A Pod for PostGIS

Let’s make folders for our data volumes:

mkdir -p ~/poddata/postgres
mkdir -p ~/poddata/pgadmin

Create the pod (with port forwarding restricted to local host):

podman pod create --name postgis -p 127.0.0.1:5432:5432 -p 127.0.0.1:8080:80

The following command fetches the PostGIS image from Docker Hub (if the latest version was not yet downloaded), creates and starts the container inside the pod. The data folder is persisted between sessions by mounting a volume. Note: On Docker Hub, the image is called postgis/postgis, but you must prefix it with docker.io (podman can use images from other hubs, too). If you want a specific version, add a tag like postgis/postgis:16-3.4.

podman run -d --pod postgis --name postgres \
  -e POSTGRES_USER=gisuser \
  -e POSTGRES_PASSWORD=mypassword \
  -v ~/poddata/postgres:/var/lib/postgresql/data:Z \
  docker.io/postgis/postgis

Now we do the same with pgAdmin:

podman run -d --pod postgis --name pgadmin \
  -e PGADMIN_DEFAULT_EMAIL=mail@example.com \
  -e PGADMIN_DEFAULT_PASSWORD=SuperSecret \
  -v ~/poddata/pgadmin:/var/lib/pgadmin:Z \
  docker.io/dpage/pgadmin4

Wait a few seconds, then log in into pgAdmin: http://localhost:8080/
To connect to the database in pgAdmin: Hostname localhost, port 5432, user and password as given in the podman run command.

Now you can rightclick the server and create a new database (you only need to give the name, e.g. “gis”), open the query window and add the PostGIS extension:

CREATE EXTENSION postgis;

Manage your pod

After rebooting your system, you start the pod with

podman start postgis

If you want to stop the pod and all it’s containers:

podman pod stop postgis

View logs:

podman logs postgres
podman logs pgadmin

If you want to have the database always up and running, you can manage it with systemd.

Connect with QGIS or OGR

With the same credentials, you can access the database from QGIS and with ogr2ogr. You can use ogr2ogr to get data from all kinds of file formats into the database. This command-line tool is a part of gdal, and you have it already installed if you use e.g. QGIS.
For example load a shapefile:

ogr2ogr -nln nyc_census_blocks_2000 -nlt PROMOTE_TO_MULTI -lco GEOMETRY_NAME=geom -lco FID=gid -lco PRECISION=NO Pg:"dbname=gis host=localhost user=gisuser password=mypassword port=5432" nyc_census_blocks.shp

Be sure to use the correct quotes and the correct password. The option -nlt PROMOTE_TO_MULTI is only needed if you have a mix of e.g. polygons and multi-polygons. Note that ogr2ogr can filter the data while loading it into the database using an SQL query: Simply add -sql your-sql-query to the command. This even works if the input file is not a database, e.g. with shapefiles.

In QGIS, if you add a layer to the database using the DB Manager, make sure to check the right options: You might want to have “Convert field names to lowercase” and “Create spatial index” checked. With a layer without any multi-part features (multi-polygons etc.) you want “Do not promote to multi-polygon” to be checked. With a layer containing multi-polygons, it must be unchecked. You can run any SELECT query and load the result as a new layer.

Upgrading

There is no such thing as upgrading a container: You simply delete it and create a new one, and point the volume to the same folder. If you are upgrading to a higher major PostgreSQL version, however, you must make a backup first, and import the backup afterwards.

You can create a backup of the database with pgAdmin or in the terminal:

podman exec -it postgres pg_dumpall -U gisuser > ~/backup/all_databases.sql

Pull the new image, stop and delete the existing container (the data in the volumes will stay):

podman pull postgis/postgis:latest
podman stop postgres
podman rm postgres

And start a new posgres container with the same podman run as above.