refactor: simplify Docker entrypoints — agent bundles log appender
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m54s
CI / docker (push) Successful in 1m16s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 57s
SonarQube / sonarqube (push) Successful in 4m0s

The agent shaded JAR now includes the log appender classes. Remove
PropertiesLauncher, -Dloader.path, and separate appender JAR references.

All JVM types now use: java -javaagent:/app/agent.jar -jar app.jar
Plain Java uses -cp with explicit main class. Native runs binary directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-16 01:20:48 +02:00
parent a4a5986f38
commit 3666994b9e
2 changed files with 8 additions and 13 deletions

View File

@@ -110,7 +110,7 @@ java -jar cameleer-server-app/target/cameleer-server-app-1.0-SNAPSHOT.jar
**runtime/** — Docker orchestration **runtime/** — Docker orchestration
- `DockerRuntimeOrchestrator` — implements RuntimeOrchestrator; Docker Java client (zerodep transport), container lifecycle - `DockerRuntimeOrchestrator` — implements RuntimeOrchestrator; Docker Java client (zerodep transport), container lifecycle
- `DeploymentExecutor`@Async staged deploy: PRE_FLIGHT -> PULL_IMAGE -> CREATE_NETWORK -> START_REPLICAS -> HEALTH_CHECK -> SWAP_TRAFFIC -> COMPLETE. Container names are `{tenantId}-{envSlug}-{appSlug}-{replicaIndex}` (globally unique on Docker daemon). Primary network for app containers is set via `CAMELEER_SERVER_RUNTIME_DOCKERNETWORK` env var (in SaaS mode: `cameleer-tenant-{slug}`); apps also connect to `cameleer-traefik` (routing) and `cameleer-env-{tenantId}-{envSlug}` (per-environment discovery) as additional networks. Resolves `runtimeType: auto` to concrete type from `AppVersion.detectedRuntimeType` at PRE_FLIGHT (fails deployment if unresolvable). Builds framework-specific Docker entrypoint per runtime type (Spring Boot PropertiesLauncher, Quarkus `-jar`, plain Java classpath, native binary). Sets per-replica `CAMELEER_AGENT_INSTANCEID` env var to `{envSlug}-{appSlug}-{replicaIndex}` so container logs and agent logs share the same instance identity. Sets `CAMELEER_AGENT_*` env vars from `ResolvedContainerConfig` (routeControlEnabled, replayEnabled, health port). These are startup-only agent properties — changing them requires redeployment. - `DeploymentExecutor`@Async staged deploy: PRE_FLIGHT -> PULL_IMAGE -> CREATE_NETWORK -> START_REPLICAS -> HEALTH_CHECK -> SWAP_TRAFFIC -> COMPLETE. Container names are `{tenantId}-{envSlug}-{appSlug}-{replicaIndex}` (globally unique on Docker daemon). Primary network for app containers is set via `CAMELEER_SERVER_RUNTIME_DOCKERNETWORK` env var (in SaaS mode: `cameleer-tenant-{slug}`); apps also connect to `cameleer-traefik` (routing) and `cameleer-env-{tenantId}-{envSlug}` (per-environment discovery) as additional networks. Resolves `runtimeType: auto` to concrete type from `AppVersion.detectedRuntimeType` at PRE_FLIGHT (fails deployment if unresolvable). Builds Docker entrypoint per runtime type (all JVM types use `-javaagent:/app/agent.jar -jar`, plain Java uses `-cp` with main class, native runs binary directly). Sets per-replica `CAMELEER_AGENT_INSTANCEID` env var to `{envSlug}-{appSlug}-{replicaIndex}` so container logs and agent logs share the same instance identity. Sets `CAMELEER_AGENT_*` env vars from `ResolvedContainerConfig` (routeControlEnabled, replayEnabled, health port). These are startup-only agent properties — changing them requires redeployment.
- `DockerNetworkManager` — ensures bridge networks (cameleer-traefik, cameleer-env-{slug}), connects containers - `DockerNetworkManager` — ensures bridge networks (cameleer-traefik, cameleer-env-{slug}), connects containers
- `DockerEventMonitor` — persistent Docker event stream listener (die, oom, start, stop), updates deployment status - `DockerEventMonitor` — persistent Docker event stream listener (die, oom, start, stop), updates deployment status
- `TraefikLabelBuilder` — generates Traefik Docker labels for path-based or subdomain routing. Also emits `cameleer.replica` and `cameleer.instance-id` labels per container for labels-first identity. - `TraefikLabelBuilder` — generates Traefik Docker labels for path-based or subdomain routing. Also emits `cameleer.replica` and `cameleer.instance-id` labels per container for labels-first identity.
@@ -293,11 +293,11 @@ Deployments move through these statuses:
### Runtime Type Detection ### Runtime Type Detection
The server detects the app framework from uploaded JARs and builds framework-specific Docker entrypoints: The server detects the app framework from uploaded JARs and builds Docker entrypoints. The agent shaded JAR bundles the log appender, so no separate `cameleer-log-appender.jar` or `PropertiesLauncher` is needed:
- **Detection** (`RuntimeDetector`): runs at JAR upload time. Checks ZIP magic bytes (non-ZIP = native binary), then probes `META-INF/MANIFEST.MF` Main-Class: Spring Boot loader prefix → `spring-boot`, Quarkus entry point → `quarkus`, other Main-Class → `plain-java` (extracts class name). Results stored on `AppVersion` (`detected_runtime_type`, `detected_main_class`). - **Detection** (`RuntimeDetector`): runs at JAR upload time. Checks ZIP magic bytes (non-ZIP = native binary), then probes `META-INF/MANIFEST.MF` Main-Class: Spring Boot loader prefix → `spring-boot`, Quarkus entry point → `quarkus`, other Main-Class → `plain-java` (extracts class name). Results stored on `AppVersion` (`detected_runtime_type`, `detected_main_class`).
- **Runtime types** (`RuntimeType` enum): `AUTO`, `SPRING_BOOT`, `QUARKUS`, `PLAIN_JAVA`, `NATIVE`. Configurable per app/environment via `containerConfig.runtimeType` (default `"auto"`). - **Runtime types** (`RuntimeType` enum): `AUTO`, `SPRING_BOOT`, `QUARKUS`, `PLAIN_JAVA`, `NATIVE`. Configurable per app/environment via `containerConfig.runtimeType` (default `"auto"`).
- **Entrypoint per type**: Spring Boot uses `PropertiesLauncher` with `-Dloader.path` for log appender; Quarkus uses `-jar` (appender compiled in); plain Java uses classpath with appender JAR; native runs binary directly (agent compiled in). All JVM types get `-javaagent:/app/agent.jar`. - **Entrypoint per type**: The agent shaded JAR bundles the log appender, so all JVM types use the same simple pattern: `java -javaagent:/app/agent.jar -jar app.jar`. Plain Java uses `-cp` with explicit main class instead of `-jar`. Native runs the binary directly. All JVM types get `-javaagent:/app/agent.jar`.
- **Custom arguments** (`containerConfig.customArgs`): freeform string appended to the start command. Validated against a strict pattern to prevent shell injection (entrypoint uses `sh -c`). - **Custom arguments** (`containerConfig.customArgs`): freeform string appended to the start command. Validated against a strict pattern to prevent shell injection (entrypoint uses `sh -c`).
- **AUTO resolution**: at deploy time (PRE_FLIGHT), `"auto"` resolves to the detected type from `AppVersion`. Fails deployment if detection was unsuccessful — user must set type explicitly. - **AUTO resolution**: at deploy time (PRE_FLIGHT), `"auto"` resolves to the detected type from `AppVersion`. Fails deployment if detection was unsuccessful — user must set type explicitly.
- **UI**: Resources tab shows Runtime Type dropdown (with detection hint from latest uploaded version) and Custom Arguments text field. - **UI**: Resources tab shows Runtime Type dropdown (with detection hint from latest uploaded version) and Custom Arguments text field.
@@ -399,7 +399,7 @@ Mean processing time = `camel.route.policy.total_time / camel.route.policy.count
<!-- gitnexus:start --> <!-- gitnexus:start -->
# GitNexus — Code Intelligence # GitNexus — Code Intelligence
This project is indexed by GitNexus as **cameleer-server** (6301 symbols, 15892 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. This project is indexed by GitNexus as **cameleer-server** (6304 symbols, 15892 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. > If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.

View File

@@ -117,16 +117,11 @@ public class DockerRuntimeOrchestrator implements RuntimeOrchestrator {
String customArgs = request.customArgs() != null && !request.customArgs().isBlank() String customArgs = request.customArgs() != null && !request.customArgs().isBlank()
? " " + request.customArgs() : ""; ? " " + request.customArgs() : "";
String entrypoint = switch (request.runtimeType()) { String entrypoint = switch (request.runtimeType()) {
case "quarkus" -> "exec java -javaagent:/app/agent.jar" + customArgs + " -jar " + appJarPath; case "plain-java" -> "exec java -javaagent:/app/agent.jar" + customArgs +
case "plain-java" -> "exec java -javaagent:/app/agent.jar -cp " + appJarPath + " -cp " + appJarPath + " " + request.mainClass();
":/app/cameleer-log-appender.jar" + customArgs + " " + request.mainClass();
case "native" -> "exec " + appJarPath + customArgs; case "native" -> "exec " + appJarPath + customArgs;
default -> { // spring-boot (default) default -> // spring-boot, quarkus, and others all use -jar
String launcher = request.mainClass() != null ? request.mainClass() "exec java -javaagent:/app/agent.jar" + customArgs + " -jar " + appJarPath;
: "org.springframework.boot.loader.launch.PropertiesLauncher";
yield "exec java -javaagent:/app/agent.jar -Dloader.path=/app/cameleer-log-appender.jar" +
customArgs + " -cp " + appJarPath + " " + launcher;
}
}; };
createCmd.withEntrypoint("sh", "-c", entrypoint); createCmd.withEntrypoint("sh", "-c", entrypoint);