Deploying Java Applications
This comprehensive guide covers everything you need to know about deploying Java applications via Deploy with Git, from simple Spring Boot applications to complex microservices using Maven or Gradle.
Overview
Deploy with Git automatically detects Java applications by looking for:
pom.xmlfile (Maven)build.gradleorbuild.gradle.ktsfile (Gradle).java-versionfor version specification (optional)
Basic Java Deployment
Simple Spring Boot Application
docker run -d \
--name spring-boot-api \
-e GIT_REPO_URL=https://github.com/your-username/spring-boot-api \
-e APP_PORT=8080 \
-p 8080:8080 \
runonflux/orbit:latest
What Happens Automatically
- Detection: Finds
pom.xmlorbuild.gradleand identifies as Java project - Version Selection:
- Checks
JAVA_VERSIONenvironment variable - Checks
.java-versionfile - Checks
<java.version>or<maven.compiler.target>in pom.xml - Checks
sourceCompatibilityin build.gradle - Falls back to Java 21 LTS
- Checks
- Runtime Installation:
- Downloads Eclipse Temurin JDK from Adoptium
- Extracts to
/opt/flux-tools/java - Installs Maven 3.9.6 to
/opt/flux-tools/maven - Sets JAVA_HOME and M2_HOME environment variables
- Dependencies:
- Maven: Runs
mvn dependency:go-offline -B - Gradle: Runs
gradle dependencies --no-daemon(auto-installs Gradle 8.5 if needed)
- Maven: Runs
- Build:
- Maven:
mvn clean package -DskipTests -B - Gradle:
gradle build -x test --no-daemon
- Maven:
- Memory Configuration: Auto-configures JVM heap (75% of container memory, min 512MB, max 8GB)
- Start: Executes JAR with
java $JAVA_OPTS -jar {jar} --server.port=$APP_PORT
Framework-Specific Guides
Spring Boot
Spring Boot is the most popular Java framework. Deploy with Git automatically detects and optimizes Spring Boot applications:
docker run -d \
--name spring-boot-rest-api \
-e GIT_REPO_URL=https://github.com/your-username/spring-boot-api \
-e APP_PORT=8080 \
-e JAVA_VERSION=21 \
-p 8080:8080 \
runonflux/orbit:latest
Example Maven pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<groupId>com.example</groupId>
<artifactId>my-api</artifactId>
<version>1.0.0</version>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Example Application:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@GetMapping("/health")
public Map<String, String> health() {
return Map.of("status", "healthy");
}
@GetMapping("/")
public Map<String, String> root() {
return Map.of("message", "Hello from Spring Boot!");
}
}
Key Features:
- Auto-configures
--server.portfromAPP_PORTenvironment variable - Detects Spring Boot framework and optimizes build
- Supports Spring Boot 2.x and 3.x
- Handles both JAR and WAR packaging
Quarkus
Quarkus is a Kubernetes-native Java framework optimized for GraalVM and HotSpot:
docker run -d \
--name quarkus-api \
-e GIT_REPO_URL=https://github.com/your-username/quarkus-api \
-e APP_PORT=8080 \
-p 8080:8080 \
runonflux/orbit:latest
Example Maven pom.xml:
<project>
<properties>
<quarkus.version>3.6.0</quarkus.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
</dependencies>
</project>
Key Features:
- Detects Quarkus framework automatically
- Fast startup time
- Low memory footprint
- Handles Quarkus-specific JAR naming (
*-runner.jar)
Micronaut
Micronaut is a modern JVM-based framework for building microservices:
docker run -d \
--name micronaut-api \
-e GIT_REPO_URL=https://github.com/your-username/micronaut-api \
-e APP_PORT=8080 \
-p 8080:8080 \
runonflux/orbit:latest
Build Tool Configuration
Maven
Deploy with Git fully supports Maven projects and automatically handles:
Maven Wrapper (Preferred):
# If your project has mvnw, Deploy with Git uses it automatically
./mvnw clean package -DskipTests -B
System Maven (Fallback):
# If no wrapper, uses installed Maven 3.9.6
mvn clean package -DskipTests -B
Skip Tests:
Tests are automatically skipped during build (-DskipTests). To run tests:
docker run -d \
-e BUILD_COMMAND="mvn clean package -B" \
runonflux/orbit:latest
Gradle
Deploy with Git fully supports Gradle projects with both Groovy and Kotlin DSL:
Gradle Wrapper (Preferred):
# If your project has gradlew, Deploy with Git uses it automatically
./gradlew build -x test --no-daemon
System Gradle (Auto-installed):
# If no wrapper, Gradle 8.5 is installed automatically
gradle build -x test --no-daemon
Example build.gradle:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = '21'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
Example build.gradle.kts (Kotlin DSL):
plugins {
java
id("org.springframework.boot") version "3.2.0"
id("io.spring.dependency-management") version "1.1.4"
}
group = "com.example"
version = "1.0.0"
java {
sourceCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
}
Configuration Options
Environment Variables
| Variable | Description | Default | Example |
|---|---|---|---|
JAVA_VERSION | Force specific Java version | Auto-detected or 21 | 17, 21 |
JAVA_OPTS | JVM options | Auto-configured | -Xms512m -Xmx2048m |
MAVEN_OPTS | Maven-specific options | None | -Xmx1024m |
GRADLE_OPTS | Gradle-specific options | None | -Xmx1024m |
BUILD_COMMAND | Override build command | Auto (mvn/gradle) | mvn clean install |
RUN_COMMAND | Override run command | Auto-detected JAR | java -jar custom.jar |
BUILD_TIMEOUT | Build timeout in seconds | 1800 (30 min) | 3600 |
Java Version Detection Priority
JAVA_VERSIONenvironment variable (highest priority).java-versionfile in project root<java.version>in pom.xml<maven.compiler.target>in pom.xmlsourceCompatibilityin build.gradle- Default: Java 21 LTS
Memory Configuration
Deploy with Git automatically configures JVM memory based on container resources:
Automatic Configuration:
# Container with 4GB RAM:
# JAVA_OPTS=-Xms3072m -Xmx3072m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 ...
Manual Override:
docker run -d \
-e JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC" \
runonflux/orbit:latest
Memory Calculation:
- Uses 75% of container memory for heap
- Minimum: 512MB
- Maximum: 8GB
- Uses G1GC for optimal performance
JAR File Detection
Deploy with Git automatically finds and runs the correct JAR file:
Detection Priority:
- Saved JAR path from build (
/app/.java_jar_file) - Search in
target/(Maven) orbuild/libs/(Gradle) - Exclude:
*-sources.jar,*-javadoc.jar,*-tests.jar - Prefer:
*-boot.jar,*-runner.jar,*-exec.jar,*-all.jar
Advanced Configurations
Multi-Module Projects (Monorepo)
Deploy specific modules from a monorepo:
docker run -d \
--name user-service \
-e GIT_REPO_URL=https://github.com/company/monorepo \
-e PROJECT_PATH=user-service \
-e APP_PORT=8080 \
-p 8080:8080 \
runonflux/orbit:latest
Monorepo Structure:
monorepo/
├── pom.xml # Parent POM
├── common/ # Shared library
├── user-service/ # Microservice 1
│ ├── pom.xml
│ └── target/user-service.jar
├── order-service/ # Microservice 2
│ └── pom.xml
└── payment-service/ # Microservice 3
└── pom.xml
What Happens:
- Clones entire repo
- Sets working directory to
user-service/ - Builds from root (builds all modules)
- Finds JAR in
user-service/target/ - Runs only the user-service JAR
Custom Build Commands
Override the default build command:
docker run -d \
-e BUILD_COMMAND="mvn clean install -P production" \
runonflux/orbit:latest
Custom JVM Options
Configure JVM for specific requirements:
# High-throughput application
docker run -d \
-e JAVA_OPTS="-Xms2g -Xmx4g -XX:+UseParallelGC" \
runonflux/orbit:latest
# Low-latency application
docker run -d \
-e JAVA_OPTS="-Xms1g -Xmx1g -XX:+UseZGC -XX:+UnlockExperimentalVMOptions" \
runonflux/orbit:latest
Maven Profiles
Activate specific Maven profiles:
docker run -d \
-e MAVEN_OPTS="-P production,security" \
runonflux/orbit:latest
CI/CD Integration
GitHub Webhooks
Enable automatic deployments on push:
docker run -d \
--name spring-boot-api \
-e GIT_REPO_URL=https://github.com/your-username/spring-boot-api \
-e APP_PORT=8080 \
-e WEBHOOK_PORT=9001 \
-e WEBHOOK_SECRET=your-secret-key \
-p 8080:8080 \
-p 9001:9001 \
runonflux/orbit:latest
Configure webhook in GitHub:
- Payload URL:
http://your-server:9001/webhook - Content type:
application/json - Secret:
your-secret-key - Events: Just the push event
Dependency Caching
Dependencies are cached based on build file hash:
Maven: Hash of pom.xml
Gradle: Hash of build.gradle or build.gradle.kts
If hash hasn't changed, dependency installation is skipped (saves 30-180 seconds per deployment).
Automatic Rollback
Failed deployments automatically rollback to the last working version:
# Deployment fails
[ERROR] Java build failed with exit code 1
[INFO] Rolling back to previous commit: abc1234
[SUCCESS] Rollback completed
Troubleshooting
Build Timeout
If builds take longer than 30 minutes:
docker run -d \
-e BUILD_TIMEOUT=3600 \
runonflux/orbit:latest
Out of Memory (OOM)
Increase container memory or manually configure heap:
# Increase heap size
docker run -d \
-e JAVA_OPTS="-Xms1g -Xmx2g" \
runonflux/orbit:latest
Wrong JAR File Detected
Specify the exact JAR to run:
docker run -d \
-e RUN_COMMAND="java -jar target/my-app-1.0.0.jar" \
runonflux/orbit:latest
Maven/Gradle Wrapper Issues
If wrapper has wrong permissions or line endings:
# Deploy with Git automatically:
# 1. Makes wrapper executable
# 2. Handles Windows line endings (CRLF)
Java Version Mismatch
Force specific Java version:
docker run -d \
-e JAVA_VERSION=17 \
runonflux/orbit:latest
Best Practices
1. Use Wrappers
Include mvnw or gradlew in your repository for reproducible builds:
# Generate Maven wrapper
mvn wrapper:wrapper
# Generate Gradle wrapper
gradle wrapper
2. Specify Java Version
Explicitly declare Java version in build files:
Maven:
<properties>
<java.version>21</java.version>
</properties>
Gradle:
java {
sourceCompatibility = '21'
}
3. Health Check Endpoint
Include a /health endpoint for monitoring:
@GetMapping("/health")
public Map<String, String> health() {
return Map.of("status", "healthy");
}
4. Read Port from Environment
Always read APP_PORT (passed as --server.port):
// Not needed! Deploy with Git automatically passes:
// --server.port=$APP_PORT
// But if you need it in code:
String port = System.getenv("APP_PORT");
5. Externalize Configuration
Use Spring profiles or environment variables for configuration:
@Value("${database.url:${DATABASE_URL:jdbc:postgresql://localhost:5432/db}}")
private String databaseUrl;
6. Log to STDOUT
Always log to standard output (not files):
// Good: Spring Boot logs to STDOUT by default
logger.info("Application started");
// Avoid: File-based logging in containers
// Use Flux Network's log aggregation instead
Example Deployments
Production Spring Boot API
docker run -d \
--name production-api \
-e GIT_REPO_URL=https://github.com/company/spring-boot-api \
-e GIT_BRANCH=main \
-e APP_PORT=8080 \
-e JAVA_VERSION=21 \
-e WEBHOOK_PORT=9001 \
-e WEBHOOK_SECRET=${WEBHOOK_SECRET} \
-e DATABASE_URL=${DATABASE_URL} \
-e REDIS_URL=${REDIS_URL} \
-p 8080:8080 \
-p 9001:9001 \
runonflux/orbit:latest
Microservice with Resource Limits
docker run -d \
--name user-service \
--memory="2g" \
--cpus="2" \
-e GIT_REPO_URL=https://github.com/company/microservices \
-e PROJECT_PATH=user-service \
-e APP_PORT=8080 \
-e JAVA_OPTS="-Xms512m -Xmx1536m -XX:+UseG1GC" \
-p 8080:8080 \
runonflux/orbit:latest