# QingLong 3.0 Worker deployment baseline The Worker is an outbound-only, headless process. It opens one shared TLS 1.3 client authority to the Cluster Worker ingress and owns one local execution journal. It does not expose an HTTP Service, database connection or Kubernetes API credential. The committed base intentionally references, but does not create, `ql3-worker-config`, `ql3-worker-identity` or the mutable credential target. The separate `credential-bootstrap` asset creates an empty, labelled `ql3-worker-credential` exactly once so the delivery authority needs only exact-name `get` and `update`, never broad Secret creation in the Worker namespace. Copy the ConfigMap and TLS identity examples into a private overlay, replace every placeholder and use a separately issued Worker ID, certificate, `ql3w` token and PVC for every deployed Worker. Do not put the `ql3w` token in the TLS identity Secret. Never scale this Deployment above one replica. A replica is not a stateless copy: the Worker ID, Session, credential, journal, logs, receipts and running POSIX processes form one authority. Horizontal capacity is added by deploying another independently named Worker with another identity and volume. Build the image from the repository root: ```bash node scripts/ql3-worker-image-lock.cjs docker build \ --file deploy/containers/ql3-worker/Dockerfile \ --tag qinglong3-worker:3.0.0-alpha.2 \ --build-arg SOURCE_REVISION="$(git rev-parse HEAD)" \ . ``` Production rollout must take the Worker `@sha256:` reference from the same verified `cluster` or `all` release set as control, control-ai and admin. A version/source tag or a successful control image alone is not Worker release authority. Render the private Worker overlay, run the offline deployment-lock post-renderer with `--required-images=worker`, audit the locked manifest, and apply only that locked output. See [`docs/operations/ql3-release-set-deployment.md`](../../../docs/operations/ql3-release-set-deployment.md). The builder and runtime dependency roots have separate npm v3 locks generated from the reviewed workspace `pnpm-lock.yaml`. The runtime image contains only `runtime-core`, `local-process`, `worker-runtime` and their 24 external runtime packages. The bundled durable launcher is copied explicitly and made executable; no QingLong 2.x server, UI, SQLite or PostgreSQL package is present. Each Worker identity needs two namespaces: one Worker namespace containing only that identity's Deployment, PVC, ConfigMap, TLS Secret and credential target, and a separate staging namespace containing only immutable credential delivery stages. Never deploy either into the shared `qinglong3-system` namespace. A single Worker namespace is not sufficient because the stage authority must not be able to list the TLS private-key Secret. Before applying, create both namespaces and materialize the private ConfigMap/TLS Secret. The committed names are `qinglong3-worker` and `qinglong3-worker-credential-staging`; a private overlay must replace both for every independently named Worker. It must also replace `qinglong.io/worker-identity-generation` with a stable, non-secret generation identifier derived by the operator's release process. Then apply either the edge base or the node resource overlay and the credential-admin RBAC. Render the private credential-bootstrap overlay and submit it with create-only semantics before the first delivery: ```bash kubectl kustomize deploy/kubernetes/ql3-worker/base > /private/workstation/path/worker-rendered.yaml # or render deploy/kubernetes/ql3-worker/overlays/node # Materialize and audit worker-locked.yaml using the release-set procedure, # then apply only the locked output: kubectl apply -f /private/workstation/path/worker-locked.yaml kubectl apply -k deploy/kubernetes/ql3-worker/credential-admin kubectl kustomize deploy/kubernetes/ql3-worker/credential-bootstrap \ | kubectl create -f - ``` An `AlreadyExists` response is a safety stop, not an instruction to apply, replace or delete the target. The normal base/GitOps reconciliation set must exclude this mutable Secret; if an external reconciler imports it, configure that reconciler to ignore the target data, labels and annotations owned by credential delivery. Never use server-side apply to continuously reconcile the bootstrap manifest. The first Pod remains pending until credential delivery populates the prepared `ql3-worker-credential`. Publication is not complete after only replacing that Secret. `WorkerCredentialKubernetesDeliveryAdapter` stages immutable Secrets in the separate staging namespace, then reads the exact single-replica `Recreate` Deployment, verifies that it projects the dedicated Secret, and replaces the PodTemplate with delivery ID, credential ID, generation, token digest and publication digest annotations under the same `resourceVersion` fence. A crash between Secret and Deployment updates is replayed from the durable delivery ledger; the adapter returns success only after the PodTemplate converges. It owns no watcher, timer, controller loop or Worker-side Kubernetes credential. Run a delivery through `createWorkerCredentialKubernetesKubeConfigTokenRequestSession`, using an external OIDC/client-certificate identity mapped to the dedicated `qinglong:worker-credential-operators` Kubernetes group. That group can only create the `serviceaccounts/token` subresource for the exact delivery ServiceAccount; it cannot use the delivery RBAC itself. The session requests a TokenRequest credential, not an automatically mounted or persisted ServiceAccount token: ```bash kubectl -n qinglong3-worker-credential-staging create token \ ql3-worker-credential-admin --duration=10m ``` The command above is an operator troubleshooting equivalent, not the product execution path: it prints the bearer token and therefore must never be used by automation. The production session receives only the issuer kubeconfig, constructs the delivery client in memory, validates the issued JWT subject and at-most-600-second lifetime, runs 8 required-allow and 20 required-deny SelfSubjectAccessReview checks before mutation, and invalidates the restricted client in `finally`. It never returns the token or adapter. The ServiceAccount has `automountServiceAccountToken: false`. In the staging namespace it can only `get/list/create/delete` Secrets. In the Worker namespace it can only `get/update` the exact prepared credential Secret and exact Worker Deployment. It cannot read the TLS Secret, list Worker Secrets, access Pods, create a target Secret, patch/delete workloads, mint a replacement token or inspect cluster-scoped resources. Stage `create` and `list` cannot safely be narrowed by `resourceNames`, which is why the empty staging namespace is a required isolation boundary. The issuer kubeconfig remains external operator authority and must use strong, short-lived authentication; do not bind the token-issuer Role to the delivery ServiceAccount, Worker Pod, control Pod or a broad system group. Approval and durable product command binding are separate management-plane gates and are not implied by possession of this Kubernetes role. The projected TLS Secret, credential Secret and ConfigMap are not consumed directly. Kubernetes projects them through symlinks and group-readable modes, while the Worker credential boundary requires direct files, a `0700` parent and `0400` private material. The non-root init container creates its own `private/` subdirectory inside the fsGroup-writable tmpfs, copies the bounded inputs there and initializes `0700` recovery directories on the PVC before the main process starts. It never relies on changing the root-owned mount-point mode. CA/key/certificate rotation uses the same `Recreate` boundary but remains an explicit deployment operation: update `ql3-worker-identity`, advance `qinglong.io/worker-identity-generation` in the private overlay and wait for the old Pod to terminate before accepting the replacement Session. Never reuse the credential adapter as TLS-key authority; separating the Secrets prevents its least-privilege API client from reading the Worker private key. The PVC is mandatory. Replacing it with `emptyDir` can erase the only evidence needed to decide whether a process was spawned or completed after a restart. The Pod uses `Recreate` and a 360-second termination grace so the node profile's five-minute drain can keep heartbeating and settle completion evidence. An incomplete drain deliberately does not exit successfully. The process entrypoint itself retains one ref'ed lifecycle handle while it waits for SIGINT/SIGTERM. A pending JavaScript Promise alone does not keep Node alive; removing this handle makes an otherwise active Worker exit with code 0 and puts an `Always`-restart Pod into `CrashLoopBackOff`. The handle is cleared with signal authority after proof-bearing stop, does not poll Kubernetes and does not replace the application's single execution cadence. There is no synthetic Kubernetes readiness or liveness probe. A running PID does not prove that startup reconciliation completed or that the Worker Session is schedulable, and an automatic liveness kill can destroy the only drain owner. Operational readiness is the current durable Worker Session observed through the Cluster control plane. The manual `ql3-worker-kubernetes-rollout-live` workflow and `qinglong/worker-kubernetes-rollout-live-contract@v2` prove the current Worker image through three distinct Pod/Session generations, per-Session heartbeat, credential and mTLS identity Recreate, startup reconciliation, shared PVC and graceful offline transition. This single-node K3s/local-path evidence is not a claim about multi-node CSI detach/attach or physical node loss. For routers or other small non-Kubernetes devices, run the same `ql3-worker` binary with `QL3_WORKER_CAPACITY_PROFILE=edge`, one concurrent run, the 2-second cadence defaults and private persistent directories. Do not install the Cluster PostgreSQL, control-plane, admin or UI closure on that device.