You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AFK — well-scoped: a small stateless HTTP service + a new S3
bucket + the TektonConfig event-listener wiring.
Why
ceph-tekton is keeping state to a minimum: artifacts in S3,
secrets in Vault, no project-owned databases. The Tekton Results
deploy issue (#59)
was filed initially but its postgres metadata store cuts against
that posture — we'd own a DB to back up, patch, and monitor for
a service whose state we'd rather hold in S3.
The lighter shape: catch the CloudEvents Tekton already emits
on PipelineRun lifecycle transitions (dev.tekton.event.pipelinerun.successful.v1
.failed.v1 + .cancelled.v1) at a small stateless HTTP sink,
and have the sink write:
One archive JSON per terminal event — the full PipelineRun
payload that came in the CloudEvent — to s3://ceph-build-archive/pipelineruns/year=YYYY/month=MM/day=DD/<name>-<uid>.json
One analytics Parquet row per terminal event — the
denormalised fields the build team queries (pipeline, branch,
sha, distro, arch, status, durations, taskrun breakdown,
artifact URIs + digests) — to a Hive-partitioned prefix under
the same bucket.
#59 into
one component** that delivers both archive (replay a 6-month-old
build) and analytics (DuckDB queries over Parquet for trend
spotting) without postgres.
What to build
1. ceph-build-archive bucket
Add a 5th bucket to terraform/modules/s3-buckets/:
TaskRun summary: taskruns_json (a nested JSON column listing
task, status, start, end, distro, arch, step-durations) — keep
nested rather than fan out so the per-pipeline schema is stable
Artifacts: artifacts_json (the type-hinted IMAGES + ARTIFACT_OUTPUTS rolled up — one row per artifact emitted)
Attestation pointers: rekor_uuids (array)
Partitioning: Hive-style year=YYYY/month=MM/day=DD/ so DuckDB's
partition pruner skips out-of-range dates.
4. TektonConfig wiring
Set spec.pipeline.default-cloud-events-sink (or per-PipelineRun
override via the same field) to point at the sink's Service URL.
DuckDB query recipes ("long pole task by distro", "queue
time trend", "signed-Rekor latency", "build success rate by
branch")
How to replay an archived PipelineRun (aws s3 cp ... && kubectl create -f <archived.json> — the JSON is the full
PipelineRun object the sink captured)
Schema documentation (Parquet columns + types)
Eventual-promotion path to Iceberg if scale ever demands it
6. e2e assertion
hack/e2e/assert-build-archive-sink.sh:
Spins up the sink Deployment + Service on kind
Configures TektonConfig to point at it
Runs a smoke PipelineRun
Asserts an archive JSON + Parquet row land in the test bucket
(in-cluster MinIO or another httpd-mocked S3)
Acceptance criteria
ceph-build-archive bucket terraform-managed across all
three envs, private by default
Sink Deployment + Service installed in kustomize/base/build-archive-sink/
TektonConfig in the Sepia overlay points its cloud-events
sink at the Service
Terminal PipelineRuns drop one JSON + one Parquet row to
the configured S3 path
duckdb -c "SELECT pipeline, avg(duration_seconds) FROM 's3://ceph-build-archive/analytics/**/*.parquet' GROUP BY 1"
returns expected shape against a populated bucket
docs/build-archive.md covers the architecture, schema,
query recipes, and the replay-from-archive procedure
e2e assertion wired into hack/e2e/run-all.sh
Sink can be idempotently re-deployed without losing or
duplicating archived rows
Dependencies
#60
(TektonConfig pruner): the pruner is only safe to enable
aggressively once this sink is reliably catching events.
Order: deploy sink first → verify archive lands → only then
flip the pruner on.
RGW STS-OIDC trust must be configured (separate phase-1 work)
so the sink can mint short-lived S3 creds from its projected
SA token.
Supersedes
#58 —
the per-PipelineRun-Task that landed Parquet rows. Same goal,
caught at the event boundary instead of from a finally: Task,
so no per-Pipeline wiring needed.
#59 —
Tekton Results + postgres. The CloudEvents sink delivers the
same archive coverage without a database.
Type
AFK — well-scoped: a small stateless HTTP service + a new S3
bucket + the TektonConfig event-listener wiring.
Why
ceph-tekton is keeping state to a minimum: artifacts in S3,
secrets in Vault, no project-owned databases. The Tekton Results
deploy issue (#59)
was filed initially but its postgres metadata store cuts against
that posture — we'd own a DB to back up, patch, and monitor for
a service whose state we'd rather hold in S3.
The lighter shape: catch the CloudEvents Tekton already emits
on PipelineRun lifecycle transitions (
dev.tekton.event.pipelinerun.successful.v1.failed.v1+.cancelled.v1) at a small stateless HTTP sink,and have the sink write:
payload that came in the CloudEvent — to
s3://ceph-build-archive/pipelineruns/year=YYYY/month=MM/day=DD/<name>-<uid>.jsondenormalised fields the build team queries (pipeline, branch,
sha, distro, arch, status, durations, taskrun breakdown,
artifact URIs + digests) — to a Hive-partitioned prefix under
the same bucket.
This **collapses #58
one component** that delivers both archive (replay a 6-month-old
build) and analytics (DuckDB queries over Parquet for trend
spotting) without postgres.
What to build
1.
ceph-build-archivebucketAdd a 5th bucket to
terraform/modules/s3-buckets/:internal URLs, and occasionally leaked secrets. First private
bucket in the module (same posture [phase-1] Deploy Tekton Results with S3 backend on Sepia #59 had specified).
Historical trend queries want as much history as we can afford.
Variables:
build_archive_bucket_name(defaultceph-build-archive)build_archive_public_read(default false)build_archive_expiration_days(default 0 = never expire)2. The sink:
ceph-build-archive-sinkA small Go HTTP server that:
/cloudeventsfor incoming Tekton CloudEvents.events (success / failed / cancelled).
(
data.pipelineRun).AWS SDK.
generate-sbom's uploader step uses today).(pipelinerun.UID, pipelinerun.status.completionTime)so a re-delivered eventdoesn't write twice.
Deploys as a
Deployment+Service(no Knative dependency).Tekton's event-listener URI in TektonConfig points at the Service
DNS name.
3. Parquet schema (sketch — finalise during implementation)
One row per terminal PipelineRun. Columns:
pipeline,pipelinerun,namespace,uid,event_type,event_timebranch,sha,event_source(push/pr/cron/tag)status(Succeeded/Failed/Cancelled),failure_reasonstart_time,completion_time,duration_secondstaskruns_json(a nested JSON column listingtask, status, start, end, distro, arch, step-durations) — keep
nested rather than fan out so the per-pipeline schema is stable
artifacts_json(the type-hintedIMAGES+ARTIFACT_OUTPUTSrolled up — one row per artifact emitted)rekor_uuids(array)Partitioning: Hive-style
year=YYYY/month=MM/day=DD/so DuckDB'spartition pruner skips out-of-range dates.
4. TektonConfig wiring
Set
spec.pipeline.default-cloud-events-sink(or per-PipelineRunoverride via the same field) to point at the sink's Service URL.
5. Documentation
docs/build-archive.mdcovering:archive + Parquet)
time trend", "signed-Rekor latency", "build success rate by
branch")
aws s3 cp ... && kubectl create -f <archived.json>— the JSON is the fullPipelineRun object the sink captured)
6. e2e assertion
hack/e2e/assert-build-archive-sink.sh:(in-cluster MinIO or another httpd-mocked S3)
Acceptance criteria
ceph-build-archivebucket terraform-managed across allthree envs, private by default
kustomize/base/build-archive-sink/sink at the Service
the configured S3 path
duckdb -c "SELECT pipeline, avg(duration_seconds) FROM 's3://ceph-build-archive/analytics/**/*.parquet' GROUP BY 1"returns expected shape against a populated bucket
docs/build-archive.mdcovers the architecture, schema,query recipes, and the replay-from-archive procedure
hack/e2e/run-all.shduplicating archived rows
Dependencies
(TektonConfig pruner): the pruner is only safe to enable
aggressively once this sink is reliably catching events.
Order: deploy sink first → verify archive lands → only then
flip the pruner on.
so the sink can mint short-lived S3 creds from its projected
SA token.
Supersedes
the per-PipelineRun-Task that landed Parquet rows. Same goal,
caught at the event boundary instead of from a
finally:Task,so no per-Pipeline wiring needed.
Tekton Results + postgres. The CloudEvents sink delivers the
same archive coverage without a database.
Reference
https://tekton.dev/docs/pipelines/events/
cloud-events-sinkconfig:https://tekton.dev/docs/pipelines/install/#customizing-the-pipelines-controller-behavior
https://www.redhat.com/en/blog/operating-tekton-scale-10-lessons-learned