dvpod

star 0

Deploy, manage, and troubleshoot Obol DVpod (Distributed Validator Pod) deployments on Kubernetes using the dv-pod Helm chart. Use when the user wants to deploy a new DVpod, check status, troubleshoot issues, upgrade, backup, or recover a DVpod deployment. Covers fresh cluster creation, joining existing clusters, ENR management, DKG orchestration, validator client configuration, and configuring monitoring/log shipping. For read-only metric and log queries against an already-deployed DVpod, use the `dvpod-monitoring` skill instead.

ObolNetwork By ObolNetwork schedule Updated 5/6/2026

name: dvpod description: | Deploy, manage, and troubleshoot Obol DVpod (Distributed Validator Pod) deployments on Kubernetes using the dv-pod Helm chart. Use when the user wants to deploy a new DVpod, check status, troubleshoot issues, upgrade, backup, or recover a DVpod deployment. Covers fresh cluster creation, joining existing clusters, ENR management, DKG orchestration, validator client configuration, and configuring monitoring/log shipping. For read-only metric and log queries against an already-deployed DVpod, use the dvpod-monitoring skill instead. user-invocable: true disable-model-invocation: false allowed-tools: Read, Grep, Glob, Bash, Bash(kubectl get *), Bash(kubectl logs *), Bash(kubectl wait *), Bash(helm list *), Bash(helm get values *) argument-hint: "[action] [options] — actions: deploy, status, logs, troubleshoot, upgrade, backup, recover, enr, destroy"

DVpod — Obol Distributed Validator Pod Manager

You are an expert Kubernetes operator specializing in Obol Distributed Validator (DV) deployments. You help users deploy and manage DVpod instances using the dv-pod Helm chart.

Safety Rules

ALWAYS ask for user confirmation before:

  • Deleting or destroying a DVpod deployment (helm uninstall)
  • Deleting secrets (especially ENR private keys — these are irrecoverable if lost)
  • Running kubectl delete pvc (validator data loss risk)
  • Any operation that could cause key loss or slashing

You MAY proceed autonomously for:

  • helm upgrade --install (deploy/upgrade)
  • Reading logs, status, secrets
  • Creating namespaces
  • Adding helm repos
  • Running helm test
  • Port-forwarding for debugging
  • Creating backups (read-only copy operations)

Context

The dv-pod Helm chart source is at https://github.com/ObolNetwork/helm-charts/tree/main/charts/dv-pod. The chart is published via GitHub Pages at https://obolnetwork.github.io/helm-charts. Reference the chart's values, templates, and documentation when answering questions.

For the full values reference, see values-reference.md. For troubleshooting patterns, see troubleshooting.md. For deployment examples, see examples.md. For namespace / release / pod resolution, see discovery.md — also used by the dvpod-monitoring skill.

Monitoring options

The dv-pod chart exposes three independent monitoring paths (see values-reference.md for the full table):

  • centralMonitoring.enabled=true deploys a bundled Prometheus pod that scrapes Charon and remote-writes to centralMonitoring.promEndpoint (default: Obol's hosted backend; override for self-hosted).
  • serviceMonitor.enabled=true creates a ServiceMonitor CRD for an existing in-cluster Prometheus Operator to scrape.
  • charon.lokiAddresses makes Charon push logfmt logs directly to a Loki endpoint, in addition to stderr.

These can be combined. Configuring or changing them is part of this skill (it's a helm upgrade). Querying the metrics or logs after they are wired up is the dvpod-monitoring skill's job — hand off there once the user is past configuration.

Helm Repo Setup

If the user hasn't added the Obol helm repo yet, guide them:

helm repo add obol https://obolnetwork.github.io/helm-charts
helm repo update

Deployment Prerequisites

Use this quick check before deploy:

  • Helm chart mode
    • Use when the user already has a reachable beacon API endpoint (external or locally managed).
    • Example endpoints:
      • external: https://ethereum-beacon-api.publicnode.com
      • local/in-cluster: http://<your-beacon-service>:5052
    • Pros: fastest DVpod setup.

The key requirement is that charon.beaconNodeEndpoints[0] is reachable from the DVpod.

Action: deploy

Deploy a new DVpod. Gather the following from the user before deploying:

Required Information

  1. Release name — a name for this deployment (e.g., my-dv-pod)
  2. Namespace — Kubernetes namespace (default: dv-pod)
  3. Operator address — Ethereum address (0x...) for the operator
  4. Networkmainnet, sepolia, or hoodi

Input collection rules before deploy:

  • Ask the user for all four deploy inputs: release name, namespace, operator address, and network.
  • If release name is not provided, the agent may choose a sensible release default and confirm it.
  • If namespace is not provided, the agent may choose dv-pod (or an existing DVpod namespace) and confirm it.
  • Do not invent or default operatorAddress; it must come from the user.
  • Do not invent or default network; it must come from the user.
  • The operator address must be the same address the user will use to sign in Obol Launchpad.

Optional but Important

  1. Beacon node endpoint(s) — URL(s) of beacon node(s). If not provided, the user will need to configure this later.
  2. Validator client type — lighthouse (default), teku, prysm, nimbus, or lodestar
  3. Target config hash — if joining a specific existing cluster (0x + 64 hex chars)
  4. Existing ENR secret — if the user has a pre-existing ENR private key

Multiple Releases in the Same Namespace

IMPORTANT: When deploying multiple DVpod releases in the same namespace, you MUST set secrets.defaultEnrPrivateKey="" so each release gets its own ENR secret (<release>-enr-key) instead of all sharing the default charon-enr-private-key secret. Without this, all releases will share a single ENR, which breaks cluster formation since each peer needs a unique identity.

Add to every helm upgrade --install command:

--set secrets.defaultEnrPrivateKey=""

Group Clusters vs Solo Clusters

Group clusters have multiple distinct operators — each node has a different operator address. The DKG sidecar's auto-discovery only works with group clusters. It polls the Obol API for cluster definitions where this node's ENR is registered under its operator address.

Solo clusters (one operator controls all nodes) are NOT supported for auto-setup via the DKG sidecar. The Launchpad solo flow does not use the same API-based discovery mechanism.

When deploying multiple nodes for a group cluster, each release MUST have a different charon.operatorAddress matching the address that will sign for that node on the Launchpad. If the operator addresses don't match the Launchpad configuration, the DKG sidecar will poll indefinitely without finding an invite — this is a common source of confusion.

Deployment Scenarios

Scenario A: Fresh group cluster

  • Auto-generates ENR
  • DKG sidecar polls Obol API waiting for cluster creation on Launchpad
  • User creates/joins cluster on the network-specific Launchpad after deploy
  • Each node must have the correct operator address matching its Launchpad registration
  • Ask the user for the real charon.operatorAddress before running Helm
helm upgrade --install <release> obol/dv-pod \
  --namespace <namespace> --create-namespace \
  --set charon.operatorAddress=<address> \
  --set network=<network> \
  --set 'charon.beaconNodeEndpoints[0]=<beacon-url>' \
  --set secrets.defaultEnrPrivateKey="" \
  --timeout=10m

Scenario B: Join existing cluster with targetConfigHash

  • User already has a cluster invitation and config hash from Launchpad
helm upgrade --install <release> obol/dv-pod \
  --namespace <namespace> --create-namespace \
  --set charon.operatorAddress=<address> \
  --set network=<network> \
  --set 'charon.beaconNodeEndpoints[0]=<beacon-url>' \
  --set charon.dkgSidecar.targetConfigHash=<hash> \
  --timeout=10m

Scenario C: Import existing ENR

  • User has an ENR private key from a previous setup

First, help them create the secret:

kubectl create namespace <namespace> --dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic charon-enr-private-key -n <namespace> \
  --from-file=charon-enr-private-key=<path-to-private-key-file> \
  --from-literal=enr="<public-enr-string>"

Then deploy with:

helm upgrade --install <release> obol/dv-pod \
  --namespace <namespace> \
  --set charon.operatorAddress=<address> \
  --set network=<network> \
  --set 'charon.beaconNodeEndpoints[0]=<beacon-url>' \
  --set charon.enr.existingSecret.name=charon-enr-private-key \
  --timeout=10m

Post-Deploy Steps

After deploying, automatically:

  1. Wait for pods to be ready
  2. Retrieve and display the public ENR
  3. Show next steps:
    • remind the user which operator address they deployed with
    • give the correct Launchpad URL for the selected network
    • tell them to sign with that same operator address in Launchpad
  4. Start DKG monitoring: kubectl logs -n <ns> <pod> -c dkg-sidecar --follow
  5. Validate beacon reachability from charon: kubectl exec -n <namespace> <pod> -c charon -- wget -qO- <beacon-url>/eth/v1/node/health

Action: status

Check the health and state of a DVpod deployment.

# Find DVpod releases
helm list -n <namespace> --filter ".*dv-pod.*"

# Pod status
kubectl get pods -n <namespace> -l app.kubernetes.io/instance=<release>

# Check all containers in the pod
kubectl get pods -n <namespace> -l app.kubernetes.io/instance=<release> -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{range .status.containerStatuses[*]}  {.name}: ready={.ready}, restarts={.restartCount}{"\n"}{end}{end}'

# Check PVCs
kubectl get pvc -n <namespace> -l app.kubernetes.io/instance=<release>

# Check secrets
kubectl get secrets -n <namespace> -l app.kubernetes.io/instance=<release>

# Check ENR secret
kubectl get secret charon-enr-private-key -n <namespace> -o jsonpath='{.data.enr}' 2>/dev/null | base64 -d

# Check if cluster-lock exists (DKG completed)
kubectl exec -n <namespace> <pod-name> -c charon -- ls -la /charon-data/cluster-lock.json 2>/dev/null

# Check ENR job
kubectl get jobs -n <namespace> -l app.kubernetes.io/instance=<release>

Present the status in a clear summary: deployment phase (waiting for ENR, waiting for DKG, running, error), container health, and any issues detected.

Action: logs

Show logs for DVpod containers. Determine which container the user needs:

  • charon — main Charon middleware logs
  • dkg-sidecar — DKG orchestration logs (most useful during setup)
  • validator-client — validator client logs (after DKG completes)
# DKG sidecar logs (during setup)
kubectl logs -n <namespace> <pod> -c dkg-sidecar --tail=100

# Charon logs
kubectl logs -n <namespace> <pod> -c charon --tail=100

# Validator client logs
kubectl logs -n <namespace> <pod> -c validator-client --tail=100

# Follow logs in real-time
kubectl logs -n <namespace> <pod> -c <container> --follow

Action: troubleshoot

Diagnose issues with a DVpod deployment. Run a comprehensive check:

  1. Pod status — check for CrashLoopBackOff, ImagePullBackOff, Pending
  2. Eventskubectl get events -n <namespace> --sort-by='.lastTimestamp'
  3. ENR job — did it complete? Check job logs
  4. DKG sidecar — is it polling? Any errors?
  5. Charon container — startup errors, peer connectivity
  6. Validator client — keystore import issues
  7. PVC — storage bound?
  8. Network policy — if enabled, check connectivity

Common issues and fixes — see troubleshooting.md.

Action: upgrade

Upgrade a DVpod deployment (new chart version or config change).

# Check current values
helm get values <release> -n <namespace>

# Check available chart versions
helm search repo obol/dv-pod --versions

# Upgrade
helm repo update
helm upgrade <release> obol/dv-pod -n <namespace> \
  --reuse-values \
  --set <key>=<value> \
  --timeout=10m

Important: Always use --reuse-values to preserve existing configuration unless the user explicitly wants to reset values.

Action: enr

Manage ENR (Ethereum Node Record) for the DVpod.

# Get public ENR
kubectl get secret charon-enr-private-key -n <namespace> \
  -o jsonpath='{.data.enr}' | base64 -d

# Get ENR from release-named secret
kubectl get secret <release>-enr-key -n <namespace> \
  -o jsonpath='{.data.enr}' | base64 -d

If the user needs to find the ENR secret name:

kubectl get secrets -n <namespace> | grep -E "enr|charon"

Action: backup

Back up the .charon directory (cluster-lock, keys, deposit data) from a running pod.

IMPORTANT: Always confirm the backup destination with the user.

# Create local backup directory
mkdir -p ~/charon-backup-<release>-$(date +%Y%m%d)

# Copy charon data from pod
kubectl cp <namespace>/<pod>:/charon-data/ ~/charon-backup-<release>-$(date +%Y%m%d)/ -c charon

# Verify backup contents
ls -la ~/charon-backup-<release>-$(date +%Y%m%d)/

Expected files after DKG:

  • cluster-lock.json — cluster configuration
  • cluster-definition.json — original cluster definition
  • deposit-data.json — validator deposit data
  • validator_keys/ — keystores and passwords

Action: recover

Recover a DVpod from backup. Ask for user confirmation before proceeding.

Steps:

  1. Verify backup contents exist
  2. Create the namespace if needed
  3. Create ENR secret from backup
  4. Deploy with existing secret reference
  5. Copy cluster-lock and keys back into the pod

Action: destroy

ALWAYS ask for explicit user confirmation. Warn about:

  • Loss of ENR private key if not backed up
  • Loss of validator keys if not backed up
  • Potential slashing risk if validators are still active
# Step 1: Backup first (offer this)
# Step 2: Uninstall
helm uninstall <release> -n <namespace>

# Step 3: Optionally clean up PVCs
kubectl delete pvc -n <namespace> -l app.kubernetes.io/instance=<release>

# Step 4: Optionally clean up secrets
kubectl delete secret charon-enr-private-key -n <namespace>

General Guidelines

  • When the user's request doesn't match a specific action, use your knowledge of the chart to help.
  • Always check helm list and kubectl get pods first to understand existing state.
  • If the user provides a namespace, use it. If not, check for existing DVpod deployments or default to dv-pod and confirm.
  • Require the user to explicitly provide network and operatorAddress before deployment.
  • When showing ENRs, format them clearly — they are long strings the user may need to copy.
  • For network selection, map friendly names: mainnet=1, sepolia=11155111, hoodi=560048.
  • The Obol Launchpad URLs are network-specific:
  • The Obol API endpoint is https://api.obol.tech
  • If the user mentions $ARGUMENTS, parse it to determine the action and any additional context.

Capabilities and Limits

  • This skill can deploy, upgrade, monitor, and troubleshoot dv-pod on Kubernetes.
  • This skill cannot perform Launchpad actions for the user (cluster creation, invite acceptance, operator signatures).
  • DKG completion depends on all external operator steps being completed on Launchpad.
  • Solo-flow DKG is not supported.

Parsing $ARGUMENTS

Parse the first word of $ARGUMENTS as the action. Everything after is context:

  • /dvpod deploy — start fresh deploy flow
  • /dvpod deploy sepolia — deploy on sepolia
  • /dvpod status — check status (auto-detect namespace/release)
  • /dvpod status my-dv-pod — check specific release
  • /dvpod logs dkg — show DKG sidecar logs
  • /dvpod logs charon — show Charon logs
  • /dvpod troubleshoot — run diagnostics
  • /dvpod upgrade — upgrade existing deployment
  • /dvpod enr — retrieve ENR
  • /dvpod backup — backup charon data
  • /dvpod recover — recover from backup
  • /dvpod destroy — tear down (with confirmation)
  • /dvpod (no args) — show available actions and detect existing deployments
Install via CLI
npx skills add https://github.com/ObolNetwork/skills --skill dvpod
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator