This document provides a detailed implementation guide for the official Docker images feature added to platform-java.
This implementation adds complete Docker support to platform-java, enabling users to quickly deploy the platform using containers while maintaining support for multiple registries and variants.
-
Dockerfile
- Multi-stage build using Maven for compilation
- Base image:
eclipse-temurin:21-jre-noble(Debian-based) - Size: ~500-600 MB compressed
- Exposes ports: 8080 (API/Console), 9090 (Prometheus), 9999 (JMX)
- Includes health check endpoint
- Configurable via environment variables
-
Dockerfile.alpine
- Alpine variant for lightweight deployments
- Base image:
eclipse-temurin:21-jre-alpine - Size: ~200-250 MB compressed
- Identical functionality to standard image but optimized for size
-
.dockerignore
- Excludes unnecessary files from Docker build context
- Reduces build time and image size
- Excludes: git history, documentation, examples, IDE configs
-
docker-compose.yml
- Complete observability stack setup:
- platform-java service (main application)
- Prometheus (metrics collection)
- Grafana (visualization and dashboards)
- Named volumes for data persistence
- Health checks for all services
- Network isolation
- Service dependencies configured
- Complete observability stack setup:
-
platform-config.yaml
- Default platform configuration for Docker deployments
- Enables REST API (8080)
- Enables Prometheus metrics (9090)
- Configures filesystem watcher for auto-deployment
- Structured logging support
-
prometheus.yml
- Prometheus scrape configuration
- Targets platform-java metrics endpoint
- 10-second scrape interval for fine-grained metrics
- 15-second evaluation interval
-
.env.example
- Template for environment variables
- Docker credentials for publish workflow
- JVM configuration defaults
- Monitoring system settings
- .github/workflows/docker-publish.yml
- Publishes Docker images to three registries:
- Docker Hub:
flossware/platform-java - GitHub Container Registry:
ghcr.io/FlossWare/platform-java - Quay.io:
quay.io/flossware/platform-java
- Docker Hub:
- Semantic versioning support
- Separate Alpine variant builds
- Automated testing of built images
- Build caching via GitHub Actions
- Triggered on:
- Pushes to main branch
- Git tags matching
v*
- Publishes Docker images to three registries:
- DOCKER.md
- Comprehensive Docker usage guide
- Quick start examples
- Image variants and sizes
- Configuration options
- Deployment patterns
- Kubernetes integration examples
- Troubleshooting guide
- Security best practices
- CI/CD integration examples
- Build Stage: Maven builds the entire project including platform-launcher JAR
- Runtime Stage:
- Copies compiled JAR from build stage
- Sets up directories and permissions
- Configures health check
- Defines environment variables
- Creates default configuration file
The GitHub Actions workflow:
-
On Push to main:
- Builds image with
maintag - Builds image with
latesttag - Pushes to all three registries
- Runs automated tests
- Builds image with
-
On Release (tag v)*:
- Builds image with version tag (e.g.,
1.1) - Builds image with major.minor tags
- Builds Alpine variants
- Pushes to all registries
- Builds image with version tag (e.g.,
docker run -p 8080:8080 flossware/platform-java:latestdocker-compose up -ddocker run -p 8080:8080 \
-v /path/to/platform.yaml:/app/config/platform.yaml \
flossware/platform-java:latest- URL: https://hub.docker.com/r/flossware/platform-java
- Requires: Docker Hub account with credentials in GitHub Secrets
- Images:
flossware/platform-java:latest,1.1,main, etc.
- URL: https://github.com/FlossWare/platform-java/pkgs/container/platform-java
- Automatic: Uses GITHUB_TOKEN (no additional secrets needed)
- Images:
ghcr.io/FlossWare/platform-java:latest
- URL: https://quay.io/repository/flossware/platform-java
- Requires: Quay.io account with credentials in GitHub Secrets
- Images:
quay.io/flossware/platform-java:latest
To enable the docker-publish workflow, add these secrets to your GitHub repository:
- DOCKER_USERNAME - Docker Hub username
- DOCKER_PASSWORD - Docker Hub personal access token
- QUAY_USERNAME - Quay.io username (optional)
- QUAY_PASSWORD - Quay.io personal access token (optional)
GHCR uses GITHUB_TOKEN automatically (no additional setup needed).
| Variable | Default | Purpose |
|---|---|---|
JAVA_OPTS |
-Xms512m -Xmx1024m |
JVM memory configuration |
PLATFORM_CONFIG |
/app/config/platform.yaml |
Config file path |
PLATFORM_APPS_DIR |
/app/apps |
App descriptors directory |
PLATFORM_LOGS_DIR |
/app/logs |
Logs directory |
Key settings in /app/config/platform.yaml:
api:
enabled: true # Enable REST API
port: 8080 # Bind port
bind-address: 0.0.0.0 # Listen on all interfaces
metrics:
prometheus:
enabled: true # Enable Prometheus endpoint
port: 9090
watcher:
enabled: true # Auto-deployment from watch dir
watch-directory: /app/apps
logging:
level: INFO # Log level
format: json # Structured loggingdocker-compose up -d
# Full stack with Prometheus and GrafanaapiVersion: apps/v1
kind: Deployment
metadata:
name: platform-java
spec:
replicas: 2
template:
spec:
containers:
- name: platform-java
image: flossware/platform-java:1.1
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "2000m"docker service create \
--name platform-java \
--publish 8080:8080 \
flossware/platform-java:latest# Standard image
docker build -t platform-java:test .
# Alpine variant
docker build -f Dockerfile.alpine -t platform-java:alpine .# Start container
docker run -d -p 8080:8080 --name test-platform platform-java:test
# Check health
curl http://localhost:8080/api/health
# Verify web console
curl -I http://localhost:8080/console
# View logs
docker logs test-platform
# Cleanup
docker stop test-platform
docker rm test-platform# Start full stack
docker-compose up -d
# Verify services
curl http://localhost:8080/console # Platform web console
curl http://localhost:9091/graph # Prometheus UI
curl http://localhost:3000 # Grafana (admin/admin)
# Cleanup
docker-compose downThe workflow implements semantic versioning:
| Trigger | Tags |
|---|---|
| Push to main | main, latest |
| Release v1.1 | 1.1, 1, latest |
| Release v1.2 | 1.2, 1 (updated), latest (updated) |
| Release v2.0 | 2.0, 2, latest (updated) |
Alpine variants get -alpine suffix for each tag:
latest-alpine1.1-alpinemain-alpine
- API authentication disabled by default (suitable for development)
- Container runs as non-root user
- Read-only filesystem can be enabled
- Resource limits configurable
-
Enable API authentication in
platform.yaml:api: auth-enabled: true
-
Use reverse proxy (nginx/Caddy) with TLS:
upstream platform { server platform-java:8080; } server { listen 443 ssl; proxy_pass http://platform; }
-
Set resource limits:
docker run --memory 2g --cpus 2 platform-java:latest
-
Use network isolation:
docker network create internal --driver bridge docker run --network internal platform-java:latest
- Endpoint:
http://platform-java:9090/metrics - Interval: 10 seconds (configurable)
- Format: OpenMetrics
- Add Prometheus data source (http://prometheus:9090)
- Import dashboards showing:
- Application states
- Resource utilization
- API latencies
- Error rates
# Average response time over 5m
rate(http_requests_total[5m])
# Memory usage
jvm_memory_used_bytes{type="heap"}
# Thread count per application
jvm_threads_live
# Automatically triggered on:
# - Push to main branch
# - Git tags matching v* pattern
# Publishes to:
# - Docker Hub
# - GitHub Container Registry
# - Quay.io (if credentials provided)
# Includes:
# - Build verification
# - Image scanning (future enhancement)
# - Push validationdocker-build:
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHASolution: Check logs and configuration
docker logs platform-java
# Verify platform.yaml is properly formatted YAMLSolution: Ensure API is enabled
api:
enabled: true
port: 8080Solution: Reduce JVM heap
docker run -e JAVA_OPTS="-Xms256m -Xmx512m" platform-java:latestSolution: Map to different host port
docker run -p 8888:8080 platform-java:latest- Standard image: ~3-5 minutes (includes Maven build)
- Alpine image: ~3-5 minutes
- Subsequent builds: ~1-2 minutes (with caching)
- Startup time: ~10-15 seconds
- Memory footprint: ~512 MB (baseline)
- Throughput: ~1000+ requests/sec (varies by app)
- Standard: ~150-180 MB (compressed), ~500-600 MB (uncompressed)
- Alpine: ~60-80 MB (compressed), ~200-250 MB (uncompressed)
- Image Scanning: Integrate vulnerability scanning (Trivy)
- Distroless Base: Use distroless for minimal images
- Sample Apps: Pre-configured image with sample applications
- Dev Image: Development variant with additional tools
- SBOM Generation: Software Bill of Materials for supply chain
- Image Signing: Cosign for image authenticity verification