Skip to content

Commit

Permalink
feat(kubernetes): add new Besu Kubernetes chart files
Browse files Browse the repository at this point in the history
  • Loading branch information
謝明華 authored and 謝明華 committed Aug 9, 2024
1 parent c3ddf6a commit e18f03d
Show file tree
Hide file tree
Showing 21 changed files with 1,762 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/eth/instance/infra/kubernetes/charts/besu-genesis/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v1
version: 0.1.0
appVersion: latest
name: besu-genesis
description: Besu Genesis generator with Helm chart in Kubernetes
keywords:
- ethereum
- besu
- hyperledger
- enterprise
- blockchain
- pegasys
- consensys
home: https://besu.hyperledger.org
sources:
- https://github.com/hyperledger/besu
maintainers:
- name: Joshua Fernandes
email: [email protected]
icon: http://besu.hyperledger.org/en/latest/favicon.ico
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "besu-genesis.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 "besu-genesis.fullname" -}}
{{- $name := default .Chart.Name -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" $name .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}


{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "besu-genesis.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "besu-genesis.name" . }}-cleanup
labels:
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
azure.workload.identity/use: "true"
{{- end }}
app.kubernetes.io/name: besu-genesis-job-cleanup
app.kubernetes.io/component: genesis-job-cleanup
app.kubernetes.io/part-of: {{ include "besu-genesis.fullname" . }}
app.kubernetes.io/namespace: {{ .Release.Namespace }}
app.kubernetes.io/managed-by: helm
namespace: {{ .Release.Namespace }}
annotations:
helm.sh/hook-weight: "0"
helm.sh/hook: "pre-delete"
helm.sh/hook-delete-policy: "hook-succeeded"
spec:
backoffLimit: 3
completions: 1
template:
metadata:
labels:
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
azure.workload.identity/use: "true"
{{- end}}
app.kubernetes.io/name: besu-genesis-job-cleanup
app.kubernetes.io/component: genesis-job-cleanup
app.kubernetes.io/part-of: {{ include "besu-genesis.fullname" . }}
app.kubernetes.io/namespace: {{ .Release.Namespace }}
app.kubernetes.io/managed-by: helm
spec:
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
serviceAccountName: {{ .Values.azure.serviceAccountName }}
{{- else if and (eq .Values.cluster.provider "aws") (.Values.cluster.cloudNativeServices) }}
serviceAccountName: {{ .Values.aws.serviceAccountName }}
{{- else }}
serviceAccountName: {{ include "besu-genesis.name" . }}-sa
{{- end }}
restartPolicy: "Never"
containers:
- name: delete-genesis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
securityContext:
runAsUser: 0
imagePullPolicy: {{ .Values.image.pullPolicy }}
command:
- /bin/bash
- -c
args:
- |
{{- if .Values.quorumFlags.removeGenesisOnDelete }}

echo "Deleting genesis configmap in k8s ..."
kubectl delete configmap --namespace {{ .Release.Namespace }} besu-genesis

echo "Deleting node-enodes configmap in k8s ..."
kubectl delete configmap --namespace {{ .Release.Namespace }} besu-peers

{{- end}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "besu-genesis.name" . }}-init
labels:
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
azure.workload.identity/use: "true"
{{- end }}
app.kubernetes.io/name: besu-genesis-job
app.kubernetes.io/component: genesis-job
app.kubernetes.io/part-of: {{ include "besu-genesis.fullname" . }}
app.kubernetes.io/namespace: {{ .Release.Namespace }}
app.kubernetes.io/release: {{ .Release.Name }}
app.kubernetes.io/managed-by: helm
namespace: {{ .Release.Namespace }}
annotations:
helm.sh/hook-delete-policy: "hook-succeeded"
spec:
# backoffLimit: 3
completions: 1
template:
metadata:
labels:
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
azure.workload.identity/use: "true"
{{- end }}
app.kubernetes.io/name: besu-genesis-job
app.kubernetes.io/component: genesis-job
app.kubernetes.io/part-of: {{ include "besu-genesis.fullname" . }}
app.kubernetes.io/namespace: {{ .Release.Namespace }}
app.kubernetes.io/managed-by: helm
spec:
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
serviceAccountName: {{ .Values.azure.serviceAccountName }}
{{- else if and (eq .Values.cluster.provider "aws") (.Values.cluster.cloudNativeServices) }}
serviceAccountName: {{ .Values.aws.serviceAccountName }}
{{- else }}
serviceAccountName: {{ include "besu-genesis.name" . }}-sa
{{- end }}
restartPolicy: "Never"
containers:
- name: generate-genesis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
securityContext:
runAsUser: 0
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: generated-config
mountPath: /generated-config
command:
- /bin/bash
- -c
args:
- |
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
function safeWriteSecret {
key=$1
fpath=$2
az keyvault secret show --vault-name {{ .Values.azure.keyvaultName }} --name $key > /dev/null 2>&1
if [ $? -ne 0 ]; then
az keyvault secret set --vault-name {{ .Values.azure.keyvaultName }} --name $key --file $fpath --encoding utf-8
else
# if the key exists pull it from keyvault so that when you update the enodes configmap, you have the right value
az keyvault secret show --vault-name {{ .Values.azure.keyvaultName }} --name $key | jq -r '.value' > $fpath
fi
}
az login --federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)" --service-principal -u {{ .Values.azure.identityClientId }} -t {{ .Values.azure.tenantId }}
az account set --subscription {{ .Values.azure.subscriptionId }}

{{- else if and (eq .Values.cluster.provider "aws") (.Values.cluster.cloudNativeServices) }}

function safeWriteSecret {
key=$1
fpath=$2
aws secretsmanager describe-secret --secret-id $key > /dev/null 2>&1
if [ $? -ne 0 ]; then
aws secretsmanager create-secret --name $key --description $key --secret-string file://$fpath
else
# if the key exists pull it from keyvault so that when you update the enodes configmap, you have the right value
aws secretsmanager get-secret-value --secret-id $key | jq -r '.SecretString' > $fpath
fi
}

{{- else }}

function safeWriteSecret {
key=$1
fpath=$2
kubectl create secret generic ${key}-keys --namespace {{ .Release.Namespace }} --from-file=nodekey=${fpath}/nodekey --from-file=nodekey.pub=${fpath}/nodekey.pub --from-file=enode=${fpath}/nodekey.pub --from-file=accountPrivate.key=${fpath}/accountPrivateKey --from-file=accountPassword=${fpath}/accountPassword --from-file=accountKeystore=${fpath}/accountKeystore --from-file=accountAdddress=${fpath}/accountAddress
}

{{- end }}

function safeWriteBesuPeersConfigmap {
FOLDER_PATH=$1
kubectl get configmap --namespace {{ .Release.Namespace }} besu-peers
if [ $? -ne 0 ]; then
kubectl create configmap --namespace {{ .Release.Namespace }} besu-peers --from-file=static-nodes.json=$FOLDER_PATH/static-nodes.json
fi
}

function safeWriteGenesisConfigmap {
FOLDER_PATH=$1
kubectl get configmap --namespace {{ .Release.Namespace }} besu-genesis
if [ $? -ne 0 ]; then
kubectl create configmap --namespace {{ .Release.Namespace }} besu-genesis --from-file=genesis.json=$FOLDER_PATH/besu/genesis.json
fi
}

echo "Creating config ..."
FOLDER_PATH=$(quorum-genesis-tool --consensus {{ .Values.rawGenesisConfig.genesis.config.algorithm.consensus }} {{ if .Values.rawGenesisConfig.blockchain.nodes.generate }} --validators {{ .Values.rawGenesisConfig.blockchain.nodes.count }} {{ else }} --validators 0 {{ end }} --members 0 --bootnodes 0 --chainID {{ .Values.rawGenesisConfig.genesis.config.chainId }} --blockperiod {{ .Values.rawGenesisConfig.genesis.config.algorithm.blockperiodseconds }} --epochLength {{ .Values.rawGenesisConfig.genesis.config.algorithm.epochlength }} --requestTimeout {{ .Values.rawGenesisConfig.genesis.config.algorithm.requesttimeoutseconds }} --difficulty {{ .Values.rawGenesisConfig.genesis.difficulty }} --gasLimit {{ .Values.rawGenesisConfig.genesis.gasLimit }} --coinbase {{ .Values.rawGenesisConfig.genesis.coinbase }} {{ if .Values.rawGenesisConfig.blockchain.accountPassword }} --accountPassword {{ .Values.rawGenesisConfig.blockchain.accountPassword }} {{ end }} --quickstartDevAccounts {{ .Values.rawGenesisConfig.genesis.includeQuickStartAccounts }} --alloc {{ if .Values.rawGenesisConfig.genesis.alloc }} '{{ .Values.rawGenesisConfig.genesis.alloc | toJson }}' {{ else }} '{}' {{ end }} --outputPath /generated-config | tail -1 | sed -e "s/^Artifacts in folder: //")

echo "Creating bootnodes configmap in k8s ..."
echo "[]" > /tmp/besu-bootnodes
kubectl create configmap --namespace {{ .Release.Namespace }} besu-bootnodes --from-file=bootnodes=/tmp/besu-bootnodes

echo $FOLDER_PATH
echo "Creating genesis configmap in k8s ..."
safeWriteGenesisConfigmap $FOLDER_PATH

# create the static-nodes with proper dns names for the quorum nodes
echo "[" > $FOLDER_PATH/static-nodes.json
echo "Creating validator secrets in k8s ..."
i=1
for f in $(find $FOLDER_PATH -type d -iname "validator*" -exec basename {} \;); do
if [ -d $FOLDER_PATH/${f} ]; then
echo $f
echo "Creating keys in vault for validator-${i} ..."

{{- if and (ne .Values.cluster.provider "local") (.Values.cluster.cloudNativeServices) }}

safeWriteSecret besu-node-validator-${i}-nodekey $FOLDER_PATH/${f}/nodekey
safeWriteSecret besu-node-validator-${i}-nodekeypub $FOLDER_PATH/${f}/nodekey.pub
safeWriteSecret besu-node-validator-${i}-enode $FOLDER_PATH/${f}/nodekey.pub
safeWriteSecret besu-node-validator-${i}-address $FOLDER_PATH/${f}/address
kubectl create configmap --namespace {{ .Release.Namespace }} besu-node-validator-${i}-address --from-file=address=$FOLDER_PATH/${f}/address

safeWriteSecret besu-node-validator-${i}-accountPrivateKey $FOLDER_PATH/${f}/accountPrivateKey
safeWriteSecret besu-node-validator-${i}-accountPassword $FOLDER_PATH/${f}/accountPassword
safeWriteSecret besu-node-validator-${i}-accountKeystore $FOLDER_PATH/${f}/accountKeystore
safeWriteSecret besu-node-validator-${i}-accountAddress $FOLDER_PATH/${f}/accountAddress

{{- else }}

safeWriteSecret besu-node-validator-${i} "$FOLDER_PATH/${f}"
kubectl create configmap --namespace {{ .Release.Namespace }} besu-node-validator-${i}-address --from-file=address=$FOLDER_PATH/${f}/address

{{- end }}
# add to the static-nodes
pubkey=$(cat $FOLDER_PATH/${f}/nodekey.pub )
echo ",\"enode://$pubkey@besu-node-validator-$i-0.besu-node-validator-$i.{{ .Release.Namespace }}.svc.cluster.local:30303?discport=0\"" >> $FOLDER_PATH/static-nodes.json

i=$((i+1))
fi
done

echo "]" >> $FOLDER_PATH/static-nodes.json
# remove the extra comma to make it valid json
sed -i '0,/,/s///' $FOLDER_PATH/static-nodes.json
safeWriteBesuPeersConfigmap $FOLDER_PATH

echo "Completed ..."

volumes:
- name: generated-config
emptyDir: {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

{{- if not .Values.cluster.cloudNativeServices }}
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "besu-genesis.name" . }}-sa
namespace: {{ .Release.Namespace }}

{{- end }}

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "besu-genesis.name" . }}-role
namespace: {{ .Release.Namespace }}
rules:
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["create", "get", "list", "update", "delete" ]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch" ]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "besu-genesis.name" . }}-rb
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "besu-genesis.name" . }}-role
subjects:
- kind: ServiceAccount
namespace: {{ .Release.Namespace }}
{{- if and (eq .Values.cluster.provider "azure") (.Values.cluster.cloudNativeServices) }}
name: {{ .Values.azure.serviceAccountName }}
{{- else if and (eq .Values.cluster.provider "aws") (.Values.cluster.cloudNativeServices) }}
name: {{ .Values.aws.serviceAccountName }}
{{- else }}
name: {{ include "besu-genesis.name" . }}-sa
{{- end}}
50 changes: 50 additions & 0 deletions src/eth/instance/infra/kubernetes/charts/besu-genesis/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---

quorumFlags:
removeGenesisOnDelete: true

cluster:
provider: local # choose from: local | aws | azure
cloudNativeServices: false # set to true to use Cloud Native Services (SecretsManager and IAM for AWS; KeyVault & Managed Identities for Azure)

aws:
# the aws cli commands uses the name 'quorum-sa' so only change this if you altered the name
serviceAccountName: quorum-sa
# the region you are deploying to
region: ap-southeast-2

azure:
serviceAccountName: quorum-sa
# the clientId of the user assigned managed identity created in the template
identityClientId: azure-clientId
keyvaultName: azure-keyvault
# the tenant ID of the key vault
tenantId: azure-tenantId
# the subscription ID to use - this needs to be set explicitly when using multi tenancy
subscriptionId: azure-subscriptionId

# the raw Genesis config
# rawGenesisConfig.blockchain.nodes set the number of validators/signers
rawGenesisConfig:
genesis:
config:
chainId: 1337
algorithm:
consensus: qbft
blockperiodseconds: 10
epochlength: 30000
requesttimeoutseconds: 20
gasLimit: '0xf7b760'
difficulty: '0x1'
coinbase: '0x0000000000000000000000000000000000000000'
blockchain:
nodes:
generate: true
count: 4
accountPassword: 'password'


image:
repository: consensys/quorum-k8s-hooks
tag: qgt-0.2.15
pullPolicy: IfNotPresent
Loading

0 comments on commit e18f03d

Please sign in to comment.