The dalp Helm chart is an umbrella chart: one release that composes its subcharts into a DALP Instance, each subchart pinned to the same chart version. You install it with one helm install after you apply the Gateway API CRD bundle once per cluster, and the release waits on its database migration, not on index rebuilds. The chart needs Kubernetes 1.23 or later, because it renders autoscaling/v2 HorizontalPodAutoscalers. The Subcharts table lists the components, Topologies explains which to enable, and Values and secrets prepares the deployment settings.
Install
Apply the Gateway API CRD bundle once per cluster, before the first install. The docs subchart renders an HTTPRoute by default, and dapp (the Console), dapi (the Platform API), blockscout and investorPortal render one when you set their httpRoute.enabled. A release that renders any of them without the CRDs fails to create it:
helm template envoy-gateway-crds oci://docker.io/envoyproxy/gateway-crds-helm \
--version 1.10.0 \
--set crds.gatewayAPI.enabled=true \
--set crds.gatewayAPI.channel=standard \
--set crds.envoyGateway.enabled=true \
| kubectl apply --server-side --force-conflicts -f ---server-side is required for this apply. The command pulls the bundle from Docker Hub, and the bundle is not part of DALP. --force-conflicts takes over any field another tool set on these CRDs, so run it only on a cluster where nothing else manages Gateway API, or mirror the bundle and apply your own copy. Gateway API CRDs ship separately explains why the bundle is a separate step and how often to repeat it.
Install the chart from the SettleMint OCI registry, pinning the chart version you deploy:
helm install dalp oci://pkg.distribution.settlemint.com/settlemint/dalp \
--version <chart version> \
--namespace dalp --create-namespace \
--values my-values.yamlSupply your own my-values.yaml, or repeated -- flags, on top of the chart's defaults. A first install fails until it sets global.datastores for PostgreSQL and Redis, the object storage settings, ENCRYPTION_, BETTER_AUTH_SECRET, CUSTODY_ and global., as Values and secrets describes. The chart and its images come from SettleMint's registries, and Prerequisites lists the pull access the cluster needs. Deploying to OpenShift needs the additional overlay in OpenShift.
Once helm install returns, helm status dalp -- reports deployed and kubectl get pods -- shows every pod Running or Completed. With local sign-in, the first account created on the fresh instance becomes a Platform admin and every later sign-up is a member, so create the first account before the Console is reachable from outside your network. Security and compliance posture says how to restore the role when no Platform admin is left.
A release moves through five states, with off-ramps for a missing CRD bundle, a failed migration hook and a helm upgrade that runs out its wait.
Migrations gate a release, index rebuilds do not
A schema migration runs as a Helm hook on the dapp subchart, and whether it gates the release depends on dapp.migrator.hookType. The default, pre, runs it as a pre-install and pre-upgrade hook before any workload rolls out, so a failed migration fails the release before a pod ever serves traffic. Set it to post when the same Helm release creates the database, so it exists before the migration runs against it. Set it to none to run the job as a plain, unhooked Job with no release gate.
By default, a failed job survives the upgrade that ran it, and the next helm upgrade removes it, so read its logs before you retry. With the pre default, a catch-up run of the same migration also follows the rollout and can still fail the release. Upgrades and migrations states the retry limit, timeout and clean-up defaults.
An indexer index rebuild is a different kind of operation and does not block a release. It runs behind an already-healthy deployment, re-derives projections from already-ingested chain data, and a rebuild in progress does not fail or delay helm upgrade. Do not wire an index rebuild into a release gate the way you would a migration. A failed pre-upgrade migration blocks the new rollout. A projection rebuild has a separate completion signal. Affected reads can remain stale or unavailable until it completes.
Subcharts
pgbouncer gates both the connection-pooling workload and the application URL routing, so it also decides how dapp and dapi reach PostgreSQL. investorPortal deploys the Investor portal, the standalone investor-facing web app for sign-in, funding, primary-issuance offers and secondary-market trading. The chart also carries canton, investorDocs, utilaSigningAgent and simulator blocks, all off by default.
Every subchart pins the same chart version as the umbrella chart, so a dalp release at one version installs dapp, dapi, docs and the rest at that same version. Mixing subchart versions inside one release is not supported.
Gateway API CRDs ship separately
The docs subchart creates an HTTPRoute by default, and dapp, dapi, blockscout and investorPortal do when their httpRoute is enabled, but the dalp chart does not bundle the Gateway API custom resource definitions. The bundle exceeds the size Helm allows inside a release's stored secret, and Helm cannot upgrade CRDs that ship inside a subchart's own crds/ directory anyway, so a chart that bundled them could install once and never refresh them again.
Apply the bundle as a separate step, with the command in Install: gateway-crds-helm, applied server-side once per cluster. The controller that serves the routes is yours to supply and is not part of the dalp chart.
The CRD bundle's version is the one in that install command, not the dalp chart version, so a dalp upgrade alone never tells you the CRDs also need a refresh.
Kubernetes validates a resource's kind against installed CRDs before it stores it. A release started without the bundle applied fails to create its HTTPRoute resources, and that surfaces as a helm install or helm upgrade error.
Values to set
global.pgbouncer.enabled, defaulttrue. It also decides howdappanddapireach PostgreSQL. See Subcharts.dapp.migrator.hookType, defaultpre. Sets whether a failed migration gates the release at all. See Migrations gate a release, index rebuilds do not.dapp.migrator.timeout, default600seconds. It bounds all attempts together.overprovisioning.enabled, defaultfalse. Reserves standing rollout headroom so an upgrade does not stall on a tight scheduler pool.- Chart version. Pin it on every install and upgrade so that each release is a reviewed change.
- Gateway CRD bundle version, set by the
--versionof the CRD command. It changes independently of thedalpchart version, so check both. See Gateway API CRDs ship separately.
What goes wrong
A helm upgrade times out before the last workload reports ready
Run helm upgrade with a --timeout sized to your deployment's worst case, such as 30 to 40 minutes, and adjust for
your cluster. Helm's own default wait is 5 minutes. A timeout abort does not roll back completed steps by itself, so
check helm history and the workload status before you retry. progressDeadlineSeconds is 1500 seconds (25 minutes)
on both dapi and dapp, above the Kubernetes default of 600. A single surge pod can spend up to its boot budget
plus relaunch headroom before /readyz reports ready, so a tighter number needs its own margin. On the Kubernetes
default of 600 seconds, dapp would trip before the PgBouncer pooler it waits on, which needs up to 900, and that
reads as a Console failure when the fault is the pooler. dapp's 1500 seconds outlasts it. The API fleets roll with
max and max, one pod at a time, so a tight timeout can fire before the last workload reports
ready. A tight scheduler pool adds its own stall: see overprovisioning.enabled.
The readiness check keeps failing and the database looks fine
Kubernetes' readiness and startup probes differ by workload in what they check and
how long they wait, so confirm which one is failing with kubectl describe pod before assuming Postgres is the
problem. dapi's /readyz probes Postgres through a dedicated health session every 15 seconds. The probe has a
10-second timeout and allows three failures. An unavailable database removes the pod from service after roughly 45
seconds, or up to about 55 seconds including reporting lag. dapi's startup probe answers on /healthz instead, with
its own 180-second boot budget. dapp's startup and readiness probes both answer on /readyz. Its liveness probe
answers on /healthz. The startup probe budgets 300 seconds (5 minutes) for slow first-boot SSR and SDK warmup, and
only once that clears does the readiness probe start applying its own 3-second, process-only budget. A pod stuck in
that 300-second startup window looks identical to a hung readiness probe in kubectl get pods output, so check which
probe is failing before assuming either.
An indexer or runner rollout looks stuck when the api workload rolled fine
dapi renders each role as its own Deployment: the /api/v1 and /api/v2 fleets, a runner, a scheduler, and an
indexer with a separate rebuild Deployment. The API fleets and the runner have their own HorizontalPodAutoscaler. The
indexer, its rebuild pods and the scheduler run a fixed replica count. The API fleets roll max and
max, the same one-at-a-time pattern as dapp. The indexer rolls the other way, max
and max, and holds a replacement back for a 90-second minReadySeconds before it counts as ready. The
runner and the scheduler use the Recreate strategy, so their old pods stop before the new ones start. The indexer
and the runner each have a PodDisruptionBudget that keeps at least one pod up. Expect the indexer, runner and
scheduler to take an old pod down before a new one is ready. This protects capacity in those roles and is not a stuck
rollout.
Redis restarts and pods keep serving
Redis does not gate startup. Cache and notification connections are supervised per pod, so bringing the platform up
before Redis is ready is supported: pods serve from their in-process cache and reconnect on a jittered exponential
backoff capped at 30 seconds, with no attempt limit. Reconnection checks that Redis is serving requests rather than
only accepting connections, so an endpoint still loading a snapshot is retried instead of treated as healthy. While
disconnected, cached reads stay correct but remain private to each pod, and change notifications use each listener's
own reconcile interval. Watch dalp_, labelled per redis_role, so you can tell
which of the two clients, cache or notifications, is the one that dropped. The Redis alert
(severity warning) confirms roughly six minutes into a sustained outage, identifying a pod that has not recovered
from more than a brief restart.
An indexer's head socket drops and live indexing waits for the reconnect
The Ledger Data indexer learns about new blocks from a standard newHeads
subscription on the chain node's WebSocket. It sends eth_blockNumber on the same socket every 10 seconds. It
reconnects when no reply arrives, or when the reply is more than three blocks past the last head the subscription
delivered. It reads the head over HTTP on every new subscription, so blocks mined during an outage are indexed after
the reconnect. A connection-state gauge reports three values (connected, disconnected, or circuit broken), and a
separate dalp_ series tracks how long the socket has been down, because the state gauge
alone cannot distinguish a two-second blip from a standing outage. The Indexer alert
(severity warning) confirms roughly six minutes into a sustained outage, keyed per network, long enough that an
ordinary reconnect never pages. Live indexing does not advance while the socket is down, because no poll runs beside
the subscription. Once the socket reconnects, the indexer reads the current head and indexes every block it missed.
Frequently asked questions
Does turning off a subchart delete its data?
Disabling a subchart removes its rendered resources from the release on the next upgrade. External databases are separate, but PVC retention and underlying volume deletion depend on the workload and storage policies. Inspect the rendered change and confirm a recoverable backup before disabling a stateful component.
How often do the Gateway API CRDs need reapplying?
Only when you move to a newer bundle version. A dalp upgrade alone does not need it. Gateway API CRDs ship separately explains why.
Does each Platform API role scale on its own?
Yes. By default the /api/v2 fleet ranges 2 to 24 replicas and the /api/v1 fleet 1 to 4, both at 50% CPU utilisation, and the runner ranges 2 to 12 replicas at 75%. The indexer does not autoscale: it runs dapi. pods, 2 by default, next to its rebuild pods. The scheduler runs one pod. A replica-count change on one role leaves the other roles, and each role's own rollout strategy, untouched.
Does the migration job still run if I disable dapp?
No. The migration job is a dapp subchart template, so dapp. skips the whole subchart, migration hook included, the same way it skips every other dapp object. A deployment without dapp must arrange the required database migration separately before starting services against the new schema.