View the video here: https://www.youtube.com/watch?v=_Nk8p18pAhU
Population, Population by continent over time, key metrics, gdp per capita vs life expectancy. Select country helps you see key metrics for a countr (population, gdp per capita log normalised, life expectancy linear.). Select metric buttpn changes top two charts, colour coded. Colour changes. Slider for year. Operated by arrow keys or by mouse. Help icons incase you dont know whats going on. Download csv, bubble sizes correlate to population.
Created by the CIUK25 representatives for the Coding Society of the University of Warwick, we aim to produce a visualisation of the "Gapminder" dataset, a collection of data points regarding population, GDP per capita, and life expectancy per country, per year (1952-2007).
We use two containers, ucl-cc-codesoc-ucl-ccc-codesoc conveniently abbreviatable to UCCUCC (pronounced UCK UCK). The main reason behind this was to have a layer of abstraction between our website and the database holding data for our website. This proved convenient for when we wanted to develop locally, not needing to spin up both containers and refresh both on a website update. Having streamlit in our UCCUCC container meant that we could both make it production-ready, as well as just run locally with ease with whatever flags we required.
Next, for container orchestration, we chose to avoid Kubernetes due to the extreme complexity of local running for a simple two-container setup, and instead went for the docker-compose route. The benefit of this is that we get the simplified setup with no additional maintenance, whilst our dual-container setup means that if we needed to deal with additional load, we could then migrate to k8s in future and spin up multiple pods.
We acknowledge there is a security risk inside of this setup, with the database password being transparent in the compose.yaml, but this is as a result of there being no access to GitHub secrets in the ucl-cc-codesoc repository. If there was an easy way to handle this, we would have done it! However since the database is only storing the gapminder dataset, which is freely available in the repository anyway, we decided this was a deprioritised issue.
Our UCCUCC container exposes the internal 8501 port to the external 8080 port for use according to the rules of the challenge. This form of containerisation also makes it easy for us to introduce a load balancer if necessary, as we have already introduced intra-container port forwarding with very little complexity cost.
Next, we choose to instantiate and hold a live database for our gapminder data, and query continuously from the UCCUCC container in the case that in future, this is updated live, and that we want to expand the dataset. We could also introduce caching layers between our two containers, perhaps using something like redis, but decided that if we didn't need k8s to handle load, we didn't need the caching layer either.
The deployment uses two containers, one containing a Postgres SQL database and one running the streamlit application.
The same dockerfile is used to deploy both containers, so only one run command is needed.
To run both containers:
docker compose up --build
Check if you have any containers running:
docker ps
Safely bring down a container
docker-compose down -v
docker-compose up --build
Clean Up:
docker df
Returns an output like:
| CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
| ------------ | ----------- | ---------------------- | ------------ | ------------- | ------------------------------------------- | ------------ |
| 87119005b5e9 | postgres:15 | "docker-entrypoint.s…" | 44 hours ago | Up 20 seconds | 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp | gapminder-db |
To stop a container:
docker stop <container ID>
To kill a container:
docker rm <container ID>
- You may get an error saying the docker daemon isn't running, to start (on Linux):
sudo systemctl start docker
Or use the docker desktop application.
- The application wants to deploy on port :8080 sometimes there's something else on this port and you can find out what it is with:
lsof -i :8080
You can try:
docker system prune
This removes all stopped containers.
There is also the option on docker desktop called Clean/Purge.
When testing locally, it is much faster to just run the database container, and then run streamlit locally.
docker compose up -d db
and then run:
streamlit run src/app.py --server.port=8080
