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;
|
||||
}
|
||||
|
||||
/** 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")
|
||||
public void executeAsync(Deployment deployment) {
|
||||
long deployStart = System.currentTimeMillis();
|
||||
@@ -96,6 +103,7 @@ public class DeploymentExecutor {
|
||||
App app = appService.getById(deployment.appId());
|
||||
Environment env = envService.getById(deployment.environmentId());
|
||||
String jarPath = appService.resolveJarPath(deployment.appVersionId());
|
||||
String generation = generationOf(deployment);
|
||||
|
||||
var globalDefaults = new ConfigMerger.GlobalRuntimeDefaults(
|
||||
parseMemoryLimitMb(globalMemoryLimit),
|
||||
@@ -192,11 +200,11 @@ public class DeploymentExecutor {
|
||||
List<String> newContainerIds = new ArrayList<>();
|
||||
|
||||
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;
|
||||
|
||||
// Per-replica labels (include replica index and instance-id)
|
||||
Map<String, String> labels = TraefikLabelBuilder.build(app.slug(), env.slug(), tenantId, config, i);
|
||||
// Per-replica labels (include replica index, generation, and instance-id)
|
||||
Map<String, String> labels = TraefikLabelBuilder.build(app.slug(), env.slug(), tenantId, config, i, generation);
|
||||
labels.putAll(prometheusLabels);
|
||||
|
||||
// Per-replica env vars (set agent instance ID to match container log identity)
|
||||
|
||||
@@ -10,9 +10,13 @@ public final class TraefikLabelBuilder {
|
||||
private TraefikLabelBuilder() {}
|
||||
|
||||
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 instanceId = envSlug + "-" + appSlug + "-" + replicaIndex;
|
||||
String instanceId = envSlug + "-" + appSlug + "-" + replicaIndex + "-" + generation;
|
||||
Map<String, String> labels = new LinkedHashMap<>();
|
||||
|
||||
labels.put("traefik.enable", "true");
|
||||
@@ -21,6 +25,7 @@ public final class TraefikLabelBuilder {
|
||||
labels.put("cameleer.app", appSlug);
|
||||
labels.put("cameleer.environment", envSlug);
|
||||
labels.put("cameleer.replica", String.valueOf(replicaIndex));
|
||||
labels.put("cameleer.generation", generation);
|
||||
labels.put("cameleer.instance-id", instanceId);
|
||||
|
||||
labels.put("traefik.http.services." + svc + ".loadbalancer.server.port",
|
||||
|
||||
Reference in New Issue
Block a user