Zum Inhalt

cusy Map

Screenshot der cusy-Map-Kartenansicht

  • Kund*in: cusy
  • Zeitraum: 2024 und fortdauernd
  • Aufgaben: Architektur, Front- und Backend, CI/CD, Operations
  • Technologien: Python, FastAPI, Protomaps (OpenStreetMap), MapLibre GL JS
  • Website: map.cusy.io
  • Repositories: ce.cusy.io/maps

Als Dienstleister mit starkem Fokus auf Datenschutz bietet cusy eine komplett in Deutschland gehostete Karteninfrastruktur auf der Basis von OpenStreetMap (OSM) an. Kund*innen können eine Karte der Welt auf ihrer Website (oder in ihrem Intranet) einbinden, ohne Tracking durch US-Konzerne und ohne schwer kalkulierbare API-Gebühren. Die Karte lässt sich bezüglich Look & Feel, Inhalt und Design nach Wunsch anpassen. Adresssuche und Geocoding sind ebenfalls enthalten.

Meine Aufgaben

Projektziel war die Evaluation und Umsetzung einer Kartenapplikation auf Basis von OSM-Daten. Der Betrieb sollte dabei möglichst wartungsarm möglich sein, um Stabilität zu gewährleisten und laufende Kosten gering zu halten.

Technologieauswahl

Das OpenStreetMap-Projekt stellt seit jeher seine Kartendaten frei zur Verfügung. Lange Zeit war der Betrieb eines eigenen Tile-Servers, der aus der rohen Datenbasis Bilderkacheln erzeugt, die im Browser dargestellt werden können, aufwendig und mit nicht zu unterschätzenden Hardwareanforderungen verbunden.

Seit 2021 gibt es mit dem Protomaps-Projekt jedoch eine spannende Alternative, die serverseitig ausschließlich eine ca. 120 GiB große statische Datei und einen generischen Webserver voraussetzt. Die Kartendaten liegen als ungestylte Vektoren vor und werden im PMTiles-Format ausgeliefert und über JavaScript im Browser gerendert. Dank des speziellen PMTiles-Dateiformats und HTTP Range Requests werden dabei nur die Zoomstufen und Kartenausschnitte heruntergeladen, die auch tatsächlich benötigt werden.

Auch für Geocoding, also die Übersetzung von Adressen und Ortsnamen in Geokoordinaten (oder umgekehrt) galt es eine möglichst einfache Lösung zu finden, da OpenStreetMaps Geocoder Nominatim eine Menge Software-Abhängigkeiten mit sich bringt. Unter anderem verlangt er den Betrieb einer Postgres-Datenbank mit dem kompletten OSM-Datenbestand; die Installationsanleitung spricht von 1 TB Storage, 128 GB RAM, und 5 Tagen Laufzeit für den Import der Daten.

Auch hier habe ich eine schlankere und einfachere Lösung gefunden: photon braucht nur eine Java-Runtime, ca. 250 GB Storage und kommt bei sporadischer Benutzung auch mit 16 oder 32 GB RAM aus.

Ich habe auch etwas Evaluation mit SQLite und dessen Volltextsuche durchgeführt. Die Ergebnisse waren zwar vielversprechend und ich möchte darüber bei Gelegenheit noch einen Blogbeitrag verfassen, aber Geocoding ist leider komplexer als nur Volltextsuche, und die Entwicklungszeit hätte in keinem Verhältnis zu der nur geringen Verschlankung des Setups gestanden.

Frontend

MapLibre GL JS ist eine moderne JavaScript-basierte Library zur Darstellung von Kartendaten im Browser unter Zuhilfenahme von WebGL.

Protomaps bietet mit pmtiles eine JavaScript-Library, mit der sich das PMTiles-Datenformat in MapLibre GL JS integrieren lässt. Sobald das geschehen ist, müssen die Vektordaten aber auch noch gestyled werden. Auch hier bietet Protomaps wieder eine passende Library, die aber z.B. Schriftarten und Symbole noch von Protomaps' Server bzw. GitHub nachlädt.

Mit MapLibre GL JS UI habe ich ein TypeScript-Paket geschrieben, das all diese Abhängigkeiten bündelt und auch den nötigen Glue-Code bereits enthält, damit die Einbindung auf Websites möglichst einfach und mit wenig Boilerplate umgesetzt werden kann. Auch das Selbsthosten der Assets wird vereinfacht.

Außerdem unterstützt meine Library Convenience-Features wie verbesserte Dark-Mode-Styles, automatisches Umschalten zwischen Light und Dark Mode, und automatisches Anpassen der Karten- und UI-Sprache an die im Browser gesetzten Präferenzen.

Backend

Photon hat zwar eine einfach zu verwendende API, aber sie direkt ins Internet zu exposen ist womöglich suboptimal – schon allein aus Sicherheitsgründen.

Daher habe ich Polarizer geschrieben; eine FastAPI-Applikation, die nur ausgewählte Parameter weiterleitet und Konfigurationsprofile unterstützt. So können z.B. Suchen auf bestimmte Kartenbereiche eingeschränkt werden, oder Treffer in der Nähe eines bestimmten Ortes (z.B. dem Firmensitz) bevorzugt werden.

Operations

Ich administriere das komplette cusy-Map-Setup auf einem Hetzner Cloud-Server.

Das Deployment wurde erst mit NixOS, dann mit Debian und Ansible umgesetzt, und schließlich mit pyinfra. Wir haben hier gleich drei konkurrierende Technologien eingesetzt, weil wir im Verlauf des Projekts erst den Hoster gewechselt haben und dann Ansible für manche Tasks unnötig komplex fanden. Mit pyinfra sind wir allerdings auch nicht wirklich glücklich und werden in absehbarer Zeit einen weiteren alternativen Ansatz versuchen, der aber noch nicht spruchreif ist.