Initial implementation: NATS->S3 archiver + search/retrieve CLI #1
Reference in New Issue
Block a user
Delete Branch "benvin/logarchiver-initial"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
The centralized logging stack (argocd-apps #296) archives raw logs with a plain Vector consumer (gzip NDJSON to Ceph RGW) — no index, no encryption. logarchiver replaces that archiver leg with the capabilities that outgrew Vector: zstd compression, OpenPGP encryption keyed from Ben's Vault GPG secrets engine (private key never leaves Vault), a searchable ClickHouse index ("vault logs from host X between dates Y and Z"), and sink-conditional acks — a batch is acknowledged to JetStream only after the object is durably in S3 AND indexed, which a stock Vector NATS consumer cannot do. It is one Go binary that is both the service and the operator CLI. The argocd manifest swap is a separate later task; this is designed for drop-in fit.
What changed
logarchiver run): durable JetStream pull consumer (streamLOGS, durablearchiver, subject filter defaultlogs.k8s.vault.>); per-subject batching by size/count/time; NDJSON → zstd → encrypt → S3 PUT → ClickHouse index row → ack; Nak + redelivery on any failure; Prometheus metrics, structured slog, graceful drain.LARC1): the Vault GPG engine only does whole-payload decrypt, so objects use a wrapped-DEK envelope — bulk is AES-256-GCM framed under a random data key and only that key is OpenPGP-encrypted to the engine's public key. Retrieval round-trips just the tiny wrapped key regardless of object size. Public key from the engine or a mounted file (configurable); fingerprint recorded per object; periodic refresh for rotation. The honest account of engine support and a possible follow-up enhancement are indocs/retrieval-runbook.md.search(query the index),fetch(download + engine-decrypt + unzstd → NDJSON, optionally re-filtered by host/time),init-schema(create/print the DDL), cobracompletion.logs.archive_index, one row per object (subject, hosts[], min/max ts, counts, sizes, zstd/pgp metadata, key fingerprint); DDL shipped asschema/archive_index.sql+internal/index/ddl.go.go build/go vet/go test -raceclean; golangci-lint v2 (docker) clean..woodpecker/build/test/pre-commit on PR; onv*tag a container imagegit.unkin.net/unkin/logarchiver(buildx) plus a Gitea binary release +rpm-internalRPM (nfpm) for the CLI. All steps set k8s resources +serviceAccountName: default(no new SA required).config.example.yaml.https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
5ec89b0028toc05ccfcb5d