diff --git a/.vscode/settings.json b/.vscode/settings.json index 33d286c..a224322 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -147,5 +147,6 @@ "workbench.editor.revealIfOpen": true, "workbench.fontAliasing": "auto", "workbench.tips.enabled": false, - "workbench.tree.enableStickyScroll": true + "workbench.tree.enableStickyScroll": true, + "chatgpt.openOnStartup": false } diff --git a/charts/network/charts/network-nodes/README.md b/charts/network/charts/network-nodes/README.md index 20bbc07..ff014bc 100644 --- a/charts/network/charts/network-nodes/README.md +++ b/charts/network/charts/network-nodes/README.md @@ -88,6 +88,13 @@ A Helm chart for Kubernetes | livenessProbe.periodSeconds | int | `10` | Frequency of liveness checks in seconds. | | livenessProbe.timeoutSeconds | int | `2` | Timeout in seconds before marking the probe as failed. | | nameOverride | string | `""` | Override for the short chart name used in resource naming. | +| networkPolicy.annotations | object | `{}` | Additional annotations to add to the NetworkPolicy metadata. | +| networkPolicy.egress | list | `[{"ports":[{"port":53,"protocol":"UDP"}],"to":[{"namespaceSelector":{},"podSelector":{"matchLabels":{"k8s-app":"kube-dns"}}}]},{"ports":[{"port":30303,"protocol":"TCP"}],"to":[{"podSelector":{"matchLabels":{"app.kubernetes.io/name":"besu-statefulset"}}}]},{"ports":[{"port":30303,"protocol":"TCP"}],"to":[{"ipBlock":{"cidr":"0.0.0.0/0","except":["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]}}]}]` | NetworkPolicy egress rules. Leave empty to deny all egress when enabled. | +| networkPolicy.enabled | bool | `false` | Create a NetworkPolicy restricting Besu pod ingress and egress. | +| networkPolicy.ingress | list | `[{"from":[{"podSelector":{"matchLabels":{"app.kubernetes.io/name":"txsigner"}}},{"podSelector":{"matchLabels":{"app.kubernetes.io/name":"erpc"}}},{"podSelector":{"matchLabels":{"app.kubernetes.io/name":"blockscout-stack"}}},{"podSelector":{"matchLabels":{"app.kubernetes.io/name":"graph-node"}}}],"ports":[{"port":8545,"protocol":"TCP"},{"port":8546,"protocol":"TCP"},{"port":8547,"protocol":"TCP"},{"port":9545,"protocol":"TCP"}]},{"from":[{"podSelector":{"matchLabels":{"app.kubernetes.io/name":"besu-statefulset"}}}],"ports":[{"port":30303,"protocol":"TCP"}]}]` | NetworkPolicy ingress rules. Leave empty to deny all ingress when enabled. | +| networkPolicy.labels | object | `{}` | Additional labels to add to the NetworkPolicy metadata. | +| networkPolicy.podSelector | object | `{}` | Optional override for the default pod selector; defaults to Besu workload labels when empty. | +| networkPolicy.policyTypes | list | `[]` | Policy types enforced by the NetworkPolicy. When empty, inferred from ingress/egress rules or defaults to both. | | nodeSelector | object | `{}` | | | openShiftRoute.alternateBackends | list | `[]` | Additional backend references to balance traffic across services. | | openShiftRoute.annotations | object | `{}` | | @@ -116,8 +123,24 @@ A Helm chart for Kubernetes | podAnnotations."prometheus.io/port" | string | `"9545"` | Container port value used by Prometheus to scrape metrics. | | podAnnotations."prometheus.io/scheme" | string | `"http"` | HTTP scheme (http or https) used for metrics scraping. | | podAnnotations."prometheus.io/scrape" | string | `"true"` | Enables Prometheus scraping of the Besu metrics endpoint. | +| podDisruptionBudgets.rpc | object | `{"annotations":{},"enabled":false,"labels":{},"maxUnavailable":null,"minAvailable":1,"unhealthyPodEvictionPolicy":""}` | PodDisruptionBudget governing RPC pods. | +| podDisruptionBudgets.rpc.annotations | object | `{}` | Additional annotations applied to the RPC PodDisruptionBudget. | +| podDisruptionBudgets.rpc.enabled | bool | `false` | Enable the RPC PodDisruptionBudget. | +| podDisruptionBudgets.rpc.labels | object | `{}` | Additional labels applied to the RPC PodDisruptionBudget. | +| podDisruptionBudgets.rpc.maxUnavailable | string | `nil` | Maximum RPC pods that can be disrupted at once. Mutually exclusive with minAvailable. | +| podDisruptionBudgets.rpc.minAvailable | int | `1` | Minimum RPC pods that must remain available. Mutually exclusive with maxUnavailable. | +| podDisruptionBudgets.rpc.unhealthyPodEvictionPolicy | string | `""` | Optional unhealthy pod eviction policy (Default or AlwaysAllow). | +| podDisruptionBudgets.validator | object | `{"annotations":{},"enabled":false,"labels":{},"maxUnavailable":null,"minAvailable":1,"unhealthyPodEvictionPolicy":""}` | PodDisruptionBudget controlling voluntary disruptions for validator pods. | +| podDisruptionBudgets.validator.annotations | object | `{}` | Additional annotations applied to the validator PodDisruptionBudget. | +| podDisruptionBudgets.validator.enabled | bool | `false` | Enable the validator PodDisruptionBudget. | +| podDisruptionBudgets.validator.labels | object | `{}` | Additional labels applied to the validator PodDisruptionBudget. | +| podDisruptionBudgets.validator.maxUnavailable | string | `nil` | Maximum validator pods that can be disrupted at once. Mutually exclusive with minAvailable. | +| podDisruptionBudgets.validator.minAvailable | int | `1` | Minimum validator pods that must remain available. Mutually exclusive with maxUnavailable. | +| podDisruptionBudgets.validator.unhealthyPodEvictionPolicy | string | `""` | Optional unhealthy pod eviction policy (Default or AlwaysAllow). | | podLabels | object | `{}` | | | podSecurityContext | object | `{}` | | +| priorityClassNames.rpc | string | `""` | PriorityClass name assigned to RPC pods. Leave empty to inherit namespace defaults. | +| priorityClassNames.validator | string | `""` | PriorityClass name assigned to validator pods. Leave empty to inherit namespace defaults. | | readinessProbe | string | `nil` | | | resources | object | `{}` | | | rpcReplicaCount | int | `2` | Number of RPC node replicas provisioned via StatefulSet. | diff --git a/charts/network/charts/network-nodes/templates/networkpolicy.yaml b/charts/network/charts/network-nodes/templates/networkpolicy.yaml new file mode 100644 index 0000000..783782f --- /dev/null +++ b/charts/network/charts/network-nodes/templates/networkpolicy.yaml @@ -0,0 +1,54 @@ +{{- if .Values.networkPolicy.enabled }} +{{- $root := . -}} +{{- $np := .Values.networkPolicy | default (dict) -}} +{{- $labels := get $np "labels" | default (dict) -}} +{{- $annotations := get $np "annotations" | default (dict) -}} +{{- $podSelector := get $np "podSelector" | default (dict) -}} +{{- $hasCustomSelector := gt (len $podSelector) 0 -}} +{{- $ingress := get $np "ingress" | default (list) -}} +{{- $egress := get $np "egress" | default (list) -}} +{{- $policyTypes := get $np "policyTypes" | default (list) -}} +{{- if not $policyTypes }} + {{- if gt (len $ingress) 0 }} + {{- $policyTypes = append $policyTypes "Ingress" -}} + {{- end }} + {{- if gt (len $egress) 0 }} + {{- $policyTypes = append $policyTypes "Egress" -}} + {{- end }} + {{- if eq (len $policyTypes) 0 }} + {{- $policyTypes = list "Ingress" "Egress" -}} + {{- end }} +{{- end }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "nodes.fullname" $root }} + labels: + {{- include "nodes.labels" $root | nindent 4 }} + {{- with $labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + podSelector: + {{- if $hasCustomSelector }} + {{- toYaml $podSelector | nindent 4 }} + {{- else }} + matchLabels: + {{- include "nodes.selectorLabels" $root | nindent 6 }} + {{- end }} + policyTypes: + {{- toYaml $policyTypes | nindent 4 }} + {{- if gt (len $ingress) 0 }} + ingress: + {{- toYaml $ingress | nindent 4 }} + {{- end }} + {{- if gt (len $egress) 0 }} + egress: + {{- toYaml $egress | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/network/charts/network-nodes/templates/poddisruptionbudgets.yaml b/charts/network/charts/network-nodes/templates/poddisruptionbudgets.yaml new file mode 100644 index 0000000..fc8b7c4 --- /dev/null +++ b/charts/network/charts/network-nodes/templates/poddisruptionbudgets.yaml @@ -0,0 +1,49 @@ +{{- $root := . -}} +{{- $pdbValues := .Values.podDisruptionBudgets | default (dict) -}} +{{- $components := list + (dict "name" "validator" "config" (default (dict) (get $pdbValues "validator"))) + (dict "name" "rpc" "config" (default (dict) (get $pdbValues "rpc"))) +-}} +{{- range $component := $components }} + {{- $cfg := $component.config -}} + {{- if and $cfg (get $cfg "enabled") }} + {{- $minRaw := get $cfg "minAvailable" -}} + {{- $hasMin := and (hasKey $cfg "minAvailable") (ne $minRaw nil) (not (and (kindIs "string" $minRaw) (eq $minRaw ""))) -}} + {{- $maxRaw := get $cfg "maxUnavailable" -}} + {{- $hasMax := and (hasKey $cfg "maxUnavailable") (ne $maxRaw nil) (not (and (kindIs "string" $maxRaw) (eq $maxRaw ""))) -}} + {{- $effectiveHasMin := and $hasMin (not $hasMax) -}} + {{- if not (or $effectiveHasMin $hasMax) }} + {{- fail (printf "podDisruptionBudgets.%s requires minAvailable or maxUnavailable" $component.name) -}} + {{- end }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "nodes.fullname" $root }}-{{ $component.name }} + labels: + {{- include "nodes.labels" $root | nindent 4 }} + app.kubernetes.io/component: {{ $component.name }} + {{- with (get $cfg "labels") }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with (get $cfg "annotations") }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if $effectiveHasMin }} + minAvailable: {{ $minRaw }} + {{- end }} + {{- if $hasMax }} + maxUnavailable: {{ $maxRaw }} + {{- end }} + {{- $policy := get $cfg "unhealthyPodEvictionPolicy" -}} + {{- if and $policy (ne $policy "") }} + unhealthyPodEvictionPolicy: {{ $policy }} + {{- end }} + selector: + matchLabels: + {{- include "nodes.selectorLabels" $root | nindent 6 }} + app.kubernetes.io/component: {{ $component.name }} + {{- end }} +{{- end }} diff --git a/charts/network/charts/network-nodes/templates/statefulset-rpc.yaml b/charts/network/charts/network-nodes/templates/statefulset-rpc.yaml index 4ef0ea9..d2c3f22 100644 --- a/charts/network/charts/network-nodes/templates/statefulset-rpc.yaml +++ b/charts/network/charts/network-nodes/templates/statefulset-rpc.yaml @@ -31,6 +31,8 @@ spec: {{- $privateKeyFilename := default "privateKey" .Values.config.privateKeyFilename }} {{- $shouldMountPersistence := $persistenceEnabled }} {{- $rpcReplicaBudget := .Values.rpcReplicaCount | int }} + {{- $priorityClasses := .Values.priorityClassNames | default (dict) }} + {{- $rpcPriorityClass := default "" (get $priorityClasses "rpc") }} {{- $initContainers := .Values.initContainers | default (dict) }} {{- $sharedInitContainers := get $initContainers "shared" }} {{- $rpcInitContainers := get $initContainers "rpc" }} @@ -68,6 +70,9 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "nodes.serviceAccountName" . }} + {{- if $rpcPriorityClass }} + priorityClassName: {{ $rpcPriorityClass | quote }} + {{- end }} {{- with .Values.podSecurityContext }} securityContext: {{- toYaml . | nindent 8 }} diff --git a/charts/network/charts/network-nodes/templates/statefulset-validator.yaml b/charts/network/charts/network-nodes/templates/statefulset-validator.yaml index 6d9141b..4ca9f7c 100644 --- a/charts/network/charts/network-nodes/templates/statefulset-validator.yaml +++ b/charts/network/charts/network-nodes/templates/statefulset-validator.yaml @@ -32,6 +32,8 @@ spec: {{- $staticNodesConfigMapName := default "besu-static-nodes" (get $globalNodes "staticNodesConfigMapName") }} {{- $validatorPodPrefix := default "besu-node-validator" (get $globalNodes "podPrefix") }} {{- $validatorReplicaBudget := (include "nodes.validatorReplicaCount" . | int) }} + {{- $priorityClasses := .Values.priorityClassNames | default (dict) }} + {{- $validatorPriorityClass := default "" (get $priorityClasses "validator") }} {{- $initContainers := .Values.initContainers | default (dict) }} {{- $sharedInitContainers := get $initContainers "shared" }} {{- $validatorInitContainers := get $initContainers "validator" }} @@ -69,6 +71,9 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "nodes.serviceAccountName" . }} + {{- if $validatorPriorityClass }} + priorityClassName: {{ $validatorPriorityClass | quote }} + {{- end }} {{- with .Values.podSecurityContext }} securityContext: {{- toYaml . | nindent 8 }} diff --git a/charts/network/charts/network-nodes/values.yaml b/charts/network/charts/network-nodes/values.yaml index c5e65c3..143f2b0 100644 --- a/charts/network/charts/network-nodes/values.yaml +++ b/charts/network/charts/network-nodes/values.yaml @@ -49,6 +49,123 @@ podAnnotations: # Additional labels applied to all Besu pods. podLabels: {} +# PodDisruptionBudget configuration for validator and RPC workloads. +podDisruptionBudgets: + # -- PodDisruptionBudget controlling voluntary disruptions for validator pods. + validator: + # -- Enable the validator PodDisruptionBudget. + enabled: false + # -- Minimum validator pods that must remain available. Mutually exclusive with maxUnavailable. + minAvailable: 1 + # -- Maximum validator pods that can be disrupted at once. Mutually exclusive with minAvailable. + maxUnavailable: + # -- Optional unhealthy pod eviction policy (Default or AlwaysAllow). + unhealthyPodEvictionPolicy: "" + # -- Additional annotations applied to the validator PodDisruptionBudget. + annotations: {} + # -- Additional labels applied to the validator PodDisruptionBudget. + labels: {} + # -- PodDisruptionBudget governing RPC pods. + rpc: + # -- Enable the RPC PodDisruptionBudget. + enabled: false + # -- Minimum RPC pods that must remain available. Mutually exclusive with maxUnavailable. + minAvailable: 1 + # -- Maximum RPC pods that can be disrupted at once. Mutually exclusive with minAvailable. + maxUnavailable: + # -- Optional unhealthy pod eviction policy (Default or AlwaysAllow). + unhealthyPodEvictionPolicy: "" + # -- Additional annotations applied to the RPC PodDisruptionBudget. + annotations: {} + # -- Additional labels applied to the RPC PodDisruptionBudget. + labels: {} + +# NetworkPolicy configuration applied to Besu pods. +networkPolicy: + # -- Create a NetworkPolicy restricting Besu pod ingress and egress. + enabled: false + # -- Optional override for the default pod selector; defaults to Besu workload labels when empty. + podSelector: {} + # -- Policy types enforced by the NetworkPolicy. When empty, inferred from ingress/egress rules or defaults to both. + policyTypes: [] + # -- Additional labels to add to the NetworkPolicy metadata. + labels: {} + # -- Additional annotations to add to the NetworkPolicy metadata. + annotations: {} + # -- NetworkPolicy ingress rules. Leave empty to deny all ingress when enabled. + ingress: + # Allow blockchain clients to reach RPC, WS, GraphQL, and metrics endpoints. + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: txsigner + - podSelector: + matchLabels: + app.kubernetes.io/name: erpc + - podSelector: + matchLabels: + app.kubernetes.io/name: blockscout-stack + - podSelector: + matchLabels: + app.kubernetes.io/name: graph-node + # - podSelector: {} # Uncomment to allow any pod within the namespace. + ports: + - protocol: TCP + port: 8545 + - protocol: TCP + port: 8546 + - protocol: TCP + port: 8547 + - protocol: TCP + port: 9545 + # Permit intra-cluster P2P traffic among Besu nodes. + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: besu-statefulset + ports: + - protocol: TCP + port: 30303 + + # -- NetworkPolicy egress rules. Leave empty to deny all egress when enabled. + egress: + # Allow DNS resolution for outbound hosts. + - to: + - namespaceSelector: {} + podSelector: + matchLabels: + k8s-app: kube-dns + ports: + - protocol: UDP + port: 53 + # Permit Besu pods to speak to peers inside the namespace. + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: besu-statefulset + ports: + - protocol: TCP + port: 30303 + # Allow outbound P2P connections to external peers (public networks). + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + # Adjust the except list to match internal cluster CIDRs to avoid bypassing other policies. + ports: + - protocol: TCP + port: 30303 + +# PriorityClass configuration applied to Besu workloads. +priorityClassNames: + # -- PriorityClass name assigned to validator pods. Leave empty to inherit namespace defaults. + validator: "" + # -- PriorityClass name assigned to RPC pods. Leave empty to inherit namespace defaults. + rpc: "" + # Pod-level security context shared by all containers. podSecurityContext: {}