Dockerfile Overview
The application uses a production-ready multi-stage Dockerfile:Dockerfile
The image uses Eclipse Temurin JRE 21 (a lightweight Java runtime) and follows security best practices by running as a non-root user.
Building the Docker Image
Build the Application JAR
First, build the Spring Boot application using Gradle:This creates the JAR file in
build/libs/user-management-api-0.0.1-SNAPSHOT.jar.Running with Docker
Basic Run Command
Run the container with environment variables:Corrected Connection for Host Database
Run in Detached Mode
Run the container in the background:Docker Compose (Recommended)
For local development, Docker Compose provides a complete environment with both the API and PostgreSQL database.Docker Compose Configuration
Create adocker-compose.yml file in the project root:
docker-compose.yml
The API service waits for the database to be healthy before starting, ensuring proper initialization order.
Starting with Docker Compose
Start All Services
Start both the database and API:The
--build flag rebuilds the image if the code has changed.Access the Application
The API is now available at:
- API: http://localhost:8080
- Swagger UI: http://localhost:8080/swagger-ui/index.html
- Health Check: http://localhost:8080/actuator/health
Managing Docker Compose
Environment Variables Reference
All configuration can be overridden with environment variables:| Variable | Default | Description |
|---|---|---|
ENVIRONMENT | local | Active Spring profile |
SPRING_DATASOURCE_URL | jdbc:postgresql://localhost:5432/user_db | Database JDBC URL |
SPRING_DATASOURCE_USERNAME | postgres | Database username |
SPRING_DATASOURCE_PASSWORD | password | Database password |
Using Environment Files
Create a.env file for Docker Compose:
.env
docker-compose.yml:
docker-compose.yml
Production Deployment
Cloud Run Deployment
The project includes Google Cloud Build configuration for automated deployment:cloudbuild.yaml
The CI/CD pipeline automatically runs tests, builds the Docker image, and deploys to Cloud Run with secrets from Secret Manager.
Pushing to Container Registry
Troubleshooting
Cannot connect to database from container
Cannot connect to database from container
Problem: API container cannot reach PostgreSQL.Solution:
- Use
host.docker.internalinstead oflocalhost - On Linux, add
--add-host=host.docker.internal:host-gateway - Or use Docker Compose to run both services in the same network
Port already in use
Port already in use
Problem: Port 8080 is already bound.Solution: Change the host port mapping:
Image build fails
Image build fails
Problem: Docker build cannot find the JAR file.Solution: Ensure you’ve built the application first:
Container keeps restarting
Container keeps restarting
Problem: Container starts but immediately exits.Solution: Check the logs:Common issues:
- Database connection failure
- Missing environment variables
- Port conflicts
Out of memory errors
Out of memory errors
Problem: Container runs out of memory.Solution: Increase container memory or add JVM options:Update the Dockerfile:
Best Practices
Use Multi-Stage Builds
For production, consider a multi-stage build that compiles the application inside Docker:
Optimize Image Size
- Use JRE instead of JDK (already done)
- Use Alpine-based images for smaller size
- Clean up unnecessary files
- Use
.dockerignoreto exclude build artifacts
Security Hardening
- Run as non-root user (already implemented)
- Use specific image versions, not
latest - Scan images for vulnerabilities:
docker scan user-management-api - Use secrets management for production
Next Steps
Configuration
Learn about configuration options
Testing
Understand the testing strategy
API Reference
Explore the API endpoints
Architecture
Learn about hexagonal architecture