diff --git a/dysnix/agave/.helmignore b/dysnix/agave/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/dysnix/agave/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/dysnix/agave/Chart.yaml b/dysnix/agave/Chart.yaml new file mode 100644 index 00000000..98ad68c3 --- /dev/null +++ b/dysnix/agave/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +name: agave +description: Agave (previously Solana) blockchain node Helm chart +type: application + +version: 0.1.0 +appVersion: v2.0.18 + +keywords: + - agave + - solana + - crypto + - web3 + - cryptocurrency + - blockchain + +sources: + - https://github.com/dysnix/charts + - https://github.com/dysnix/docker-agave + - https://github.com/anza-xyz/agave + - https://github.com/solana-labs/solana + +maintainers: + - name: VladStarr + email: vlad.derigin@dysnix.com diff --git a/dysnix/agave/README.md b/dysnix/agave/README.md new file mode 100644 index 00000000..e3123178 --- /dev/null +++ b/dysnix/agave/README.md @@ -0,0 +1,123 @@ +# Agave helm chart + +A Helm chart to deploy Agave node inside Kubernetes cluster. + +## Parameters + +### Global parameters + +| Name | Description | Value | +| ---------------------------- | ---------------------------------------------------- | ----------------------------- | +| `replicaCount` | Number of pods to deploy in the Stateful Set | `1` | +| `image.repository` | Agave image repository | `ghcr.io/dysnix/docker-agave` | +| `image.tag` | Agave image tag | `""` | +| `image.pullPolicy` | Agave image pull policy | `IfNotPresent` | +| `imagePullSecrets` | Agave image pull secrets | `[]` | +| `nameOverride` | String to partially override release name | `""` | +| `fullnameOverride` | String to fully override release name | `""` | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `serviceAccount.name` | The name of the ServiceAccount to use | `""` | +| `serviceAccount.automount` | Whether to auto mount the service account token | `true` | +| `serviceAccount.annotations` | Additional custom annotations for the ServiceAccount | `{}` | +| `podLabels` | Extra labels for pods | `{}` | +| `podAnnotations` | Annotations for pods | `{}` | +| `extraContainerPorts` | Additional ports to expose on Agave container | `[]` | +| `podSecurityContext` | Configure securityContext for entire pod | `{}` | +| `securityContext` | Configure securityContext for Agave container | `{}` | +| `resources` | Set container requests and limits for CPU or memory | `{}` | +| `livenessProbe` | Agave container livenessProbe | `{}` | +| `startupProbe` | Agave container startupProbe | `{}` | +| `readinessProbe` | Agave container readinessProbe | `{}` | +| `affinity` | Affinity for pod assignment | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `volumes` | Pod extra volumes | `[]` | +| `volumeMounts` | Container extra volumeMounts | `[]` | + +### Services configuration + +| Name | Description | Value | +| ------------------------------------------- | ------------------------------------------- | ----------- | +| `services.rpc.enabled` | Enable Agave RPC service | `true` | +| `services.rpc.type` | Agave RPC service type | `ClusterIP` | +| `services.rpc.port` | Agave RPC service port (+1 for websocket) | `8899` | +| `services.rpc.extraPorts` | Agave RPC service extra ports to expose | `[]` | +| `services.rpc.publishNotReadyAddresses` | Route trafic even when pod is not ready | `false` | +| `services.metrics.enabled` | Enable Agave metrics service | `false` | +| `services.metrics.type` | Agave metrics service type | `ClusterIP` | +| `services.metrics.port` | Agave metrics service port | `9122` | +| `services.metrics.extraPorts` | Agave metrics service extra ports to expose | `[]` | +| `services.metrics.publishNotReadyAddresses` | Route trafic even when pod is not ready | `true` | + +### Ingress configuration + +| Name | Description | Value | +| -------------- | ------------------------------------------------------ | ----- | +| `ingress.http` | Ingress configuration for Agave RPC HTTP endpoint | `{}` | +| `ingress.ws` | Ingress configuration for Agave RPC WebSocket endpoint | `{}` | + +### Metrics configuration + +| Name | Description | Value | +| -------------------------------------- | ---------------------------------------------- | ---------------------- | +| `metrics.enabled` | Enable Agave node metrics collection | `false` | +| `metrics.target` | Where to push Agave metrics | `exporter` | +| `metrics.exporter` | influxdb-exporter configuration | `{}` | +| `metrics.serviceMonitor.enabled` | Enable Prometheus ServiceMonitor | `false` | +| `metrics.influxdb.existingSecret.name` | Name of secret containing InfluxDB credentials | `agave-metrics-config` | +| `metrics.influxdb.existingSecret.key` | Key name inside the secret | `config` | + +### Agave node configuration + +| Name | Description | Value | +| -------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | +| `agaveArgs` | `agave-validator` arguments | `{}` | +| `gracefulShutdown.timeout` | Seconds to wait for graceful shutdown | `120` | +| `gracefulShutdown.options` | `agave-validator exit` arguments | `{}` | +| `gracefulShutdown.options.force` | Do not wait for restart-window, useful for non-validators | `false` | +| `gracefulShutdown.options.skip-health-check` | Skip health check before exit | `false` | +| `gracefulShutdown.options.skip-health-check` | Skip check for a new snapshot before exit | `false` | +| `rustLog` | Logging configuration | `agave=info,solana_metrics=warn` | +| `plugins.enabled` | Enable download of Geyser plugins | `false` | +| `plugins.containerPorts` | Extra container ports for added plugins | `[]` | +| `plugins.servicePorts` | Extra service ports for added plugins | `[]` | +| `plugins.yellowstoneGRPC.enabled` | Enable download of Yellowstone gRPC | `false` | +| `plugins.yellowstoneGRPC.version` | Yellowstone gRPC version | `v3.0.0+solana.2.0.17` | +| `plugins.yellowstoneGRPC.downloadURL` | From where the plugin needs to be downloaded | `https://github.com/rpcpool/yellowstone-grpc/releases/download/` | +| `plugins.yellowstoneGRPC.listenIP` | Yellowstone gRPC listen IP address, without port | `$(MY_POD_IP)` | +| `plugins.yellowstoneGRPC.config` | Yellowstone gRPC config.json file | `look in values.yaml` | +| `plugins.jitoGRPC.enabled` | Enable download of Jito gRPC | `false` | +| `plugins.jitoGRPC.version` | Jito gRPC version | `v1.17.20` | +| `plugins.jitoGRPC.downloadURL` | From where the plugin needs to be downloaded | `https://github.com/jito-foundation/geyser-grpc-plugin/releases/download/v2.0.51/libgeyser_grpc_plugin_server.so` | +| `plugins.jitoGRPC.listenIP` | Jito gRPC listen IP address, without port | `$(MY_POD_IP)` | +| `plugins.jitoGRPC.config` | Jito gRPC config.json file | `look in values.yaml` | +| `identity.validatorKeypair` | Validator keypair string (required) | `""` | +| `identity.voteKeypair` | Vote keypair string (required only for validator) | `""` | +| `identity.existingSecret` | Use existing secret with keypairs instead of specifying them above | `""` | +| `identity.mountPath` | Keypair files mount path | `/secrets` | + +### Agave ledger db persistence config + +| Name | Description | Value | +| --------------------------------------- | ------------------------------- | -------------------------- | +| `persistence.ledger.type` | Ledger persistence type | `pvc` | +| `persistence.ledger.pvc.annotations` | PVC volume annotations | `{}` | +| `persistence.ledger.pvc.accessMode` | PVC volume access mode | `ReadWriteOnce` | +| `persistence.ledger.pvc.storageClass` | PVC volume storage class name | `""` | +| `persistence.ledger.pvc.size` | PVC volume size | `2Ti` | +| `persistence.ledger.existingClaim.name` | Existing PVC configuration | `agave-ledger-volume` | +| `persistence.ledger.hostPath.type` | hostPath volume type | `Directory` | +| `persistence.ledger.hostPath.path` | hostPath directory on host node | `/blockchain/agave-ledger` | + +### Agave accounts db persistence config + +| Name | Description | Value | +| ----------------------------------------- | ------------------------------- | ---------------------------- | +| `persistence.accounts.type` | Accounts persistence type | `pvc` | +| `persistence.accounts.pvc.annotations` | PVC volume annotations | `{}` | +| `persistence.accounts.pvc.accessMode` | PVC volume access mode | `ReadWriteOnce` | +| `persistence.accounts.pvc.storageClass` | PVC volume storage class name | `""` | +| `persistence.accounts.pvc.size` | PVC volume size | `2Ti` | +| `persistence.accounts.existingClaim.name` | Existing PVC configuration | `agave-accounts-volume` | +| `persistence.accounts.hostPath.type` | hostPath volume type | `Directory` | +| `persistence.accounts.hostPath.path` | hostPath directory on host node | `/blockchain/agave-accounts` | diff --git a/dysnix/agave/ci/ct-values.yaml b/dysnix/agave/ci/ct-values.yaml new file mode 100644 index 00000000..1904716f --- /dev/null +++ b/dysnix/agave/ci/ct-values.yaml @@ -0,0 +1,14 @@ +identity: + validatorKeypair: "[83,14,17,234,154,118,131,15,148,222,164,240,217,177,178,62,27,15,138,43,9,91,110,197,8,2,78,43,207,188,61,233,43,161,169,18,238,213,255,243,237,121,111,151,144,122,230,225,113,224,121,179,4,232,179,183,82,60,135,13,4,52,66,199]" + +readinessProbe: + enabled: false + +startupProbe: + enabled: false + +gracefulShutdown: + options: + force: true + skip-health-check: true + skip-new-snapshot-check: true diff --git a/dysnix/agave/templates/_helpers.tpl b/dysnix/agave/templates/_helpers.tpl new file mode 100644 index 00000000..151d5ae9 --- /dev/null +++ b/dysnix/agave/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "agave.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "agave.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "agave.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "agave.labels" -}} +helm.sh/chart: {{ include "agave.chart" . }} +{{ include "agave.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "agave.selectorLabels" -}} +app.kubernetes.io/name: {{ include "agave.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "agave.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "agave.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/dysnix/agave/templates/configmap-plugins.yaml b/dysnix/agave/templates/configmap-plugins.yaml new file mode 100644 index 00000000..22621600 --- /dev/null +++ b/dysnix/agave/templates/configmap-plugins.yaml @@ -0,0 +1,17 @@ +{{- if .Values.plugins.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "agave.fullname" $ }}-plugins-config + labels: + {{- include "agave.labels" . | nindent 4 }} +data: + {{- if .Values.plugins.yellowstoneGRPC.enabled }} + yellowstone-grpc-config.json: |- + {{- .Values.plugins.yellowstoneGRPC.config | nindent 4 }} + {{- end }} + {{- if .Values.plugins.jitoGRPC.enabled }} + jitogrpc-config.json: |- + {{- .Values.plugins.jitoGRPC.config | nindent 4 }} + {{- end }} +{{- end }} diff --git a/dysnix/agave/templates/ingress-http.yaml b/dysnix/agave/templates/ingress-http.yaml new file mode 100644 index 00000000..dfb0072a --- /dev/null +++ b/dysnix/agave/templates/ingress-http.yaml @@ -0,0 +1,46 @@ +{{- if .Values.ingress.http.enabled -}} +{{- $fullName := include "agave.fullname" . -}} +{{- $svcPort := .Values.services.rpc.port -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }}-http + labels: + {{- include "agave.labels" . | nindent 4 }} + type: http + {{- with .Values.ingress.http.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.http.className }} + ingressClassName: {{ .Values.ingress.http.className }} + {{- end }} + {{- if .Values.ingress.http.tls }} + tls: + {{- range .Values.ingress.http.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.http.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/dysnix/agave/templates/ingress-ws.yaml b/dysnix/agave/templates/ingress-ws.yaml new file mode 100644 index 00000000..2abd546f --- /dev/null +++ b/dysnix/agave/templates/ingress-ws.yaml @@ -0,0 +1,46 @@ +{{- if .Values.ingress.ws.enabled -}} +{{- $fullName := include "agave.fullname" . -}} +{{- $svcPort := add .Values.services.rpc.port 1 -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $fullName }}-ws + labels: + {{- include "agave.labels" . | nindent 4 }} + type: ws + {{- with .Values.ingress.ws.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.ws.className }} + ingressClassName: {{ .Values.ingress.ws.className }} + {{- end }} + {{- if .Values.ingress.ws.tls }} + tls: + {{- range .Values.ingress.ws.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.ws.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if .pathType }} + pathType: {{ .pathType }} + {{- end }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/dysnix/agave/templates/scripts.yaml b/dysnix/agave/templates/scripts.yaml new file mode 100644 index 00000000..1b7528e5 --- /dev/null +++ b/dysnix/agave/templates/scripts.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "agave.fullname" . }}-scripts + labels: + {{- include "agave.labels" . | nindent 4 }} +data: + start.sh: |- + {{- include (print $.Template.BasePath "/scripts/_start.tpl") . | nindent 4 }} + health.sh: |- + {{- include (print $.Template.BasePath "/scripts/_health.tpl") . | nindent 4 }} + {{- if .Values.plugins.enabled }} + download-plugins.sh: |- + {{- include (print $.Template.BasePath "/scripts/_download-plugins.tpl") . | nindent 4 }} + {{- end }} diff --git a/dysnix/agave/templates/scripts/_download-plugins.tpl b/dysnix/agave/templates/scripts/_download-plugins.tpl new file mode 100644 index 00000000..77f65fa4 --- /dev/null +++ b/dysnix/agave/templates/scripts/_download-plugins.tpl @@ -0,0 +1,47 @@ +#!/usr/bin/env sh +# shellcheck disable=SC3040,SC2046 + +set -e + +YELLOWSTONE_GRPC__PLUGIN_DIR="$PLUGINS_DIR/yellowstone-grpc" +JITO_GRPC__PLUGIN_DIR="$PLUGINS_DIR/jito-grpc" + +yellowstone_grpc_bootstrap() { + echo "Yellowstone gRPC: Downloading plugin version ${YELLOWSTONE_GRPC__VERSION}.." + mkdir -p "$YELLOWSTONE_GRPC__PLUGIN_DIR" + wget -q "${YELLOWSTONE_GRPC__DOWNLOAD_URL}/${YELLOWSTONE_GRPC__VERSION}/geyser.proto" + wget -q "${YELLOWSTONE_GRPC__DOWNLOAD_URL}/${YELLOWSTONE_GRPC__VERSION}/solana-storage.proto" + wget -qO- "${YELLOWSTONE_GRPC__DOWNLOAD_URL}/${YELLOWSTONE_GRPC__VERSION}/yellowstone-grpc-geyser-release-x86_64-unknown-linux-gnu.tar.bz2" | tar jxvf - + + echo "Yellowstone gRPC: Copying proto and lib to ${YELLOWSTONE_GRPC__PLUGIN_DIR}.." + cp -r /tmp/*.proto "$YELLOWSTONE_GRPC__PLUGIN_DIR/" + cp -r /tmp/yellowstone-grpc-geyser-release/lib "$YELLOWSTONE_GRPC__PLUGIN_DIR/" + + echo "Yellowstone gRPC: Copying config file to ${YELLOWSTONE_GRPC__PLUGIN_DIR}.." + cp -L "$YELLOWSTONE_GRPC__CONFIG_PATH" "$YELLOWSTONE_GRPC__PLUGIN_DIR/config.json" + + echo "Yellowstone gRPC: Changing listen IP address in config file to ${YELLOWSTONE_GRPC__LISTEN_IP}.." + sed -i "s/LISTEN_IP/${YELLOWSTONE_GRPC__LISTEN_IP}/g" "$YELLOWSTONE_GRPC__PLUGIN_DIR/config.json" + + echo "Yellowstone gRPC: Bootstrap done!" +} + +jito_grpc_bootstrap() { + mkdir -p "$JITO_GRPC__PLUGIN_DIR" + + echo "Jito gRPC: Copying config file to ${JITO_GRPC__PLUGIN_DIR}.." + cp -L "$JITO_GRPC__CONFIG_PATH" "$JITO_GRPC__PLUGIN_DIR/config.json" + + echo "Jito gRPC: Changing listen IP address in config file to ${JITO_GRPC__LISTEN_IP}.." + sed -i "s/LISTEN_IP/${JITO_GRPC__LISTEN_IP}/g" "$JITO_GRPC__PLUGIN_DIR/config.json" + + echo "Jito gRPC: Bootstrap done!" +} + +main() { + cd /tmp + if [ "$YELLOWSTONE_GRPC__ENABLED" = "1" ]; then yellowstone_grpc_bootstrap; fi + if [ "$JITO_GRPC__ENABLED" = "1" ]; then jito_grpc_bootstrap; fi +} + +main \ No newline at end of file diff --git a/dysnix/agave/templates/scripts/_health.tpl b/dysnix/agave/templates/scripts/_health.tpl new file mode 100644 index 00000000..f8eb663b --- /dev/null +++ b/dysnix/agave/templates/scripts/_health.tpl @@ -0,0 +1,21 @@ +#!/usr/bin/env sh +# shellcheck disable=SC3040,SC2046 + +set -e + +HTTP_PORT='{{ get .Values.agaveArgs "rpc-port" }}' + +# expected outputs: +# - {"jsonrpc":"2.0","result":"ok","id":1} +# - {"jsonrpc":"2.0","error":{"code":-32005,"message":"Node is unhealthy","data":{}},"id":1} +get_health() { + curl -s "http://$MY_POD_IP:$HTTP_PORT" \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc":"2.0","method":"getHealth","id":1}' +} + +if get_health | jq -r --exit-status '.error.message'; then + exit 1 +fi + +exit 0 \ No newline at end of file diff --git a/dysnix/agave/templates/scripts/_start.tpl b/dysnix/agave/templates/scripts/_start.tpl new file mode 100644 index 00000000..72499c9e --- /dev/null +++ b/dysnix/agave/templates/scripts/_start.tpl @@ -0,0 +1,20 @@ +#!/bin/sh + +exec agave-validator + {{- range $arg, $val := .Values.agaveArgs }} + {{- if and $arg $val }} \{{ end }} + {{- if kindIs "float64" $val }} + --{{ $arg }}={{ int $val }} + {{- else if kindIs "bool" $val }} + {{- if $val }} + --{{ $arg }} + {{- end }} + {{- else if kindIs "slice" $val }} + {{- range $key, $nestedVal := $val }} + {{- if $key }} \{{ end }} + --{{ $arg }}={{ $nestedVal }} + {{- end }} + {{- else }} + --{{ $arg }}={{ $val }} + {{- end }} + {{- end }} \ No newline at end of file diff --git a/dysnix/agave/templates/secret.yaml b/dysnix/agave/templates/secret.yaml new file mode 100644 index 00000000..90bdda76 --- /dev/null +++ b/dysnix/agave/templates/secret.yaml @@ -0,0 +1,16 @@ +{{- if not (or .Values.identity.existingSecret .Values.identity.validatorKeypair) }} +{{- fail "identity.validatorKeypair or identity.existingSecret have not been provided." }} +{{- end }} +{{- if not .Values.identity.existingSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "agave.fullname" . }}-identity + labels: + {{- include "agave.labels" $ | nindent 4 }} +data: + validator-keypair.json: {{ .Values.identity.validatorKeypair | b64enc | quote }} + {{- if .Values.identity.voteKeypair }} + vote-keypair.json: {{ .Values.identity.voteKeypair | b64enc | quote }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/dysnix/agave/templates/service-metrics.yaml b/dysnix/agave/templates/service-metrics.yaml new file mode 100644 index 00000000..398d9b11 --- /dev/null +++ b/dysnix/agave/templates/service-metrics.yaml @@ -0,0 +1,39 @@ +{{- with .Values.services.metrics }} +{{- if .enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "agave.fullname" $ }}-metrics + {{- with .annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + service-type: metrics + {{- include "agave.labels" $ | nindent 4 }} +spec: + type: {{ .type }} + {{- if eq .type "LoadBalancer" }} + {{- with .loadBalancerIP }} + loadBalancerIP: {{ . }} + {{- end }} + {{- end }} + {{- with .externalTrafficPolicy }} + externalTrafficPolicy: {{ . }} + {{- end }} + {{- with .internalTrafficPolicy }} + internalTrafficPolicy: {{ . }} + {{- end }} + publishNotReadyAddresses: {{ .publishNotReadyAddresses }} + ports: + - port: {{ .port }} + targetPort: exporter + protocol: TCP + name: exporter + {{- with .extraPorts }} + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + {{- include "agave.selectorLabels" $ | nindent 4 }} +{{- end }} +{{- end }} diff --git a/dysnix/agave/templates/service.yaml b/dysnix/agave/templates/service.yaml new file mode 100644 index 00000000..577ff0ea --- /dev/null +++ b/dysnix/agave/templates/service.yaml @@ -0,0 +1,48 @@ +{{- with .Values.services.rpc }} +{{- if .enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "agave.fullname" $ }} + {{- with .annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + service-type: rpc + {{- include "agave.labels" $ | nindent 4 }} +spec: + type: {{ .type }} + {{- if eq .type "LoadBalancer" }} + {{- with .loadBalancerIP }} + loadBalancerIP: {{ . }} + {{- end }} + {{- end }} + {{- with .externalTrafficPolicy }} + externalTrafficPolicy: {{ . }} + {{- end }} + {{- with .internalTrafficPolicy }} + internalTrafficPolicy: {{ . }} + {{- end }} + publishNotReadyAddresses: {{ .publishNotReadyAddresses }} + ports: + - port: {{ .port }} + targetPort: http + protocol: TCP + name: http + - port: {{ add .port 1 }} + targetPort: ws + protocol: TCP + name: ws + {{- if $.Values.plugins.enabled }} + {{- with $.Values.plugins.servicePorts }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + {{- with .extraPorts }} + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + {{- include "agave.selectorLabels" $ | nindent 4 }} +{{- end }} +{{- end }} diff --git a/dysnix/agave/templates/serviceaccount.yaml b/dysnix/agave/templates/serviceaccount.yaml new file mode 100644 index 00000000..9841bbb1 --- /dev/null +++ b/dysnix/agave/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "agave.serviceAccountName" . }} + labels: + {{- include "agave.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/dysnix/agave/templates/servicemonitor.yaml b/dysnix/agave/templates/servicemonitor.yaml new file mode 100644 index 00000000..bbfc2412 --- /dev/null +++ b/dysnix/agave/templates/servicemonitor.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.services.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "agave.fullname" . }} + labels: + {{- include "agave.labels" . | nindent 4 }} +spec: + jobLabel: app.kubernetes.io/instance + selector: + matchLabels: + service-type: metrics + {{- include "agave.selectorLabels" . | nindent 6 }} + endpoints: + - port: exporter + path: /metrics + {{- with (omit .Values.metrics.serviceMonitor "enabled" "extraEndpoints") }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.extraEndpoints }} + {{- toYaml . | nindent 4 }} + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace | quote }} +{{- end }} diff --git a/dysnix/agave/templates/statefulset.yaml b/dysnix/agave/templates/statefulset.yaml new file mode 100644 index 00000000..cd5702a2 --- /dev/null +++ b/dysnix/agave/templates/statefulset.yaml @@ -0,0 +1,320 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "agave.fullname" . }} + labels: + {{- include "agave.labels" . | nindent 4 }} +spec: + serviceName: {{ include "agave.name" . }} + updateStrategy: + {{- toYaml .Values.updateStrategy | nindent 4 }} + selector: + matchLabels: + {{- include "agave.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/scripts: {{ include (print $.Template.BasePath "/scripts.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "agave.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + terminationGracePeriodSeconds: {{ .Values.gracefulShutdown.timeout }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "agave.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- /* for better p2p connectivity */}} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + initContainers: + - name: sysctl + image: busybox:latest + securityContext: + privileged: true + command: ["sh", "-c"] + {{- /* as per agave validator requirements */}} + args: + - | + sysctl -w vm.max_map_count=1000000 + sysctl -w net.core.rmem_default=134217728 + sysctl -w net.core.rmem_max=134217728 + sysctl -w net.core.wmem_default=134217728 + sysctl -w net.core.wmem_max=134217728 + sysctl -w fs.nr_open=1000000 + {{- with .Values.plugins }} + {{- if .enabled }} + - name: download-plugins + image: busybox:latest + command: ["/scripts/download-plugins.sh"] + env: + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: PLUGINS_DIR + value: /plugins + - name: YELLOWSTONE_GRPC__ENABLED + value: {{ ternary "1" "0" .yellowstoneGRPC.enabled | quote }} + - name: YELLOWSTONE_GRPC__DOWNLOAD_URL + value: {{ .yellowstoneGRPC.downloadURL }} + - name: YELLOWSTONE_GRPC__VERSION + value: {{ .yellowstoneGRPC.version }} + - name: YELLOWSTONE_GRPC__CONFIG_PATH + value: /config/yellowstone-grpc-config.json + - name: YELLOWSTONE_GRPC__LISTEN_IP + value: {{ .yellowstoneGRPC.listenIP }} + - name: JITO_GRPC__ENABLED + value: {{ ternary "1" "0" .jitoGRPC.enabled | quote }} + - name: JITO_GRPC__CONFIG_PATH + value: /config/jitogrpc-config.json + - name: JITO_GRPC__LISTEN_IP + value: {{ .jitoGRPC.listenIP }} + volumeMounts: + - name: plugins + mountPath: /plugins + - name: plugins-config + mountPath: /config + - name: scripts + mountPath: /scripts + {{- end }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["/scripts/start.sh"] + {{- /* proper handling of node restart */}} + lifecycle: + preStop: + exec: + command: + - agave-validator + - --ledger={{ .Values.agaveArgs.ledger }} + - exit + {{- range $k, $v := .Values.gracefulShutdown.options }} + {{- if kindIs "float64" $v }} + - --{{ $k }}={{ $v }} + {{- else if kindIs "bool" $v }} + {{- if $v }} + - --{{ $k }} + {{- end }} + {{- else }} + - --{{ $k }}={{ $v }} + {{- end }} + {{- end }} + env: + - name: RUST_LOG + value: {{ .Values.rustLog }} + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + {{- if .Values.metrics.enabled }} + - name: SOLANA_METRICS_CONFIG + {{- if eq .Values.metrics.target "influxdb" }} + valueFrom: + secretKeyRef: + name: {{ .Values.metrics.influxdb.existingSecret.name }} + key: {{ .Values.metrics.influxdb.existingSecret.key }} + {{- else if eq .Values.metrics.target "exporter" }} + value: "host=http://$(MY_POD_IP):9122,db=default,u=admin,p=test123" + {{- end }} + {{- end }} + ports: + - name: http + containerPort: {{ get .Values.agaveArgs "rpc-port" }} + protocol: TCP + - name: ws + containerPort: {{ get .Values.agaveArgs "rpc-port" | add 1 }} + protocol: TCP + {{- if .Values.plugins.enabled }} + {{- with .Values.plugins.containerPorts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- with .Values.extraContainerPorts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.startupProbe.enabled }} + {{- with (omit .Values.startupProbe "enabled") }} + startupProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + {{- with (omit .Values.readinessProbe "enabled") }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + {{- with (omit .Values.livenessProbe "enabled") }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: ledger + mountPath: /data/ledger + - name: accounts + mountPath: /data/accounts + - name: scripts + mountPath: /scripts + - name: identity + mountPath: {{ .Values.identity.mountPath }} + {{- if .Values.plugins.enabled }} + - name: plugins + mountPath: /plugins + {{- end }} + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if and .Values.metrics.enabled (eq .Values.metrics.target "exporter") }} + {{- with .Values.metrics.exporter }} + - name: exporter + image: "{{ .image.repository }}:{{ .image.tag }}" + imagePullPolicy: {{ .image.pullPolicy }} + args: + - --web.listen-address=$(MY_POD_IP):9122 + - --udp.bind-address=$(MY_POD_IP):9123 + - --web.telemetry-path=/metrics + - --timestamps + env: + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + ports: + - name: exporter + containerPort: 9122 + protocol: TCP + - name: udp + containerPort: 9123 + protocol: UDP + resources: + {{- toYaml .resources | nindent 12 }} + {{- end }} + {{- end }} + volumes: + {{- with .Values.persistence }} + {{- if ne .ledger.type "pvc" }} + - name: ledger + {{- if eq .ledger.type "hostPath" }} + hostPath: + type: {{ .ledger.hostPath.type }} + path: {{ .ledger.hostPath.path }} + {{- else if eq .ledger.type "existingClaim" }} + persistentVolumeClaim: + claimName: {{ .ledger.existingClaim.name }} + {{- end }} + {{- end }} + {{- if ne .accounts.type "pvc" }} + - name: accounts + {{- if eq .accounts.type "hostPath" }} + hostPath: + type: {{ .accounts.hostPath.type }} + path: {{ .accounts.hostPath.path }} + {{- else if eq .accounts.type "existingClaim" }} + persistentVolumeClaim: + claimName: {{ .accounts.existingClaim.name }} + {{- end }} + {{- end }} + {{- end }} + - name: scripts + configMap: + name: {{ include "agave.fullname" . }}-scripts + defaultMode: 0755 + - name: identity + secret: + defaultMode: 0600 + {{- if .Values.identity.existingSecret }} + secretName: {{ .Values.identity.existingSecret }} + {{- else }} + secretName: {{ include "agave.fullname" . }}-identity + {{- end }} + {{- if .Values.plugins.enabled }} + - name: plugins + emptyDir: {} + - name: plugins-config + configMap: + name: {{ include "agave.fullname" . }}-plugins-config + {{- end }} + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumeClaimTemplates: + {{- with .Values.persistence.ledger }} + {{- if eq .type "pvc" }} + - metadata: + name: ledger + labels: + {{- include "agave.selectorLabels" $ | nindent 8 }} + {{- with .pvc.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + accessModes: + - {{ .pvc.accessMode }} + {{- if .pvc.storageClass }} + {{- if eq .pvc.storageClass "-" }} + storageClassName: "" + {{- else }} + storageClassName: {{ .pvc.storageClass | quote }} + {{- end }} + {{- end }} + resources: + requests: + storage: {{ .pvc.size | quote }} + {{- end }} + {{- end }} + {{- with .Values.persistence.accounts }} + {{- if eq .type "pvc" }} + - metadata: + name: accounts + labels: + {{- include "agave.selectorLabels" $ | nindent 8 }} + {{- with .pvc.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + accessModes: + - {{ .pvc.accessMode }} + {{- if .pvc.storageClass }} + {{- if eq .pvc.storageClass "-" }} + storageClassName: "" + {{- else }} + storageClassName: {{ .pvc.storageClass | quote }} + {{- end }} + {{- end }} + resources: + requests: + storage: {{ .pvc.size | quote }} + {{- end }} + {{- end }} diff --git a/dysnix/agave/values.yaml b/dysnix/agave/values.yaml new file mode 100644 index 00000000..f38dd25b --- /dev/null +++ b/dysnix/agave/values.yaml @@ -0,0 +1,526 @@ +## @section Global parameters +## + +## @param replicaCount Number of pods to deploy in the Stateful Set +## +replicaCount: 1 + +## @param image.repository Agave image repository +## @param image.tag [default: ""] Agave image tag +## @param image.pullPolicy Agave image pull policy +## +image: + repository: ghcr.io/dysnix/docker-agave + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +## @param imagePullSecrets Agave image pull secrets +imagePullSecrets: [] + +## @param nameOverride String to partially override release name +## +nameOverride: "" +## @param fullnameOverride String to fully override release name +## +fullnameOverride: "" + +## ServiceAccount configuration +## +serviceAccount: + ## @param serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param serviceAccount.name The name of the ServiceAccount to use + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param serviceAccount.automount Whether to auto mount the service account token + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server + ## + automount: true + ## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} + +## @param podLabels Extra labels for pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} + +## @param podAnnotations Annotations for pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} + +## @param extraContainerPorts [array] Additional ports to expose on Agave container +## Example: +## - name: grpc +## protocol: TCP +## containerPort: 10000 +extraContainerPorts: [] + +## @param podSecurityContext [object] Configure securityContext for entire pod +## Example: +## podSecurityContext: +## fsGroup: 2000 +podSecurityContext: {} + # fsGroup: 2000 + +## @param securityContext [object] Configure securityContext for Agave container +## Example: +## securityContext: +## capabilities: +## drop: +## - ALL +## readOnlyRootFilesystem: true +## runAsNonRoot: true +## runAsUser: 1000 +## +securityContext: {} + +## @param resources Set container requests and limits for CPU or memory +## Example: +## resources: +## requests: +## cpu: 16 +## memory: 384Gi +## limits: +## memory: 500Gi +## +resources: {} + +## @param livenessProbe [object] Agave container livenessProbe +## +livenessProbe: + enabled: false + failureThreshold: 10 + periodSeconds: 30 + timeoutSeconds: 5 + tcpSocket: + port: http + +## http server starts only when all loading tasks are finished +## this includes: ledger db loading, downloading/unpacking snapshot, etc. +## @param startupProbe [object] Agave container startupProbe +## +startupProbe: + enabled: true + failureThreshold: 1440 # wait 2 hours for initial startup + periodSeconds: 5 + timeoutSeconds: 2 + tcpSocket: + port: http + +## @param readinessProbe [object] Agave container readinessProbe +## +readinessProbe: + enabled: true + timeoutSeconds: 3 + failureThreshold: 2 + successThreshold: 1 + periodSeconds: 10 + exec: + command: + - sh + - /scripts/health.sh + +## @param affinity Affinity for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## +affinity: {} + +## @param nodeSelector Node labels for pod assignment +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ +## +nodeSelector: {} + +## @param tolerations Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] + +## @param volumes [array] Pod extra volumes +## Example: +## volumes: +## - name: secret +## secret: +## secretName: agave-secret +## +volumes: [] + +## @param volumeMounts [array] Container extra volumeMounts +## Example: +## volumeMounts: +## - name: keypair +## mountPath: /secrets +volumeMounts: [] + +## @section Services configuration +## +services: + rpc: + ## @param services.rpc.enabled Enable Agave RPC service + ## + enabled: true + ## @param services.rpc.type Agave RPC service type + ## + type: ClusterIP + ## @param services.rpc.port Agave RPC service port (+1 for websocket) + ## + port: 8899 + ## @param services.rpc.extraPorts Agave RPC service extra ports to expose + ## Example: + ## - name: grpc + ## protocol: TCP + ## port: 10000 + ## targetPort: grpc + ## + extraPorts: [] + ## @param services.rpc.publishNotReadyAddresses Route trafic even when pod is not ready + ## + publishNotReadyAddresses: false + metrics: + ## @param services.metrics.enabled Enable Agave metrics service + ## + enabled: false + ## @param services.metrics.type Agave metrics service type + ## + type: ClusterIP + ## @param services.metrics.port Agave metrics service port + ## + port: 9122 + ## @param services.metrics.extraPorts Agave metrics service extra ports to expose + ## Example: + ## - name: grpc-prom + ## protocol: TCP + ## port: 8999 + ## targetPort: grpc-prom + ## + extraPorts: [] + ## @param services.metrics.publishNotReadyAddresses Route trafic even when pod is not ready + ## + publishNotReadyAddresses: true + +## @section Ingress configuration +## +ingress: + ## @param ingress.http [object] Ingress configuration for Agave RPC HTTP endpoint + ## + http: + enabled: false + className: "" + annotations: {} + # cert-manager.io/cluster-issuer: letsencrypt-prod + hosts: + - host: agave.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: agave-tls + # hosts: + # - agave.local + ## @param ingress.ws [object] Ingress configuration for Agave RPC WebSocket endpoint + ## + ws: + enabled: false + className: "" + annotations: {} + # cert-manager.io/cluster-issuer: letsencrypt-prod + hosts: + - host: agave.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: agave-tls + # hosts: + # - agave.local + +## @section Metrics configuration +## +metrics: + ## @param metrics.enabled Enable Agave node metrics collection + ## + enabled: false + ## @param metrics.target Where to push Agave metrics + ## `exporter` - (default) push metrics to built-in influxdb-exporter for scraping via Prometheus + ## `influxdb` - push metrics to external InfluxDB instance + ## + target: exporter + ## @param metrics.exporter [object] influxdb-exporter configuration + ## + exporter: + image: + repository: prom/influxdb-exporter + tag: v0.11.5 + pullPolicy: IfNotPresent + resources: {} + # requests: + # cpu: 100m + # memory: 128Mi + # limits: + # memory: 256Mi + serviceMonitor: + ## @param metrics.serviceMonitor.enabled Enable Prometheus ServiceMonitor + enabled: false + # interval: 10s + # scrapeTimeout: 2s + # honorLabels: true + # relabelings: [] + # metricRelabelings: [] + # extraEndpoints: + # - port: exporter + # path: /metrics + # interval: 10s + # scrapeTimeout: 2s + influxdb: + existingSecret: + ## @param metrics.influxdb.existingSecret.name Name of secret containing InfluxDB credentials + ## + name: agave-metrics-config + ## @param metrics.influxdb.existingSecret.key Key name inside the secret + ## + key: config + +## @section Agave node configuration + +## @param agaveArgs [object] `agave-validator` arguments +## +agaveArgs: + identity: /secrets/validator-keypair.json + expected-genesis-hash: 4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY + known-validator: + - 5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on + - 7XSY3MrYnK8vq693Rju17bbPkCN3Z7KvvfvJx4kdrsSY + - Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN + - 9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv + - eoKpUABi59aT4rR9HGS3LcMecfut9x7zJyodWWP43YQ + - dDzy5SR3AXdYWVqbDEkVFdvSPCtS9ihF5kJkHCtXoFs + entrypoint: + - entrypoint.testnet.solana.com:8001 + - entrypoint2.testnet.solana.com:8001 + - entrypoint3.testnet.solana.com:8001 + full-rpc-api: true + no-voting: true # enable voting if you are running a validator + no-os-network-limits-test: true + no-port-check: true + only-known-rpc: false # it is hard to find a fresh snapshot from default known validators + log: "-" + ledger: /data/ledger + accounts: /data/accounts + rpc-port: 8899 + rpc-bind-address: ${MY_POD_IP} + private-rpc: true + dynamic-port-range: 8000-8020 + wal-recovery-mode: skip_any_corrupted_record + limit-ledger-size: true + health-check-slot-distance: 150 + enable-extended-tx-metadata-storage: false + enable-rpc-transaction-history: false + rpc-pubsub-enable-block-subscription: false + maximum-local-snapshot-age: 1500 # re-download snapshot when our local is >1500 slots old + minimal-snapshot-download-speed: 104857600 # 100 MB/s + account-index: [] # indexing for better rpc performance + +## Graceful shutdown options +## +gracefulShutdown: + ## @param gracefulShutdown.timeout Seconds to wait for graceful shutdown + ## + timeout: 120 + ## @param gracefulShutdown.options [object] `agave-validator exit` arguments + ## + options: + ## @param gracefulShutdown.options.force [default: false] Do not wait for restart-window, useful for non-validators + ## + force: false + ## @param gracefulShutdown.options.skip-health-check [default: false] Skip health check before exit + ## + skip-health-check: false + ## @param gracefulShutdown.options.skip-health-check [default: false] Skip check for a new snapshot before exit + ## + skip-new-snapshot-check: false + # max-delinquent-stake: 5 + # min-idle-time: 10 + +## @param rustLog Logging configuration +## +rustLog: agave=info,solana_metrics=warn + +plugins: + ## @param plugins.enabled Enable download of Geyser plugins + ## + enabled: false + ## @param plugins.containerPorts [array] Extra container ports for added plugins + ## Example: + ## - name: grpc + ## containerPort: 10000 + ## protocol: TCP + ## + containerPorts: [] + ## @param plugins.servicePorts [array] Extra service ports for added plugins + ## Example: + ## - name: grpc + ## protocol: TCP + ## port: 10000 + ## targetPort: grpc + ## + servicePorts: [] + ## Yellowstone gRPC plugin config + ## + yellowstoneGRPC: + ## @param plugins.yellowstoneGRPC.enabled Enable download of Yellowstone gRPC + ## + enabled: false + ## @param plugins.yellowstoneGRPC.version Yellowstone gRPC version + ## + version: v3.0.0+solana.2.0.17 + ## @param plugins.yellowstoneGRPC.downloadURL From where the plugin needs to be downloaded + ## + downloadURL: https://github.com/rpcpool/yellowstone-grpc/releases/download/ + ## @param plugins.yellowstoneGRPC.listenIP Yellowstone gRPC listen IP address, without port + ## works by replacing LISTEN_IP string inside json file with the value provided + ## default: Pod IP address from K8s downward API + ## + listenIP: $(MY_POD_IP) + ## @param plugins.yellowstoneGRPC.config [string, default: look in values.yaml] Yellowstone gRPC config.json file + ## + config: |- + { + "libpath": "lib/libyellowstone_grpc_geyser.so", + "log": { + "level": "info" + }, + "grpc": { + "address": "LISTEN_IP:10000", + "max_decoding_message_size": "4_194_304", + "snapshot_plugin_channel_capacity": null, + "snapshot_client_channel_capacity": "50_000_000", + "channel_capacity": "100_000", + "unary_concurrency_limit": 100, + "unary_disabled": false + }, + "prometheus": { + "address": "LISTEN_IP:8999" + }, + "block_fail_action": "log" + } + ## Jito gRPC plugin config + ## + jitoGRPC: + ## @param plugins.jitoGRPC.enabled Enable download of Jito gRPC + ## + enabled: false + ## @param plugins.jitoGRPC.version Jito gRPC version + ## + version: v1.17.20 + ## @param plugins.jitoGRPC.downloadURL From where the plugin needs to be downloaded + ## + downloadURL: https://github.com/jito-foundation/geyser-grpc-plugin/releases/download/v2.0.51/libgeyser_grpc_plugin_server.so + ## @param plugins.jitoGRPC.listenIP Jito gRPC listen IP address, without port + ## works by replacing LISTEN_IP string inside json file with the value provided + ## default: Pod IP address from K8s downward API + ## + listenIP: $(MY_POD_IP) + ## @param plugins.jitoGRPC.config [string, default: look in values.yaml] Jito gRPC config.json file + ## + config: |- + { + "libpath": "/lib/libgeyser_grpc_plugin_server.so", + "bind_address": "LISTEN_IP:10000", + "account_update_buffer_size": 100000, + "slot_update_buffer_size": 100000, + "block_update_buffer_size": 100000, + "transaction_update_buffer_size": 100000, + "geyser_service_config": { + "heartbeat_interval_ms": 1000, + "subscriber_buffer_size": 1000000 + } + } + +## You need first to create a keypair JSON files +## I.e. agave-keygen new --no-bip39-passphrase --silent && cat /root/.config/agave/id.json +## +identity: + ## @param identity.validatorKeypair Validator keypair string (required) + ## + validatorKeypair: "" + ## @param identity.voteKeypair Vote keypair string (required only for validator) + ## + voteKeypair: "" + ## @param identity.existingSecret Use existing secret with keypairs instead of specifying them above + ## + existingSecret: "" + ## @param identity.mountPath Keypair files mount path + ## + mountPath: /secrets + +persistence: + ## @section Agave ledger db persistence config + ## + ledger: + ## @param persistence.ledger.type Ledger persistence type + ## `pvc` - create PVC automatically + ## `existingClaim` - use already existing PVC + ## `hostPath` - use hostPath volume + ## + type: pvc + pvc: + ## @param persistence.ledger.pvc.annotations PVC volume annotations + ## + annotations: {} + ## @param persistence.ledger.pvc.accessMode PVC volume access mode + ## + accessMode: ReadWriteOnce + ## @param persistence.ledger.pvc.storageClass PVC volume storage class name + ## + storageClass: "" + ## @param persistence.ledger.pvc.size PVC volume size + ## + size: 2Ti + existingClaim: + ## @param persistence.ledger.existingClaim.name Existing PVC configuration + ## + name: agave-ledger-volume + hostPath: + ## @param persistence.ledger.hostPath.type hostPath volume type + ## + type: Directory + ## @param persistence.ledger.hostPath.path hostPath directory on host node + ## + path: /blockchain/agave-ledger + ## @section Agave accounts db persistence config + ## + accounts: + ## @param persistence.accounts.type Accounts persistence type + ## `pvc` - create PVC automatically + ## `existingClaim` - use already existing PVC + ## `hostPath` - use hostPath volume + ## + type: pvc + pvc: + ## @param persistence.accounts.pvc.annotations PVC volume annotations + ## + annotations: {} + ## @param persistence.accounts.pvc.accessMode PVC volume access mode + ## + accessMode: ReadWriteOnce + ## @param persistence.accounts.pvc.storageClass PVC volume storage class name + ## + storageClass: "" + ## @param persistence.accounts.pvc.size PVC volume size + ## + size: 2Ti + existingClaim: + ## @param persistence.accounts.existingClaim.name Existing PVC configuration + ## + name: agave-accounts-volume + hostPath: + ## @param persistence.accounts.hostPath.type hostPath volume type + ## + type: Directory + ## @param persistence.accounts.hostPath.path hostPath directory on host node + ## + path: /blockchain/agave-accounts