Files
geoipapi/README.md
Ask Bjørn Hansen c991335da7
All checks were successful
continuous-integration/drone/push Build is passing
Add comprehensive test suite and documentation
- Complete unit, integration, and E2E test coverage (189 test cases)
- Enhanced CI/CD pipeline with race detection and quality checks
- Comprehensive godoc documentation for all packages
- Updated README with API docs, examples, and deployment guides
2025-07-02 01:02:28 -07:00

338 lines
8.1 KiB
Markdown

# GeoIP API
A high-performance HTTP service that provides MaxMind GeoIP data for IP geolocation lookups. Designed to run as a lightweight daemon within Kubernetes clusters to serve geolocation data to other services.
## Features
- **Fast HTTP API** for IP geolocation lookups
- **Multiple response formats**: country codes and full JSON data
- **OpenTelemetry tracing** with standard Traceparent headers
- **Automatic database discovery** in standard system paths
- **Health check endpoint** with actual database verification
- **Go client library** for easy integration
- **Comprehensive test coverage** with unit, integration, and E2E tests
## API Endpoints
### Country Lookup
```
GET /api/country?ip=192.0.2.1
```
Returns the lowercase ISO country code (e.g., `us`, `gb`)
### Full JSON Data
```
GET /api/json?ip=192.0.2.1
```
Returns complete MaxMind GeoIP data in JSON format including:
- Country, city, and region information
- Latitude/longitude coordinates
- ISP and organization data (if available)
- Time zone information
### Health Check
```
GET /healthz
```
Performs an actual GeoIP lookup to verify database connectivity and returns the country code for a test IP.
## Installation
### From Source
```bash
go build -o geoipapi
./geoipapi
```
### Using Docker
```bash
docker build -t geoipapi .
docker run -p 8009:8009 geoipapi
```
## Database Setup
The service automatically searches for MaxMind databases in standard locations:
- `/usr/share/GeoIP/` (Linux default)
- `/usr/local/share/GeoIP/` (FreeBSD)
- `/opt/local/share/GeoIP/` (MacPorts)
- `/opt/homebrew/var/GeoIP/` (Homebrew)
### Supported Database Files
- **Country databases**: `GeoIP2-Country.mmdb`, `GeoLite2-Country.mmdb`
- **City databases**: `GeoIP2-City.mmdb`, `GeoLite2-City.mmdb`
- **ISP databases**: `GeoIP2-ISP.mmdb`
### Installing GeoLite2 Databases (Free)
1. Create a free MaxMind account at https://www.maxmind.com/en/geolite2/signup
2. Download the databases manually, or
3. Use the built-in MaxMind package for automatic downloads:
```go
import "go.ntppool.org/geoipapi/maxmind"
maxmind.LicenseKey = "your_license_key_here"
maxmind.EditionIDs = "GeoLite2-City,GeoLite2-Country"
maxmind.Path = "/usr/share/GeoIP/"
err := maxmind.DownloadGeoLite2DB()
```
## Configuration
### Environment Variables
- **OpenTelemetry**: Standard OTel environment variables are supported
- `OTEL_EXPORTER_OTLP_ENDPOINT`
- `OTEL_SERVICE_NAME`
- `OTEL_RESOURCE_ATTRIBUTES`
### Server Configuration
The server runs on port 8009 by default with the following timeouts:
- **Read timeout**: 1 second
- **Write timeout**: 10 seconds
## OpenTelemetry Support
The service includes comprehensive OpenTelemetry instrumentation:
- **HTTP requests** are automatically traced
- **Database lookups** are instrumented with spans
- **Health checks** are filtered from tracing to reduce noise
- **Custom attributes** include IP addresses and operation details
Tracing works seamlessly with the OpenTelemetry Collector and common observability platforms.
## Go Client Library
Use the provided Go client for easy integration:
```go
package main
import (
"context"
"fmt"
"log"
"net/netip"
"os"
"go.ntppool.org/geoipapi/client/geoipapi"
)
func main() {
// Set the service endpoint
os.Setenv("geoip_service", "geoip-service:8009")
ctx := context.Background()
ip := netip.MustParseAddr("8.8.8.8")
city, err := geoipapi.GetCity(ctx, ip)
if err != nil {
log.Fatal(err)
}
fmt.Printf("IP: %s\n", ip)
fmt.Printf("Country: %s\n", city.Country.IsoCode)
fmt.Printf("City: %s\n", city.City.Names["en"])
fmt.Printf("Location: %f, %f\n", city.Location.Latitude, city.Location.Longitude)
}
```
### Client Configuration
Set the `geoip_service` environment variable to point to your GeoIP API service:
```bash
export geoip_service="geoip-service.default.svc.cluster.local:8009"
```
## Command Line Usage
The service can also be used as a command-line tool for IP lookups:
```bash
./geoipapi 8.8.8.8 1.1.1.1 192.168.1.1
```
Output:
```
8.8.8.8: us
1.1.1.1: us
192.168.1.1:
```
## Development
### Running Tests
The project includes comprehensive test coverage:
```bash
# Run all tests
go test ./...
# Run tests with race detection
go test -race ./...
# Run only fast tests
go test -short ./...
# Run with coverage
go test -cover ./...
```
### Test Types
- **Unit tests**: Test individual functions and components
- **Integration tests**: Test HTTP API endpoints with a running server
- **End-to-end tests**: Test complete client-server workflows
- **Race condition tests**: Verify thread safety under concurrent load
### Code Quality
```bash
# Format code
gofumpt -w .
# Lint code
go vet ./...
# Verify dependencies
go mod verify
```
## Architecture
### Core Components
1. **HTTP Server** (`geoipapi.go`): Main API server with endpoint handlers
2. **MaxMind Package** (`maxmind/`): Database download and management utilities
3. **Client Library** (`client/geoipapi/`): Go client for consuming the HTTP API
### Database Discovery
The service automatically discovers MaxMind databases by:
1. Searching standard system paths
2. Looking for supported database filenames
3. Opening the first available database for each type
4. Gracefully handling missing databases
### Error Handling
- **Invalid IP addresses** return HTTP 500 with "data error"
- **Missing databases** are detected during health checks
- **Network errors** in the client include proper context
- **Tracing errors** are recorded in spans for debugging
## Deployment
### Kubernetes
Example Kubernetes deployment:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: geoipapi
spec:
replicas: 3
selector:
matchLabels:
app: geoipapi
template:
metadata:
labels:
app: geoipapi
spec:
containers:
- name: geoipapi
image: your-registry/geoipapi:latest
ports:
- containerPort: 8009
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector:4317"
- name: OTEL_SERVICE_NAME
value: "geoipapi"
volumeMounts:
- name: geoip-data
mountPath: /usr/share/GeoIP
readinessProbe:
httpGet:
path: /healthz
port: 8009
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8009
initialDelaySeconds: 15
periodSeconds: 20
volumes:
- name: geoip-data
configMap:
name: geoip-databases
---
apiVersion: v1
kind: Service
metadata:
name: geoipapi
spec:
selector:
app: geoipapi
ports:
- port: 8009
targetPort: 8009
```
### Performance Considerations
- **Database caching**: MaxMind databases are loaded once on startup
- **Connection pooling**: HTTP client uses connection pooling for better performance
- **Concurrent requests**: Server handles multiple concurrent requests efficiently
- **Memory usage**: Minimal memory footprint suitable for container environments
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes with tests
4. Run the full test suite: `go test ./...`
5. Format code: `gofumpt -w .`
6. Submit a pull request
### CI/CD
The project uses Drone CI with the following pipeline:
1. **Dependencies**: Download Go modules
2. **Testing**: Run unit, integration, and race tests
3. **Code Quality**: Run `go vet`, `gofumpt`, and `go mod verify`
4. **Build**: Compile the binary
5. **Docker**: Build and push container image
## License
This project is licensed under the terms specified in the LICENSE file.
## Support
For issues and questions:
- **Bug reports**: Create an issue in the GitHub repository
- **Feature requests**: Submit a feature request with use case details
- **Documentation**: Check the Go docs: `go doc go.ntppool.org/geoipapi`
## Related Projects
- **MaxMind GeoIP2**: https://www.maxmind.com/en/geoip2-services-and-databases
- **OpenTelemetry Go**: https://github.com/open-telemetry/opentelemetry-go
- **Kubernetes ingress-nginx**: https://github.com/kubernetes/ingress-nginx (inspiration for MaxMind handling)