Running Multiple Containers

Using Pods to link it all together

Jon Reades - j.reades@ucl.ac.uk

1st October 2025

Find a PostGIS Image

Search Quay.io – on a modern M-chip Mac you need to use arm64 images, on Windows it’s usually amd64; however, in most cases you don’t need to search for these explicitly because ‘builds’ for most images are completed for both.

Create a ‘Pod’

This pod exposes two ‘ports’ (8888 and 5432) to the wider world.

podman pod create -p 8888:8888 -p 5432:5432 myapp

In this case we ‘map’ 8888 inside the pod to 8888 outside the pod, but we could change this: -p 7777:8888 so that requests for 7777 from the outside world are ‘forwarded’ to 8888 inside the pod.

Attach PostGIS to the Pod

There’s a lot going on here that took quite some to figure out1, but the key thing turned out to be the pg_hba.conf file which tells Postgres on which ports it can listen.

podman run --rm -d --name postgres --pod myapp \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=test \
-e POSTGRES_DB=test \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v "${PWD}"/data/postgres:/var/lib/postgresql/data \
-v /tmp:/tmp \
-v "${PWD}"/data/postgres/pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf \
quay.io/taolu/postgis:14-3.5-alpine

This command is telling Podman to start a postgis image (14-3.5-alpine) it downloads from Quay with a test of startup options set at launch. The first three are specifying the databasei, user, and password. The remainder are connecting various ‘mount points’ on the container to locations on the host computer. So the data that is added to the database will be stored under the current working directory (PWD == Print Working Directory). We allow Postgis to the use the computer’s /tmp folder for working data. And the final bit is taking a local copy that we’ve set up of pg_hba.conf and putting that in the place that a regular Postgres server would expect to find it.

You can now connect using psql on port 5432.

For example:

psql -h localhost -p 5432 -U postgres -d test 

Attach SDS to the Pod

Only containers inside the Pod can talk to other containers in the pod. So for the SDS container to talk to PostGIS, they both need to be attached to the pod using myapp.

podman run --rm -d --name sds --pod=myapp \
-v "$(pwd):/home/jovyan/work" \
docker.io/jreades/sds:2025-amd \
start.sh \
jupyter lab --LabApp.password='' --ServerApp.password='' --NotebookApp.token=''

You can now connect using your browser: http://localhost:8888/

Tip

The rest of this short tutorial is all run on the SDS container using your browser as the interface. This is true even for bits about the command line interface: in Jupyter you pick File > New > Terminal.

Install psycopg2

If I haven’t had time to update the SDS container then you can do this on the SDS Terminal in your browser using the folllowing command:

pip install psycopg2`

This is because the sqlalchemy framework is already there but the psycopg2 driver for Postgres isn’t.

Run Python

Now you will start a new Notebook (File > New > Notebook) and create code cells for each of the following sections of code.

Load Data

from sqlalchemy import create_engine
engine = create_engine('postgresql://postgres:test@localhost:5432/test')

import geopandas as gpd
gdf = gpd.read_file('work/data/src/TM_WORLD_BORDERS-0.3.gpkg')
gdf.to_postgis('world', engine)

Query Data

insp = inspect(engine) 
insp.get_table_names()
import geopandas as gpd

gdf = gpd.read_postgis('SELECT * FROM msoa', geom_col='geometry', con=engine)

gdf.head(2)
gdf.plot()
gdf = gpd.read_postgis("""
    SELECT * 
    FROM msoa 
    WHERE "MSOA21NM" LIKE 'Waltham%%'
""", geom_col='geometry', con=con)
gdf.plot()

Query the Data without Python

One final thing: if you run a Terminal on your computer (so not in the SDS terminal any more) you can also query the data that was just loaded. Your computer is the only other machine that access the pod.

psql -h localhost -p 5432 -U postgres -d test
SELECT * FROM world LIMIT 0;
SELECT "NAME", "ISO3", "POP2005", "REGION" FROM world LIMIT 5;
SELECT "NAME", "POP2005" FROM world WHERE AREA > 900000;