Skip to content

Commit

Permalink
Merge pull request #10 from graphops/chris/erigon-revision
Browse files Browse the repository at this point in the history
Add various features to Erigon chart
  • Loading branch information
chriswessels authored Sep 20, 2022
2 parents 2fd8a27 + d6680ca commit ef37082
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 25 deletions.
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ insert_final_newline = true

# Matches multiple files with brace expansion notation
# Set default charset
[*.{json,yaml,yml}]
[*.{json,yaml,yml,gotmpl}]
charset = utf-8
indent_style = space
indent_size = 2
indent_size = 2
4 changes: 2 additions & 2 deletions charts/erigon/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.2.6
version: 0.3.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "v2022.09.01"
appVersion: "v2022.09.03"
72 changes: 71 additions & 1 deletion charts/erigon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Deploy and scale [Erigon](https://github.com/ledgerwatch/erigon) inside Kubernetes with ease

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ![Version: 0.2.6](https://img.shields.io/badge/Version-0.2.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2022.09.01](https://img.shields.io/badge/AppVersion-v2022.09.01-informational?style=flat-square)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) ![Version: 0.3.0](https://img.shields.io/badge/Version-0.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2022.09.03](https://img.shields.io/badge/AppVersion-v2022.09.03-informational?style=flat-square)

## Features

Expand All @@ -12,6 +12,7 @@ Deploy and scale [Erigon](https://github.com/ledgerwatch/erigon) inside Kubernet
- Readiness checks to ensure traffic only hits `Pod`s that are healthy and ready to serve requests
- Support for `ServiceMonitor`s to configure Prometheus to scrape metrics ([prometheus-operator](https://github.com/prometheus-operator/prometheus-operator))
- Support for configuring Grafana dashboards for Erigon ([grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana))
- Support for exposing a NodePort to enable inbound P2P dials for better peering

## Quickstart

Expand All @@ -26,6 +27,34 @@ Once the release is installed, Erigon will begin syncing. You can use `kubectl l

JSON-RPC is available at `<release-name>-erigon-rpcdaemon:8545` by default.

## Specifying the Engine API JWT

To use Erigon on a network that requires a Consensus Client, you will need to configure a JWT that is used by the Consensus Client to authenticate with the Engine API on port `8551`. You will need to pass the same JWT to your Consensus Client.

You can specify the JWT for Erigon either as a literal value, or as a reference to a key in an existing Kubernetes Secret. If you specify a literal value, it will be wrapped into a new Kubernetes Secret and passed into the Erigon Pod.

Using a literal value:

```yaml
# values.yaml

statefulNode:
jwt:
fromLiteral: some-secure-random-value-that-you-generate # You can generate this with: openssl rand -hex 32
```
Using an existing Kubernetes Secret:
```yaml
# values.yaml

statefulNode:
jwt:
existingSecret:
name: my-ethereum-mainnet-jwt-secret
key: jwt
```
## JSON-RPC
### Built-in JSON-RPC
Expand All @@ -46,6 +75,37 @@ You can enable autoscaling for your scalable `Deployment` of `rpcdaemon`s. When

If doing this, be sure to configure `rpcdaemon.resources.requests` with appropriate values, as the CPU and Memory utilization targets set in the autoscaling config are relative to the requested resource values.

## Enabling inbound P2P dials

By default, your Erigon node will not have an internet-accessible port for P2P traffic. This makes it harder for your node to establish a strong set of peers because you cannot accept inbound P2P dials. To change this behaviour, you can set `statefulNode.p2pNodePort.enabled` to `true`. This will make your node accessible via the Internet using a `Service` of type `NodePort`. When using `statefulNode.p2pNodePort.enabled`, the exposed IP address on your Erigon ENR record will be the "External IP" of the Node where the Pod is running. When using this mode, `statefulNode.replicaCount` will be locked to `1`.

```yaml
# values.yaml
statefulNode:
p2pNodePort:
enabled: true
port: 31000 # Must be globally unique and available on the host
```

## Restoring chaindata from a snapshot

You can specify a snapshot URL that will be used to bootstrap Erigon's `chaindata` state. When enabled, an init container will perform a streaming extraction of the snapshot into storage. The snapshot should be a gzipped tarball of `chaindata`.

Example:
```yaml
# values.yaml
statefulNode:
fromSnapshot:
enable: true
snapshotUrl: https://matic-blockchain-snapshots.s3-accelerate.amazonaws.com/matic-mainnet/erigon-archive-snapshot-2022-07-15.tar.gz
```

Once Erigon's state has been bootstrapped, the snapshot URL will be saved to storage at `/from_snapshot`. Any time the Erigon Pod starts, as long as the snapshot configuration has not changed, Erigon will boot with the existing state. If you modify the snapshot configuration, the init container will remove existing chaindata and bootstrap state again.

You can monitor progress by following the logs of the `stateful-node-init` container: `kubectl logs --since 1m -f release-name-stateful-node-0 -c stateful-node-init`

## Upgrading

We recommend that you pin the version of the Chart that you deploy. You can use the `--version` flag with `helm install` and `helm upgrade` to specify a chart version constraint.
Expand Down Expand Up @@ -97,7 +157,17 @@ We do not recommend that you upgrade the application by overriding `image.tag`.
| statefulNode.affinity | | object | `{}` |
| statefulNode.affinityPresets.antiAffinityByHostname | Configure anti-affinity rules to prevent multiple Erigon instances on the same host | bool | `true` |
| statefulNode.extraArgs | Additional CLI arguments to pass to `erigon` | list | `[]` |
| statefulNode.fromSnapshot.enabled | Enable initialising Erigon state from a remote Snapshot | bool | `false` |
| statefulNode.fromSnapshot.snapshotUrl | URL for snapshot to download and extract to bootstrap storage | string | `nil` |
| statefulNode.jwt | JWT for clients to authenticate with the Engine API. Specify either `existingSecret` OR `fromLiteral`. | object | `{"existingSecret":{"key":"jwt","name":"some-secret-name"},"fromLiteral":"xxxx"}` |
| statefulNode.jwt.existingSecret | Load the JWT from an existing Kubernetes Secret. Takes precedence over `fromLiteral` if set. | object | `{"key":"jwt","name":"some-secret-name"}` |
| statefulNode.jwt.fromLiteral | Use this literal value for the JWT | string | `"xxxx"` |
| statefulNode.nodeSelector | | object | `{}` |
| statefulNode.p2pNodePort.enabled | Expose P2P port via NodePort | bool | `false` |
| statefulNode.p2pNodePort.initContainer.image.pullPolicy | Container pull policy | string | `"IfNotPresent"` |
| statefulNode.p2pNodePort.initContainer.image.repository | Container image to fetch nodeport information | string | `"lachlanevenson/k8s-kubectl"` |
| statefulNode.p2pNodePort.initContainer.image.tag | Container tag | string | `"v1.21.3"` |
| statefulNode.p2pNodePort.port | NodePort to be used. Must be unique. | int | `31000` |
| statefulNode.podAnnotations | Annotations for the `Pod` | object | `{}` |
| statefulNode.podSecurityContext | Pod-wide security context | object | `{"fsGroup":101337,"runAsGroup":101337,"runAsNonRoot":true,"runAsUser":101337}` |
| statefulNode.resources | | object | `{}` |
Expand Down
60 changes: 60 additions & 0 deletions charts/erigon/README.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Readiness checks to ensure traffic only hits `Pod`s that are healthy and ready to serve requests
- Support for `ServiceMonitor`s to configure Prometheus to scrape metrics ([prometheus-operator](https://github.com/prometheus-operator/prometheus-operator))
- Support for configuring Grafana dashboards for Erigon ([grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana))
- Support for exposing a NodePort to enable inbound P2P dials for better peering

## Quickstart

Expand All @@ -26,6 +27,34 @@ Once the release is installed, Erigon will begin syncing. You can use `kubectl l

JSON-RPC is available at `<release-name>-erigon-rpcdaemon:8545` by default.

## Specifying the Engine API JWT

To use Erigon on a network that requires a Consensus Client, you will need to configure a JWT that is used by the Consensus Client to authenticate with the Engine API on port `8551`. You will need to pass the same JWT to your Consensus Client.

You can specify the JWT for Erigon either as a literal value, or as a reference to a key in an existing Kubernetes Secret. If you specify a literal value, it will be wrapped into a new Kubernetes Secret and passed into the Erigon Pod.

Using a literal value:

```yaml
# values.yaml

statefulNode:
jwt:
fromLiteral: some-secure-random-value-that-you-generate # You can generate this with: openssl rand -hex 32
```

Using an existing Kubernetes Secret:

```yaml
# values.yaml

statefulNode:
jwt:
existingSecret:
name: my-ethereum-mainnet-jwt-secret
key: jwt
```

## JSON-RPC

### Built-in JSON-RPC
Expand All @@ -46,6 +75,37 @@ You can enable autoscaling for your scalable `Deployment` of `rpcdaemon`s. When

If doing this, be sure to configure `rpcdaemon.resources.requests` with appropriate values, as the CPU and Memory utilization targets set in the autoscaling config are relative to the requested resource values.

## Enabling inbound P2P dials

By default, your Erigon node will not have an internet-accessible port for P2P traffic. This makes it harder for your node to establish a strong set of peers because you cannot accept inbound P2P dials. To change this behaviour, you can set `statefulNode.p2pNodePort.enabled` to `true`. This will make your node accessible via the Internet using a `Service` of type `NodePort`. When using `statefulNode.p2pNodePort.enabled`, the exposed IP address on your Erigon ENR record will be the "External IP" of the Node where the Pod is running. When using this mode, `statefulNode.replicaCount` will be locked to `1`.

```yaml
# values.yaml

statefulNode:
p2pNodePort:
enabled: true
port: 31000 # Must be globally unique and available on the host
```

## Restoring chaindata from a snapshot

You can specify a snapshot URL that will be used to bootstrap Erigon's `chaindata` state. When enabled, an init container will perform a streaming extraction of the snapshot into storage. The snapshot should be a gzipped tarball of `chaindata`.

Example:
```yaml
# values.yaml

statefulNode:
fromSnapshot:
enable: true
snapshotUrl: https://matic-blockchain-snapshots.s3-accelerate.amazonaws.com/matic-mainnet/erigon-archive-snapshot-2022-07-15.tar.gz
```

Once Erigon's state has been bootstrapped, the snapshot URL will be saved to storage at `/from_snapshot`. Any time the Erigon Pod starts, as long as the snapshot configuration has not changed, Erigon will boot with the existing state. If you modify the snapshot configuration, the init container will remove existing chaindata and bootstrap state again.

You can monitor progress by following the logs of the `stateful-node-init` container: `kubectl logs --since 1m -f release-name-stateful-node-0 -c stateful-node-init`

{{ template "graphops.upgradingSection" . }}

{{ template "chart.requirementsSection" . }}
Expand Down
16 changes: 16 additions & 0 deletions charts/erigon/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,19 @@ Create the name of the service account to use
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

{{- define "erigon.p2pPort" -}}
{{- if .p2pNodePort.enabled }}
{{- print .p2pNodePort.port }}
{{- else }}
{{- printf "30303" -}}
{{- end }}
{{- end -}}

{{- define "erigon.replicas" -}}
{{- if .p2pNodePort.enabled }}
{{- print 1 }}
{{ else }}
{{- default 1 .replicaCount }}
{{- end}}
{{- end -}}
17 changes: 17 additions & 0 deletions charts/erigon/templates/stateful-node/jwt-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{- $values := $.Values.statefulNode }}
{{- $componentName := "stateful-node" }}
{{- $componentLabel := include "erigon.componentLabelFor" $componentName }}

{{- if $values.jwt.fromLiteral }}
---
apiVersion: v1
type: Opaque
kind: Secret
metadata:
name: {{ include "erigon.fullname" . }}-{{ $componentName }}-jwt
labels:
{{- include "erigon.labels" . | nindent 4 }}
{{- $componentLabel | nindent 4 }}
data:
jwt.hex: {{ $values.jwt.fromLiteral | b64enc }}
{{- end }}
33 changes: 32 additions & 1 deletion charts/erigon/templates/stateful-node/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ metadata:
labels:
{{- include "erigon.labels" . | nindent 4 }}
{{- $componentLabel | nindent 4 }}
serviceMonitorTarget: "true" # Additional label to prevent matching the headless service above
spec:
type: {{ $values.service.type }}
ports:
Expand All @@ -39,4 +40,34 @@ spec:
{{- end }}
selector:
{{- include "erigon.selectorLabels" . | nindent 4 }}
{{- $componentLabel | nindent 4 }}
{{- $componentLabel | nindent 4 }}
{{- if $values.p2pNodePort.enabled }}
{{- $port := $values.p2pNodePort.port }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "erigon.fullname" . }}-{{ $componentName }}-p2p-0
labels:
{{- include "erigon.labels" . | nindent 4 }}
{{- $componentLabel | nindent 4 }}
pod: {{ include "erigon.fullname" . }}-{{ $componentName }}-0
type: p2p # this label is used by the initContainer to select this service
spec:
type: NodePort
externalTrafficPolicy: Local
ports:
- name: tcp-p2p
port: {{ include "erigon.p2pPort" $values }}
protocol: TCP
targetPort: tcp-p2p
nodePort: {{ $port }}
- name: udp-p2p
port: {{ include "erigon.p2pPort" $values }}
protocol: UDP
targetPort: udp-p2p
nodePort: {{ $port }}
selector:
{{- include "erigon.selectorLabels" . | nindent 4 }}
statefulset.kubernetes.io/pod-name: "{{ include "erigon.fullname" $ }}-{{ $componentName }}-0"
{{- end }}
1 change: 1 addition & 0 deletions charts/erigon/templates/stateful-node/servicemonitor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ spec:
matchLabels:
{{- include "erigon.selectorLabels" . | nindent 6 }}
{{- $componentLabel | nindent 6 }}
serviceMonitorTarget: "true" # Additional label to prevent matching the headless service
endpoints:
- port: http-metrics
path: /debug/metrics/prometheus
Expand Down
Loading

0 comments on commit ef37082

Please sign in to comment.