feat: support dev code queue deployment

This commit is contained in:
Codex
2026-05-18 01:31:58 +00:00
parent 21a9b73850
commit 50ef729827
9 changed files with 831 additions and 35 deletions
+50 -26
View File
@@ -131,7 +131,7 @@ const nativeK3sInstallVersion = "v1.34.1+k3s1";
const nativeK3sImage = "rancher/k3s:v1.34.1-k3s1";
const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock";
const unideskRepoUrl = "https://github.com/pikasTech/unidesk";
const devApplySupportedServiceIds = new Set(["backend-core", "frontend"]);
const devApplySupportedServiceIds = new Set(["backend-core", "frontend", "code-queue"]);
const deployEnvironmentTargets: Record<DeployEnvironment, DeployEnvironmentTarget> = {
dev: {
environment: "dev",
@@ -568,12 +568,13 @@ function frontendCoreDeployService(config: UniDeskConfig): UniDeskMicroserviceCo
};
}
function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined {
function devK3sDeployService(id: string): UniDeskMicroserviceConfig | undefined {
const specs: Record<string, {
name: string;
description: string;
dockerfile: string;
composeService: string;
composeFile: string;
containerName: string;
nodeBaseUrl: string;
nodePort: number;
@@ -586,6 +587,7 @@ function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined
name: "UniDesk Dev Backend Core",
description: "Isolated dev backend-core deployed into D601 native k3s namespace unidesk-dev.",
dockerfile: "src/components/backend-core/Dockerfile",
composeFile: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml",
composeService: "backend-core-dev",
containerName: "k3s:backend-core-dev",
nodeBaseUrl: "k3s://backend-core-dev",
@@ -599,6 +601,7 @@ function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined
name: "UniDesk Dev Frontend",
description: "Isolated dev frontend deployed into D601 native k3s namespace unidesk-dev.",
dockerfile: "src/components/frontend/Dockerfile",
composeFile: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml",
composeService: "frontend-dev",
containerName: "k3s:frontend-dev",
nodeBaseUrl: "k3s://frontend-dev",
@@ -608,6 +611,20 @@ function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined
allowedMethods: ["GET", "HEAD"],
allowedPathPrefixes: ["/"],
},
"code-queue": {
name: "UniDesk Dev Code Queue",
description: "Isolated dev Code Queue execution plane deployed into D601 native k3s namespace unidesk-dev.",
dockerfile: "src/components/microservices/code-queue/Dockerfile",
composeFile: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml",
composeService: "code-queue-scheduler-dev",
containerName: "k3s:code-queue-scheduler-dev",
nodeBaseUrl: "k3s://code-queue-dev",
nodePort: 4222,
healthPath: "/health",
route: "/dev/code-queue",
allowedMethods: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
allowedPathPrefixes: ["/", "/api/", "/logs"],
},
};
const spec = specs[id];
if (spec === undefined) return undefined;
@@ -620,7 +637,7 @@ function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined
url: unideskRepoUrl,
commitId: "deploy-dev",
dockerfile: spec.dockerfile,
composeFile: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml",
composeFile: spec.composeFile,
composeService: spec.composeService,
containerName: spec.containerName,
},
@@ -647,7 +664,9 @@ function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined
development: {
providerId: "D601",
sshPassthrough: true,
worktreePath: `/home/ubuntu/unidesk-dev-core-deploy/${id}`,
worktreePath: id === "code-queue"
? "/home/ubuntu/unidesk-dev-code-queue-deploy/code-queue"
: `/home/ubuntu/unidesk-dev-core-deploy/${id}`,
},
frontend: {
route: spec.route,
@@ -657,7 +676,7 @@ function devCoreDeployService(id: string): UniDeskMicroserviceConfig | undefined
}
function coreDeployService(config: UniDeskConfig, id: string, environment: DeployEnvironment | null): UniDeskMicroserviceConfig | undefined {
if (environment === "dev") return devCoreDeployService(id);
if (environment === "dev") return devK3sDeployService(id);
if (id === "frontend") return frontendCoreDeployService(config);
return undefined;
}
@@ -666,7 +685,7 @@ function isCoreDeployService(service: UniDeskMicroserviceConfig): boolean {
return service.id === "frontend" && service.providerId === "main-server" && service.backend.proxyMode === "core-direct";
}
function isDevK3sCoreService(service: UniDeskMicroserviceConfig): boolean {
function isDevK3sDeployService(service: UniDeskMicroserviceConfig): boolean {
return service.deployment.mode === "k3sctl-managed"
&& service.deployment.namespace === deployEnvironmentTargets.dev.namespace
&& devApplySupportedServiceIds.has(service.id);
@@ -685,7 +704,7 @@ function selectServices(config: UniDeskConfig, manifest: DeployManifest, service
if (serviceId !== null && selected.length === 0) throw new Error(`deploy manifest does not contain service: ${serviceId}`);
return selected.map((desired) => {
if (manifest.environment === "dev") {
const service = devCoreDeployService(desired.id);
const service = devK3sDeployService(desired.id);
if (service === undefined) {
throw new Error(`deploy --env dev service ${desired.id} is not enabled in this executor yet; currently supported: ${[...devApplySupportedServiceIds].join(", ")}`);
}
@@ -746,7 +765,7 @@ function targetExportDir(service: UniDeskMicroserviceConfig, runId: string): str
}
function targetWorkDir(service: UniDeskMicroserviceConfig): string {
if (isDevK3sCoreService(service)) return service.development.worktreePath;
if (isDevK3sDeployService(service)) return service.development.worktreePath;
if (service.deployment.mode === "k3sctl-managed") return k3sDeployDir;
if (targetIsMain(service) && isUnideskRepo(service.repository.url)) {
return rootPath(".state", "deploy", "work", safeId(service.id));
@@ -780,7 +799,7 @@ function sourceBuildContext(service: UniDeskMicroserviceConfig): string {
}
function buildImageTag(service: UniDeskMicroserviceConfig): string {
if (isDevK3sCoreService(service)) return `unidesk-${service.id}:dev`;
if (isDevK3sDeployService(service)) return `unidesk-${service.id}:dev`;
if (service.deployment.mode === "k3sctl-managed") return `unidesk-${service.id}:d601`;
if (targetIsMain(service)) {
if (["project-manager", "baidu-netdisk", "oa-event-flow"].includes(service.repository.composeService)) return service.repository.composeService;
@@ -1025,7 +1044,7 @@ function claudeqqDeployAssetOverlayCommands(): string[] {
}
function syncK8sControlManifestsScript(service: UniDeskMicroserviceConfig): string {
if (isDevK3sCoreService(service)) {
if (isDevK3sDeployService(service)) {
const manifest = k8sManifestPath(service);
if (!existsSync(rootPath(manifest))) throw new Error(`${service.id} dev k3s control manifest missing: ${manifest}`);
const encoded = Buffer.from(readFileSync(rootPath(manifest), "utf8"), "utf8").toString("base64");
@@ -1098,7 +1117,7 @@ function buildImageScript(service: UniDeskMicroserviceConfig, desired: DeployMan
"if ! docker buildx version >/dev/null 2>&1; then",
" if ! docker buildx inspect default >/dev/null 2>&1; then echo target_build_builder=missing >&2; exit 1; fi",
"fi",
...(isDevK3sCoreService(service) ? [
...(isDevK3sDeployService(service) ? [
"if ! docker image inspect oven/bun:1-alpine >/dev/null 2>&1; then",
" docker pull oven/bun:1-alpine",
"fi",
@@ -1113,12 +1132,11 @@ function buildImageScript(service: UniDeskMicroserviceConfig, desired: DeployMan
].filter((line) => line.length > 0).join("\n");
}
function patchDevK3sCoreManifestScript(service: UniDeskMicroserviceConfig, desired: DeployManifestService, resolvedCommit: string): string {
function patchDevK3sManifestScript(service: UniDeskMicroserviceConfig, desired: DeployManifestService, resolvedCommit: string): string {
const manifest = `${targetWorkDir(service)}/${k8sManifestPath(service)}`;
const image = buildImageTag(service);
const serviceId = service.id;
const deploymentName = service.repository.composeService;
const manifestServiceId = deploymentName;
return [
"set -euo pipefail",
`manifest=${shellQuote(manifest)}`,
@@ -1128,27 +1146,27 @@ function patchDevK3sCoreManifestScript(service: UniDeskMicroserviceConfig, desir
`repo=${shellQuote(desired.repo)}`,
`commit=${shellQuote(resolvedCommit)}`,
`requested_commit=${shellQuote(desired.commitId)}`,
`manifest_service_id=${shellQuote(manifestServiceId)}`,
`python3 - "$manifest" "$service_id" "$deployment_name" "$image" "$repo" "$commit" "$requested_commit" "$manifest_service_id" <<'PY'`,
`python3 - "$manifest" "$service_id" "$deployment_name" "$image" "$repo" "$commit" "$requested_commit" <<'PY'`,
"import re",
"import sys",
"path, service_id, deployment_name, image, repo, commit, requested_commit, manifest_service_id = sys.argv[1:]",
"path, service_id, deployment_name, image, repo, commit, requested_commit = sys.argv[1:]",
"text = open(path, encoding='utf-8').read()",
"segments = re.split(r'(?m)^---\\s*$', text)",
"kept = []",
"for segment in segments:",
" if not segment.strip():",
" continue",
" if f'\\n name: {deployment_name}\\n' in ('\\n' + segment + '\\n'):",
" haystack = '\\n' + segment + '\\n'",
" if f'unidesk.ai/deploy-service-id: {service_id}' in segment or f'\\n name: {deployment_name}\\n' in haystack:",
" kept.append(segment)",
"if not kept:",
" raise SystemExit(f'deployment/service {deployment_name} not found in {path}')",
" raise SystemExit(f'dev service {service_id}/{deployment_name} not found in {path}')",
"patched = []",
"for segment in kept:",
" segment = segment.replace('unidesk.ai/image-source: deploy-dev-commit', 'unidesk.ai/image-source: deploy-env-commit')",
" segment = re.sub(r'image: unidesk-[^\\n]+:dev-placeholder', f'image: {image}', segment)",
" segment = re.sub(r'value: replace-with-deploy-dev-commit', f'value: {commit}', segment)",
" segment = segment.replace(f'value: {manifest_service_id}', f'value: {service_id}')",
" segment = segment.replace('value: https://github.com/pikasTech/unidesk', f'value: {repo}')",
" patched.append(segment.strip() + '\\n')",
"out = '---\\n'.join(patched)",
"open(path, 'w', encoding='utf-8').write(out)",
@@ -1480,6 +1498,7 @@ function importK3sImageScript(service: UniDeskMicroserviceConfig): string {
function cleanupLegacyDirectCodeQueueScript(service: UniDeskMicroserviceConfig): string {
if (service.id !== "code-queue") return "";
if (isDevK3sDeployService(service)) return "";
return [
"set -euo pipefail",
"container=code-queue-backend",
@@ -1507,6 +1526,9 @@ function k8sNamespaceForService(service: UniDeskMicroserviceConfig): string {
}
function k8sDeploymentsForService(service: UniDeskMicroserviceConfig): string[] {
if (isDevK3sDeployService(service) && service.id === "code-queue") {
return ["d601-dev-provider-egress-proxy", "code-queue-scheduler-dev", "code-queue-read-dev", "code-queue-write-dev"];
}
if (service.id === "code-queue") return ["d601-provider-egress-proxy", "d601-tcp-egress-gateway", "code-queue", "code-queue-read", "code-queue-write"];
return [service.repository.composeService];
}
@@ -1514,7 +1536,7 @@ function k8sDeploymentsForService(service: UniDeskMicroserviceConfig): string[]
function applyK8sScript(service: UniDeskMicroserviceConfig): string {
const manifest = `${targetWorkDir(service)}/${k8sManifestPath(service)}`;
const namespace = k8sNamespaceForService(service);
const cleanup = service.id === "code-queue"
const cleanup = service.id === "code-queue" && !isDevK3sDeployService(service)
? [
`KUBECONFIG=${shellQuote(k8sKubeconfig)} kubectl -n ${shellQuote(namespace)} delete endpointslice d601-provider-egress-proxy --ignore-not-found`,
`KUBECONFIG=${shellQuote(k8sKubeconfig)} kubectl -n ${shellQuote(namespace)} delete deployment code-queue-d518 --ignore-not-found`,
@@ -1636,14 +1658,16 @@ function devK3sServiceHealthScript(service: UniDeskMicroserviceConfig): string {
const namespace = k8sNamespaceForService(service);
const deployment = service.repository.composeService;
const path = service.backend.healthPath;
const port = service.backend.nodePort;
return [
"set -euo pipefail",
`namespace=${shellQuote(namespace)}`,
`deployment=${shellQuote(deployment)}`,
`path=${shellQuote(path)}`,
`pod=$(KUBECONFIG=${shellQuote(k8sKubeconfig)} kubectl -n "$namespace" get pod -l app.kubernetes.io/name=${shellQuote(service.id)},unidesk.ai/environment=dev -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)`,
`port=${shellQuote(String(port))}`,
`pod=$(KUBECONFIG=${shellQuote(k8sKubeconfig)} kubectl -n "$namespace" get pod -l app.kubernetes.io/instance="$deployment",unidesk.ai/deploy-service-id=${shellQuote(service.id)},unidesk.ai/environment=dev -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)`,
"if [ -z \"$pod\" ]; then echo '{\"ok\":false,\"error\":\"dev deployment pod not found\"}'; exit 0; fi",
`KUBECONFIG=${shellQuote(k8sKubeconfig)} kubectl -n "$namespace" exec "$pod" -- wget -q -T 5 -O - "http://127.0.0.1:8080$path"`,
`KUBECONFIG=${shellQuote(k8sKubeconfig)} kubectl -n "$namespace" exec "$pod" -- wget -q -T 5 -O - "http://127.0.0.1:$port$path"`,
].join("\n");
}
@@ -1651,7 +1675,7 @@ async function serviceHealth(config: UniDeskConfig, service: UniDeskMicroservice
if (isCoreDeployService(service)) {
return await directHttpJson(`${service.backend.nodeBaseUrl}${service.backend.healthPath}`, service.backend.timeoutMs);
}
if (isDevK3sCoreService(service)) {
if (isDevK3sDeployService(service)) {
const result = await runTargetCommand(config, service, devK3sServiceHealthScript(service), "/home/ubuntu", 30_000, 20_000);
let body: unknown = null;
try {
@@ -1918,7 +1942,7 @@ async function step(
}
async function readDockerImageCommit(config: UniDeskConfig, service: UniDeskMicroserviceConfig): Promise<string | null> {
if (isDevK3sCoreService(service)) return null;
if (isDevK3sDeployService(service)) return null;
const result = await runTargetCommand(config, service, dockerCommitProbeScript(service), targetIsMain(service) ? repoRoot : "/home/ubuntu", 30_000, 20_000);
const commit = parseFullCommit(result.stdout);
return commit.length > 0 ? commit : null;
@@ -2066,8 +2090,8 @@ async function applyOneService(config: UniDeskConfig, service: UniDeskMicroservi
if (!pushStep(steps, controlManifestSync)) return { ok: false, serviceId: service.id, startedAt, finishedAt: nowIso(), resolvedCommit, before, steps };
}
if (isDevK3sCoreService(service)) {
const patchManifest = await step(config, service, "patch-dev-k3s-manifest", patchDevK3sCoreManifestScript(service, desired, resolvedCommit), targetWorkDir(service), 60_000, false);
if (isDevK3sDeployService(service)) {
const patchManifest = await step(config, service, "patch-dev-k3s-manifest", patchDevK3sManifestScript(service, desired, resolvedCommit), targetWorkDir(service), 60_000, false);
if (!pushStep(steps, patchManifest)) return { ok: false, serviceId: service.id, startedAt, finishedAt: nowIso(), resolvedCommit, before, steps };
}