feat: Deployment improvements & environmental overrides (#103)

This PR contains improvements to the DataHaven deployment
infrastructure:
1. Directory restructure: Moved from `deployment/` to `deploy/` (more
common for K8s / Helm -based deployment configs).
2. Added **local environment** support: updated CLI to support deploying
to a local K8s cluster.
3. Manual deployment script: `deploy/scripts/deploy.sh` for manual
deployments.
4. Environment-specific configurations: Structured values files for each
environment.
5. Chart organization: Renamed bridges-common-relay to relay for
clarity.

---------

Co-authored-by: Gonza Montiel <gon.montiel@gmail.com>
Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
This commit is contained in:
Steve Degosserie 2025-06-26 13:48:33 +02:00 committed by GitHub
parent a6c1cb2ab2
commit c3e6f1258b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 614 additions and 114 deletions

190
deploy/README.md Normal file
View file

@ -0,0 +1,190 @@
# DataHaven Deployment
This directory contains all the necessary files and configurations for deploying DataHaven to various environments.
## Directory Structure
```
deploy/
├── charts/ # Helm charts
│ ├── node/ # Node chart
│ │ └── datahaven/ # DataHaven-specific node configurations
│ │ ├── dh-bootnode.yaml
│ │ └── dh-validator.yaml
│ └── relay/ # Relay chart
│ └── snowbridge/ # Snowbridge-specific relay configurations
│ ├── dh-beacon-relay.yaml # Beacon chain relay
│ ├── dh-beefy-relay.yaml # BEEFY consensus relay
│ └── dh-execution-relay.yaml # Execution layer relay
├── environments/ # Environment-specific configurations
│ ├── local/ # Local development environment
│ │ └── values.yaml
│ ├── stagenet/ # Staging environment
│ └── values.yaml
└── scripts/ # Deployment scripts
```
## Prerequisites
- Kubernetes cluster
- kubectl configured
- Helm 3.x installed
## Deployment
To deploy to a specific environment:
```bash
./scripts/deploy.sh <environment>
```
Example:
```bash
./scripts/deploy.sh local
```
Available environments:
- `local`: Local development environment (minimal resources)
- `stagenet`: Staging environment for pre-release testing
## Environment Details
### Local
- Single replica
- Minimal resources (256Mi memory, 100m CPU)
- Local image tags
- Small persistence size
### Stagenet
- 2 replicas
- Medium resources (512Mi memory, 200m CPU)
- Stagenet image tags
- 20Gi persistence size
## Configuration Structure
The configuration is organized in layers, with later layers overriding earlier ones:
1. Base Configurations (`charts/node/datahaven/`):
- Base configurations for DataHaven nodes
- Default values for bootnode and validator
2. Environment-Specific Configurations (`environments/<env>/values.yaml`):
- Environment-specific settings
- Resource configurations
- Image tags
- Replica counts
- Storage configurations
The deployment process:
1. Loads base configurations from the respective chart directories
2. Applies environment-specific overrides from `environments/<env>/values.yaml`
3. Deploys the components with the merged configuration
## Components
### Nodes
- **Bootnode**: Entry point for the network
- **Validator**: Validates transactions and produces blocks
### Relays
- **Snowbridge Relays**: Handle cross-chain communication with Ethereum
- **Beacon Relay**: Relays Ethereum beacon chain data
- **BEEFY Relay**: Relays BEEFY consensus data for finality
- **Execution Relay**: Relays Ethereum execution layer data
## Development
For local development:
1. Ensure you have a local Kubernetes cluster (e.g., Minikube, Kind)
2. Deploy using the local environment:
```bash
./scripts/deploy.sh local
```
## Troubleshooting
Common issues and solutions:
1. Namespace doesn't exist:
```bash
kubectl create namespace kt-datahaven-<env>
```
2. Helm dependencies need updating:
```bash
helm dependency update charts/node
helm dependency update charts/relay
```
3. View deployment status:
```bash
kubectl get all -n kt-datahaven-<env>
```
4. Preview deployment changes:
```bash
./scripts/deploy.sh <env> true
```
## Manual Deployment (Advanced)
For advanced users who want to deploy components individually or need more control:
### DataHaven Bootnode & Validators
#### Deploy individual components
```bash
cd deploy
helm upgrade --install dh-bootnode charts/node -f charts/node/datahaven/dh-bootnode.yaml -f ../environments/<env>/values.yaml -n kt-datahaven-<env>
helm upgrade --install dh-validator charts/node -f charts/node/datahaven/dh-validator.yaml -f ../environments/<env>/values.yaml -n kt-datahaven-<env>
```
#### Access validator node with Polkadot.js apps
```bash
kubectl port-forward svc/dh-validator-0 -n kt-datahaven-<env> 9955:9955
# Then visit: https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9955#/explorer
```
#### Remove DataHaven components
```bash
helm uninstall dh-bootnode -n kt-datahaven-<env>
helm uninstall dh-validator -n kt-datahaven-<env>
```
#### Cleanup volumes
```bash
kubectl delete pvc -l app.kubernetes.io/instance=dh-bootnode -n kt-datahaven-<env>
kubectl delete pvc -l app.kubernetes.io/instance=dh-validator -n kt-datahaven-<env>
```
### Snowbridge Relayers
#### Create required secrets
```bash
kubectl create secret generic dh-beefy-relay-ethereum-key --from-literal=pvk="<ETHEREUM_PRIVATE_KEY>" -n kt-datahaven-<env>
kubectl create secret generic dh-beacon-relay-substrate-key --from-literal=pvk="<SUBSTRATE_PRIVATE_KEY>" -n kt-datahaven-<env>
kubectl create secret generic dh-execution-relay-substrate-key --from-literal=pvk="<SUBSTRATE_PRIVATE_KEY>" -n kt-datahaven-<env>
```
#### Deploy individual relay components
```bash
cd deploy
helm upgrade --install dh-beacon-relay charts/relay -f charts/relay/snowbridge/dh-beacon-relay.yaml -f ../environments/<env>/values.yaml -n kt-datahaven-<env>
helm upgrade --install dh-beefy-relay charts/relay -f charts/relay/snowbridge/dh-beefy-relay.yaml -f ../environments/<env>/values.yaml -n kt-datahaven-<env>
helm upgrade --install dh-execution-relay charts/relay -f charts/relay/snowbridge/dh-execution-relay.yaml -f ../environments/<env>/values.yaml -n kt-datahaven-<env>
```
#### Remove relay components
```bash
helm uninstall dh-beacon-relay -n kt-datahaven-<env>
helm uninstall dh-beefy-relay -n kt-datahaven-<env>
helm uninstall dh-execution-relay -n kt-datahaven-<env>
```
#### Delete relay secrets
```bash
kubectl delete secret dh-beefy-relay-ethereum-key -n kt-datahaven-<env>
kubectl delete secret dh-beacon-relay-substrate-key -n kt-datahaven-<env>
kubectl delete secret dh-execution-relay-substrate-key -n kt-datahaven-<env>
```

View file

@ -11,7 +11,6 @@ imagePullSecrets:
- name: datahaven-dockerhub
node:
chain: stagenet-local
command: datahaven-node
# customChainspec: true # see extraInitContainers, chainspec-generator
role: full
@ -63,4 +62,4 @@ extraContainers:
- name: chain-data
subPath: chainspec.json
mountPath: /usr/share/nginx/html/chainspec.json
readOnly: true
readOnly: true

View file

@ -11,7 +11,6 @@ imagePullSecrets:
- name: datahaven-dockerhub
node:
chain: stagenet-local
command: datahaven-node
# customChainspecUrl: http://dh-bootnode:8080/chainspec.json
# forceDownloadChainspec: true
@ -78,4 +77,4 @@ extraInitContainers:
fi
volumeMounts:
- mountPath: /chain-data
name: chain-data
name: chain-data

View file

@ -230,4 +230,4 @@ spec:
{{- end }}
{{- end }}
---
{{ end }}
{{ end }}

View file

@ -0,0 +1,54 @@
# Global settings
global:
environment: local
namespace: kt-datahaven-local
# Common image settings
image:
tag: local
pullPolicy: IfNotPresent
imagePullSecrets:
- name: datahaven-dockerhub
# Common node settings
node:
chain: local
chainData:
storageClass: "hostpath"
persistence:
size: 10Gi
chainKeystore:
storageClass: "hostpath"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "200m"
# Override settings for bootnode
dh-bootnode:
node:
customNodeKey: 80c30ac6ba927c6e5c0c9681aa9674f1d181d180853bcd3485cee9d18e931238
# Override settings for validator
dh-validator:
node:
customNodeKey:
# To generate new key run: docker run --rm -t moonsonglabs/datahaven:latest key generate-node-key
# 12D3KooWL5Av1ZZSKkaittmxXBmZpzP7zgiB1AAnWHEw7MxzqnFp
- bdf71a910354e231095366230621eaefb5f99465045f1501478fd3d9b5deef98
# 12D3KooWAxFonTS177T81CTDeH6mfvJQWYEJeVQ1gPrnULjNY8Cn
- 2a775a9db9fb0ff40afacb4aa7ccbf2a5d04c6d980bb1437c196c8e38a6cd948
# Common relay settings
relay:
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "200m"

View file

@ -0,0 +1,52 @@
# Global settings
global:
environment: stagenet
namespace: kt-datahaven-stagenet
# Common image settings
image:
repository: moonsonglabs/datahaven
tag: stagenet
pullPolicy: Always
imagePullSecrets:
- name: datahaven-dockerhub
# Common node settings
node:
chain: stagenet-local
chainData:
persistence:
size: 20Gi
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "500m"
# Override settings for bootnode
dh-bootnode:
node:
customNodeKey: 80c30ac6ba927c6e5c0c9681aa9674f1d181d180853bcd3485cee9d18e931238
# Override settings for validator
dh-validator:
node:
customNodeKey:
# To generate new key run: docker run --rm -t moonsonglabs/datahaven:latest key generate-node-key
# 12D3KooWL5Av1ZZSKkaittmxXBmZpzP7zgiB1AAnWHEw7MxzqnFp
- bdf71a910354e231095366230621eaefb5f99465045f1501478fd3d9b5deef98
# 12D3KooWAxFonTS177T81CTDeH6mfvJQWYEJeVQ1gPrnULjNY8Cn
- 2a775a9db9fb0ff40afacb4aa7ccbf2a5d04c6d980bb1437c196c8e38a6cd948
# Common relay settings
relay:
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "500m"

136
deploy/scripts/deploy.sh Executable file
View file

@ -0,0 +1,136 @@
#!/bin/bash
# Exit on error
set -e
# Default values
ENVIRONMENT=${1:-local}
DRY_RUN=${2:-false}
NAMESPACE="kt-datahaven-${ENVIRONMENT}"
VALUES_FILE="$(dirname "$0")/../environments/${ENVIRONMENT}/values.yaml"
NODE_CHART="$(dirname "$0")/../charts/node"
RELAY_CHART="$(dirname "$0")/../charts/relay"
# Validate environment
if [[ ! -f "${VALUES_FILE}" ]]; then
echo "Error: Invalid environment '${ENVIRONMENT}'"
echo "Available environments:"
echo "- local (local development)"
echo "- stagenet (staging environment)"
echo "- testnet (testing environment)"
echo "- mainnet (production environment)"
exit 1
fi
# Validate namespace exists
if ! kubectl get namespace "${NAMESPACE}" >/dev/null 2>&1; then
echo "Creating namespace ${NAMESPACE}"
kubectl create namespace "${NAMESPACE}"
fi
# Update dependencies
echo "Updating Helm dependencies..."
helm dependency update "${NODE_CHART}"
helm dependency update "${RELAY_CHART}"
# Deploy DataHaven nodes
echo "Deploying DataHaven nodes..."
# Deploy bootnode
echo "Deploying DataHaven bootnode..."
if [[ "${DRY_RUN}" == "true" ]]; then
echo "=== Bootnode Configuration Preview ==="
helm template dh-bootnode "${NODE_CHART}" \
-f "${NODE_CHART}/datahaven/dh-bootnode.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--debug
echo "=== End Bootnode Configuration Preview ==="
else
helm upgrade --install dh-bootnode "${NODE_CHART}" \
-f "${NODE_CHART}/datahaven/dh-bootnode.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--wait
fi
# Deploy validator
echo "Deploying DataHaven validator..."
if [[ "${DRY_RUN}" == "true" ]]; then
echo "=== Validator Configuration Preview ==="
helm template dh-validator "${NODE_CHART}" \
-f "${NODE_CHART}/datahaven/dh-validator.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--debug
echo "=== End Validator Configuration Preview ==="
else
helm upgrade --install dh-validator "${NODE_CHART}" \
-f "${NODE_CHART}/datahaven/dh-validator.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--wait
fi
# Deploy Snowbridge relays
echo "Deploying Snowbridge relays..."
# Deploy Beacon relay
echo "Deploying Snowbridge Beacon relay..."
if [[ "${DRY_RUN}" == "true" ]]; then
echo "=== Snowbridge Beacon Relay Configuration Preview ==="
helm template snowbridge-beacon-relay "${RELAY_CHART}" \
-f "${RELAY_CHART}/snowbridge/dh-beacon-relay.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--debug
echo "=== End Snowbridge Beacon Relay Configuration Preview ==="
else
helm upgrade --install snowbridge-beacon-relay "${RELAY_CHART}" \
-f "${RELAY_CHART}/snowbridge/dh-beacon-relay.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--wait
fi
# Deploy BEEFY relay
echo "Deploying Snowbridge BEEFY relay..."
if [[ "${DRY_RUN}" == "true" ]]; then
echo "=== Snowbridge BEEFY Relay Configuration Preview ==="
helm template snowbridge-beefy-relay "${RELAY_CHART}" \
-f "${RELAY_CHART}/snowbridge/dh-beefy-relay.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--debug
echo "=== End Snowbridge BEEFY Relay Configuration Preview ==="
else
helm upgrade --install snowbridge-beefy-relay "${RELAY_CHART}" \
-f "${RELAY_CHART}/snowbridge/dh-beefy-relay.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--wait
fi
# Deploy Execution relay
echo "Deploying Snowbridge Execution relay..."
if [[ "${DRY_RUN}" == "true" ]]; then
echo "=== Snowbridge Execution Relay Configuration Preview ==="
helm template snowbridge-execution-relay "${RELAY_CHART}" \
-f "${RELAY_CHART}/snowbridge/dh-execution-relay.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--debug
echo "=== End Snowbridge Execution Relay Configuration Preview ==="
else
helm upgrade --install snowbridge-execution-relay "${RELAY_CHART}" \
-f "${RELAY_CHART}/snowbridge/dh-execution-relay.yaml" \
-f "${VALUES_FILE}" \
-n "${NAMESPACE}" \
--wait
fi
if [[ "${DRY_RUN}" == "true" ]]; then
echo "Dry run completed. No changes were made."
else
echo "Deployment completed successfully!"
fi

View file

@ -1,64 +0,0 @@
# DataHaven Helm charts
## DataHaven Bootnode & Validators
### Deploy
```sh
cd deployment/charts/node
helm upgrade --install dh-bootnode . -f ./datahaven/dh-bootnode.yaml -n kt-datahaven-stagenet
helm upgrade --install dh-validator . -f ./datahaven/dh-validator.yaml -n kt-datahaven-stagenet
```
### Access validator node with Polkadot.js apps
```sh
kubectl port-forward svc/dh-validator-0 -n kt-datahaven-stagenet 9955:9955
https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9955#/explorer
```
### Remove
```sh
helm uninstall dh-bootnode -n kt-datahaven-stagenet
helm uninstall dh-validator -n kt-datahaven-stagenet
```
### Cleanup volumes
```sh
kubectl delete pvc -l app.kubernetes.io/instance=dh-bootnode -n kt-datahaven-stagenet
kubectl delete pvc -l app.kubernetes.io/instance=dh-validator -n kt-datahaven-stagenet
```
## Snowbridge Relayers
### Create secrets
```sh
kubectl create secret generic dh-beefy-relay-ethereum-key --from-literal=pvk="<PRIVATE_KEY>" -n kt-datahaven-stagenet
kubectl create secret generic dh-beacon-relay-substrate-key --from-literal=pvk="<PRIVATE_KEY>" -n kt-datahaven-stagenet
kubectl create secret generic dh-execution-relay-substrate-key --from-literal=pvk="<PRIVATE_KEY>" -n kt-datahaven-stagenet
```
### Deploy
```sh
helm upgrade --install dh-beacon-relay . -f ./snowbridge/dh-beacon-relay.yaml -n kt-datahaven-stagenet
helm upgrade --install dh-beefy-relay . -f ./snowbridge/dh-beefy-relay.yaml -n kt-datahaven-stagenet
helm upgrade --install dh-execution-relay . -f ./snowbridge/dh-execution-relay.yaml -n kt-datahaven-stagenet
```
## Remove
```sh
helm uninstall dh-beacon-relay -n kt-datahaven-stagenet
helm uninstall dh-beefy-relay -n kt-datahaven-stagenet
helm uninstall dh-execution-relay -n kt-datahaven-stagenet
```
### Delete secrets
```sh
kubectl delete secret <secret_name> -n kt-datahaven-stagenet
```

View file

@ -56,6 +56,7 @@ export const deploymentChecks = async (
logger.success("Helm is installed");
switch (options.environment) {
case "local":
case "stagenet":
launchedNetwork.kubeNamespace = `kt-${options.kurtosisEnclaveName}`;
break;

View file

@ -18,7 +18,7 @@ export const cleanup = async (
return;
}
if (options.environment === "stagenet") {
if (options.isPrivateNetwork) {
await checkAndCleanKurtosisDeployment(options);
}

View file

@ -64,11 +64,13 @@ export const deployDataHavenSolochain = async (
logger.info("🚀 Deploying DataHaven bootnode with helm chart...");
const bootnodeTimeout = "5m"; // 5 minutes
logger.debug(
await $`helm upgrade --install dh-bootnode . -f ./datahaven/dh-bootnode.yaml \
await $`helm upgrade --install dh-bootnode charts/node \
-f charts/node/datahaven/dh-bootnode.yaml \
-f environments/${options.environment}/values.yaml \
-n ${launchedNetwork.kubeNamespace} \
--wait \
--timeout ${bootnodeTimeout}`
.cwd(path.join(process.cwd(), "../deployment/charts/node"))
.cwd(path.join(process.cwd(), "../deploy"))
.text()
);
logger.success("DataHaven bootnode deployed successfully");
@ -76,11 +78,13 @@ export const deployDataHavenSolochain = async (
logger.info("🚀 Deploying DataHaven validators with helm chart...");
const validatorTimeout = "5m"; // 5 minutes
logger.debug(
await $`helm upgrade --install dh-validator . -f ./datahaven/dh-validator.yaml \
await $`helm upgrade --install dh-validator charts/node \
-f charts/node/datahaven/dh-validator.yaml \
-f environments/${options.environment}/values.yaml \
-n ${launchedNetwork.kubeNamespace} \
--wait \
--timeout ${validatorTimeout}`
.cwd(path.join(process.cwd(), "../deployment/charts/node"))
.cwd(path.join(process.cwd(), "../deploy"))
.text()
);
logger.success("DataHaven validators deployed successfully");

View file

@ -14,6 +14,7 @@ import { performValidatorOperations } from "./validator";
// Non-optional properties determined by having default values
export interface DeployOptions {
environment: DeployEnvironment;
isPrivateNetwork?: boolean;
kubeNamespace?: string;
kurtosisEnclaveName: string;
slotTime: number;
@ -101,13 +102,15 @@ export const deployPreActionHook = (
thisCmd.error("--verified requires --blockscout to be set");
}
if (opts.environment === "stagenet" && opts.kubeNamespace !== undefined) {
opts.isPrivateNetwork = opts.environment === "local" || opts.environment === "stagenet";
if (opts.isPrivateNetwork && opts.kubeNamespace !== undefined) {
logger.warn(
"⚠️ --kube-namespace is not allowed in stagenet environment. The Kurtosis namespace will be used instead."
"⚠️ --kube-namespace is not allowed in private networks (local and stagenet). The Kurtosis namespace will be used instead."
);
}
if (opts.environment !== "stagenet" && opts.elRpcUrl === undefined) {
thisCmd.error("--eth-rpc-url is required in non-stagenet environment");
if (!opts.isPrivateNetwork && opts.elRpcUrl === undefined) {
thisCmd.error("--eth-rpc-url is required in public networks (testnet and mainnet)");
}
};

View file

@ -25,8 +25,8 @@ export const deployKurtosis = async (
printHeader("Deploying Kurtosis Ethereum Network");
invariant(
options.environment === "stagenet",
"❌ Kurtosis should only be used in stagenet environment"
options.isPrivateNetwork,
"❌ Kurtosis should only be used in private networks (local and stagenet)"
);
await runKurtosisEnclave(options, "configs/kurtosis/minimal.yaml");

View file

@ -22,7 +22,7 @@ import type { DeployOptions } from ".";
const ETH_EL_RPC_PORT = 8546;
const ETH_CL_HTTP_PORT = 4000;
const RELAYER_CONFIG_DIR = "../deployment/charts/bridges-common-relay/configs";
const RELAYER_CONFIG_DIR = "../deploy/charts/relay/configs";
const RELAYER_CONFIG_PATHS = {
BEACON: path.join(RELAYER_CONFIG_DIR, "beacon-relay.json"),
BEEFY: path.join(RELAYER_CONFIG_DIR, "beefy-relay.json"),
@ -222,11 +222,13 @@ export const deployRelayers = async (options: DeployOptions, launchedNetwork: La
// Deploying relayer with helm chart
const relayerTimeout = "2m"; // 2 minutes
logger.debug(
await $`helm upgrade --install ${containerName} . -f ./snowbridge/${containerName}.yaml \
await $`helm upgrade --install ${containerName} charts/relay \
-f charts/relay/snowbridge/${containerName}.yaml \
-f environments/${options.environment}/values.yaml \
-n ${launchedNetwork.kubeNamespace} \
--wait \
--timeout ${relayerTimeout}`
.cwd(path.join(process.cwd(), "../deployment/charts/bridges-common-relay"))
.cwd(path.join(process.cwd(), "../deploy"))
.text()
);

View file

@ -12,7 +12,7 @@ export const performValidatorOperations = async (options: DeployOptions, network
}
// If not specified, prompt for funding
const shouldFundValidators = options.environment === "stagenet";
const shouldFundValidators = options.isPrivateNetwork;
if (shouldFundValidators) {
await fundValidators({

View file

@ -21,11 +21,11 @@ function parseIntValue(value: string): number {
// Function to parse and validate DeployEnvironment
function parseDeployEnvironment(value: string): DeployEnvironment {
if (value === "stagenet" || value === "testnet" || value === "mainnet") {
if (value === "local" || value === "stagenet" || value === "testnet" || value === "mainnet") {
return value;
}
throw new InvalidArgumentError(
"Invalid environment. Must be one of 'stagenet', 'testnet', or 'mainnet'."
"Invalid environment. Must be one of 'local', 'stagenet', 'testnet', or 'mainnet'."
);
}
@ -50,12 +50,7 @@ program
`
)
.description("Deploy a full DataHaven network stack to a Kubernetes cluster")
.option(
"--e, --environment <value>",
"Environment to deploy to",
parseDeployEnvironment,
"stagenet"
)
.option("--e, --environment <value>", "Environment to deploy to", parseDeployEnvironment, "local")
.option(
"--k, --kube-namespace <value>",
"Kubernetes namespace to deploy to. In 'stagenet' this parameter is ignored and the Kurtosis namespace is used instead. Default will be `datahaven-<environment>`."
@ -63,7 +58,7 @@ program
.option(
"--ke, --kurtosis-enclave-name <value>",
"Name of the Kurtosis enclave",
"datahaven-stagenet"
"datahaven-local"
)
.option("--st, --slot-time <number>", "Set slot time in seconds", parseIntValue, 12)
.option("--kn, --kurtosis-network-args <value>", "CustomKurtosis network args")
@ -76,11 +71,11 @@ program
)
.option(
"--el-rpc-url <value>",
"URL of the Ethereum Execution Layer (EL) RPC endpoint to use. In stagenet environment, the Kurtosis Ethereum network will be used. In testnet and mainnet environment, this parameter is required."
"URL of the Ethereum Execution Layer (EL) RPC endpoint to use. In local & stagenet environments (private networks), the Kurtosis Ethereum network will be used. In testnet and mainnet environments (public networks), this parameter is required."
)
.option(
"--cl-endpoint <value>",
"URL of the Ethereum Consensus Layer (CL) endpoint to use. In stagenet environment, the Kurtosis Ethereum network will be used. In testnet and mainnet environment, this parameter is required."
"URL of the Ethereum Consensus Layer (CL) endpoint to use. In local & stagenet environments (private networks), the Kurtosis Ethereum network will be used. In testnet and mainnet environments (public networks), this parameter is required."
)
.option(
"--rit, --relayer-image-tag <value>",

View file

@ -160,6 +160,12 @@ should-send-metrics: true
kurtosis-clusters:
docker:
type: "docker"
docker.k8s:
type: "kubernetes"
config:
kubernetes-cluster-name: "docker-desktop"
storage-class: "hostpath"
enclave-size-in-megabytes: 10
minikube:
type: "kubernetes"
config:
@ -175,7 +181,57 @@ kurtosis-clusters:
EOF
```
This will add three kurtosis clusters. You won't need all of them at once, but is good to have them configured. First one is docker, second is for minikube (useful for some), and the third one is the one we'll use for the deployment to kubernetes. Alternatively, you can check your current Kurtosis config file:
This will add four kurtosis clusters. You won't need all of them at once, but is good to have them configured.
1. **Docker containers**
This is usually only for running kurtosis directly to docker containers, it doesn't need a specific config, and it's equivalent to what we use in the `bun cli launch` command.
```yaml
docker:
type: "docker"
```
2. **Docker Kubernetes**
For macOS users or everyone that can run Docker Desktop, you can check this docs to enable Kubernetes natively on your Docker Desktop app: https://docs.docker.com/desktop/features/kubernetes/
```yaml
docker.k8s:
type: "kubernetes"
config:
kubernetes-cluster-name: "docker-desktop"
storage-class: "hostpath"
enclave-size-in-megabytes: 10
```
2. **Minikube**
Great tool for running local Kubernetes clusters, you can check installation instructions here: https://minikube.sigs.k8s.io/docs/start/
```yaml
minikube:
type: "kubernetes"
config:
kubernetes-cluster-name: "minikube"
storage-class: "standard"
enclave-size-in-megabytes: 10
```
4. **Kubernetes**
This is gonna be for a production deployment.
```yaml
cloud:
type: "kubernetes"
config:
kubernetes-cluster-name: "vira-dh-poc-cluster"
storage-class: "gp2"
enclave-size-in-megabytes: 10
```
If yout don't want all of them, you can always check your Kurtosis config file and add the desired clusters under `kurtosis-clusters:`
```bash
kurtosis config path
@ -187,23 +243,21 @@ And manually paste the contents:
config-version: 2
should-send-metrics: true
kurtosis-clusters:
docker:
type: "docker"
minikube:
type: "kubernetes"
config:
kubernetes-cluster-name: "minikube"
storage-class: "standard"
enclave-size-in-megabytes: 10
cloud:
type: "kubernetes"
config:
kubernetes-cluster-name: "vira-dh-poc-cluster"
storage-class: "gp2"
enclave-size-in-megabytes: 10
...
```
#### 4. For local deploymeny
Assuming well use Docker Kubernetes cluster:
```bash
# Set your Docker kubernetes
kurtosis cluster set docker.k8s
# In a separete terminal, run and keep the gateway running (we still need this to communicate from local machine to the local kubernetes cluster)
kurtosis gateway
```
#### 5. For production deploymeny
```bash
# Set your cloud cluster as the target
kurtosis cluster set cloud
@ -212,8 +266,8 @@ kurtosis cluster set cloud
kurtosis gateway
```
#### 4. (Optional) Test a simple deployment
#### 5. Test a simple deployment (recommended)
Before going any further, it's highly recommended that you test your config by creating a simple test network and runing it. Below, the steps:
```bash
# Creates a test-network.yml file
@ -223,9 +277,16 @@ echo -e "participants:\n - el_type: geth\n cl_type: prysm\n vc_type: prys
kurtosis run --enclave local-eth-testnet github.com/ethpandaops/ethereum-package --args-file test-network.yml
```
You can also go for testing against the provided hello-world by Kurtosis.
```bash
~ kurtosis run --enclave test-k8s github.com/kurtosis-tech/awesome-kurtosis/hello-world
```
## Deployment
### Access to GitHub
> ⚠️ **WARNING**
> This is a permissioned step. You need to get credentials for DockerHub.
>
@ -242,6 +303,8 @@ docker login -u <username>
docker manifest inspect moonsonglabs/datahaven:main
```
### Remote deployment
#### 3. Run the deploy command with the credentials
```bash
@ -252,6 +315,12 @@ If everything went well, you will see something like:
> [17:24:01.058] INFO (59757): ✅ Deploy function completed successfully in 28.4 minutes
### Local deployment
```bash
bun cli deploy --docker-username=<username> --docker-password=<pass> --docker-email=<email> --e local
```
## Access Kubernetes dashboard: k9s
```bash
@ -262,6 +331,66 @@ k9s -n kt-datahaven-stagenet
You can also check https://k9scli.io/topics/commands/ for a list of available commands and bindings.
## Troubleshooting
### Using the right context
Ensure your Kubernetes context (shown by 'kubectl config current-context') matches the cluster Kurtosis is set to use (shown by 'kurtosis cluster get').
For Docker Desktop, use 'docker-desktop' context and 'docker.k8s' cluster. For Minikube, use 'minikube' context and 'minikube' cluster.
```bash
# List available contexts
kubectl config get-contexts
# If you want to use Docker Desktop's Kubernetes, switch context:
kubectl config use-context docker-desktop
# If you want to use Minikube, switch context:
kubectl config use-context minikube
# Verify your current context:
kubectl config current-context
# Make sure your Kurtosis cluster matches your Kubernetes context:
kurtosis cluster get
```
### RBAC Permission Issues (Kubernetes clusters only)
You shouldn't, but If you get an error like "Failed to create cluster role with name 'kurtosis-logs-collector-*'" or "is attempting to grant RBAC permissions not currently held", you can use this to fix the RBAC permissions:
```bash
# Get the service account name from the error message and create a cluster role binding
kubectl create clusterrolebinding kurtosis-logs-collector --clusterrole=cluster-admin --serviceaccount=<namespace>:<serviceaccount>
# Example (replace with the actual service account from your error):
kubectl create clusterrolebinding kurtosis-logs-collector --clusterrole=cluster-admin --serviceaccount=kurtosis-engine-43c7ccedab104a1f86fa8839637141e2:kurtosis-engine-43c7ccedab104a1f86fa8839637141e2
```
**Note:** This gives the Kurtosis engine cluster-admin privileges, which is acceptable for local development but should be avoided in production environments.
### Make sure storage-class matches your config
If say you're using a kurtosis cluster that has a storage-class different from `"hostpath"`when you run locally (i.e. `"standard"`, for minikube), then you might get some errors when trying to execute the helm charts.
Look for this chunk in `deploy/environments/local/values.yaml`:
```yaml
# Common node settings
node:
chain: local
chainData:
storageClass: "hostpath"
persistence:
size: 10Gi
...
```
And try changing storageClass to whatever you have configured in the cluster. Good luck!
## Help commands (for reference only)
> ⚠️ **WARNING**

View file

@ -237,4 +237,4 @@ export function parseRelayConfig(
}
}
export type DeployEnvironment = "stagenet" | "testnet" | "mainnet";
export type DeployEnvironment = "local" | "stagenet" | "testnet" | "mainnet";