Docker Images¶
This document explains the Docker image architecture in GeoServer Cloud, including the base image hierarchy and layer sharing strategy that optimizes disk usage and build times.
Base Image Hierarchy¶
GeoServer Cloud uses a layered base image strategy to maximize layer sharing across all microservices:
graph TD
A[eclipse-temurin:25-jre] --> B[gs-cloud-base-jre]
B --> C[gs-cloud-base-spring-boot]
C --> D[gs-cloud-base-geoserver-image]
D --> E[wfs]
D --> F[wms]
D --> G[wcs]
D --> H[wps]
D --> I[gwc]
D --> J[rest]
D --> K[webui]
B --> L[config]
B --> M[discovery]
B --> N[gateway] Base Images¶
| Image | Based On | Adds |
|---|---|---|
gs-cloud-base-jre | eclipse-temurin:25-jre | JVM options (--add-opens, heap settings), system CA certificates |
gs-cloud-base-spring-boot | gs-cloud-base-jre | Spring Boot layered JAR structure, curl for health checks, default config |
gs-cloud-base-geoserver-image | gs-cloud-base-spring-boot | Fonts (DejaVu, Noto, Roboto, etc.), GeoServer common dependencies, DuckDB extensions |
Service Images¶
All GeoServer OWS services (WFS, WMS, WCS, WPS, GWC, REST, WebUI) extend gs-cloud-base-geoserver-image, adding only their service-specific application code.
Infrastructure services (Config, Discovery, Gateway) extend gs-cloud-base-spring-boot directly since they don't need GeoServer dependencies.
Layer Sharing¶
The layered architecture ensures that all GeoServer microservices share ~908MB of common layers. Each service adds only 2-22MB of unique application code.
Example: GeoServer services layer analysis
| Image | Display Size | Shared | Unique |
|---|---|---|---|
| wcs | 909MB | 907.8MB | 1.7MB |
| wps | 910MB | 907.8MB | 2.3MB |
| wfs | 916MB | 907.8MB | 8.2MB |
| rest | 918MB | 907.8MB | 10.4MB |
| wms | 923MB | 907.8MB | 14.8MB |
| gwc | 922MB | 907.8MB | 14.2MB |
| webui | 929MB | 907.8MB | 21.5MB |
Actual disk usage for all 7 GeoServer services:
Instead of 7 × 920MB = 6.4GB apparent.
This means deploying all 7 GeoServer services uses less than 1GB of actual disk space, not 6.4GB as the individual image sizes might suggest.
Analyzing Layer Sharing¶
Check Actual Disk Usage¶
Use docker system df -v to see actual disk consumption with shared vs unique sizes:
Example output:
REPOSITORY TAG IMAGE ID SIZE SHARED SIZE UNIQUE SIZE
geoservercloud/geoserver-cloud-wfs 3.0.0-SNAPSHOT 12cee949a17d 916MB 907.8MB 8.163MB
geoservercloud/geoserver-cloud-wms 3.0.0-SNAPSHOT 919b96914846 923MB 907.8MB 14.78MB
...
Compare Layers Across Images¶
To see which layers are shared across images:
for img in geoservercloud/geoserver-cloud-{wms,wfs,wcs,wps,gwc,webui,rest}:3.0.0-SNAPSHOT; do
echo "=== $img ==="
docker inspect "$img" --format='{{range .RootFS.Layers}}{{.}}{{"\n"}}{{end}}'
done | sort | uniq -c | sort -rn
Layers appearing 7 times are shared across all services (the base image layers). Layers appearing once are unique to each service.
Count Total vs Unique Layers¶
# Dump all layers
for img in $(docker images --format '{{.Repository}}:{{.Tag}}' | grep 3.0.0-SNAPSHOT); do
docker inspect "$img" --format='{{range .RootFS.Layers}}{{.}}{{"\n"}}{{end}}'
done > /tmp/all-layers.txt
# Count
echo "Total layer references: $(wc -l < /tmp/all-layers.txt)"
echo "Unique layers: $(sort -u /tmp/all-layers.txt | wc -l)"
Best Practices¶
- Always build base images first - The Makefile enforces this with dependencies
- Don't skip base image rebuilds - When dependencies change, rebuild from
gs-cloud-base-geoserver-imagedown - Use
make build-image-geoserver <service>- During development, rebuild only the service you're working on - Check layer sharing periodically - Ensure changes don't accidentally break layer sharing