feat: extend k3s artifact consumers
This commit is contained in:
@@ -74,11 +74,14 @@ const defaultOptions: ArtifactRegistryOptions = {
|
||||
const supportedArtifactConsumerServices = [
|
||||
"backend-core",
|
||||
"baidu-netdisk",
|
||||
"claudeqq",
|
||||
"code-queue",
|
||||
"code-queue-mgr",
|
||||
"decision-center",
|
||||
"findjob",
|
||||
"frontend",
|
||||
"k3sctl-adapter",
|
||||
"mdtodo",
|
||||
"met-nonlinear",
|
||||
"oa-event-flow",
|
||||
"pipeline",
|
||||
@@ -124,6 +127,7 @@ interface ArtifactConsumerTarget {
|
||||
servicePort: number;
|
||||
containerName: string;
|
||||
healthPath: string;
|
||||
extraDeployments?: Array<string | { name: string; containerName?: string }>;
|
||||
applySelector?: string;
|
||||
podLabelSelector?: string;
|
||||
};
|
||||
@@ -264,6 +268,116 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
"mdtodo": {
|
||||
serviceId: "mdtodo",
|
||||
environment: "prod",
|
||||
kind: "d601-k3s",
|
||||
registryRepository: "unidesk/mdtodo",
|
||||
dockerfile: "src/components/microservices/mdtodo/Dockerfile",
|
||||
prodLiveApply: "enabled",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "unidesk-mdtodo:dev",
|
||||
targetCommitImage: (commit: string) => `unidesk-mdtodo:${commit}`,
|
||||
deployRef: "deploy.json#environments.dev.services.mdtodo",
|
||||
k3s: {
|
||||
namespace: "unidesk-dev",
|
||||
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml",
|
||||
deploymentName: "mdtodo-dev",
|
||||
serviceName: "mdtodo-dev",
|
||||
servicePort: 4267,
|
||||
containerName: "mdtodo",
|
||||
healthPath: "/health",
|
||||
podLabelSelector: "app.kubernetes.io/name=mdtodo,unidesk.ai/environment=dev",
|
||||
},
|
||||
},
|
||||
prod: {
|
||||
targetImage: "unidesk-mdtodo:d601",
|
||||
targetCommitImage: (commit: string) => `unidesk-mdtodo:${commit}`,
|
||||
deployRef: "deploy.json#environments.prod.services.mdtodo",
|
||||
k3s: {
|
||||
namespace: "unidesk",
|
||||
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/mdtodo.k8s.yaml",
|
||||
deploymentName: "mdtodo",
|
||||
serviceName: "mdtodo",
|
||||
servicePort: 4267,
|
||||
containerName: "mdtodo",
|
||||
healthPath: "/health",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"claudeqq": {
|
||||
serviceId: "claudeqq",
|
||||
environment: "prod",
|
||||
kind: "d601-k3s",
|
||||
registryRepository: "unidesk/claudeqq",
|
||||
dockerfile: "claudeqq/Dockerfile",
|
||||
sourceRepo: "https://gitee.com/lyon1998/agent_skills",
|
||||
prodLiveApply: "enabled",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "unidesk-claudeqq:dev",
|
||||
targetCommitImage: (commit: string) => `unidesk-claudeqq:${commit}`,
|
||||
deployRef: "deploy.json#environments.dev.services.claudeqq",
|
||||
k3s: {
|
||||
namespace: "unidesk-dev",
|
||||
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml",
|
||||
deploymentName: "claudeqq-dev",
|
||||
serviceName: "claudeqq-dev",
|
||||
servicePort: 3290,
|
||||
containerName: "claudeqq",
|
||||
healthPath: "/health",
|
||||
podLabelSelector: "app.kubernetes.io/name=claudeqq,unidesk.ai/environment=dev",
|
||||
},
|
||||
},
|
||||
prod: {
|
||||
targetImage: "unidesk-claudeqq:d601",
|
||||
targetCommitImage: (commit: string) => `unidesk-claudeqq:${commit}`,
|
||||
deployRef: "deploy.json#environments.prod.services.claudeqq",
|
||||
k3s: {
|
||||
namespace: "unidesk",
|
||||
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/claudeqq.k8s.yaml",
|
||||
deploymentName: "claudeqq",
|
||||
serviceName: "claudeqq",
|
||||
servicePort: 3290,
|
||||
containerName: "claudeqq",
|
||||
healthPath: "/health",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"code-queue": {
|
||||
serviceId: "code-queue",
|
||||
environment: "dev",
|
||||
kind: "d601-k3s",
|
||||
registryRepository: "unidesk/code-queue",
|
||||
dockerfile: "src/components/microservices/code-queue/Dockerfile",
|
||||
prodLiveApply: "unsupported",
|
||||
prodLiveBlockReason: "code-queue is dev-only for artifact consumer validation and has no prod artifact deploy, rollout, or manifest mutation target.",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "unidesk-code-queue:dev",
|
||||
targetCommitImage: (commit: string) => `unidesk-code-queue:${commit}`,
|
||||
deployRef: "deploy.json#environments.dev.services.code-queue",
|
||||
k3s: {
|
||||
namespace: "unidesk-dev",
|
||||
manifestRepoPath: "src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml",
|
||||
deploymentName: "code-queue-scheduler-dev",
|
||||
extraDeployments: [
|
||||
{ name: "d601-dev-provider-egress-proxy", containerName: "provider-egress-proxy" },
|
||||
"code-queue-read-dev",
|
||||
"code-queue-write-dev",
|
||||
],
|
||||
serviceName: "code-queue-scheduler-dev",
|
||||
servicePort: 4222,
|
||||
containerName: "code-queue",
|
||||
healthPath: "/health",
|
||||
podLabelSelector: "app.kubernetes.io/name=code-queue,app.kubernetes.io/component=scheduler,unidesk.ai/environment=dev",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"frontend": {
|
||||
serviceId: "frontend",
|
||||
environment: "prod",
|
||||
@@ -809,6 +923,7 @@ function plan(options: ArtifactRegistryOptions): Record<string, unknown> {
|
||||
"CI builds and publishes backend-core, frontend, and reviewed user-service artifacts on D601",
|
||||
"CD only pulls, retags, recreates/imports artifacts, and verifies live commit",
|
||||
"master server CD must not compile Rust or run docker compose build for artifact consumers",
|
||||
"code-queue is dev-only for artifact consumer validation and has no prod artifact deploy target",
|
||||
],
|
||||
renderedPaths: bundle.paths,
|
||||
artifactConsumerFlow: [
|
||||
@@ -939,7 +1054,7 @@ function artifactConsumerSpec(serviceId: string, environment: ArtifactDeployEnvi
|
||||
const explicit = artifactConsumerSpecs[key];
|
||||
if (explicit !== undefined) return explicit;
|
||||
const shared = artifactConsumerSpecs[serviceId];
|
||||
return environment !== null && shared?.targets[environment] !== undefined ? shared : null;
|
||||
return shared ?? null;
|
||||
}
|
||||
|
||||
function supportedArtifactConsumers(): Array<{ environment: ArtifactDeployEnvironment; serviceId: SupportedArtifactConsumerService; kind: ArtifactConsumerSpec["kind"] }> {
|
||||
@@ -1682,7 +1797,16 @@ function legacyDeployBackendCoreResult(options: ArtifactRegistryOptions): Record
|
||||
function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, commit: string): Record<string, unknown> {
|
||||
const environment = options.environment ?? "prod";
|
||||
const verificationBlocked = spec.runtimeVerification === "blocked";
|
||||
const livePolicy = environment === "prod" ? spec.prodLiveApply : "enabled";
|
||||
const sourceImage = artifactImageRef(options, spec, commit);
|
||||
const k3sDeployments = target.k3s === undefined
|
||||
? []
|
||||
: [
|
||||
{ name: target.k3s.deploymentName, containerName: target.k3s.containerName },
|
||||
...(target.k3s.extraDeployments ?? []).map((deployment) => typeof deployment === "string"
|
||||
? { name: deployment, containerName: target.k3s!.containerName }
|
||||
: { name: deployment.name, containerName: deployment.containerName ?? target.k3s!.containerName }),
|
||||
];
|
||||
const common = {
|
||||
ok: !verificationBlocked,
|
||||
supported: !verificationBlocked,
|
||||
@@ -1707,9 +1831,9 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
},
|
||||
boundary: `${environment} CD is artifact-consumer only: verify commit-pinned registry image, pull/import, deploy, then verify live commit/image/health; it never builds source on the runtime target`,
|
||||
liveApply: {
|
||||
policy: spec.prodLiveApply,
|
||||
policy: livePolicy,
|
||||
allowed: !verificationBlocked && (environment !== "prod" || spec.prodLiveApply === "enabled"),
|
||||
reason: spec.runtimeVerificationBlockReason ?? spec.prodLiveBlockReason ?? null,
|
||||
reason: spec.runtimeVerificationBlockReason ?? (environment === "prod" ? spec.prodLiveBlockReason ?? null : null),
|
||||
},
|
||||
};
|
||||
if (spec.kind === "compose" || spec.kind === "d601-compose") {
|
||||
@@ -1752,6 +1876,7 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
kind: "d601-k3s",
|
||||
namespace: target.k3s?.namespace,
|
||||
deployment: target.k3s?.deploymentName,
|
||||
deployments: k3sDeployments,
|
||||
service: target.k3s?.serviceName,
|
||||
stableImage: target.targetImage,
|
||||
runtimeImage: target.targetCommitImage(commit),
|
||||
@@ -1803,6 +1928,13 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art
|
||||
const sourceRepo = sourceRepoFor(options, spec);
|
||||
const commitImage = target.targetCommitImage(commit);
|
||||
const k3s = target.k3s;
|
||||
const deploymentSpecs = [
|
||||
{ name: k3s.deploymentName, containerName: k3s.containerName },
|
||||
...(k3s.extraDeployments ?? []).map((deployment) => typeof deployment === "string"
|
||||
? { name: deployment, containerName: k3s.containerName }
|
||||
: { name: deployment.name, containerName: deployment.containerName ?? k3s.containerName }),
|
||||
];
|
||||
const deploymentSpecsBase64 = Buffer.from(JSON.stringify(deploymentSpecs), "utf8").toString("base64");
|
||||
const labels = [
|
||||
`unidesk.ai/deploy-service-id=${spec.serviceId}`,
|
||||
`unidesk.ai/deploy-ref=${deployRefFor(options, spec)}`,
|
||||
@@ -1827,6 +1959,7 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art
|
||||
`namespace=${shellQuote(k3s.namespace)}`,
|
||||
`deployment=${shellQuote(k3s.deploymentName)}`,
|
||||
`container_name=${shellQuote(k3s.containerName)}`,
|
||||
`deployment_specs_b64=${shellQuote(deploymentSpecsBase64)}`,
|
||||
`service_name=${shellQuote(k3s.serviceName)}`,
|
||||
`service_port=${shellQuote(String(k3s.servicePort))}`,
|
||||
`health_path=${shellQuote(k3s.healthPath)}`,
|
||||
@@ -1858,15 +1991,37 @@ function d601K3sArtifactDeployScript(options: ArtifactRegistryOptions, spec: Art
|
||||
"root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$stable_image\" >/dev/null",
|
||||
"root_exec ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F \"$commit_image\" >/dev/null",
|
||||
"printf '%s' \"$manifest_b64\" | base64 -d > \"$manifest\"",
|
||||
"grep -F \"name: $deployment\" \"$manifest\" >/dev/null",
|
||||
"deployment_specs=$(mktemp /tmp/unidesk-artifact-k3s-deployments.XXXXXX.json)",
|
||||
"printf '%s' \"$deployment_specs_b64\" | base64 -d > \"$deployment_specs\"",
|
||||
"trap 'rm -f \"$archive\" \"$manifest\" \"$deployment_specs\" \"$health_tmp\"' EXIT",
|
||||
"python3 - \"$deployment_specs\" \"$manifest\" <<'PY'",
|
||||
"import json, sys",
|
||||
"specs = json.load(open(sys.argv[1], encoding='utf-8'))",
|
||||
"manifest = open(sys.argv[2], encoding='utf-8').read()",
|
||||
"missing = [item['name'] for item in specs if f\"name: {item['name']}\" not in manifest]",
|
||||
"if missing:",
|
||||
" raise SystemExit('manifest missing deployment(s): ' + ','.join(missing))",
|
||||
"PY",
|
||||
"if [ -n \"$apply_selector\" ]; then kubectl apply -f \"$manifest\" -l \"$apply_selector\"; else kubectl apply -f \"$manifest\"; fi",
|
||||
...(environment === "dev" && spec.serviceId === "frontend" ? [d601DevFrontendAuthPatchScript(readConfig())] : []),
|
||||
"previous_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}' 2>/dev/null || true)",
|
||||
"kubectl -n \"$namespace\" set image \"deployment/$deployment\" \"$container_name=$commit_image\"",
|
||||
"kubectl -n \"$namespace\" set env \"deployment/$deployment\" \"UNIDESK_DEPLOY_SERVICE_ID=$service_id\" \"UNIDESK_DEPLOY_REF=$deploy_ref\" \"UNIDESK_DEPLOY_REPO=$source_repo\" \"UNIDESK_DEPLOY_COMMIT=$commit\" \"UNIDESK_DEPLOY_REQUESTED_COMMIT=$commit\"",
|
||||
`kubectl -n "$namespace" annotate "deployment/$deployment" ${labels.map(shellQuote).join(" ")} --overwrite`,
|
||||
"if [ -n \"$previous_commit\" ] && [ \"$previous_commit\" != \"$commit\" ]; then kubectl -n \"$namespace\" annotate \"deployment/$deployment\" \"unidesk.ai/deploy-previous-commit=$previous_commit\" --overwrite; fi",
|
||||
"kubectl -n \"$namespace\" rollout status \"deployment/$deployment\" --timeout=180s",
|
||||
"python3 - \"$deployment_specs\" <<'PY' | while IFS=$'\\t' read -r rollout_deployment rollout_container; do",
|
||||
"import json, sys",
|
||||
"for item in json.load(open(sys.argv[1], encoding='utf-8')):",
|
||||
" print(f\"{item['name']}\\t{item['containerName']}\")",
|
||||
"PY",
|
||||
" kubectl -n \"$namespace\" set image \"deployment/$rollout_deployment\" \"$rollout_container=$commit_image\"",
|
||||
" kubectl -n \"$namespace\" set env \"deployment/$rollout_deployment\" \"UNIDESK_DEPLOY_SERVICE_ID=$service_id\" \"UNIDESK_DEPLOY_REF=$deploy_ref\" \"UNIDESK_DEPLOY_REPO=$source_repo\" \"UNIDESK_DEPLOY_COMMIT=$commit\" \"UNIDESK_DEPLOY_REQUESTED_COMMIT=$commit\" \"CODE_QUEUE_DEPLOY_COMMIT=$commit\" \"CODE_QUEUE_DEPLOY_REQUESTED_COMMIT=$commit\"",
|
||||
` kubectl -n "$namespace" annotate "deployment/$rollout_deployment" ${labels.map(shellQuote).join(" ")} --overwrite`,
|
||||
" if [ -n \"$previous_commit\" ] && [ \"$previous_commit\" != \"$commit\" ]; then kubectl -n \"$namespace\" annotate \"deployment/$rollout_deployment\" \"unidesk.ai/deploy-previous-commit=$previous_commit\" --overwrite; fi",
|
||||
"done",
|
||||
"python3 - \"$deployment_specs\" <<'PY' | while IFS= read -r rollout_deployment; do",
|
||||
"import json, sys",
|
||||
"for item in json.load(open(sys.argv[1], encoding='utf-8')):",
|
||||
" print(item['name'])",
|
||||
"PY",
|
||||
" kubectl -n \"$namespace\" rollout status \"deployment/$rollout_deployment\" --timeout=180s",
|
||||
"done",
|
||||
"deployment_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-commit}')",
|
||||
"deployment_requested_commit=$(kubectl -n \"$namespace\" get deployment \"$deployment\" -o jsonpath='{.metadata.annotations.unidesk\\.ai/deploy-requested-commit}')",
|
||||
"test \"$deployment_commit\" = \"$commit\"",
|
||||
@@ -2069,6 +2224,11 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
],
|
||||
firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry",
|
||||
artifactConsumers: {
|
||||
@@ -2088,6 +2248,8 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts deploy apply --env prod --service pipeline --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service met-nonlinear --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service k3sctl-adapter --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service mdtodo",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service claudeqq",
|
||||
],
|
||||
devCommands: [
|
||||
"bun scripts/cli.ts deploy apply --env dev --service frontend",
|
||||
@@ -2099,7 +2261,11 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts deploy apply --env dev --service findjob --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service pipeline --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service mdtodo",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service claudeqq",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service code-queue",
|
||||
],
|
||||
devOnlyConsumers: ["code-queue"],
|
||||
rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image",
|
||||
},
|
||||
legacyEntrypoints: {
|
||||
|
||||
Reference in New Issue
Block a user