Kubernetes and Helm
Mammoth ships with a Helm chart stored in the repository:
charts/mammoth
Current Distribution Model
The Helm chart is currently distributed through the Mammoth Git repository.
A dedicated Helm repository is not yet published.
Clone the repository:
git clone https://github.com/kanutocd/mammoth.git
cd mammoth
Render Manifests
helm template mammoth ./charts/mammoth \
--set image.repository=ghcr.io/kanutocd/mammoth \
--set image.tag=latest
Install
helm install mammoth ./charts/mammoth \
--set image.repository=ghcr.io/kanutocd/mammoth \
--set image.tag=latest
Upgrade
helm upgrade mammoth ./charts/mammoth \
--set image.repository=ghcr.io/kanutocd/mammoth \
--set image.tag=latest
Uninstall
helm uninstall mammoth
Required External Resources
The chart deploys Mammoth. It does not create your full CDC environment.
You must provide:
- PostgreSQL reachable from the cluster
- PostgreSQL logical replication settings
- publication
- replication slot or
auto_create_slot: truefor first-time bootstrap without an existing Mammoth checkpoint - Kubernetes Secret for the PostgreSQL password
- webhook destination reachable from the cluster
For production, manage publications and permanent replication slots as database
infrastructure and set replication.auto_create_slot: false after bootstrap.
Do not couple a retained Mammoth PVC to an automatically replaced PostgreSQL
slot: the SQLite checkpoint and the slot's retained WAL describe one continuity
history and must be recovered or reset together.
PostgreSQL Password Secret
Default chart values expect:
postgres:
existingSecret:
name: postgres-secrets
key: password
Create a development secret:
kubectl create secret generic postgres-secrets \
--from-literal=password=postgres
Image Settings
Default values:
image:
repository: ghcr.io/kanutocd/mammoth
tag: "1.5.3"
pullPolicy: IfNotPresent
Override image settings:
helm upgrade --install mammoth ./charts/mammoth \
--set image.repository=ghcr.io/kanutocd/mammoth \
--set image.tag=1.5.3
Kind Local Development
For local Kind testing with a locally built image:
kind load docker-image live_postgres_webhook-mammoth:latest --name mammoth
Install or upgrade with:
helm upgrade --install mammoth ./charts/mammoth \
--set image.repository=live_postgres_webhook-mammoth \
--set image.tag=latest \
--set image.pullPolicy=IfNotPresent
PostgreSQL Service Example
For local Kind testing, you can run PostgreSQL inside Kubernetes and expose it with a Service named postgres-service.
Example Mammoth override:
helm upgrade --install mammoth ./charts/mammoth \
--set postgres.host=postgres-service \
--set postgres.port=5432 \
--set postgres.database=mammoth_demo \
--set postgres.username=postgres
Node Identity
The chart can render optional Mammoth node identity fields for status output and future control-plane agents:
node:
node_id: mammoth-prod-1
node_name: mammoth-prod-a
fleet_id: payments-prod
environment: production
labels:
region: ap-southeast-1
Operational State Adapter
Mammoth Data Plane uses the SQLite operational state adapter by default:
operational_state:
adapter: sqlite
Webhook URL
The webhook URL must be reachable from inside Kubernetes.
This example will only work if the cluster can reach the public host:
webhook:
url: https://yourservice.com/webhooks/postgres
For an in-cluster receiver, use a Kubernetes Service DNS name:
webhook:
url: http://webhook-receiver:9292/webhook
The chart renders webhook headers and signing settings:
webhook:
headers:
X-Mammoth-Source: production_mammoth
header_env:
Authorization: MAMMOTH_WEBHOOK_AUTHORIZATION
signing:
algorithm: hmac_sha256
secret_env: MAMMOTH_WEBHOOK_SIGNING_SECRET
Back env-backed webhook values with a Kubernetes Secret:
webhook:
existingSecret:
name: webhook-secrets
keys:
MAMMOTH_WEBHOOK_AUTHORIZATION: authorization
MAMMOTH_WEBHOOK_SIGNING_SECRET: signing-secret
For fanout, set destinations. Each destination can map its own env-backed
headers and signing secret env vars to a Kubernetes Secret:
destinations:
- name: primary_webhook
type: webhook
enabled: true
url: https://example.com/webhooks/postgres
timeout_seconds: 5
header_env:
Authorization: MAMMOTH_PRIMARY_WEBHOOK_AUTHORIZATION
signing:
algorithm: hmac_sha256
secret_env: MAMMOTH_PRIMARY_WEBHOOK_SIGNING_SECRET
existingSecret:
name: primary-webhook-secrets
keys:
MAMMOTH_PRIMARY_WEBHOOK_AUTHORIZATION: authorization
MAMMOTH_PRIMARY_WEBHOOK_SIGNING_SECRET: signing-secret
- name: audit_webhook
type: webhook
enabled: true
url: https://audit.example.com/cdc
timeout_seconds: 5
route:
schemas:
- public
tables:
- orders
operations:
- insert
- update
retry:
max_attempts: 3
schedule_seconds:
- 1
- 10
The rendered Mammoth config stores only environment variable names. The Deployment sources those variables from the referenced Kubernetes Secret keys.
Delivery Runtime
The chart renders Mammoth's transaction delivery and downstream runtime settings:
delivery:
unit: transaction
ordering:
scope: transaction
runtime:
adapter: concurrent
concurrency: 1
batch_size: 1
preserve_order: true
Runtime concurrency affects downstream webhook delivery only. It does not create extra PostgreSQL replication slots or replication connections.
Persistence
The chart mounts a PVC for Mammoth's SQLite database.
SQLite is Mammoth's operational memory for:
- checkpoints
- dead letters
- delivered-envelope ledger entries used for duplicate suppression and replay
Default storage:
persistence:
storage: "1Gi"
Inspect PVCs:
kubectl get pvc
Replica Count and Replication Slots
Run one active Mammoth replica per logical replication slot.
PostgreSQL logical replication slots are consumed by one active subscriber at a
time, so the chart deliberately fixes the Deployment at one replica. The public
chart does not expose a replicaCount value.
The Recreate deployment strategy releases the slot before starting the
replacement pod. A multi-replica deployment requires a separate chart or
manifests that assign an independent slot and independent operational-state
store to each active relay.
PostgreSQL operational guardrails
Monitor retained WAL, slot readiness, PostgreSQL disk capacity, archive health,
and catalog-XID age. Mammoth's /readyz and mammoth_postgres_slot_* metrics
cover slot state; database and infrastructure tooling must cover storage and
catalog health.
The OSS chart currently starts the relay process only. To expose /readyz and
/metrics, deploy a separate process with the same ConfigMap, PostgreSQL
Secret, and operational-state PVC:
mammoth observability /app/config/mammoth.config.yaml
That process performs read-only slot and state inspection; it must not run
mammoth start or open a second replication connection.
Configure max_slot_wal_keep_size and, where supported,
idle_replication_slot_timeout according to the environment's recovery budget.
These settings can invalidate an unhealthy slot to protect PostgreSQL. They do
not provide a safe Mammoth resume point; an invalidated slot requires external
backfill or reconciliation.
Coordinate PostgreSQL schema migrations with webhook consumers because DDL is not replicated. Database upgrades must preserve and verify the existing logical slot or establish explicitly reconciled new operational state before Mammoth starts.
Useful Commands
Inspect deployment status:
kubectl get pods
kubectl get pvc
kubectl logs deploy/mammoth
kubectl describe pod -l app.kubernetes.io/name=mammoth
Inspect Helm values and manifests:
helm get values mammoth --all
helm get manifest mammoth
Restart Mammoth:
kubectl rollout restart deploy/mammoth
Troubleshooting
See:
Common topics include:
- Helm installation issues
- Kubernetes Secret configuration
- PostgreSQL connectivity
- Publications and replication slots
- Webhook delivery troubleshooting
- SQLite operational state inspection