Kubernetes Deployment
Torsten includes a Helm chart for deploying to Kubernetes as either a relay node or a block producer.
Prerequisites
- Kubernetes 1.25+
- Helm 3.x
- A
StorageClassthat supportsReadWriteOncepersistent volumes
Quick Start
Deploy a relay node on the preview testnet:
helm install torsten-relay ./charts/torsten-node \
--set network.name=preview
This will:
- Run a Mithril snapshot import (init container) for fast bootstrap
- Start the node syncing with the preview testnet
- Create a 100Gi persistent volume for the chain database
- Expose Prometheus metrics on port 12798
Chart Reference
Node Role
The chart supports two deployment modes:
# Relay node (default)
role: relay
# Block producer
role: producer
Network Selection
network:
name: preview # mainnet, preview, or preprod
port: 3001 # N2N port
hostAddr: "0.0.0.0"
Network magic is derived automatically from the network name. Override with network.magic if needed.
Persistence
persistence:
enabled: true
storageClass: "" # Use default StorageClass
size: 100Gi # 100Gi for testnet, 500Gi+ for mainnet
accessMode: ReadWriteOnce
existingClaim: "" # Use an existing PVC
Resources
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
cpu: "4"
memory: 16Gi
For mainnet, increase memory limits to 24-32Gi during initial sync and ledger replay.
Mithril Import
mithril:
enabled: true # Run Mithril import on first startup
The init container is idempotent — it skips the import on subsequent restarts if blocks already exist.
Ledger Replay
ledger:
replayLimit: null # null = unlimited (replay all blocks)
pipelineDepth: 150 # Chain sync pipeline depth
After Mithril import, the node replays all imported blocks through the ledger to build correct UTxO state, delegations, and protocol parameters. Set replayLimit: 0 to skip replay for faster startup (at the cost of incomplete ledger state).
Metrics and Monitoring
metrics:
enabled: true
port: 12798
serviceMonitor:
enabled: false # Set true if using Prometheus Operator
interval: 30s
labels: {}
When serviceMonitor.enabled is true, the chart creates a ServiceMonitor resource for automatic Prometheus scraping.
Available metrics include sync_progress_percent, blocks_applied_total, utxo_count, epoch_number, peers_connected, and more. See Monitoring for the full list.
Relay Node Deployment
A relay node connects to the Cardano network, syncs blocks, and serves them to connected peers and local clients.
Minimal Relay
helm install torsten-relay ./charts/torsten-node \
--set network.name=mainnet \
--set persistence.size=500Gi
Relay with Custom Topology
helm install torsten-relay ./charts/torsten-node \
--set network.name=mainnet \
--set persistence.size=500Gi \
-f relay-values.yaml
relay-values.yaml:
topology:
bootstrapPeers:
- address: relays-new.cardano-mainnet.iohk.io
port: 3001
localRoots:
- accessPoints:
- address: torsten-producer.default.svc.cluster.local
port: 3001
advertise: false
trustable: true
valency: 1
publicRoots:
- accessPoints:
- address: relays-new.cardano-mainnet.iohk.io
port: 3001
advertise: false
useLedgerAfterSlot: 110332800
Relay with Prometheus Operator
helm install torsten-relay ./charts/torsten-node \
--set network.name=mainnet \
--set metrics.serviceMonitor.enabled=true \
--set metrics.serviceMonitor.labels.release=prometheus
Block Producer Deployment
A block producer creates blocks when elected as slot leader. It requires KES, VRF, and operational certificate keys.
Create Keys Secret
First, create a Kubernetes secret with your block producer keys:
kubectl create secret generic torsten-producer-keys \
--from-file=kes.skey=kes.skey \
--from-file=vrf.skey=vrf.skey \
--from-file=node.cert=node.cert
Deploy the Producer
helm install torsten-producer ./charts/torsten-node \
--set role=producer \
--set network.name=mainnet \
--set producer.existingSecret=torsten-producer-keys \
--set persistence.size=500Gi
Producer Security
When role=producer, the chart automatically creates a NetworkPolicy that:
- Restricts N2N ingress to pods labeled
app.kubernetes.io/component: relay - Allows metrics scraping from any pod in the cluster
- Block producers should never be exposed directly to the internet
Producer + Relay Architecture
A typical production deployment uses one or more relay nodes that shield the block producer:
graph LR
Internet[Cardano Network] --> R1[Relay 1]
Internet --> R2[Relay 2]
R1 --> BP[Block Producer]
R2 --> BP
BP -. blocks .-> R1
BP -. blocks .-> R2
Deploy both:
# Deploy the block producer
helm install torsten-producer ./charts/torsten-node \
--set role=producer \
--set network.name=mainnet \
--set producer.existingSecret=torsten-producer-keys \
-f producer-values.yaml
# Deploy relay(s) pointing to the producer
helm install torsten-relay ./charts/torsten-node \
--set role=relay \
--set network.name=mainnet \
-f relay-values.yaml
producer-values.yaml:
topology:
bootstrapPeers: []
localRoots:
- accessPoints:
- address: torsten-relay-torsten-node.default.svc.cluster.local
port: 3001
advertise: false
trustable: true
valency: 1
publicRoots: []
useLedgerAfterSlot: -1
relay-values.yaml:
topology:
bootstrapPeers:
- address: relays-new.cardano-mainnet.iohk.io
port: 3001
localRoots:
- accessPoints:
- address: torsten-producer-torsten-node.default.svc.cluster.local
port: 3001
advertise: false
trustable: true
valency: 1
publicRoots:
- accessPoints:
- address: relays-new.cardano-mainnet.iohk.io
port: 3001
advertise: false
useLedgerAfterSlot: 110332800
Verifying the Deployment
Check pod status:
kubectl get pods -l app.kubernetes.io/name=torsten-node
View logs:
kubectl logs -f deploy/torsten-relay-torsten-node
Query the node tip:
kubectl exec deploy/torsten-relay-torsten-node -- \
torsten-cli query tip --testnet-magic 2
Check metrics:
kubectl port-forward svc/torsten-relay-torsten-node 12798:12798
curl -s http://localhost:12798/metrics | grep sync_progress
Configuration Reference
All configurable values with defaults:
| Parameter | Default | Description |
|---|---|---|
role | relay | Node role: relay or producer |
image.repository | ghcr.io/michaeljfazio/torsten | Container image |
image.tag | Chart appVersion | Image tag |
network.name | preview | Network: mainnet, preview, preprod |
network.port | 3001 | N2N port |
mithril.enabled | true | Run Mithril import on first start |
ledger.replayLimit | null | Max blocks to replay (null = unlimited) |
ledger.pipelineDepth | 150 | Chain sync pipeline depth |
persistence.enabled | true | Enable persistent storage |
persistence.size | 100Gi | Volume size |
metrics.enabled | true | Enable Prometheus metrics |
metrics.port | 12798 | Metrics port |
metrics.serviceMonitor.enabled | false | Create ServiceMonitor |
producer.existingSecret | "" | Secret with KES/VRF/cert keys |
resources.requests.cpu | 1 | CPU request |
resources.requests.memory | 4Gi | Memory request |
resources.limits.memory | 16Gi | Memory limit |