Overview
Med Agenda provides a multi-stage Dockerfile that creates an optimized production image. The Docker setup uses Amazon Corretto 21 and follows best practices for security and performance.
Dockerfile Architecture
The Dockerfile uses a multi-stage build approach:
Build Stage
The build stage uses Maven to compile the application:
# Build stage with Maven and JDK 21
FROM maven:3.9.9-amazoncorretto-21 AS build
WORKDIR /workspace
# Cache dependencies
COPY pom.xml .
RUN mvn -B -q -DskipTests dependency:go-offline
# Copy source code
COPY src ./src
# Copy PDF resources
COPY pdf ./src/main/resources/pdf
# Build the JAR
RUN mvn -B -q -DskipTests clean package
The build stage downloads dependencies first (with caching) before copying source code. This optimizes Docker layer caching and speeds up rebuilds.
Runtime Stage
The runtime stage creates a minimal production image:
# Runtime stage with minimal Alpine-based JRE
FROM amazoncorretto:21-alpine
WORKDIR /app
# Create non-root user for security
RUN addgroup -S app && adduser -S app -G app
# Copy JAR from build stage
COPY --from=build /workspace/target/*.jar /app/app.jar
USER app
# Expose default port
EXPOSE 8080
# Configure JVM options and server port
ENV SERVER_PORT=8080 \
JAVA_OPTS= ""
# Run the application
ENTRYPOINT [ "sh" , "-c" , "java $JAVA_OPTS -jar /app/app.jar" ]
The application runs as a non-root user (app) for enhanced security. Never override this to run as root in production.
Building the Docker Image
Basic Build
Build the image from the project root:
Build with default tag
Build with version tag
Build with custom name
cd backend/gestaoConsultasMedicas
docker build -t med-agenda:latest .
Build Arguments
You can customize the build process:
# Skip tests during build
docker build --build-arg SKIP_TESTS= true -t med-agenda:latest .
# Use build cache
docker build --cache-from med-agenda:latest -t med-agenda:latest .
Running with Docker
Basic Run
Run the container with environment variables:
docker run -d \
--name med-agenda \
-p 8080:8080 \
-e SPRING_DATASOURCE_URL="jdbc:postgresql://host.docker.internal:5432/medagenda" \
-e SPRING_DATASOURCE_USERNAME="postgres" \
-e SPRING_DATASOURCE_PASSWORD="your_password" \
-e ABACATE-KEY="your_payment_api_key" \
med-agenda:latest
Advanced Configuration
Custom Port
JVM Options
Environment File
docker run -d \
--name med-agenda \
-p 9090:9090 \
-e SERVER_PORT= 9090 \
-e SPRING_DATASOURCE_URL="..." \
med-agenda:latest
Docker Compose Setup
The recommended way to run Med Agenda is with Docker Compose:
docker-compose.yml
version : "3.8"
services :
api :
build : .
image : med-agenda:latest
ports :
- "8080:8080"
env_file :
- .env
restart : unless-stopped
Complete Setup with Database
For a complete local setup including PostgreSQL:
version : "3.8"
services :
db :
image : postgres:15-alpine
environment :
POSTGRES_DB : medagenda
POSTGRES_USER : postgres
POSTGRES_PASSWORD : postgres
volumes :
- postgres_data:/var/lib/postgresql/data
ports :
- "5432:5432"
healthcheck :
test : [ "CMD-SHELL" , "pg_isready -U postgres" ]
interval : 10s
timeout : 5s
retries : 5
api :
build : .
image : med-agenda:latest
ports :
- "8080:8080"
environment :
SPRING_DATASOURCE_URL : jdbc:postgresql://db:5432/medagenda
SPRING_DATASOURCE_USERNAME : postgres
SPRING_DATASOURCE_PASSWORD : postgres
JPA_DDL_AUTO : update
env_file :
- .env
depends_on :
db :
condition : service_healthy
restart : unless-stopped
volumes :
postgres_data :
Running Docker Compose
Create environment file
cp .env.example .env
# Edit .env with your configuration
View logs
docker-compose logs -f api
Container Management
Common Commands
View Logs
Restart Services
Execute Commands
Health Check
# All logs
docker-compose logs
# Follow logs
docker-compose logs -f api
# Last 100 lines
docker-compose logs --tail=100 api
Updating the Application
Rebuild image
docker-compose build --no-cache api
Production Considerations
Resource Limits
Set memory and CPU limits for production:
services :
api :
build : .
image : med-agenda:latest
deploy :
resources :
limits :
cpus : '2'
memory : 2G
reservations :
cpus : '1'
memory : 1G
# ... rest of configuration
Health Checks
Add health checks to ensure container availability:
services :
api :
build : .
image : med-agenda:latest
healthcheck :
test : [ "CMD" , "curl" , "-f" , "http://localhost:8080" ]
interval : 30s
timeout : 10s
retries : 3
start_period : 40s
# ... rest of configuration
Logging Configuration
Configure logging for production:
services :
api :
build : .
image : med-agenda:latest
logging :
driver : "json-file"
options :
max-size : "10m"
max-file : "3"
# ... rest of configuration
Security Best Practices
Always follow these security practices in production:
Never commit .env files with real credentials
Use Docker secrets or external secret management
Run containers with read-only root filesystem when possible
Limit container capabilities
Use private registries for images
Regularly update base images for security patches
services :
api :
build : .
image : med-agenda:latest
read_only : true
cap_drop :
- ALL
cap_add :
- NET_BIND_SERVICE
security_opt :
- no-new-privileges:true
# ... rest of configuration
Troubleshooting
Container exits immediately
Cannot connect to database
If using Docker Compose with local database: # Use service name, not localhost
SPRING_DATASOURCE_URL = jdbc:postgresql://db:5432/medagenda
If connecting to external database: # Use host.docker.internal on Mac/Windows
SPRING_DATASOURCE_URL = jdbc:postgresql://host.docker.internal:5432/medagenda
Build fails with dependency errors
Clear Maven cache and rebuild: docker-compose build --no-cache api
Increase JVM heap size: environment :
JAVA_OPTS : "-Xms1g -Xmx2g"
Next Steps
Database Setup Configure PostgreSQL for production
Environment Variables Complete environment configuration