From 905bed840dc4b4c0ef951f6eecacb50726ef2890 Mon Sep 17 00:00:00 2001 From: Daniel Graf Date: Wed, 4 Jun 2025 21:53:34 +0200 Subject: [PATCH] 19 finish docker integration for reitti (#20) * feat: enable actuator health endpoint and add Docker healthcheck * - added application-docker.properties - update Dockerfile and corrosponding docker-compose.yml * - removed init.sql * docs: update environment variables in README and Docker Hub description * docs: update environment variables section to table format * - removed generated-requests.http - updated application-docker.properties --- DOCKER-HUB-DESCRIPTION.md | 34 ++++--- Dockerfile | 10 ++- README.md | 37 ++++---- docker-compose-dev.yml | 36 ++++++++ docker-compose.yml | 32 +++---- generated-requests.http | 90 ------------------- init-db/init.sql | 9 -- pom.xml | 24 ++--- .../reitti/config/SecurityConfig.java | 1 + .../resources/application-docker.properties | 12 +++ 10 files changed, 109 insertions(+), 176 deletions(-) create mode 100644 docker-compose-dev.yml delete mode 100644 generated-requests.http delete mode 100644 init-db/init.sql create mode 100644 src/main/resources/application-docker.properties diff --git a/DOCKER-HUB-DESCRIPTION.md b/DOCKER-HUB-DESCRIPTION.md index 51fd4c8f..a12711d6 100644 --- a/DOCKER-HUB-DESCRIPTION.md +++ b/DOCKER-HUB-DESCRIPTION.md @@ -15,10 +15,12 @@ Reitti is a self-hosted application for tracking, analyzing, and visualizing you ```bash docker pull reitti/reitti:latest docker run -p 8080:8080 \ - -e SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/reitti \ - -e SPRING_DATASOURCE_USERNAME=postgres \ - -e SPRING_DATASOURCE_PASSWORD=postgres \ - -e SPRING_RABBITMQ_HOST=rabbitmq \ + -e POSTGIS_HOST=postgres \ + -e POSTGIS_PORT=5432 \ + -e POSTGIS_DB=reittidb \ + -e POSTGIS_USER=reitti \ + -e POSTGIS_PASSWORD=reitti \ + -e RABBITMQ_HOST=rabbitmq \ reitti/reitti:latest ``` @@ -26,16 +28,20 @@ For production use, we recommend using the provided docker-compose file that inc ## Environment Variables -- `SPRING_DATASOURCE_URL` - JDBC URL for PostgreSQL database -- `SPRING_DATASOURCE_USERNAME` - Database username -- `SPRING_DATASOURCE_PASSWORD` - Database password -- `SPRING_RABBITMQ_HOST` - RabbitMQ host -- `SPRING_RABBITMQ_PORT` - RabbitMQ port -- `SPRING_RABBITMQ_USERNAME` - RabbitMQ username -- `SPRING_RABBITMQ_PASSWORD` - RabbitMQ password -- `APP_UID` - User ID to run the application as (default: 1000) -- `APP_GID` - Group ID to run the application as (default: 1000) -- `JAVA_OPTS` - JVM options for the application +| Variable | Description | Default | +|----------|-------------|---------| +| `POSTGIS_HOST` | PostgreSQL database host | postgis | +| `POSTGIS_PORT` | PostgreSQL database port | 5432 | +| `POSTGIS_DB` | PostgreSQL database name | reittidb | +| `POSTGIS_USER` | Database username | reitti | +| `POSTGIS_PASSWORD` | Database password | reitti | +| `RABBITMQ_HOST` | RabbitMQ host | rabbitmq | +| `RABBITMQ_PORT` | RabbitMQ port | 5672 | +| `RABBITMQ_USER` | RabbitMQ username | reitti | +| `RABBITMQ_PASSWORD` | RabbitMQ password | reitti | +| `APP_UID` | User ID to run the application as | 1000 | +| `APP_GID` | Group ID to run the application as | 1000 | +| `JAVA_OPTS` | JVM options for the application | | ## Tags diff --git a/Dockerfile b/Dockerfile index a8561acf..9d4e00b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,14 +34,18 @@ RUN echo '#!/bin/sh' > /entrypoint.sh && \ echo ' # Fix ownership of all files' >> /entrypoint.sh && \ echo ' chown -R reitti:reitti $APP_HOME' >> /entrypoint.sh && \ echo 'fi' >> /entrypoint.sh && \ - echo 'exec su-exec reitti java $JAVA_OPTS -jar $APP_HOME/app.jar "$@"' >> /entrypoint.sh && \ + echo 'exec su-exec reitti java $JAVA_OPTS -jar $APP_HOME/app.jar -Dspring.profiles.active=docker "$@"' >> /entrypoint.sh && \ chmod +x /entrypoint.sh # Expose the application port EXPOSE 8080 -# Install su-exec for proper user switching -RUN apk add --no-cache su-exec +# Add healthcheck +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1 + +# Install su-exec for proper user switching and wget for healthcheck +RUN apk add --no-cache su-exec wget # Run as root initially to allow UID/GID changes USER root diff --git a/README.md b/README.md index b1c8de8b..33a9bae7 100644 --- a/README.md +++ b/README.md @@ -67,10 +67,12 @@ docker-compose up -d # Or run standalone with environment variables docker run -p 8080:8080 \ - -e SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/reitti \ - -e SPRING_DATASOURCE_USERNAME=postgres \ - -e SPRING_DATASOURCE_PASSWORD=postgres \ - -e SPRING_RABBITMQ_HOST=rabbitmq \ + -e POSTGIS_HOST=postgres \ + -e POSTGIS_PORT=5432 \ + -e POSTGIS_DB=reittidb \ + -e POSTGIS_USER=reitti \ + -e POSTGIS_PASSWORD=reitti \ + -e RABBITMQ_HOST=rabbitmq \ reitti/reitti:latest ``` @@ -78,13 +80,15 @@ docker run -p 8080:8080 \ | Variable | Description | Default | |----------|-------------|---------| -| `SPRING_DATASOURCE_URL` | JDBC URL for PostgreSQL database | jdbc:postgresql://localhost:5432/reitti | -| `SPRING_DATASOURCE_USERNAME` | Database username | postgres | -| `SPRING_DATASOURCE_PASSWORD` | Database password | postgres | -| `SPRING_RABBITMQ_HOST` | RabbitMQ host | localhost | -| `SPRING_RABBITMQ_PORT` | RabbitMQ port | 5672 | -| `SPRING_RABBITMQ_USERNAME` | RabbitMQ username | guest | -| `SPRING_RABBITMQ_PASSWORD` | RabbitMQ password | guest | +| `POSTGIS_HOST` | PostgreSQL database host | postgis | +| `POSTGIS_PORT` | PostgreSQL database port | 5432 | +| `POSTGIS_DB` | PostgreSQL database name | reittidb | +| `POSTGIS_USER` | Database username | reitti | +| `POSTGIS_PASSWORD` | Database password | reitti | +| `RABBITMQ_HOST` | RabbitMQ host | rabbitmq | +| `RABBITMQ_PORT` | RabbitMQ port | 5672 | +| `RABBITMQ_USER` | RabbitMQ username | reitti | +| `RABBITMQ_PASSWORD` | RabbitMQ password | reitti | | `SERVER_PORT` | Application server port | 8080 | | `APP_UID` | User ID to run the application as | 1000 | | `APP_GID` | Group ID to run the application as | 1000 | @@ -95,15 +99,6 @@ docker run -p 8080:8080 \ - `latest` - Latest stable release - `x.y.z` - Specific version releases -## API Endpoints - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/api/v1/import/gpx` | POST | Import GPX data files | -| `/api/v1/queue-stats` | GET | Get processing queue statistics | -| `/settings/import/gpx` | POST | Web interface for GPX import | -| `/api/v1/timeline` | GET | Get timeline data | - ## Data Flow 1. Location data is imported via API or web interface @@ -119,7 +114,7 @@ docker run -p 8080:8080 \ - **Message Queue**: RabbitMQ for asynchronous processing - **Frontend**: Thymeleaf, JavaScript - **Testing**: JUnit 5, Testcontainers -- **Containerization**: Docker, Spring Boot Docker plugin +- **Containerization**: Docker ## Contributing diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml new file mode 100644 index 00000000..acf0fd04 --- /dev/null +++ b/docker-compose-dev.yml @@ -0,0 +1,36 @@ +services: + postgis: + image: postgis/postgis:17-3.5-alpine + environment: + POSTGRES_USER: reitti + POSTGRES_PASSWORD: reitti + POSTGRES_DB: reittidb + ports: + - "5432:5432" + volumes: + - postgis-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U reitti -d reittidb"] + interval: 10s + timeout: 5s + retries: 5 + rabbitmq: + image: rabbitmq:3-management-alpine + ports: + - "5672:5672" # AMQP protocol port + - "15672:15672" # Management UI port + environment: + RABBITMQ_DEFAULT_USER: reitti + RABBITMQ_DEFAULT_PASS: reitti + volumes: + - rabbitmq-data:/var/lib/rabbitmq + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"] + interval: 30s + timeout: 10s + retries: 5 + +volumes: + postgis-data: + redis-data: + rabbitmq-data: diff --git a/docker-compose.yml b/docker-compose.yml index 4f74950a..8fbd21c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,16 @@ services: - # PostgreSQL with PostGIS and TimescaleDB extensions + reitti: + image: dedicatedcode/reitti:latest + ports: + - 8080:8080 + depends_on: + rabbitmq: + condition: service_healthy + postgis: + condition: service_healthy + restart: true postgis: image: postgis/postgis:17-3.5-alpine - container_name: reitti-postgis environment: POSTGRES_USER: reitti POSTGRES_PASSWORD: reitti @@ -11,32 +19,13 @@ services: - "5432:5432" volumes: - postgis-data:/var/lib/postgresql/data - - ./init-db:/docker-entrypoint-initdb.d healthcheck: test: ["CMD-SHELL", "pg_isready -U reitti -d reittidb"] interval: 10s timeout: 5s retries: 5 - - # Redis for caching - redis: - image: redis:7-alpine - container_name: reitti-redis - ports: - - "6379:6379" - volumes: - - redis-data:/data - command: redis-server --appendonly yes - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - - # RabbitMQ for message queuing rabbitmq: image: rabbitmq:3-management-alpine - container_name: reitti-rabbitmq ports: - "5672:5672" # AMQP protocol port - "15672:15672" # Management UI port @@ -53,5 +42,4 @@ services: volumes: postgis-data: - redis-data: rabbitmq-data: diff --git a/generated-requests.http b/generated-requests.http deleted file mode 100644 index 558c98d1..00000000 --- a/generated-requests.http +++ /dev/null @@ -1,90 +0,0 @@ -### -# @name Create new User Token -POST http://localhost:8080/api/v1/tokens -Content-Type: application/json - -{ - "name": "test-token", - "username": "daniel" -} - - -### -# @name Upload Whole Google Takeout Records.json -POST http://localhost:8080/api/v1/import/google-takeout -Content-Type: multipart/form-data; boundary=boundary -X-API-Token: d8a3e1ed-33ad-4e6c-b517-757b54d03833 - - ---boundary -Content-Disposition: form-data; name="file"; filename="Records.json" - -< /home/daniel/Downloads/takeout-20250422T152421Z-001/Takeout/Zeitachse/Records.json - -### -# @name Upload Google Takeout Records.json -POST http://localhost:8080/api/v1/import/google-takeout -Content-Type: multipart/form-data; boundary=boundary -X-API-Token: d8a3e1ed-33ad-4e6c-b517-757b54d03833 - - ---boundary -Content-Disposition: form-data; name="file"; filename="Records.json" - -< src/test/resources/data/exports/google-takeout/Records-one-day.json - -<> 2025-05-26T131205.202.json -<> 2025-05-26T130742.202.json -<> 2025-05-26T130708.202.json -<> 2025-05-26T130015.202.json -<> 2025-05-26T125856.202.json -<> 2025-05-26T123636.202.json -<> 2025-05-26T112900-2.202.json -<> 2025-05-26T112900-1.202.json -<> 2025-05-26T112900.202.json -<> 2025-05-26T112859-3.202.json -<> 2025-05-26T112859-2.202.json -<> 2025-05-26T112859-1.202.json -<> 2025-05-26T112859.202.json -<> 2025-05-26T112858-3.202.json -<> 2025-05-26T112858-2.202.json -<> 2025-05-26T112858-1.202.json -<> 2025-05-26T112858.202.json -<> 2025-05-26T112857-1.202.json -<> 2025-05-26T112857.202.json -<> 2025-05-26T112856-1.202.json -<> 2025-05-26T112856.202.json -<> 2025-05-26T112854.202.json -<> 2025-05-26T112841.202.json -<> 2025-05-26T112750.202.json -<> 2025-05-26T112750-1.202.json -<> 2025-05-26T112749-3.202.json -<> 2025-05-26T112749-2.202.json -<> 2025-05-26T112749-1.202.json -<> 2025-05-26T112749.202.json -<> 2025-05-26T112748-2.202.json -<> 2025-05-26T112748-1.202.json -<> 2025-05-26T112748.202.json -<> 2025-05-26T112747.202.json -<> 2025-05-26T112746-1.202.json -<> 2025-05-26T112746.202.json -<> 2025-05-26T112745-2.202.json -<> 2025-05-26T112745-1.202.json -<> 2025-05-26T112745.202.json -<> 2025-05-26T112744-4.202.json -<> 2025-05-26T112744-3.202.json -<> 2025-05-26T112744-2.202.json -<> 2025-05-26T112744-1.202.json -<> 2025-05-26T112744.202.json -<> 2025-05-26T112738.202.json -<> 2025-05-26T112657.202.json -<> 2025-05-26T112009.202.json -<> 2025-05-26T105346.200.json -<> 2025-05-26T105220.500.json -<> 2025-05-26T105116.400.json -<> 2025-05-26T105039.400.json - - -### -# @name Merge Trips -POST http://localhost:8080/api/v1/trips/merge/user/1 diff --git a/init-db/init.sql b/init-db/init.sql deleted file mode 100644 index 54687458..00000000 --- a/init-db/init.sql +++ /dev/null @@ -1,9 +0,0 @@ --- Enable PostGIS extension -CREATE EXTENSION IF NOT EXISTS postgis; - --- Create schema -CREATE SCHEMA IF NOT EXISTS reitti; - --- Grant privileges -GRANT ALL PRIVILEGES ON DATABASE reittidb TO reitti; -ALTER USER reitti WITH SUPERUSER; diff --git a/pom.xml b/pom.xml index 31a85d31..d50149c1 100644 --- a/pom.xml +++ b/pom.xml @@ -126,6 +126,13 @@ + + org.springframework.boot + spring-boot-maven-plugin + + true + + org.apache.maven.plugins maven-dependency-plugin @@ -146,21 +153,4 @@ - - - docker - - - - org.springframework.boot - spring-boot-maven-plugin - - true - - - - - - - diff --git a/src/main/java/com/dedicatedcode/reitti/config/SecurityConfig.java b/src/main/java/com/dedicatedcode/reitti/config/SecurityConfig.java index 4795d2e6..81861b7f 100644 --- a/src/main/java/com/dedicatedcode/reitti/config/SecurityConfig.java +++ b/src/main/java/com/dedicatedcode/reitti/config/SecurityConfig.java @@ -27,6 +27,7 @@ public class SecurityConfig { http .authorizeHttpRequests(authorize -> authorize .requestMatchers("/css/**", "/js/**", "/images/**").permitAll() + .requestMatchers("/actuator/health").permitAll() .anyRequest().authenticated() ) .addFilterBefore(bearerTokenAuthFilter, AuthorizationFilter.class) diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties new file mode 100644 index 00000000..fd3fed27 --- /dev/null +++ b/src/main/resources/application-docker.properties @@ -0,0 +1,12 @@ +# PostgreSQL configuration (commented out for now, uncomment for production) +spring.datasource.url=jdbc:postgresql://${POSTGIS_HOST:postgis}:${POSTGIS_PORT:5432}/${POSTGIS_DB:reittidb} +spring.datasource.username=${POSTGIS_USER:reitti} +spring.datasource.password=${POSTGIS_PASSWORD:reitti} + +spring.thymeleaf.cache=true + +# RabbitMQ Configuration +spring.rabbitmq.host=${RABBITMQ_HOST:rabbitmq} +spring.rabbitmq.port=${RABBITMQ_PORT:5672} +spring.rabbitmq.username=${RABBITMQ_USER:reitti} +spring.rabbitmq.password=${RABBITMQ_PASSWORD:reitti}