https://github.com/jobrunner/spatialite-base-image
Multi-arch Docker images (amd64/arm64) with GDAL, SQLite, SpatiaLite, GEOS, and librttopo for geospatial applications.
https://github.com/jobrunner/spatialite-base-image
docker-image gdal golang spatialite
Last synced: 5 months ago
JSON representation
Multi-arch Docker images (amd64/arm64) with GDAL, SQLite, SpatiaLite, GEOS, and librttopo for geospatial applications.
- Host: GitHub
- URL: https://github.com/jobrunner/spatialite-base-image
- Owner: jobrunner
- License: gpl-2.0
- Created: 2025-12-16T23:58:00.000Z (6 months ago)
- Default Branch: master
- Last Pushed: 2025-12-19T12:01:06.000Z (6 months ago)
- Last Synced: 2025-12-20T14:58:50.850Z (6 months ago)
- Topics: docker-image, gdal, golang, spatialite
- Language: Shell
- Homepage:
- Size: 76.2 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# SpatiaLite Docker Images
[](https://github.com/jobrunner/spatialite-base-image/actions/workflows/ci.yml)
[](https://github.com/jobrunner/spatialite-base-image/releases)
[](https://github.com/jobrunner/spatialite-base-image/pkgs/container/spatialite-base-image)
Multi-architecture Docker images (amd64/arm64) with GDAL, SQLite, SpatiaLite, GEOS, and librttopo.
## Images
### Versioning
Images use semantic versioning. When you tag a release `v1.2.3`, the following tags are created:
| Tag Pattern | Example | Description |
|-------------|---------|-------------|
| `X.Y.Z` | `1.2.3` | Exact version (immutable) |
| `X.Y` | `1.2` | Latest patch of minor version |
| `X` | `1` | Latest minor/patch of major version |
| `latest` | - | Latest release (use with caution) |
**Recommendation:** Use exact versions (`1.2.3`) for reproducible builds. Use `X.Y` for automatic patch updates.
### Runtime Images (for Production)
Minimal images containing only runtime libraries. Use these for your final production containers.
```
ghcr.io/jobrunner/spatialite-base-image:alpine-1.4.0
ghcr.io/jobrunner/spatialite-base-image:ubuntu-1.4.0
ghcr.io/jobrunner/spatialite-base-image:1.4.0 # Alpine (default)
```
| Base | Tags |
|------|------|
| Alpine 3.21 | `alpine-X.Y.Z`, `alpine-X.Y`, `alpine-X`, `alpine-latest`, `X.Y.Z`, `X.Y`, `X`, `latest` |
| Ubuntu 26.04 | `ubuntu-X.Y.Z`, `ubuntu-X.Y`, `ubuntu-X`, `ubuntu-latest` |
### Development Images (for Building)
Images with development headers, pkg-config files, and build tools (gcc, g++). Use these to compile applications with CGO bindings.
```
ghcr.io/jobrunner/spatialite-base-image:alpine-dev-1.4.0
ghcr.io/jobrunner/spatialite-base-image:ubuntu-dev-1.4.0
ghcr.io/jobrunner/spatialite-base-image:dev-1.4.0 # Alpine (default)
```
| Base | Tags |
|------|------|
| Alpine 3.21 | `alpine-dev-X.Y.Z`, `alpine-dev-X.Y`, `alpine-dev-X`, `alpine-dev-latest`, `dev-X.Y.Z`, `dev-X.Y`, `dev-X`, `dev` |
| Ubuntu 26.04 | `ubuntu-dev-X.Y.Z`, `ubuntu-dev-X.Y`, `ubuntu-dev-X`, `ubuntu-dev-latest` |
## Why Separate Dev and Runtime Images?
When building Go applications with CGO bindings (like GDAL or SpatiaLite), the compiled binary links against shared libraries (`.so` files). **The library versions must match between build and runtime.**
### The Problem
If you build in `golang:alpine` and run in a different SpatiaLite image:
```dockerfile
# DON'T DO THIS - version mismatch risk!
FROM golang:1.23-alpine AS builder
RUN apk add gdal-dev # installs version X
# ... build ...
FROM some-other-spatialite-image # has version Y
COPY --from=builder /app/myapp . # may crash or behave unexpectedly
```
### The Solution
Use matching dev/runtime image pairs from this repository with the **same version tag**:
```dockerfile
# BUILD with dev image
FROM ghcr.io/jobrunner/spatialite-base-image:alpine-dev-1.4.0 AS builder
# ... install Go, build ...
# RUN with matching runtime image (same version!)
FROM ghcr.io/jobrunner/spatialite-base-image:alpine-1.4.0
COPY --from=builder /app/myapp .
```
Both images are built from the same base in the same CI pipeline, guaranteeing identical library versions.
## Included Libraries
- **GDAL** - Geospatial Data Abstraction Library
- **SQLite** - Database engine
- **SpatiaLite** - Spatial extension for SQLite
- **GEOS** - Geometry Engine Open Source
- **librttopo** - RT Topology Library
- **PROJ** - Coordinate transformation library
Dev images additionally include:
- **gcc/g++** - C/C++ compilers
- **pkg-config** - Library configuration tool
- **Development headers** (`.h` files) for all libraries
## Environment Variables
All images have these pre-configured:
```
SPATIALITE_SECURITY=relaxed
SQLITE_ENABLE_LOAD_EXTENSION=1
LD_LIBRARY_PATH=/usr/lib:/usr/local/lib
```
## Security
All images include security hardening:
- **Non-root user**: Images run as `spatialite` user (UID 10001) by default
- **No SUID/SGID**: All SUID/SGID bits are removed from binaries
- **Minimal attack surface**: Only required packages are installed
### Running as root (when needed)
Dev images can be run as root for tasks requiring elevated privileges:
```bash
docker run --user root -it ghcr.io/jobrunner/spatialite-base-image:alpine-dev-1.4.0 sh
```
### Production hardening
For maximum security in production:
```bash
docker run --rm \
--read-only \
--security-opt=no-new-privileges:true \
--cap-drop=ALL \
-v $(pwd)/data:/data \
ghcr.io/jobrunner/spatialite-base-image:1.4.0
```
## Usage
### Basic Usage
```bash
# Run SQLite with SpatiaLite
docker run --rm -it ghcr.io/jobrunner/spatialite-base-image:1.4.0
# Load SpatiaLite extension
sqlite> SELECT load_extension('mod_spatialite');
sqlite> SELECT spatialite_version();
```
### Mount Local Data
```bash
docker run --rm -it \
-v $(pwd)/data:/data \
ghcr.io/jobrunner/spatialite-base-image:1.4.0 \
sqlite3 /data/mydb.sqlite
```
## Multi-Stage Build for Go Applications
### Recommended: Alpine-based Build
```dockerfile
# =============================================================================
# Build stage - use the dev image with all headers and build tools
# =============================================================================
FROM ghcr.io/jobrunner/spatialite-base-image:alpine-dev-1.4.0 AS builder
# Install Go
RUN apk add --no-cache go
WORKDIR /app
# Copy go module files first (better layer caching)
COPY go.mod go.sum ./
RUN go mod download
# Copy source code
COPY . .
# Build with CGO enabled
# The dev image has pkg-config set up correctly for all libraries
RUN CGO_ENABLED=1 go build -o /app/myapp .
# =============================================================================
# Runtime stage - use the minimal runtime image (SAME VERSION!)
# =============================================================================
FROM ghcr.io/jobrunner/spatialite-base-image:alpine-1.4.0
# Copy only the binary from builder
COPY --from=builder /app/myapp /usr/local/bin/myapp
ENTRYPOINT ["/usr/local/bin/myapp"]
```
### Ubuntu-based Build (for glibc compatibility)
Some Go libraries require glibc. Use the Ubuntu variants:
```dockerfile
# Build stage
FROM ghcr.io/jobrunner/spatialite-base-image:ubuntu-dev-1.4.0 AS builder
# Install Go
RUN apt-get update && apt-get install -y --no-install-recommends golang-go \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=1 go build -o /app/myapp .
# Runtime stage (SAME VERSION!)
FROM ghcr.io/jobrunner/spatialite-base-image:ubuntu-1.4.0
COPY --from=builder /app/myapp /usr/local/bin/myapp
ENTRYPOINT ["/usr/local/bin/myapp"]
```
### Using Specific GDAL CGO Flags
If you need explicit CGO flags (e.g., for [lukeroth/gdal](https://github.com/lukeroth/gdal)):
```dockerfile
FROM ghcr.io/jobrunner/spatialite-base-image:alpine-dev-1.4.0 AS builder
RUN apk add --no-cache go
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Use pkg-config to get the correct flags
RUN CGO_ENABLED=1 \
CGO_CFLAGS="$(pkg-config --cflags gdal)" \
CGO_LDFLAGS="$(pkg-config --libs gdal)" \
go build -o /app/myapp .
FROM ghcr.io/jobrunner/spatialite-base-image:alpine-1.4.0
COPY --from=builder /app/myapp /usr/local/bin/myapp
ENTRYPOINT ["/usr/local/bin/myapp"]
```
## Go Code Example
### Using mattn/go-sqlite3 with SpatiaLite
```go
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
func main() {
// Open database with SpatiaLite extension
db, err := sql.Open("sqlite3", "file:test.db?_load_extension=mod_spatialite")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Initialize spatial metadata
_, err = db.Exec("SELECT InitSpatialMetaData(1)")
if err != nil {
log.Fatal(err)
}
// Create a spatial table
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS locations (
id INTEGER PRIMARY KEY,
name TEXT
)
`)
if err != nil {
log.Fatal(err)
}
// Add geometry column
db.Exec(`SELECT AddGeometryColumn('locations', 'geom', 4326, 'POINT', 'XY')`)
// Insert a point
_, err = db.Exec(`
INSERT INTO locations (name, geom)
VALUES ('Berlin', GeomFromText('POINT(13.405 52.52)', 4326))
`)
if err != nil {
log.Fatal(err)
}
// Query with spatial function
var name string
var wkt string
err = db.QueryRow(`
SELECT name, AsText(geom) FROM locations WHERE id = 1
`).Scan(&name, &wkt)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Location: %s at %s\n", name, wkt)
}
```
### go.mod
```go
module myapp
go 1.23
require github.com/mattn/go-sqlite3 v1.14.24
```
## Building Images Locally
```bash
# Build Alpine runtime
docker build -f Dockerfile.alpine -t spatialite:alpine .
# Build Alpine dev
docker build -f Dockerfile.alpine-dev -t spatialite:alpine-dev .
# Build Ubuntu runtime
docker build -f Dockerfile.ubuntu -t spatialite:ubuntu .
# Build Ubuntu dev
docker build -f Dockerfile.ubuntu-dev -t spatialite:ubuntu-dev .
# Multi-arch build
docker buildx build --platform linux/amd64,linux/arm64 \
-f Dockerfile.alpine -t spatialite:alpine .
```
## Testing
```bash
# Test runtime image
docker run --rm -v $(pwd)/tests:/tests spatialite:alpine /tests/test-image.sh
# Test dev image
docker run --rm -v $(pwd)/tests:/tests spatialite:alpine-dev sh -c \
"/tests/test-image.sh && /tests/test-dev-image.sh"
```
## Development Workflow
### Branch Protection
Direct commits to `main` are not allowed. All changes must go through a Pull Request.
### Creating a Release
1. **Create a feature branch:**
```bash
git checkout -b feature/my-change
```
2. **Make your changes and update VERSION file:**
```bash
echo "1.1.0" > VERSION
```
3. **Update CHANGELOG.md** with your changes
4. **Push and create Pull Request:**
```bash
git push -u origin feature/my-change
```
5. **Wait for CI to pass** (build + test)
6. **Merge to main** - this automatically:
- Creates a git tag `v1.1.0` from VERSION file
- Builds and pushes all Docker image tags
- Creates a GitHub Release with CHANGELOG
## License
GPL-2.0-or-later
This project is licensed under the GNU General Public License v2.0 or later due to the inclusion of GPL-licensed components (librttopo). See [LICENSE](LICENSE) for details.