-
Notifications
You must be signed in to change notification settings - Fork 2
feat: handshake-node chart #418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tripura-repalle
wants to merge
7
commits into
main
Choose a base branch
from
feat-handshake-node-helm-chart
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
3d91012
feat: handshake-node chart
tripura-repalle 87e335f
fix(handshake-node): address CodeRabbit review
tripura-repalle 5883b92
fix(handshake-node): address cubic-dev-ai review
tripura-repalle 20387cb
fix(handshake-node): address cubic-dev-ai review
tripura-repalle b11c4b5
docs(handshake-node): fix rpcallowip guidance and mainnet example
tripura-repalle 5f0b497
Merge remote-tracking branch 'origin/main' into feat-handshake-node-h…
tripura-repalle fa6688c
feat: handshake-node chart
tripura-repalle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| name: publish-handshake-node-helm-chart | ||
|
|
||
| on: | ||
| push: | ||
| branches: ['main'] | ||
| paths: | ||
| - 'charts/handshake-node/**' | ||
| - '.github/workflows/publish-handshake-node-helm-chart.yml' | ||
|
|
||
| jobs: | ||
| build-and-push-handshake-node-helm-chart: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| steps: | ||
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | ||
| - name: Install Helm | ||
| uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 | ||
| - name: Package and upload chart | ||
| shell: bash | ||
| env: | ||
| REGISTRY: "ghcr.io" | ||
| REPOSITORY: "${{ github.repository }}" | ||
| TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||
| USER: "${{ github.repository_owner }}" | ||
| run: | | ||
| rm -rf dist | ||
| mkdir dist | ||
| helm package charts/handshake-node/ -d dist/ | ||
| echo "${TOKEN}" | helm registry login "${REGISTRY}" -u "${USER}" --password-stdin | ||
| for file in dist/*; do | ||
| helm push "$file" "oci://${REGISTRY}/${REPOSITORY,,}/charts" | ||
| done | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| apiVersion: v2 | ||
| name: handshake-node | ||
| description: | | ||
| Deploys handshake-node, the Go implementation of a Handshake (HNS) blockchain | ||
| full node from Blink Labs. This is distinct from the JavaScript hsd chart. | ||
| type: application | ||
| version: 0.1.0 | ||
| appVersion: "0.1.1-rc1" | ||
| kubeVersion: ">=1.24.0-0" | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
|
||
| home: https://github.com/blinklabs-io/handshake-node | ||
| sources: | ||
| - https://github.com/blinklabs-io/handshake-node | ||
| keywords: | ||
| - handshake | ||
| - hns | ||
| - blockchain | ||
| - handshake-node | ||
| - btcd | ||
| maintainers: | ||
| - name: wolf31o2 | ||
| email: wolf31o2@blinklabs.io | ||
| - name: aurora | ||
| email: aurora@blinklabs.io | ||
| - name: verbotenj | ||
| email: verbotenj@blinklabs.io | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| # handshake-node | ||
|
|
||
| Deploys [handshake-node](https://github.com/blinklabs-io/handshake-node) — the | ||
| Go implementation of a Handshake (HNS) blockchain full node from Blink Labs — | ||
| as a Kubernetes StatefulSet. | ||
|
|
||
| This chart is distinct from the [`hsd`](../hsd) chart, which packages the | ||
| JavaScript reference implementation from `handshake-org`. | ||
|
|
||
| ## TL;DR | ||
|
|
||
| ```console | ||
| helm install my-handshake-node oci://ghcr.io/blinklabs-io/helm-charts/charts/handshake-node | ||
| ``` | ||
|
|
||
| ## Introduction | ||
|
|
||
| The chart deploys a single-replica StatefulSet running `handshake-node` | ||
| against the Handshake mainnet by default. Persistent state is stored in a | ||
| PersistentVolumeClaim mounted at `/home/handshake/.handshake-node`. | ||
|
|
||
| Security-relevant defaults: | ||
|
|
||
| - The container runs as the non-root `handshake` user baked into the upstream | ||
| image with `runAsNonRoot: true`, all Linux capabilities dropped, no | ||
| privilege escalation, `readOnlyRootFilesystem: true`, and the | ||
| `RuntimeDefault` seccomp profile. | ||
| - The peer-to-peer Service is `ClusterIP` by default. Public exposure via | ||
| `NodePort` or `LoadBalancer` is an explicit operator choice. | ||
| - The authenticated TLS RPC listener (port `12037`) is not exposed unless | ||
| `rpc.enabled=true`. When enabled, the chart renders a `ClusterIP`-only | ||
| Service that stays inside the cluster. | ||
| - RPC credentials are read from an existing Kubernetes Secret via | ||
| `secretKeyRef` — they are never taken from `values.yaml` or a ConfigMap. | ||
| - The Prometheus metrics endpoint (`12039`) and Stratum server (`12040`) are | ||
| disabled by default. When enabled they are kept on private `ClusterIP` | ||
| Services. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Kubernetes 1.24+ | ||
| - Helm 3.8+ (for OCI registry support) | ||
| - A default StorageClass (or set `persistence.storageClass`) | ||
|
|
||
| ## Installing the chart | ||
|
|
||
| ```console | ||
| helm install my-handshake-node \ | ||
| oci://ghcr.io/blinklabs-io/helm-charts/charts/handshake-node \ | ||
| --namespace handshake --create-namespace | ||
| ``` | ||
|
|
||
| ## Uninstalling the chart | ||
|
|
||
| ```console | ||
| helm uninstall my-handshake-node --namespace handshake | ||
| ``` | ||
|
|
||
| The PVC is retained by default (`persistence.retention.whenDeleted=Retain`). | ||
| Delete it manually if you no longer need the chain data: | ||
|
|
||
| ```console | ||
| kubectl -n handshake delete pvc data-my-handshake-node-0 | ||
| ``` | ||
|
|
||
| ## Persistence | ||
|
|
||
| The chart provisions a PVC via `volumeClaimTemplates`: | ||
|
|
||
| ```yaml | ||
| persistence: | ||
| enabled: true | ||
| accessModes: | ||
| - ReadWriteOnce | ||
| size: 200Gi | ||
| # storageClass: fast-ssd | ||
| retention: | ||
| whenDeleted: Retain | ||
| whenScaled: Retain | ||
| ``` | ||
|
|
||
| To bind an existing claim instead, set `persistence.existingClaim`: | ||
|
|
||
| ```yaml | ||
| persistence: | ||
| enabled: true | ||
| existingClaim: my-existing-handshake-pvc | ||
| ``` | ||
|
|
||
| ## RPC Secret | ||
|
|
||
| RPC is disabled by default. To enable it, create a Kubernetes Secret with the | ||
| credentials, then reference it from `values.yaml`: | ||
|
|
||
| ```console | ||
| kubectl -n handshake create secret generic handshake-node-rpc \ | ||
| --from-literal=rpcuser=hnsuser \ | ||
| --from-literal=rpcpass='replace-with-a-strong-password' | ||
| ``` | ||
|
|
||
| ```yaml | ||
| rpc: | ||
| enabled: true | ||
| existingSecret: handshake-node-rpc | ||
| userKey: rpcuser | ||
| passwordKey: rpcpass | ||
| ``` | ||
|
|
||
| The chart injects these values as the `HANDSHAKE_NODE_RPCUSER` and | ||
| `HANDSHAKE_NODE_RPCPASS` environment variables via `secretKeyRef`. It also | ||
| renders a `ClusterIP`-only Service named `<release>-handshake-node-rpc` on | ||
| port `12037`. If you need remote clients to reach RPC, port-forward the | ||
| service or front it with an in-cluster gateway that terminates its own TLS — | ||
| do not change the Service type in this chart. | ||
|
|
||
| ## Metrics | ||
|
|
||
| Enable the Prometheus endpoint (disabled by default): | ||
|
|
||
| ```yaml | ||
| metrics: | ||
| enabled: true | ||
| # Keep this bound to a routable interface inside the pod. The daemon | ||
| # rejects non-loopback binds unless allowPublic is true. | ||
| listen: "0.0.0.0:12039" | ||
| allowPublic: true | ||
| serviceMonitor: | ||
| enabled: true | ||
| interval: 30s | ||
| ``` | ||
|
|
||
| The metrics `Service` is always `ClusterIP`. Prometheus Operator users can | ||
| turn on the `ServiceMonitor` with `metrics.serviceMonitor.enabled=true`. | ||
|
|
||
| ## Stratum | ||
|
|
||
| Stratum is disabled by default. To turn it on for internal miners: | ||
|
|
||
| ```console | ||
| kubectl -n handshake create secret generic handshake-node-stratum \ | ||
| --from-literal=stratumuser=worker \ | ||
| --from-literal=stratumpass='replace-with-a-strong-password' | ||
| ``` | ||
|
|
||
| ```yaml | ||
| stratum: | ||
| enabled: true | ||
| listen: "0.0.0.0:12040" | ||
| allowPublic: true | ||
| miningAddress: hs1qyourhandshakeaddress | ||
| auth: | ||
| existingSecret: handshake-node-stratum | ||
| service: | ||
| enabled: true | ||
| type: ClusterIP | ||
| ``` | ||
|
|
||
| Public exposure requires `stratum.allowPublic=true` and both | ||
| `stratumuser`/`stratumpass` per the upstream daemon. | ||
|
|
||
| ## Service exposure | ||
|
|
||
| The peer-to-peer Service defaults to `ClusterIP`. To advertise the node on the | ||
| public Handshake network you must explicitly opt in: | ||
|
|
||
| ```yaml | ||
| service: | ||
| p2p: | ||
| type: LoadBalancer | ||
| port: 12038 | ||
| loadBalancerSourceRanges: | ||
| - 0.0.0.0/0 | ||
| ``` | ||
|
|
||
| Use `NodePort` if you route through an external load balancer: | ||
|
|
||
| ```yaml | ||
| service: | ||
| p2p: | ||
| type: NodePort | ||
| port: 12038 | ||
| nodePort: 32038 | ||
| ``` | ||
|
|
||
| ## Mainnet operations examples | ||
|
|
||
| Full mainnet node with private RPC, metrics enabled, and a beefier PVC: | ||
|
|
||
| ```yaml | ||
| network: main | ||
| image: | ||
| tag: "0.1.1-rc1" | ||
|
|
||
| persistence: | ||
| size: 400Gi | ||
| storageClass: fast-ssd | ||
|
|
||
| rpc: | ||
| enabled: true | ||
| existingSecret: handshake-node-rpc | ||
|
|
||
| metrics: | ||
| enabled: true | ||
| serviceMonitor: | ||
| enabled: true | ||
|
|
||
| resources: | ||
| requests: | ||
| cpu: 1 | ||
| memory: 2Gi | ||
| limits: | ||
| cpu: 4 | ||
| memory: 8Gi | ||
|
|
||
| topologySpreadConstraints: | ||
| - maxSkew: 1 | ||
| topologyKey: topology.kubernetes.io/zone | ||
| whenUnsatisfiable: ScheduleAnyway | ||
| labelSelector: | ||
| matchLabels: | ||
| app.kubernetes.io/name: handshake-node | ||
| ``` | ||
|
|
||
| ## Upgrade | ||
|
|
||
| ```console | ||
| helm upgrade my-handshake-node \ | ||
| oci://ghcr.io/blinklabs-io/helm-charts/charts/handshake-node \ | ||
| --namespace handshake \ | ||
| --reuse-values \ | ||
| --version <new-chart-version> | ||
| ``` | ||
|
|
||
| The PVC survives an upgrade because retention defaults to `Retain`. Chart | ||
| upgrades that only change the container image trigger a rolling restart of | ||
| the single StatefulSet pod. | ||
|
|
||
| ## Values reference | ||
|
|
||
| See [`values.yaml`](values.yaml) for the full list of tunables. Key knobs: | ||
|
|
||
| | Key | Description | Default | | ||
| | -------------------------------- | ------------------------------------------------------------ | ------------------------------------ | | ||
| | `image.repository` | Image name | `ghcr.io/blinklabs-io/handshake-node` | | ||
| | `image.tag` | Image tag (never `latest`) | `0.1.1-rc1` | | ||
| | `network` | Handshake network: `main`, `regtest`, `simnet` | `main` | | ||
| | `persistence.size` | PVC size | `200Gi` | | ||
| | `persistence.storageClass` | StorageClass name | cluster default | | ||
| | `rpc.enabled` | Enable authenticated RPC | `false` | | ||
| | `rpc.existingSecret` | Name of Secret with `rpcuser`/`rpcpass` | `""` | | ||
| | `metrics.enabled` | Enable Prometheus endpoint | `false` | | ||
| | `metrics.serviceMonitor.enabled` | Create ServiceMonitor | `false` | | ||
| | `stratum.enabled` | Enable Stratum server | `false` | | ||
| | `service.p2p.type` | P2P Service type | `ClusterIP` | | ||
| | `podSecurityContext` | Pod-level security context | non-root, seccomp `RuntimeDefault` | | ||
| | `securityContext` | Container security context | drop ALL, no privilege escalation | | ||
| | `resources` | CPU/memory requests/limits | `{}` | |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: Publishing behavior now has another full workflow copy to keep in sync; fixes to registry auth, action pins, or packaging must be applied across every chart workflow. A reusable
workflow_callworkflow with a chart-path input would centralize this logic.Prompt for AI agents