fix: provisioned server containers — strip-prefix, Docker socket, env
- Add Traefik strip-prefix middleware so /t/{slug}/api -> /api on server
- Add priority to routers (server API=10, UI=5) to prevent conflicts
- Mount Docker socket + group_add in server containers for app deployment
- Add JAR storage, Docker network, volume env vars for runtime orchestrator
- Use HashMap for labels (>10 entries exceeds Map.of limit)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -114,14 +114,22 @@ public class DockerTenantProvisioner implements TenantProvisioner {
|
||||
|
||||
private void createServerContainer(TenantProvisionRequest req, String name) {
|
||||
String slug = req.slug();
|
||||
Map<String, String> labels = Map.of(
|
||||
"traefik.enable", "true",
|
||||
"traefik.http.routers.server-" + slug + ".rule", "PathPrefix(`/t/" + slug + "/api`) || PathPrefix(`/t/" + slug + "/actuator`)",
|
||||
"traefik.http.routers.server-" + slug + ".tls", "true",
|
||||
"traefik.http.services.server-" + slug + ".loadbalancer.server.port", "8081",
|
||||
"cameleer.tenant", slug,
|
||||
"cameleer.role", "server"
|
||||
);
|
||||
String prefix = "/t/" + slug;
|
||||
|
||||
// Traefik labels — need >10 entries, use HashMap
|
||||
var labels = new java.util.HashMap<String, String>();
|
||||
labels.put("traefik.enable", "true");
|
||||
// Router: match /t/{slug}/api/* and /t/{slug}/actuator/*
|
||||
labels.put("traefik.http.routers.server-" + slug + ".rule",
|
||||
"PathPrefix(`" + prefix + "/api`) || PathPrefix(`" + prefix + "/actuator`)");
|
||||
labels.put("traefik.http.routers.server-" + slug + ".tls", "true");
|
||||
labels.put("traefik.http.routers.server-" + slug + ".priority", "10");
|
||||
// Strip the /t/{slug} prefix so server sees /api/... and /actuator/...
|
||||
labels.put("traefik.http.middlewares.server-strip-" + slug + ".stripprefix.prefixes", prefix);
|
||||
labels.put("traefik.http.routers.server-" + slug + ".middlewares", "server-strip-" + slug);
|
||||
labels.put("traefik.http.services.server-" + slug + ".loadbalancer.server.port", "8081");
|
||||
labels.put("cameleer.tenant", slug);
|
||||
labels.put("cameleer.role", "server");
|
||||
|
||||
List<String> env = List.of(
|
||||
"SPRING_DATASOURCE_URL=" + props.datasourceUrl(),
|
||||
@@ -140,12 +148,18 @@ public class DockerTenantProvisioner implements TenantProvisioner {
|
||||
"CAMELEER_RUNTIME_ENABLED=true",
|
||||
"CAMELEER_SERVER_URL=http://" + name + ":8081",
|
||||
"CAMELEER_ROUTING_DOMAIN=" + props.publicHost(),
|
||||
"CAMELEER_ROUTING_MODE=path"
|
||||
"CAMELEER_ROUTING_MODE=path",
|
||||
"CAMELEER_JAR_STORAGE_PATH=/data/jars",
|
||||
"CAMELEER_DOCKER_NETWORK=" + props.networkName(),
|
||||
"CAMELEER_JAR_DOCKER_VOLUME=cameleer-jars-" + slug
|
||||
);
|
||||
|
||||
// Docker socket mount for app deployment within tenant server
|
||||
HostConfig hostConfig = HostConfig.newHostConfig()
|
||||
.withRestartPolicy(RestartPolicy.unlessStoppedRestart())
|
||||
.withNetworkMode(props.networkName());
|
||||
.withNetworkMode(props.networkName())
|
||||
.withBinds(new Bind("/var/run/docker.sock", new Volume("/var/run/docker.sock")))
|
||||
.withGroupAdd(List.of("0"));
|
||||
|
||||
CreateContainerResponse resp = docker.createContainerCmd(props.serverImage())
|
||||
.withName(name)
|
||||
@@ -159,7 +173,7 @@ public class DockerTenantProvisioner implements TenantProvisioner {
|
||||
.withRetries(12))
|
||||
.exec();
|
||||
|
||||
// Connect to traefik network
|
||||
// Connect to traefik network with DNS alias
|
||||
docker.connectToNetworkCmd()
|
||||
.withNetworkId(props.traefikNetwork())
|
||||
.withContainerId(resp.getId())
|
||||
@@ -168,20 +182,23 @@ public class DockerTenantProvisioner implements TenantProvisioner {
|
||||
}
|
||||
|
||||
private void createUiContainer(String slug, String uiName, String serverName) {
|
||||
Map<String, String> labels = Map.of(
|
||||
"traefik.enable", "true",
|
||||
"traefik.http.routers.ui-" + slug + ".rule", "PathPrefix(`/t/" + slug + "`)",
|
||||
"traefik.http.routers.ui-" + slug + ".tls", "true",
|
||||
"traefik.http.routers.ui-" + slug + ".priority", "1",
|
||||
"traefik.http.services.ui-" + slug + ".loadbalancer.server.port", "80",
|
||||
"traefik.http.middlewares.ui-strip-" + slug + ".stripprefix.prefixes", "/t/" + slug,
|
||||
"traefik.http.routers.ui-" + slug + ".middlewares", "ui-strip-" + slug,
|
||||
"cameleer.tenant", slug,
|
||||
"cameleer.role", "server-ui"
|
||||
);
|
||||
String prefix = "/t/" + slug;
|
||||
|
||||
var labels = new java.util.HashMap<String, String>();
|
||||
labels.put("traefik.enable", "true");
|
||||
// Router: catch-all for /t/{slug}/* (lower priority than server API)
|
||||
labels.put("traefik.http.routers.ui-" + slug + ".rule", "PathPrefix(`" + prefix + "`)");
|
||||
labels.put("traefik.http.routers.ui-" + slug + ".tls", "true");
|
||||
labels.put("traefik.http.routers.ui-" + slug + ".priority", "5");
|
||||
// Strip /t/{slug} prefix so UI sees /
|
||||
labels.put("traefik.http.middlewares.ui-strip-" + slug + ".stripprefix.prefixes", prefix);
|
||||
labels.put("traefik.http.routers.ui-" + slug + ".middlewares", "ui-strip-" + slug);
|
||||
labels.put("traefik.http.services.ui-" + slug + ".loadbalancer.server.port", "80");
|
||||
labels.put("cameleer.tenant", slug);
|
||||
labels.put("cameleer.role", "server-ui");
|
||||
|
||||
List<String> env = List.of(
|
||||
"BASE_PATH=/t/" + slug,
|
||||
"BASE_PATH=" + prefix,
|
||||
"API_URL=http://" + serverName + ":8081"
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user