Pull images via artifactapi; make transform tier stateless
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/vector-test Pipeline failed
ci/woodpecker/pr/kubeconform Pipeline was successful

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
This commit is contained in:
2026-07-27 21:19:44 +10:00
parent c39af2f9c3
commit 1202aae06f
11 changed files with 78 additions and 27 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ when:
steps:
- name: vector-test
image: timberio/vector:0.57.0-debian
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/timberio/vector:0.57.0-debian
commands:
# Dummy creds + writable dirs so the full topologies build; the unit tests
# only exercise the transforms (sources are not started).
@@ -66,7 +66,7 @@ spec:
runAsGroup: 101
containers:
- name: clickhouse
image: clickhouse/clickhouse-server:24.8
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/clickhouse/clickhouse-server:24.8
resources:
requests:
cpu: 500m
+1 -1
View File
@@ -32,7 +32,7 @@ spec:
runAsGroup: 101
containers:
- name: clickhouse-schema
image: clickhouse/clickhouse-server:24.8
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/clickhouse/clickhouse-server:24.8
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
+1 -1
View File
@@ -49,7 +49,7 @@ spec:
runAsGroup: 1000
containers:
- name: nats-bootstrap
image: natsio/nats-box:0.18.0
image: artifactapi.k8s.syd1.au.unkin.net/dockerhub/natsio/nats-box:0.18.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
+11 -7
View File
@@ -7,10 +7,13 @@
# insert a transform and append its id to the clickhouse sink `inputs` — no edge
# or VM rollout required.
#
# Durability model: JetStream (72h / 40GiB) is the outage buffer. If ClickHouse
# is down the sink blocks, back-pressure stops acking, and JetStream retains
# messages for replay. The local disk buffer is small (survives pod restarts of
# in-flight events only).
# Durability model: JetStream (72h / 40GiB) is the SOLE durability layer. This
# tier is stateless (no PVC, memory buffer). If ClickHouse is down the sink
# blocks (when_full=block); back-pressure stops the source pulling, so unpulled
# messages stay in JetStream and are redelivered. NB: Vector's NATS source has
# no end-to-end acks (acks on receipt), so a pod killed mid-outage can lose the
# in-memory buffer's worth of already-pulled events — accepted for a stateless,
# autoscalable tier.
data_dir: /vector-data-dir
api:
@@ -117,10 +120,11 @@ sinks:
max_events: 500000
max_bytes: 134217728
timeout_secs: 10
# Small local buffer — JetStream is the real outage buffer now.
# Stateless: in-memory buffer, block on full so back-pressure reaches the
# JetStream pull source (which then stops acking). JetStream is durability.
buffer:
type: disk
max_size: 2147483648
type: memory
max_events: 2000
when_full: block
healthcheck:
enabled: true
@@ -1,7 +1,14 @@
# Altinity ClickHouse operator. Cluster-scoped: watches ClickHouseInstallation
# resources in all namespaces (the logs cluster lives in the `logging` namespace).
# CRDs are installed at runtime by the chart's crdHook Job.
#
# All images are pulled through the artifactapi dockerhub remote (no direct
# upstream). Upstream official images are used; no Docker Hardened Image variant
# is adopted (DHI is subscription-gated and served from a private org namespace
# not reachable via the anonymous artifactapi dockerhub proxy).
crdHook:
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/bitnami/kubectl
resources:
requests:
cpu: 50m
@@ -11,6 +18,8 @@ crdHook:
memory: 128Mi
operator:
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/altinity/clickhouse-operator
resources:
requests:
cpu: 100m
@@ -20,6 +29,8 @@ operator:
memory: 512Mi
metrics:
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/altinity/metrics-exporter
resources:
requests:
cpu: 50m
@@ -48,6 +48,11 @@ config:
- "_INBOX.>"
container:
# Pulled through the artifactapi dockerhub remote (upstream official nats;
# no DHI variant available for nats).
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/nats
tag: 2.14.2-alpine
env:
NATS_ADMIN_PASSWORD:
valueFrom:
@@ -79,5 +84,11 @@ podTemplate:
annotations:
reloader.stakater.com/auto: "true"
# Config-reloader sidecar image, also through artifactapi.
reloader:
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/natsio/nats-server-config-reloader
tag: "0.23.0"
natsBox:
enabled: false
@@ -5,6 +5,12 @@
role: Agent
fullnameOverride: vector-agent
# Pulled through the artifactapi dockerhub remote; distroless-libc (no DHI —
# subscription-gated/private-namespace, not reachable via the anon proxy).
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/timberio/vector
tag: 0.57.0-distroless-libc
rbac:
create: true
serviceAccount:
@@ -1,14 +1,29 @@
# Vector TRANSFORM tier (StatefulSet) — the "brain": sole ClickHouse writer,
# owns all transforms, holds the only ClickHouse + NATS-consumer credentials.
# It is a pure JetStream pull consumer (no inbound ports) — durability lives in
# JetStream, so the local disk buffer is small (5Gi PVC / 2GiB buffer).
# Vector TRANSFORM tier (STATELESS Deployment) — the "brain": sole ClickHouse
# writer, owns all transforms, holds the only ClickHouse + NATS-consumer creds.
#
# Pipeline is the single source of truth in apps/base/logging/vector/
# aggregator.yaml (unit-tested by `vector test` in CI), mounted via
# existingConfigMaps.
role: Aggregator
# Stateless by design: a JetStream pull consumer with NO PVC and NO disk buffer.
# JetStream is the sole durability layer. On a ClickHouse outage the clickhouse
# sink blocks (buffer when_full=block), back-pressure stops the source pulling,
# and unpulled messages stay in JetStream for redelivery. Because Vector's NATS
# source does NOT support end-to-end acknowledgements (it acks on receipt, not
# after the sink), the only at-risk window is the in-memory buffer's worth of
# already-pulled events if a pod is killed mid-outage — the accepted trade for a
# horizontally-autoscalable stateless tier. Multiple replicas share the one
# durable consumer `transform` (JetStream pull consumers distribute work), so
# HPA is safe.
role: Stateless-Aggregator
fullnameOverride: vector-aggregator
replicas: 2
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/timberio/vector
tag: 0.57.0-distroless-libc
# Horizontal autoscaling on CPU — safe with N replicas on one durable consumer.
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 8
targetCPUUtilizationPercentage: 70
workloadResourceAnnotations:
reloader.stakater.com/auto: "true"
@@ -16,17 +31,13 @@ workloadResourceAnnotations:
podLabels:
vector.dev/exclude: "true"
# Pipeline is the single source of truth in apps/base/logging/vector/
# aggregator.yaml (unit-tested by `vector test` in CI), mounted via
# existingConfigMaps. No persistence — stateless.
dataDir: /vector-data-dir
existingConfigMaps:
- vector-aggregator-config
persistence:
enabled: true
storageClassName: cephrbd-fast-delete
size: 5Gi
accessModes:
- ReadWriteOnce
# The ONLY place ClickHouse + NATS-consumer creds are consumed.
env:
- name: CLICKHOUSE_USER
@@ -5,6 +5,10 @@ role: Stateless-Aggregator
fullnameOverride: vector-archiver
replicas: 1
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/timberio/vector
tag: 0.57.0-distroless-libc
workloadResourceAnnotations:
reloader.stakater.com/auto: "true"
@@ -5,6 +5,10 @@ role: Stateless-Aggregator
fullnameOverride: vector-vm-ingest
replicas: 2
image:
repository: artifactapi.k8s.syd1.au.unkin.net/dockerhub/timberio/vector
tag: 0.57.0-distroless-libc
workloadResourceAnnotations:
reloader.stakater.com/auto: "true"