feat(v3s): add D518 code queue standby pod

This commit is contained in:
Codex
2026-05-15 14:56:02 +00:00
parent 00add260e3
commit 9d6be83c52
10 changed files with 500 additions and 43 deletions
@@ -17,18 +17,18 @@ services:
HOST: "0.0.0.0"
PORT: "4266"
LOG_FILE: "/var/log/unidesk/v3sctl-adapter.jsonl"
V3SCTL_CLUSTER_ID: "${V3SCTL_CLUSTER_ID:-D601}"
V3SCTL_CLUSTER_ID: "${V3SCTL_CLUSTER_ID:-unidesk-v8s}"
V3SCTL_NODE_ID: "${V3SCTL_NODE_ID:-D601}"
V3SCTL_KUBECTL_ENABLED: "${V3SCTL_KUBECTL_ENABLED:-false}"
V3SCTL_KUBE_API_PROXY_ENABLED: "${V3SCTL_KUBE_API_PROXY_ENABLED:-true}"
V3SCTL_KUBECONFIG_PATH: "/var/lib/unidesk/v3s/kubeconfig"
V3SCTL_KUBECONFIG_PATH: "/var/lib/unidesk/v8s/kubeconfig"
V3SCTL_KUBE_API_CONNECT_HOST: "${V3SCTL_KUBE_API_CONNECT_HOST:-host.docker.internal}"
V3SCTL_MANIFEST_PATHS: "${V3SCTL_MANIFEST_PATHS:-v3s/code-queue.v3s.json}"
V3SCTL_SERVICES_JSON: "${V3SCTL_SERVICES_JSON:-[]}"
UNIDESK_LOG_RETENTION_BYTES: "${UNIDESK_LOG_RETENTION_BYTES:-512MiB}"
volumes:
- ${V3SCTL_ADAPTER_LOG_DIR:-../../../../.state/v3sctl-adapter/logs}:/var/log/unidesk
- ${V3SCTL_KUBECONFIG_HOST_PATH:-../../../../.state/v3s/kubeconfig}:/var/lib/unidesk/v3s/kubeconfig:ro
- ${V3SCTL_KUBECONFIG_HOST_PATH:-../../../../.state/v8s/kubeconfig}:/var/lib/unidesk/v8s/kubeconfig:ro
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
@@ -8,6 +8,7 @@ type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string
type JsonRecord = Record<string, JsonValue>;
type InstanceRole = "primary" | "standby" | "worker";
type EndpointHealthMode = "service-proxy" | "pod-ready";
interface ManagedEndpoint {
id: string;
@@ -15,6 +16,7 @@ interface ManagedEndpoint {
role: InstanceRole;
baseUrl: string;
healthPath: string;
healthMode: EndpointHealthMode;
}
interface ManagedService {
@@ -143,6 +145,11 @@ function normalizeRole(value: string): InstanceRole {
return "worker";
}
function normalizeHealthMode(value: string): EndpointHealthMode {
if (value === "service-proxy" || value === "pod-ready") return value;
return "service-proxy";
}
function parseEndpoint(value: unknown, index: number, ownerPath = "endpoint"): ManagedEndpoint {
const path = `${ownerPath}[${index}]`;
const item = asRecord(value, path);
@@ -154,6 +161,7 @@ function parseEndpoint(value: unknown, index: number, ownerPath = "endpoint"): M
role: normalizeRole(optionalStringField(item, "role", id === "D601" ? "primary" : "standby")),
baseUrl: stringField(item, "baseUrl", path).replace(/\/+$/u, ""),
healthPath: optionalStringField(item, "healthPath", "/health"),
healthMode: normalizeHealthMode(optionalStringField(item, "healthMode", "service-proxy")),
};
}
@@ -244,12 +252,12 @@ function readConfig(): RuntimeConfig {
port: envNumber("PORT", 4266),
logFile: envString("LOG_FILE", "/var/log/unidesk/v3sctl-adapter.jsonl"),
manifestPaths: paths,
clusterId: envString("V3SCTL_CLUSTER_ID", "D601"),
clusterId: envString("V3SCTL_CLUSTER_ID", "unidesk-v8s"),
nodeId: envString("V3SCTL_NODE_ID", "D601"),
kubectlEnabled: envBool("V3SCTL_KUBECTL_ENABLED", false),
kubectlContext: envString("V3SCTL_KUBECTL_CONTEXT", ""),
kubeApiProxyEnabled: envBool("V3SCTL_KUBE_API_PROXY_ENABLED", true),
kubeconfigPath: envString("V3SCTL_KUBECONFIG_PATH", "/var/lib/unidesk/v3s/kubeconfig"),
kubeconfigPath: envString("V3SCTL_KUBECONFIG_PATH", "/var/lib/unidesk/v8s/kubeconfig"),
kubeApiConnectHost: envString("V3SCTL_KUBE_API_CONNECT_HOST", "host.docker.internal"),
requestTimeoutMs: Math.max(1000, Math.min(120_000, envNumber("V3SCTL_REQUEST_TIMEOUT_MS", 30_000))),
healthTimeoutMs: Math.max(500, Math.min(30_000, envNumber("V3SCTL_HEALTH_TIMEOUT_MS", 2500))),
@@ -385,6 +393,23 @@ function serviceProxyApiPath(service: ManagedService, targetPath: string): strin
return `/api/v1/namespaces/${encodeURIComponent(service.namespace)}/services/${encodeURIComponent(`${serviceName}:${servicePort}`)}/proxy${safeTargetPath}`;
}
function endpointProxyApiPath(service: ManagedService, endpoint: ManagedEndpoint, targetPath: string): string {
const { namespace, serviceRef } = kubernetesEndpointServiceRef(service, endpoint);
const safeTargetPath = targetPath.startsWith("/") ? targetPath : `/${targetPath}`;
return `/api/v1/namespaces/${encodeURIComponent(namespace)}/services/${encodeURIComponent(serviceRef)}/proxy${safeTargetPath}`;
}
function kubernetesEndpointServiceRef(service: ManagedService, endpoint: ManagedEndpoint): { namespace: string; serviceRef: string } {
const base = new URL(endpoint.baseUrl);
if (base.protocol !== "kubernetes:") throw new Error(`endpoint ${endpoint.id} must use kubernetes:// baseUrl`);
const namespace = base.hostname || service.namespace;
const parts = base.pathname.split("/").filter(Boolean);
if (parts.length !== 2 || parts[0] !== "services" || parts[1].length === 0) {
throw new Error(`endpoint ${endpoint.id} baseUrl must be kubernetes://<namespace>/services/<service>:<port>`);
}
return { namespace, serviceRef: parts[1] };
}
function kubeProxyCurlArgs(client: KubeApiClient, method: string, url: URL, headers: Headers, hasBody: boolean, timeoutMs: number): string[] {
const args = [
"-sS",
@@ -431,11 +456,32 @@ async function kubeApiServiceProxyResponse(
targetPath: string,
query: string,
timeoutMs: number,
): Promise<Response> {
return kubeApiProxyResponse(service, req, serviceProxyApiPath(service, targetPath), query, timeoutMs);
}
async function kubeApiEndpointProxyResponse(
service: ManagedService,
endpoint: ManagedEndpoint,
req: Request,
targetPath: string,
query: string,
timeoutMs: number,
): Promise<Response> {
return kubeApiProxyResponse(service, req, endpointProxyApiPath(service, endpoint, targetPath), query, timeoutMs);
}
async function kubeApiProxyResponse(
service: ManagedService,
req: Request,
apiPath: string,
query: string,
timeoutMs: number,
): Promise<Response> {
if (kubeClient === null) {
return jsonResponse({ ok: false, error: "kubernetes api proxy is not configured", serviceId: service.id, kubeconfigPath: config.kubeconfigPath, noFallback: true }, 502);
}
const upstreamUrl = new URL(serviceProxyApiPath(service, targetPath), kubeClient.serverUrl);
const upstreamUrl = new URL(apiPath, kubeClient.serverUrl);
upstreamUrl.search = query;
const headers = forwardHeaders(req);
const bodyText = req.method === "GET" || req.method === "HEAD" ? "" : await req.text();
@@ -455,7 +501,7 @@ async function kubeApiServiceProxyResponse(
proc.exited,
]);
if (exitCode !== 0) {
log("error", "kube_api_proxy_failed", { serviceId: service.id, targetPath, exitCode, stderr: stderr.slice(0, 2000), noFallback: true });
log("error", "kube_api_proxy_failed", { serviceId: service.id, apiPath, exitCode, stderr: stderr.slice(0, 2000), noFallback: true });
return jsonResponse({ ok: false, error: "kubernetes api service proxy failed", serviceId: service.id, detail: stderr.slice(0, 4000), noFallback: true }, 502);
}
const parsed = parseCurlHeaderBody(Buffer.from(stdout));
@@ -522,14 +568,28 @@ async function probeEndpoint(endpoint: ManagedEndpoint): Promise<JsonRecord> {
async function probeKubernetesServiceActive(service: ManagedService): Promise<JsonRecord> {
const endpoint = activeEndpoint(service);
return probeKubernetesEndpoint(service, endpoint, true);
}
async function probeKubernetesEndpoint(service: ManagedService, endpoint: ManagedEndpoint, active = false): Promise<JsonRecord> {
if (!active && endpoint.healthMode === "pod-ready") return await probeKubernetesPodReady(service, endpoint);
const checkedAt = new Date().toISOString();
const response = await kubeApiServiceProxyResponse(
service,
new Request("http://v3sctl-adapter.local/health", { method: "GET", headers: { accept: "application/json" } }),
endpoint.healthPath,
"",
config.healthTimeoutMs,
);
const response = active
? await kubeApiServiceProxyResponse(
service,
new Request("http://v3sctl-adapter.local/health", { method: "GET", headers: { accept: "application/json" } }),
endpoint.healthPath,
"",
config.healthTimeoutMs,
)
: await kubeApiEndpointProxyResponse(
service,
endpoint,
new Request("http://v3sctl-adapter.local/health", { method: "GET", headers: { accept: "application/json" } }),
endpoint.healthPath,
"",
config.healthTimeoutMs,
);
const contentType = response.headers.get("content-type") ?? "application/octet-stream";
const bodyText = await response.text();
let body: JsonValue = bodyText.slice(0, 2000);
@@ -544,6 +604,7 @@ async function probeKubernetesServiceActive(service: ManagedService): Promise<Js
role: endpoint.role,
baseUrl: endpoint.baseUrl,
healthPath: endpoint.healthPath,
healthMode: endpoint.healthMode,
proxyMode: "kubernetes-api-service-proxy",
route: service.route,
healthy: response.ok,
@@ -555,9 +616,79 @@ async function probeKubernetesServiceActive(service: ManagedService): Promise<Js
};
}
function jsonAtPath(value: unknown, path: string): unknown {
return path.split(".").reduce((current, key) => {
if (typeof current !== "object" || current === null) return undefined;
return (current as Record<string, unknown>)[key];
}, value);
}
function podReady(item: unknown): boolean {
const conditions = jsonAtPath(item, "status.conditions");
return Array.isArray(conditions) && conditions.some((condition) => {
const record = typeof condition === "object" && condition !== null ? condition as Record<string, unknown> : {};
return record.type === "Ready" && record.status === "True";
});
}
function podSummary(item: unknown): JsonRecord {
const metadata = typeof jsonAtPath(item, "metadata") === "object" && jsonAtPath(item, "metadata") !== null ? jsonAtPath(item, "metadata") as Record<string, unknown> : {};
return {
name: typeof metadata.name === "string" ? metadata.name : "",
nodeName: typeof jsonAtPath(item, "spec.nodeName") === "string" ? jsonAtPath(item, "spec.nodeName") as string : "",
phase: typeof jsonAtPath(item, "status.phase") === "string" ? jsonAtPath(item, "status.phase") as string : "",
podIP: typeof jsonAtPath(item, "status.podIP") === "string" ? jsonAtPath(item, "status.podIP") as string : "",
ready: podReady(item),
};
}
async function probeKubernetesPodReady(service: ManagedService, endpoint: ManagedEndpoint): Promise<JsonRecord> {
const checkedAt = new Date().toISOString();
const { namespace } = kubernetesEndpointServiceRef(service, endpoint);
const labelSelector = new URLSearchParams({
labelSelector: `app.kubernetes.io/name=${service.id},unidesk.ai/instance-id=${endpoint.id}`,
}).toString();
const response = await kubeApiProxyResponse(
service,
new Request("http://v3sctl-adapter.local/api/pods", { method: "GET", headers: { accept: "application/json" } }),
`/api/v1/namespaces/${encodeURIComponent(namespace)}/pods`,
`?${labelSelector}`,
config.healthTimeoutMs,
);
const contentType = response.headers.get("content-type") ?? "application/octet-stream";
const bodyText = await response.text();
let body: JsonValue = bodyText.slice(0, 2000);
let pods: JsonRecord[] = [];
try {
const parsed = JSON.parse(bodyText) as JsonRecord;
const items = Array.isArray(parsed.items) ? parsed.items : [];
pods = items.map(podSummary);
body = { itemCount: items.length, pods };
} catch {
// Keep the raw text preview below.
}
const healthy = response.ok && pods.some((pod) => pod.ready === true);
return {
id: endpoint.id,
nodeId: endpoint.nodeId,
role: endpoint.role,
baseUrl: endpoint.baseUrl,
healthPath: endpoint.healthPath,
healthMode: endpoint.healthMode,
proxyMode: "kubernetes-api-pod-readiness",
route: service.route,
healthy,
status: healthy ? "healthy" : "unhealthy",
upstreamStatus: response.status,
contentType,
checkedAt,
body,
};
}
async function serviceStatus(service: ManagedService): Promise<JsonRecord> {
const instances = isKubernetesServiceRoute(service)
? [await probeKubernetesServiceActive(service)]
? await Promise.all(service.endpoints.map((endpoint) => endpoint.id === service.activeInstanceId ? probeKubernetesServiceActive(service) : probeKubernetesEndpoint(service, endpoint)))
: [{
id: service.activeInstanceId,
nodeId: activeEndpoint(service).nodeId,
@@ -576,7 +707,7 @@ async function serviceStatus(service: ManagedService): Promise<JsonRecord> {
const activeHealthy = active?.healthy === true;
const allInstancesHealthy = instances.every((item) => item.healthy === true);
const expectedNodeIds = service.expectedNodeIds;
const presentNodeIds = Array.from(new Set(instances.map((item) => String(item.nodeId))));
const presentNodeIds = Array.from(new Set(instances.filter((item) => item.healthy === true).map((item) => String(item.nodeId))));
const missingNodeIds = expectedNodeIds.filter((nodeId) => !presentNodeIds.includes(nodeId));
const topologyComplete = missingNodeIds.length === 0;
const requiredTopologyHealthy = !service.requireAllInstancesHealthy || (topologyComplete && allInstancesHealthy);
@@ -4,7 +4,43 @@ metadata:
name: unidesk
labels:
app.kubernetes.io/part-of: unidesk
unidesk.ai/v3s-cluster: unidesk-v3s
unidesk.ai/v3s-cluster: unidesk-v8s
---
apiVersion: v1
kind: Service
metadata:
name: d601-provider-egress-proxy
namespace: unidesk
labels:
app.kubernetes.io/name: provider-egress-proxy
app.kubernetes.io/part-of: unidesk
unidesk.ai/provider-id: D601
spec:
type: ClusterIP
ports:
- name: http
port: 18789
targetPort: 18789
protocol: TCP
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: d601-provider-egress-proxy
namespace: unidesk
labels:
kubernetes.io/service-name: d601-provider-egress-proxy
app.kubernetes.io/name: provider-egress-proxy
app.kubernetes.io/part-of: unidesk
unidesk.ai/provider-id: D601
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 18789
endpoints:
- addresses:
- "172.25.0.3"
---
apiVersion: apps/v1
kind: Deployment
@@ -31,6 +67,8 @@ spec:
unidesk.ai/instance-id: D601
unidesk.ai/node-id: D601
spec:
nodeSelector:
unidesk.ai/node-id: D601
terminationGracePeriodSeconds: 30
containers:
- name: code-queue
@@ -99,25 +137,25 @@ spec:
- name: CODE_QUEUE_EGRESS_PROXY_ENABLED
value: "true"
- name: CODE_QUEUE_EGRESS_PROXY_URL
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: CODE_QUEUE_EGRESS_PROXY_NO_PROXY
value: "localhost,127.0.0.1,::1,host.docker.internal,unidesk-provider-gateway-D601,74.48.78.17,backend-core,oa-event-flow,database"
value: "localhost,127.0.0.1,::1,host.docker.internal,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local,172.25.0.3,unidesk-provider-gateway-D601,74.48.78.17,backend-core,oa-event-flow,database"
- name: HTTP_PROXY
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: HTTPS_PROXY
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: ALL_PROXY
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: http_proxy
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: https_proxy
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: all_proxy
value: "http://host.docker.internal:18789"
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: NO_PROXY
value: "localhost,127.0.0.1,::1,host.docker.internal,unidesk-provider-gateway-D601,74.48.78.17,backend-core,oa-event-flow,database"
value: "localhost,127.0.0.1,::1,host.docker.internal,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local,172.25.0.3,unidesk-provider-gateway-D601,74.48.78.17,backend-core,oa-event-flow,database"
- name: no_proxy
value: "localhost,127.0.0.1,::1,host.docker.internal,unidesk-provider-gateway-D601,74.48.78.17,backend-core,oa-event-flow,database"
value: "localhost,127.0.0.1,::1,host.docker.internal,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local,172.25.0.3,unidesk-provider-gateway-D601,74.48.78.17,backend-core,oa-event-flow,database"
- name: OA_EVENT_FLOW_BASE_URL
value: "http://74.48.78.17:4255"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
@@ -226,3 +264,228 @@ spec:
- name: http
port: 4222
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: code-queue-d518
namespace: unidesk
labels:
app.kubernetes.io/name: code-queue
app.kubernetes.io/part-of: unidesk
unidesk.ai/deployment-mode: v3sctl-managed
unidesk.ai/instance-id: D518
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: code-queue
unidesk.ai/instance-id: D518
template:
metadata:
labels:
app.kubernetes.io/name: code-queue
app.kubernetes.io/part-of: unidesk
unidesk.ai/deployment-mode: v3sctl-managed
unidesk.ai/instance-id: D518
unidesk.ai/node-id: D518
spec:
nodeSelector:
unidesk.ai/node-id: D518
terminationGracePeriodSeconds: 30
containers:
- name: code-queue
image: unidesk-code-queue:d601
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 4222
envFrom:
- secretRef:
name: code-queue-env
optional: true
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "4222"
- name: CODE_QUEUE_INSTANCE_ID
value: "D518"
- name: CODE_QUEUE_SCHEDULER_ENABLED
value: "false"
- name: CODE_QUEUE_STARTUP_OA_BACKFILL_ENABLED
value: "false"
- name: CODE_QUEUE_DATA_DIR
value: "/var/lib/unidesk/code-queue"
- name: CODE_QUEUE_WORKDIR
value: "/workspace"
- name: CODE_QUEUE_CODEX_HOME
value: "/var/lib/unidesk/code-queue/codex-home"
- name: CODE_QUEUE_OPENCODE_XDG_DIR
value: "/var/lib/unidesk/code-queue/opencode-xdg"
- name: CODE_QUEUE_SOURCE_CODEX_CONFIG
value: "/root/.codex/config.toml"
- name: CODE_QUEUE_DEFAULT_MODEL
value: "gpt-5.5"
- name: CODE_QUEUE_MODELS
value: "gpt-5.5,gpt-5.4-mini,gpt-5.4,minimax-m2.7"
- name: CODE_QUEUE_MODEL_REASONING_EFFORTS
value: "gpt-5.5=xhigh"
- name: CODE_QUEUE_SANDBOX
value: "danger-full-access"
- name: CODE_QUEUE_APPROVAL_POLICY
value: "never"
- name: CODE_QUEUE_MAX_ACTIVE_QUEUES
value: "0"
- name: CODE_QUEUE_DATABASE_POOL_MAX
value: "2"
- name: NODE_OPTIONS
value: "--max-old-space-size=1024"
- name: CODE_QUEUE_IN_MEMORY_OUTPUT_RECORDS
value: "10"
- name: CODE_QUEUE_IN_MEMORY_EVENT_RECORDS
value: "10"
- name: CODE_QUEUE_MAIN_PROVIDER_ID
value: "D518"
- name: CODE_QUEUE_REMOTE_WORKDIR
value: "/home/ubuntu"
- name: CODE_QUEUE_EXECUTION_PROVIDER_IDS
value: "D518"
- name: CODE_QUEUE_DEV_CONTAINER_MASTER_HOST
value: "74.48.78.17"
- name: CODE_QUEUE_DEV_CONTAINER_DEFAULT_PROVIDER_ID
value: "D518"
- name: CODE_QUEUE_DEV_CONTAINER_WORKDIR
value: "/home/ubuntu"
- name: CODE_QUEUE_EGRESS_PROXY_ENABLED
value: "false"
- name: CODE_QUEUE_EGRESS_PROXY_URL
value: ""
- name: CODE_QUEUE_EGRESS_PROXY_NO_PROXY
value: "localhost,127.0.0.1,::1,host.docker.internal,74.48.78.17,backend-core,oa-event-flow,database"
- name: HTTP_PROXY
value: ""
- name: HTTPS_PROXY
value: ""
- name: ALL_PROXY
value: ""
- name: http_proxy
value: ""
- name: https_proxy
value: ""
- name: all_proxy
value: ""
- name: NO_PROXY
value: "localhost,127.0.0.1,::1,host.docker.internal,74.48.78.17,backend-core,oa-event-flow,database"
- name: no_proxy
value: "localhost,127.0.0.1,::1,host.docker.internal,74.48.78.17,backend-core,oa-event-flow,database"
- name: OA_EVENT_FLOW_BASE_URL
value: "http://74.48.78.17:4255"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
value: "false"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL
value: ""
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE
value: "private"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_USER_ID
value: "645275593"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_MAX_RESPONSE_CHARS
value: "12000"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_TIMEOUT_MS
value: "15000"
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_SEND_ATTEMPTS
value: "3"
- name: LOG_FILE
value: "/var/log/unidesk/code-queue-d518.jsonl"
- name: UNIDESK_LOG_RETENTION_BYTES
value: "1GiB"
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
- name: workspace
mountPath: /workspace
- name: workspace
mountPath: /root/unidesk
- name: codex-config
mountPath: /root/.codex/config.toml
readOnly: true
- name: ssh-dir
mountPath: /root/.ssh
readOnly: true
- name: logs
mountPath: /var/log/unidesk
- name: state
mountPath: /var/lib/unidesk/code-queue
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 20
livenessProbe:
httpGet:
path: /health
port: http
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 6
startupProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 60
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
memory: 4Gi
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
type: Socket
- name: workspace
hostPath:
path: /home/ubuntu/cq-deploy
type: Directory
- name: codex-config
hostPath:
path: /home/ubuntu/.codex/config.toml
type: File
- name: ssh-dir
hostPath:
path: /home/ubuntu/.ssh
type: Directory
- name: logs
hostPath:
path: /home/ubuntu/cq-deploy/.state/code-queue/logs
type: DirectoryOrCreate
- name: state
hostPath:
path: /home/ubuntu/cq-deploy/.state/code-queue
type: DirectoryOrCreate
---
apiVersion: v1
kind: Service
metadata:
name: code-queue-d518
namespace: unidesk
labels:
app.kubernetes.io/name: code-queue
app.kubernetes.io/part-of: unidesk
unidesk.ai/deployment-mode: v3sctl-managed
unidesk.ai/instance-id: D518
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: code-queue
unidesk.ai/instance-id: D518
ports:
- name: http
port: 4222
targetPort: http
@@ -9,8 +9,8 @@
"adapterServiceId": "v3sctl-adapter",
"controlPlane": {
"type": "kubernetes",
"cluster": "unidesk-v3s",
"context": "kind-unidesk-v3s"
"cluster": "unidesk-v8s",
"context": "unidesk-v8s"
},
"route": {
"kind": "kubernetes-service",
@@ -29,7 +29,16 @@
"nodeId": "D601",
"role": "primary",
"baseUrl": "kubernetes://unidesk/services/code-queue:4222",
"healthPath": "/health"
"healthPath": "/health",
"healthMode": "service-proxy"
},
{
"id": "D518",
"nodeId": "D518",
"role": "standby",
"baseUrl": "kubernetes://unidesk/services/code-queue-d518:4222",
"healthPath": "/health",
"healthMode": "pod-ready"
}
],
"requireAllInstancesHealthy": false