Three changes from review:
1. Pull every container image through the artifactapi dockerhub remote instead
of direct upstream: clickhouse-server, altinity operator + metrics-exporter,
bitnami/kubectl (crdHook), nats + nats-server-config-reloader, nats-box
(bootstrap Job), and vector (all tiers + the CI image). Requires
terraform-artifactapi#16 (dockerhub allowlist patterns) merged first.
2. Keep upstream official images (no Docker Hardened Images). DHI exists for
clickhouse-server and vector but is subscription-gated and served from a
private org namespace not reachable via the anonymous artifactapi dockerhub
proxy; its shell-less images would also break the bash bootstrap Jobs and the
shell-based vector-test CI step. Use vector's distroless-libc for runtime
pods (near-hardened) and the debian variant only for CI.
3. Make the transform tier a stateless Deployment (was a StatefulSet): no PVC,
no disk buffer — JetStream is the sole durability layer. The ClickHouse sink
uses an in-memory block buffer so a ClickHouse outage back-pressures the
JetStream pull source (unpulled messages are retained/redelivered). Add a CPU
HPA (2-8) — safe because JetStream pull consumers distribute work across N
replicas on the one durable consumer. Caveat documented: vector's NATS source
has no end-to-end acks (acks on receipt), so a pod killed mid-outage can lose
its in-memory buffer window; accepted trade for a stateless autoscaling tier.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
Rework the logging pipeline around a durable message bus so logs survive a
ClickHouse outage, can be replayed after a bad transform, and fan out to
multiple independent consumers. Add long-term raw-log backup to S3.
Topology becomes edge -> JetStream -> consumers -> sinks:
- Dedicated JetStream NATS cluster (3 replicas, file storage) in the logging
namespace. Deliberately separate from app messaging (streamstack) for
blast-radius isolation. Stream LOGS (subjects logs.>, retention=limits, 40GiB
/ 72h) is the outage buffer; durable consumers give independent offsets.
- Edge publishers (thin): the k8s DaemonSet and a new VM-ingest Deployment
(HTTP NDJSON front door behind the logs-ingest Gateway) publish into JetStream
(logs.k8s.<ns>.<container> / logs.vm.<host>). No parsing on the edge.
- Transform tier (StatefulSet): pulls the whole stream via the durable
`transform` consumer, routes by subject, shapes, and remains the sole
ClickHouse writer. Its disk buffer shrinks (JetStream is the outage buffer).
- Archiver (Deployment): its OWN durable `archiver` consumer (independent
offsets — archive lag never affects the ClickHouse path) writes RAW,
pre-transform events to a Ceph RGW S3 bucket (cephrgw-operator ObjectStoreUser
+ Bucket + BucketAccess) as gzipped NDJSON keyed by raw/<subject>/YYYY/MM/DD/.
Default subject filter is Vault audit (logs.k8s.vault.>), configurable.
Auth: distinct NATS users (producer publish-only, consumer pull+ack, admin for
the stream/consumer bootstrap Job) with passwords from Vault (nats-auth Secret);
S3 creds from the BucketAccess Secret. Streams/consumers are provisioned by an
idempotent PostSync bootstrap Job.
Add local kubeconform schemas for the ceph.unkin.net CRDs (datreeio lacks them)
and extend the vector-test CI to cover the agent, VM-ingest and archiver
configs. Verified end-to-end locally: NATS ACLs, vector JetStream publish, and
durable-consumer pull+ack (at-least-once) all work.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv