feat: add Prometheus docker_sd_configs labels to agent containers
Labels prometheus.scrape, prometheus.path, and prometheus.port are now set on every deployed container based on the resolved runtime type, enabling automatic Prometheus service discovery via docker_sd_configs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -107,6 +107,7 @@ java -jar cameleer3-server-app/target/cameleer3-server-app-1.0-SNAPSHOT.jar
|
||||
- `DockerNetworkManager` — ensures bridge networks (cameleer-traefik, cameleer-env-{slug}), connects containers
|
||||
- `DockerEventMonitor` — persistent Docker event stream listener (die, oom, start, stop), updates deployment status
|
||||
- `TraefikLabelBuilder` — generates Traefik Docker labels for path-based or subdomain routing
|
||||
- `PrometheusLabelBuilder` — generates Prometheus Docker labels (`prometheus.scrape/path/port`) per runtime type for `docker_sd_configs` auto-discovery
|
||||
- `DisabledRuntimeOrchestrator` — no-op when runtime not enabled
|
||||
|
||||
**storage/** — PostgreSQL repositories (JdbcTemplate)
|
||||
@@ -235,6 +236,7 @@ When deployed via the cameleer-saas platform, this server orchestrates customer
|
||||
|
||||
- **ConfigMerger** (`core/runtime/ConfigMerger.java`) — pure function: resolve(globalDefaults, envConfig, appConfig) -> ResolvedContainerConfig. Three-layer merge: global (application.yml) -> environment (defaultContainerConfig JSONB) -> app (containerConfig JSONB). Includes `runtimeType` (default `"auto"`) and `customArgs` (default `""`).
|
||||
- **TraefikLabelBuilder** (`app/runtime/TraefikLabelBuilder.java`) — generates Traefik Docker labels for path-based (`/{envSlug}/{appSlug}/`) or subdomain-based (`{appSlug}-{envSlug}.{domain}`) routing. Supports strip-prefix and SSL offloading toggles.
|
||||
- **PrometheusLabelBuilder** (`app/runtime/PrometheusLabelBuilder.java`) — generates Prometheus `docker_sd_configs` labels per resolved runtime type: Spring Boot `/actuator/prometheus:8081`, Quarkus/native `/q/metrics:9000`, plain Java `/metrics:9464`. Labels merged into container metadata alongside Traefik labels at deploy time.
|
||||
- **DockerNetworkManager** (`app/runtime/DockerNetworkManager.java`) — manages two Docker network tiers:
|
||||
- `cameleer-traefik` — shared network; Traefik, server, and all app containers attach here. Server joined via docker-compose with `cameleer3-server` DNS alias.
|
||||
- `cameleer-env-{slug}` — per-environment isolated network; containers in the same environment discover each other via Docker DNS. In SaaS mode, env networks are tenant-scoped: `cameleer-env-{tenantId}-{envSlug}` (overloaded `envNetworkName(tenantId, envSlug)` method) to prevent cross-tenant collisions when multiple tenants have identically-named environments.
|
||||
@@ -298,7 +300,7 @@ In SaaS mode, each tenant's server and its deployed apps are isolated at the Doc
|
||||
<!-- gitnexus:start -->
|
||||
# GitNexus — Code Intelligence
|
||||
|
||||
This project is indexed by GitNexus as **cameleer3-server** (5967 symbols, 15136 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
||||
This project is indexed by GitNexus as **cameleer3-server** (5968 symbols, 15141 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.
|
||||
|
||||
|
||||
@@ -162,6 +162,7 @@ public class DeploymentExecutor {
|
||||
|
||||
Map<String, String> baseEnvVars = buildEnvVars(app, env, config);
|
||||
Map<String, String> labels = TraefikLabelBuilder.build(app.slug(), env.slug(), tenantId, config);
|
||||
labels.putAll(PrometheusLabelBuilder.build(resolvedRuntimeType));
|
||||
|
||||
List<Map<String, Object>> replicaStates = new ArrayList<>();
|
||||
List<String> newContainerIds = new ArrayList<>();
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.cameleer3.server.app.runtime;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class PrometheusLabelBuilder {
|
||||
|
||||
private PrometheusLabelBuilder() {}
|
||||
|
||||
public static Map<String, String> build(String resolvedRuntimeType) {
|
||||
Map<String, String> labels = new LinkedHashMap<>();
|
||||
labels.put("prometheus.scrape", "true");
|
||||
|
||||
switch (resolvedRuntimeType) {
|
||||
case "spring-boot" -> {
|
||||
labels.put("prometheus.path", "/actuator/prometheus");
|
||||
labels.put("prometheus.port", "8081");
|
||||
}
|
||||
case "quarkus", "native" -> {
|
||||
labels.put("prometheus.path", "/q/metrics");
|
||||
labels.put("prometheus.port", "9000");
|
||||
}
|
||||
case "plain-java" -> {
|
||||
labels.put("prometheus.path", "/metrics");
|
||||
labels.put("prometheus.port", "9464");
|
||||
}
|
||||
default -> {
|
||||
labels.put("prometheus.path", "/actuator/prometheus");
|
||||
labels.put("prometheus.port", "8081");
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.cameleer3.server.app.runtime;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PrometheusLabelBuilderTest {
|
||||
|
||||
@Test
|
||||
void springBootLabels() {
|
||||
Map<String, String> labels = PrometheusLabelBuilder.build("spring-boot");
|
||||
assertEquals("true", labels.get("prometheus.scrape"));
|
||||
assertEquals("/actuator/prometheus", labels.get("prometheus.path"));
|
||||
assertEquals("8081", labels.get("prometheus.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void quarkusLabels() {
|
||||
Map<String, String> labels = PrometheusLabelBuilder.build("quarkus");
|
||||
assertEquals("true", labels.get("prometheus.scrape"));
|
||||
assertEquals("/q/metrics", labels.get("prometheus.path"));
|
||||
assertEquals("9000", labels.get("prometheus.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nativeLabels() {
|
||||
Map<String, String> labels = PrometheusLabelBuilder.build("native");
|
||||
assertEquals("true", labels.get("prometheus.scrape"));
|
||||
assertEquals("/q/metrics", labels.get("prometheus.path"));
|
||||
assertEquals("9000", labels.get("prometheus.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void plainJavaLabels() {
|
||||
Map<String, String> labels = PrometheusLabelBuilder.build("plain-java");
|
||||
assertEquals("true", labels.get("prometheus.scrape"));
|
||||
assertEquals("/metrics", labels.get("prometheus.path"));
|
||||
assertEquals("9464", labels.get("prometheus.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownDefaultsToSpringBoot() {
|
||||
Map<String, String> labels = PrometheusLabelBuilder.build("unknown");
|
||||
assertEquals("true", labels.get("prometheus.scrape"));
|
||||
assertEquals("/actuator/prometheus", labels.get("prometheus.path"));
|
||||
assertEquals("8081", labels.get("prometheus.port"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user