deploy: gen-suffixed container names + cameleer.generation label
Append an 8-char generation id (first 8 chars of deployment UUID) to:
- container name: {tenant}-{env}-{app}-{replica}-{gen}
- CAMELEER_AGENT_INSTANCEID (so old+new agents are distinct in the registry)
- Traefik cameleer.instance-id label
And emit a new standalone cameleer.generation label so dashboards
(Prometheus/Grafana) can pin deploy boundaries without regex on
instance-id.
Strategy branching comes next — this commit is foundation only; the
interim destroy-then-start flow still runs regardless of strategy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,13 @@ public class DeploymentExecutor {
|
|||||||
this.applicationConfigRepository = applicationConfigRepository;
|
this.applicationConfigRepository = applicationConfigRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Deployment-scoped id suffix — distinguishes container names and
|
||||||
|
* CAMELEER_AGENT_INSTANCEID across redeploys so old + new replicas can
|
||||||
|
* coexist during a blue/green swap. First 8 chars of the deployment UUID. */
|
||||||
|
static String generationOf(Deployment deployment) {
|
||||||
|
return deployment.id().toString().substring(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
@Async("deploymentTaskExecutor")
|
@Async("deploymentTaskExecutor")
|
||||||
public void executeAsync(Deployment deployment) {
|
public void executeAsync(Deployment deployment) {
|
||||||
long deployStart = System.currentTimeMillis();
|
long deployStart = System.currentTimeMillis();
|
||||||
@@ -96,6 +103,7 @@ public class DeploymentExecutor {
|
|||||||
App app = appService.getById(deployment.appId());
|
App app = appService.getById(deployment.appId());
|
||||||
Environment env = envService.getById(deployment.environmentId());
|
Environment env = envService.getById(deployment.environmentId());
|
||||||
String jarPath = appService.resolveJarPath(deployment.appVersionId());
|
String jarPath = appService.resolveJarPath(deployment.appVersionId());
|
||||||
|
String generation = generationOf(deployment);
|
||||||
|
|
||||||
var globalDefaults = new ConfigMerger.GlobalRuntimeDefaults(
|
var globalDefaults = new ConfigMerger.GlobalRuntimeDefaults(
|
||||||
parseMemoryLimitMb(globalMemoryLimit),
|
parseMemoryLimitMb(globalMemoryLimit),
|
||||||
@@ -192,11 +200,11 @@ public class DeploymentExecutor {
|
|||||||
List<String> newContainerIds = new ArrayList<>();
|
List<String> newContainerIds = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < config.replicas(); i++) {
|
for (int i = 0; i < config.replicas(); i++) {
|
||||||
String instanceId = env.slug() + "-" + app.slug() + "-" + i;
|
String instanceId = env.slug() + "-" + app.slug() + "-" + i + "-" + generation;
|
||||||
String containerName = tenantId + "-" + instanceId;
|
String containerName = tenantId + "-" + instanceId;
|
||||||
|
|
||||||
// Per-replica labels (include replica index and instance-id)
|
// Per-replica labels (include replica index, generation, and instance-id)
|
||||||
Map<String, String> labels = TraefikLabelBuilder.build(app.slug(), env.slug(), tenantId, config, i);
|
Map<String, String> labels = TraefikLabelBuilder.build(app.slug(), env.slug(), tenantId, config, i, generation);
|
||||||
labels.putAll(prometheusLabels);
|
labels.putAll(prometheusLabels);
|
||||||
|
|
||||||
// Per-replica env vars (set agent instance ID to match container log identity)
|
// Per-replica env vars (set agent instance ID to match container log identity)
|
||||||
|
|||||||
@@ -10,9 +10,13 @@ public final class TraefikLabelBuilder {
|
|||||||
private TraefikLabelBuilder() {}
|
private TraefikLabelBuilder() {}
|
||||||
|
|
||||||
public static Map<String, String> build(String appSlug, String envSlug, String tenantId,
|
public static Map<String, String> build(String appSlug, String envSlug, String tenantId,
|
||||||
ResolvedContainerConfig config, int replicaIndex) {
|
ResolvedContainerConfig config, int replicaIndex,
|
||||||
|
String generation) {
|
||||||
|
// Traefik router/service keys stay generation-agnostic so load balancing
|
||||||
|
// spans old + new replicas during a blue/green overlap. instance-id and
|
||||||
|
// the new generation label carry the per-deploy identity.
|
||||||
String svc = envSlug + "-" + appSlug;
|
String svc = envSlug + "-" + appSlug;
|
||||||
String instanceId = envSlug + "-" + appSlug + "-" + replicaIndex;
|
String instanceId = envSlug + "-" + appSlug + "-" + replicaIndex + "-" + generation;
|
||||||
Map<String, String> labels = new LinkedHashMap<>();
|
Map<String, String> labels = new LinkedHashMap<>();
|
||||||
|
|
||||||
labels.put("traefik.enable", "true");
|
labels.put("traefik.enable", "true");
|
||||||
@@ -21,6 +25,7 @@ public final class TraefikLabelBuilder {
|
|||||||
labels.put("cameleer.app", appSlug);
|
labels.put("cameleer.app", appSlug);
|
||||||
labels.put("cameleer.environment", envSlug);
|
labels.put("cameleer.environment", envSlug);
|
||||||
labels.put("cameleer.replica", String.valueOf(replicaIndex));
|
labels.put("cameleer.replica", String.valueOf(replicaIndex));
|
||||||
|
labels.put("cameleer.generation", generation);
|
||||||
labels.put("cameleer.instance-id", instanceId);
|
labels.put("cameleer.instance-id", instanceId);
|
||||||
|
|
||||||
labels.put("traefik.http.services." + svc + ".loadbalancer.server.port",
|
labels.put("traefik.http.services." + svc + ".loadbalancer.server.port",
|
||||||
|
|||||||
Reference in New Issue
Block a user