Skip to content

Chogos/geoip-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

geoip-api

Small Go HTTP service that exposes MaxMind GeoLite2 City and ASN lookups as a flat JSON REST API. Built for Kubernetes on EKS where an init container delivers .mmdb files to a shared volume; this service only reads them. Reloads happen via fsnotify with an atomic pointer swap, so the hot lookup path is lock-free and the process never restarts when databases update.

Endpoints

Path Description
GET /lookup/{ip} Combined City + ASN lookup, flat JSON
GET /healthz Liveness; always 200 once started
GET /readyz 200 only when the City reader is loaded
GET /metrics Prometheus (separate listener)
$ curl -s localhost:8080/lookup/2.125.160.216 | jq
{
  "ip": "2.125.160.216",
  "city": {
    "country_iso_code": "GB",
    "country_name": "United Kingdom",
    "city_name": "Boxford",
    "subdivision_iso_code": "WBK",
    "subdivision_name": "West Berkshire",
    "postal_code": "OX1",
    "latitude": 51.75,
    "longitude": -1.25,
    "accuracy_radius": 100,
    "time_zone": "Europe/London"
  },
  "asn": {
    "number": 1221,
    "organization": "Telstra Pty Ltd"
  }
}

$ curl -s -o /dev/null -w '%{http_code}\n' localhost:8080/lookup/not-an-ip
400

$ curl -s localhost:8080/lookup/192.168.1.1
{"ip":"192.168.1.1"}

city and asn are omitted entirely when no record is found in the corresponding database (or that database is not loaded). 400 is returned only for syntactically invalid IPs.

Configuration

Var Default Purpose
GEOIP_DB_DIR /var/lib/geoip Directory with GeoLite2-City.mmdb and GeoLite2-ASN.mmdb
GEOIP_LISTEN_ADDR :8080 Main API listener
GEOIP_METRICS_ADDR :9090 Metrics listener (separate so NetworkPolicy can restrict it)
GEOIP_LOG_LEVEL info debug, info, warn, error
GEOIP_RELOAD_DEBOUNCE 1s fsnotify debounce window
GEOIP_SHUTDOWN_GRACE 5s Graceful HTTP drain and old-reader close delay

Metrics

Metric Type Labels Notes
geoip_lookups_total counter result (ok, not_found, bad_request, error) per-request outcome
geoip_lookup_duration_seconds histogram [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05]
geoip_db_build_timestamp_seconds gauge database (city, asn) from mmdb BuildEpoch
geoip_db_reload_total counter database, result (ok, error) each reload attempt
geoip_db_loaded gauge database 0 / 1

Local development

make build
GEOIP_DB_DIR=./testdata ./bin/geoip-api
# in another terminal
curl -s localhost:8080/lookup/2.125.160.216 | jq
curl -s localhost:9090/metrics | grep geoip_

Tests use MaxMind's official test data, downloaded on demand into testdata/ (pinned by commit SHA + verified by testdata/SHA256SUMS). The .mmdb files are gitignored.

make testdata   # one-off fetch (also run automatically by `make test`)
make test

To update the pinned fixtures: bump MMDB_REF in the Makefile, delete testdata/*.mmdb, run make testdata (it will fail the checksum), and replace testdata/SHA256SUMS with the new sums (shasum -a 256 testdata/*.mmdb).

Kubernetes deployment notes

  • An init container pulls GeoLite2-City.mmdb and GeoLite2-ASN.mmdb from S3 into an emptyDir volume mounted at /var/lib/geoip. This service only reads. A sidecar (or a CronJob with kubectl rollout restart, or a periodic init re-run) is expected to refresh the volume; this service picks up changes automatically via fsnotify.
  • Expose 8080 (serve) and 9090 (metrics) as separate containerPorts so a NetworkPolicy can restrict scraping to the Prometheus namespace.
  • Set readinessProbe to /readyz on 8080 and livenessProbe to /healthz. Readiness is gated on the City database being loaded; ASN is treated as optional.
  • The image is distroless nonroot and the binary is fully static — no shell, no package manager.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors