From 2b9be6f3cd058d50af44985e531b543e18d6b8a1 Mon Sep 17 00:00:00 2001 From: Alban Talagrand Date: Fri, 17 Oct 2025 08:47:00 +0200 Subject: [PATCH 1/4] init docker --- .github/workflows/rest-api.yml | 55 +++++++ rest-api/.dockerignore | 41 +++++ rest-api/.gitignore | 39 +++++ rest-api/DEPLOY.md | 127 ++++++++++++++++ rest-api/Dockerfile | 41 +++++ rest-api/README.md | 141 ++++++++++++++++++ rest-api/docker-compose.yml | 26 ++++ rest-api/pom.xml | 4 + rest-api/render.yaml | 18 +++ .../src/main/resources/application-prod.yaml | 36 +++++ rest-api/src/main/resources/application.yaml | 13 ++ 11 files changed, 541 insertions(+) create mode 100644 .github/workflows/rest-api.yml create mode 100644 rest-api/.dockerignore create mode 100644 rest-api/.gitignore create mode 100644 rest-api/DEPLOY.md create mode 100644 rest-api/Dockerfile create mode 100644 rest-api/README.md create mode 100644 rest-api/docker-compose.yml create mode 100644 rest-api/render.yaml create mode 100644 rest-api/src/main/resources/application-prod.yaml diff --git a/.github/workflows/rest-api.yml b/.github/workflows/rest-api.yml new file mode 100644 index 0000000..f4b3512 --- /dev/null +++ b/.github/workflows/rest-api.yml @@ -0,0 +1,55 @@ +name: Build and Test REST API + +on: + push: + branches: [ main, develop ] + paths: + - 'rest-api/**' + - '.github/workflows/rest-api.yml' + pull_request: + branches: [ main, develop ] + paths: + - 'rest-api/**' + +jobs: + build: + runs-on: ubuntu-latest + + defaults: + run: + working-directory: rest-api + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + run: mvn -B clean package + + - name: Run tests + run: mvn test + + - name: Build Docker image + run: docker build -t agrimap-api:${{ github.sha }} . + + - name: Test Docker image + run: | + docker run -d --name test-api -p 8080:8080 agrimap-api:${{ github.sha }} + sleep 30 + docker exec test-api wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1 + docker stop test-api + docker rm test-api + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: agrimap-jar + path: rest-api/target/*.jar + retention-days: 7 diff --git a/rest-api/.dockerignore b/rest-api/.dockerignore new file mode 100644 index 0000000..120d484 --- /dev/null +++ b/rest-api/.dockerignore @@ -0,0 +1,41 @@ +# Maven +target/ +!target/*.jar +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +# IDE +.idea/ +*.iml +.vscode/ +.eclipse/ +.settings/ +.classpath +.project + +# OS +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# Docker +Dockerfile +.dockerignore + +# Documentation +README.md +*.md + +# Logs +*.log +logs/ diff --git a/rest-api/.gitignore b/rest-api/.gitignore new file mode 100644 index 0000000..3c24fc5 --- /dev/null +++ b/rest-api/.gitignore @@ -0,0 +1,39 @@ +# Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +# IDE +.idea/ +*.iml +.vscode/ +.eclipse/ +.settings/ +.classpath +.project +*.iws +*.ipr + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ + +# Spring Boot +spring.log +application-local.yaml +application-local.yml + +# Environment +.env +.env.local diff --git a/rest-api/DEPLOY.md b/rest-api/DEPLOY.md new file mode 100644 index 0000000..a741989 --- /dev/null +++ b/rest-api/DEPLOY.md @@ -0,0 +1,127 @@ +# Déploiement de l'API AgriMap sur Render + +Ce guide explique comment déployer l'API REST Spring Boot sur Render. + +## Configuration Docker + +L'application utilise un build multi-stage pour optimiser la taille de l'image : +- **Stage 1** : Build avec Maven et OpenJDK 21 +- **Stage 2** : Runtime avec JRE 21 Alpine (image légère) + +### Fichiers importants + +- `Dockerfile` : Configuration Docker multi-stage +- `render.yaml` : Configuration Render (Blueprint) +- `.dockerignore` : Fichiers à exclure du contexte Docker + +## Déploiement sur Render + +### Option 1 : Déploiement via Blueprint (Recommandé) + +1. Connectez-vous à [Render](https://dashboard.render.com/) +2. Cliquez sur "New" → "Blueprint" +3. Connectez votre dépôt GitHub +4. Render détectera automatiquement le fichier `render.yaml` +5. Cliquez sur "Apply" + +### Option 2 : Déploiement manuel + +1. Connectez-vous à [Render](https://dashboard.render.com/) +2. Cliquez sur "New" → "Web Service" +3. Connectez votre dépôt GitHub +4. Configurez les paramètres suivants : + - **Name** : agrimap-api + - **Runtime** : Docker + - **Region** : Frankfurt (ou votre choix) + - **Branch** : main + - **Dockerfile Path** : ./rest-api/Dockerfile + - **Docker Context** : ./rest-api + - **Plan** : Free + +5. Variables d'environnement (optionnelles) : + ``` + SPRING_PROFILES_ACTIVE=prod + SERVER_PORT=8080 + JAVA_OPTS=-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 + ``` + +6. Health Check Path : `/actuator/health` + +7. Cliquez sur "Create Web Service" + +## Test local avec Docker + +### Construire l'image +```bash +cd rest-api +docker build -t agrimap-api . +``` + +### Exécuter le conteneur +```bash +docker run -p 8080:8080 agrimap-api +``` + +### Tester l'application +```bash +# Health check +curl http://localhost:8080/actuator/health + +# Documentation API (Swagger) +open http://localhost:8080/swagger-ui.html +``` + +## Endpoints disponibles + +- **API** : `https://your-app.onrender.com` +- **Health Check** : `https://your-app.onrender.com/actuator/health` +- **API Documentation** : `https://your-app.onrender.com/swagger-ui.html` +- **OpenAPI Spec** : `https://your-app.onrender.com/v3/api-docs` + +## Notes importantes + +### Plan gratuit Render +- Le service s'endort après 15 minutes d'inactivité +- Premier démarrage peut prendre 30-60 secondes +- 750 heures gratuites par mois + +### CORS +L'application est configurée pour accepter les requêtes depuis : +- `localhost:*` +- `*.onrender.com` + +Pour ajouter d'autres origines, modifiez `application.yaml`. + +### Monitoring +- Les logs sont disponibles dans le dashboard Render +- Le health check s'exécute toutes les 30 secondes +- Metrics disponibles via `/actuator/info` + +## Mise à jour de l'application + +Les déploiements automatiques sont activés : +1. Poussez vos changements sur la branche `main` +2. Render détecte automatiquement les changements +3. Build et déploiement automatique + +## Troubleshooting + +### L'application ne démarre pas +- Vérifiez les logs dans le dashboard Render +- Vérifiez que le port 8080 est bien exposé +- Vérifiez les variables d'environnement + +### Health check échoue +- Assurez-vous que Spring Boot Actuator est dans les dépendances +- Vérifiez que `/actuator/health` retourne un status 200 + +### Build échoue +- Vérifiez que Java 21 est spécifié dans le Dockerfile +- Vérifiez que toutes les dépendances Maven sont disponibles +- Consultez les logs de build + +## Support + +Pour plus d'informations : +- [Documentation Render](https://render.com/docs) +- [Spring Boot Docker](https://spring.io/guides/topicals/spring-boot-docker/) diff --git a/rest-api/Dockerfile b/rest-api/Dockerfile new file mode 100644 index 0000000..2a19fac --- /dev/null +++ b/rest-api/Dockerfile @@ -0,0 +1,41 @@ +# Multi-stage build for optimized image size +FROM maven:3.9-eclipse-temurin-21-alpine AS build + +# Set working directory +WORKDIR /app + +# Copy pom.xml and download dependencies (cached layer) +COPY pom.xml . +RUN mvn dependency:go-offline -B + +# Copy source code +COPY src ./src + +# Build the application +RUN mvn clean package -DskipTests -B + +# Runtime stage +FROM eclipse-temurin:21-jre-alpine + +# Set working directory +WORKDIR /app + +# Create non-root user for security +RUN addgroup -S spring && adduser -S spring -G spring +USER spring:spring + +# Copy the built jar from build stage +COPY --from=build /app/target/*.jar app.jar + +# Expose port +EXPOSE 8080 + +# Set JVM options for containerized environments +ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom" + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1 + +# Run the application +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] diff --git a/rest-api/README.md b/rest-api/README.md new file mode 100644 index 0000000..4d3b8ec --- /dev/null +++ b/rest-api/README.md @@ -0,0 +1,141 @@ +# AgriMap REST API + +API REST pour la gestion et le monitoring de parcelles agricoles avec données météorologiques. + +## 🚀 Démarrage rapide + +### Prérequis +- Java 21 +- Maven 3.9+ +- Docker (optionnel) + +### Développement local + +```bash +# Avec Maven +cd rest-api +mvn spring-boot:run + +# Avec Docker Compose +cd rest-api +docker-compose up +``` + +L'API sera disponible sur `http://localhost:8080` + +## 📚 Documentation + +- **Swagger UI** : http://localhost:8080/swagger-ui.html +- **OpenAPI Spec** : http://localhost:8080/v3/api-docs +- **Health Check** : http://localhost:8080/actuator/health + +## 🐳 Docker + +### Build et test local + +```bash +cd rest-api +./docker-test.sh +``` + +Ou manuellement : + +```bash +# Build +docker build -t agrimap-api . + +# Run +docker run -p 8080:8080 agrimap-api +``` + +### Avec Docker Compose + +```bash +docker-compose up -d +docker-compose logs -f +docker-compose down +``` + +## ☁️ Déploiement sur Render + +Voir le guide détaillé : [DEPLOY.md](./DEPLOY.md) + +### Déploiement rapide + +1. Push votre code sur GitHub +2. Connectez-vous à [Render](https://dashboard.render.com/) +3. New → Blueprint +4. Sélectionnez votre repo +5. Render détectera automatiquement `render.yaml` + +## 🔧 Configuration + +### Variables d'environnement + +| Variable | Description | Défaut | +|----------|-------------|--------| +| `SERVER_PORT` | Port du serveur | `8080` | +| `SPRING_PROFILES_ACTIVE` | Profil actif | `default` | +| `ALLOWED_ORIGIN` | Origine CORS autorisée | `http://localhost:3000` | + +### Profils + +- **default** : Configuration par défaut +- **prod** : Configuration de production (compression, logs optimisés) + +## 🏗️ Architecture + +``` +src/ +├── main/ +│ ├── java/com/krma/agrimap/ +│ │ ├── api/ # Controllers REST +│ │ ├── config/ # Configuration Spring +│ │ ├── domain/ # Modèles métier +│ │ ├── infra/ # Intégrations externes +│ │ └── util/ # Utilitaires +│ └── resources/ +│ ├── application.yaml # Config par défaut +│ └── application-prod.yaml # Config production +``` + +## 🧪 Tests + +```bash +# Exécuter les tests +mvn test + +# Avec coverage +mvn clean test jacoco:report +``` + +## 📦 Build + +```bash +# Build JAR +mvn clean package + +# Skip tests +mvn clean package -DskipTests + +# Le JAR sera dans target/agrimap-0.0.1-SNAPSHOT.jar +``` + +## 🔗 APIs externes utilisées + +- **OpenMeteo** : Données météorologiques +- **WhereTheISS** : Données de géolocalisation + +## 📝 License + +Voir LICENSE + +## 🤝 Contribution + +Les contributions sont les bienvenues ! + +1. Fork le projet +2. Créez votre branche (`git checkout -b feature/AmazingFeature`) +3. Commit vos changements (`git commit -m 'Add some AmazingFeature'`) +4. Push vers la branche (`git push origin feature/AmazingFeature`) +5. Ouvrez une Pull Request diff --git a/rest-api/docker-compose.yml b/rest-api/docker-compose.yml new file mode 100644 index 0000000..2909c6f --- /dev/null +++ b/rest-api/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + api: + build: + context: . + dockerfile: Dockerfile + container_name: agrimap-api + ports: + - "8080:8080" + environment: + - SPRING_PROFILES_ACTIVE=prod + - SERVER_PORT=8080 + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/actuator/health"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 60s + restart: unless-stopped + networks: + - agrimap-network + +networks: + agrimap-network: + driver: bridge diff --git a/rest-api/pom.xml b/rest-api/pom.xml index 80af4ce..599c987 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -49,6 +49,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-actuator + org.projectlombok lombok diff --git a/rest-api/render.yaml b/rest-api/render.yaml new file mode 100644 index 0000000..0dded35 --- /dev/null +++ b/rest-api/render.yaml @@ -0,0 +1,18 @@ +services: + - type: web + name: agrimap-api + runtime: docker + plan: free + region: frankfurt # ou oregon, singapore selon votre préférence + branch: main + dockerfilePath: ./rest-api/Dockerfile + dockerContext: ./rest-api + envVars: + - key: SPRING_PROFILES_ACTIVE + value: prod + - key: SERVER_PORT + value: 8080 + - key: JAVA_OPTS + value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0" + healthCheckPath: /actuator/health + autoDeploy: true diff --git a/rest-api/src/main/resources/application-prod.yaml b/rest-api/src/main/resources/application-prod.yaml new file mode 100644 index 0000000..6dbda44 --- /dev/null +++ b/rest-api/src/main/resources/application-prod.yaml @@ -0,0 +1,36 @@ +# Production configuration +server: + port: ${SERVER_PORT:8080} + compression: + enabled: true + mime-types: application/json,application/xml,text/html,text/xml,text/plain + error: + include-message: never + include-stacktrace: never + +spring: + web: + cors: + allowed-origins: + - "https://*.onrender.com" + - "${ALLOWED_ORIGIN:http://localhost:3000}" + +logging: + level: + root: INFO + com.krma.agrimap: INFO + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" + +management: + endpoints: + web: + exposure: + include: health,info,metrics + endpoint: + health: + show-details: when-authorized + metrics: + export: + simple: + enabled: true diff --git a/rest-api/src/main/resources/application.yaml b/rest-api/src/main/resources/application.yaml index 8c6dafa..7fc3032 100644 --- a/rest-api/src/main/resources/application.yaml +++ b/rest-api/src/main/resources/application.yaml @@ -1,3 +1,6 @@ +server: + port: ${SERVER_PORT:8080} + spring: application: name: agrimap @@ -6,6 +9,7 @@ spring: allowed-origins: - "http://localhost:*" - "https://localhost:*" + - "https://*.onrender.com" allowed-methods: - GET - POST @@ -17,6 +21,15 @@ spring: allow-credentials: true max-age: 3600 +management: + endpoints: + web: + exposure: + include: health,info + endpoint: + health: + show-details: when-authorized + api: openmeteo: rootUri: https://api.open-meteo.com From b2cf82bd59a906534de7f41b3526c0f6c263bc12 Mon Sep 17 00:00:00 2001 From: Alban Talagrand Date: Fri, 17 Oct 2025 09:05:12 +0200 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20ajout=20de=20l'origine=20autoris?= =?UTF-8?q?=C3=A9e=20pour=20CORS=20dans=20la=20configuration=20de=20produc?= =?UTF-8?q?tion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest-api/src/main/resources/application-prod.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/rest-api/src/main/resources/application-prod.yaml b/rest-api/src/main/resources/application-prod.yaml index 6dbda44..f70f951 100644 --- a/rest-api/src/main/resources/application-prod.yaml +++ b/rest-api/src/main/resources/application-prod.yaml @@ -14,6 +14,7 @@ spring: allowed-origins: - "https://*.onrender.com" - "${ALLOWED_ORIGIN:http://localhost:3000}" + - "https://agrimap.nabal.fr" logging: level: From 032fd2b983d4f0370fcea302a1ebae03659c6e0c Mon Sep 17 00:00:00 2001 From: Alban Talagrand Date: Fri, 17 Oct 2025 09:15:14 +0200 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20mise=20=C3=A0=20jour=20des=20origine?= =?UTF-8?q?s=20autoris=C3=A9es=20pour=20CORS=20dans=20la=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/krma/agrimap/config/CorsConfig.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/rest-api/src/main/java/com/krma/agrimap/config/CorsConfig.java b/rest-api/src/main/java/com/krma/agrimap/config/CorsConfig.java index a81654e..f3eecbb 100644 --- a/rest-api/src/main/java/com/krma/agrimap/config/CorsConfig.java +++ b/rest-api/src/main/java/com/krma/agrimap/config/CorsConfig.java @@ -19,7 +19,9 @@ public void addCorsMappings(@NonNull CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns( "http://localhost:*", - "https://localhost:*" + "https://localhost:*", + "https://agrimap.nabal.fr", + "https://*.onrender.com" ) .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") .allowedHeaders("*") @@ -30,30 +32,20 @@ public void addCorsMappings(@NonNull CorsRegistry registry) { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - - // Autoriser tous les domaines localhost avec n'importe quel port configuration.setAllowedOriginPatterns(Arrays.asList( "http://localhost:*", - "https://localhost:*" + "https://localhost:*", + "https://agrimap.nabal.fr", + "https://*.onrender.com" )); - - // Autoriser toutes les méthodes HTTP communes configuration.setAllowedMethods(Arrays.asList( "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH" )); - - // Autoriser tous les headers configuration.setAllowedHeaders(Arrays.asList("*")); - - // Permettre l'envoi de cookies et credentials configuration.setAllowCredentials(true); - - // Cache des informations CORS pendant 1 heure configuration.setMaxAge(3600L); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); - return source; } } From 9c93a43b802983d242c914e4207b13bd6d393687 Mon Sep 17 00:00:00 2001 From: Nabal22 Date: Fri, 17 Oct 2025 09:22:23 +0200 Subject: [PATCH 4/4] Update rest-api/render.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- rest-api/render.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-api/render.yaml b/rest-api/render.yaml index 0dded35..06b88f1 100644 --- a/rest-api/render.yaml +++ b/rest-api/render.yaml @@ -3,7 +3,7 @@ services: name: agrimap-api runtime: docker plan: free - region: frankfurt # ou oregon, singapore selon votre préférence + region: frankfurt # or oregon, singapore according to your preference branch: main dockerfilePath: ./rest-api/Dockerfile dockerContext: ./rest-api