diff --git a/charts/avalanche/.helmignore b/charts/avalanche/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/avalanche/.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/charts/avalanche/Chart.yaml b/charts/avalanche/Chart.yaml new file mode 100644 index 0000000..916906c --- /dev/null +++ b/charts/avalanche/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +description: Helm chart for avalanche node +name: avalanche +version: 0.0.1 +appVersion: master +keywords: +- Avalanche +- validator +- blockchain +- AVAX +home: https://www.avax.network +sources: +- https://github.com/ava-labs/avalanchego +maintainers: + - name: Ivan Genev diff --git a/charts/avalanche/README.md b/charts/avalanche/README.md new file mode 100644 index 0000000..a639016 --- /dev/null +++ b/charts/avalanche/README.md @@ -0,0 +1,2 @@ +Avalanche +===== diff --git a/charts/avalanche/templates/NOTES.txt b/charts/avalanche/templates/NOTES.txt new file mode 100644 index 0000000..d208e2b --- /dev/null +++ b/charts/avalanche/templates/NOTES.txt @@ -0,0 +1,20 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "avalanche.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "avalanche.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "avalanche.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.http.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "avalanche.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/avalanche/templates/_helper_nginx.conf b/charts/avalanche/templates/_helper_nginx.conf new file mode 100644 index 0000000..29e1843 --- /dev/null +++ b/charts/avalanche/templates/_helper_nginx.conf @@ -0,0 +1,29 @@ +upstream {{ template "avalanche.proxyname" . }} { + server localhost:{{ .Values.service.http.port }}; +} + +{{- if .Values.proxy.logFormat }} + log_format rpc escape=none + {{- range .Values.proxy.logFormat }} + '{{ . }}' + {{- end }}; +{{- end }} + +server { + listen {{ .Values.proxy.port }}; + location / { + proxy_pass http://{{ template `avalanche.proxyname` . }}; + {{- if .Values.proxy.serverConfig }} + {{- range .Values.proxy.serverConfig }} + {{ . }} + {{- end }} + {{- end }} + {{- if .Values.proxy.logFormat }} + access_log /var/log/nginx/access.log rpc; + {{- end }} + } + location /nginx_status { + stub_status; + access_log off; + } +} diff --git a/charts/avalanche/templates/_helpers.yaml.tpl b/charts/avalanche/templates/_helpers.yaml.tpl new file mode 100644 index 0000000..4e0611b --- /dev/null +++ b/charts/avalanche/templates/_helpers.yaml.tpl @@ -0,0 +1,84 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "avalanche.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 "avalanche.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 "avalanche.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "avalanche.statefulset.apiVersion" -}} +{{- if .Capabilities.APIVersions.Has "apps/v1beta2" -}} +{{- print "apps/v1beta2" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "avalanche.ingress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- end -}} +{{- end -}} + + +{{/* +Properly format optional additional arguments to avalanchego +*/}} +{{- define "avalanche.extraArgs" -}} +{{- range .Values.extraArgs -}} +{{ " " }}{{ . }} +{{- end -}} +{{- end -}} + +{{/* +Determine service account name for statefulset. +*/}} +{{- define "avalanche.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} +{{- default (include "avalanche.fullname" .) .Values.serviceAccount.name | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- default "default" .Values.serviceAccount.name -}} +{{- end -}} +{{- end -}} + +{{/* +Determine proxy name for statefulset. +*/}} +{{- define "avalanche.proxyname" -}} +{{- if .Values.proxy.enabled -}} +{{- printf "%s-%s" .Chart.Name "proxy" | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} diff --git a/charts/avalanche/templates/configmap.yaml b/charts/avalanche/templates/configmap.yaml new file mode 100644 index 0000000..9e7883f --- /dev/null +++ b/charts/avalanche/templates/configmap.yaml @@ -0,0 +1,14 @@ +{{- if .Values.proxy.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "avalanche.proxyname" . }} + labels: + app: {{ template "avalanche.name" . }} + chart: {{ template "avalanche.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + nginx.conf: | +{{ include (print $.Template.BasePath "/_helper_nginx.conf") . | indent 4 }} +{{- end }} diff --git a/charts/avalanche/templates/ingress.yaml b/charts/avalanche/templates/ingress.yaml new file mode 100644 index 0000000..2353aa9 --- /dev/null +++ b/charts/avalanche/templates/ingress.yaml @@ -0,0 +1,45 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "avalanche.fullname" . -}} +{{- $servicePort := .Values.service.http.port -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: {{ template "avalanche.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "avalanche.name" . }} + chart: {{ template "avalanche.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - http: + paths: + - path: {{ $ingressPath }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $servicePort }} + {{- if . }} + host: {{ . | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/avalanche/templates/service.yaml b/charts/avalanche/templates/service.yaml new file mode 100644 index 0000000..6f5e521 --- /dev/null +++ b/charts/avalanche/templates/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "avalanche.fullname" . }} + labels: + app: {{ template "avalanche.name" . }} + chart: {{ template "avalanche.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - name: http + port: {{ .Values.service.http.port }} + {{- if .Values.proxy.enabled }} + targetPort: {{ .Values.proxy.port }} + {{- else }} + targetPort: {{ .Values.service.http.port }} + {{- end }} + protocol: TCP + selector: + app: {{ template "avalanche.name" . }} + release: {{ .Release.Name }} diff --git a/charts/avalanche/templates/serviceaccount.yaml b/charts/avalanche/templates/serviceaccount.yaml new file mode 100644 index 0000000..52e9bf5 --- /dev/null +++ b/charts/avalanche/templates/serviceaccount.yaml @@ -0,0 +1,7 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "avalanche.serviceAccountName" . | quote }} + namespace: {{ .Release.Namespace | quote }} +{{- end -}} diff --git a/charts/avalanche/templates/statefulset.yaml b/charts/avalanche/templates/statefulset.yaml new file mode 100644 index 0000000..e130b44 --- /dev/null +++ b/charts/avalanche/templates/statefulset.yaml @@ -0,0 +1,132 @@ +apiVersion: {{ template "avalanche.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "avalanche.fullname" . }} + labels: + app: {{ template "avalanche.name" . }} + chart: {{ template "avalanche.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + updateStrategy: + type: {{ .Values.updateStrategy }} + podManagementPolicy: "Parallel" + serviceName: {{ template "avalanche.fullname" . }} + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: {{ template "avalanche.name" . }} + release: {{ .Release.Name }} + template: + metadata: + name: {{ template "avalanche.fullname" . }} + labels: + app: {{ template "avalanche.name" . }} + release: {{ .Release.Name }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} +{{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | trimSuffix "\n" | indent 8 }} +{{- end }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + serviceAccountName: {{ include "avalanche.serviceAccountName" . | quote }} + containers: + {{- if .Values.sidecarContainers }} + {{- toYaml .Values.sidecarContainers | nindent 8 }} + {{- end }} + {{- if .Values.proxy.enabled }} + - name: {{ template "avalanche.proxyname" . }} + image: {{ .Values.proxy.image }} + imagePullPolicy: {{ .Values.proxy.pullPolicy }} + ports: + - name: proxy + containerPort: {{ .Values.proxy.port }} + {{- if .Values.proxy.resources }} + resources: + {{- toYaml .Values.proxy.resources | nindent 12 }} + {{- end }} + livenessProbe: + httpGet: + scheme: HTTP + path: /nginx_status + port: {{ .Values.proxy.port }} + initialDelaySeconds: 30 + timeoutSeconds: 30 + volumeMounts: + - name: {{ template "avalanche.proxyname" . }} + mountPath: /etc/nginx/conf.d/default.conf + readOnly: true + subPath: nginx.conf + {{- end }} + - name: {{ .Chart.Name }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: [ "/avalanchego/build/avalanchego", + "--db-dir={{ .Values.mountPath }} ", + {{- if ne .Values.service.http.port "9650" }} + "--http-port={{ .Values.service.http.port }} ", + {{- end }} + {{- if ne .Values.service.staking.port "9651" }} + "--staking-port={{ .Values.service.staking.port }}", + {{- end }} + "{{- template `avalanche.extraArgs` . }}" ] + volumeMounts: + - name: data + mountPath: {{ .Values.mountPath }} + ports: + - name: http + containerPort: {{ .Values.service.http.port }} + - name: staking + containerPort: {{ .Values.service.staking.port }} + env: + {{- range $key, $val := .Values.environment }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end}} + resources: +{{ toYaml .Values.resources | indent 12 }} + livenessProbe: + httpGet: + scheme: HTTP + path: /ext/health + port: {{ .Values.service.http.port }} + initialDelaySeconds: 30 + timeoutSeconds: 30 + {{- if .Values.proxy.enabled }} + volumes: + - name: {{ template "avalanche.proxyname" . }} + configMap: + name: {{ template "avalanche.proxyname" . }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + volumeClaimTemplates: + - metadata: + {{- if $.Values.persistence.VolumeName }} + name: {{ $.Values.persistence.VolumeName }} + {{- else }} + name: data + {{- end}} + spec: + accessModes: [ {{ $.Values.persistence.accessMode | quote }} ] + {{- if $.Values.persistence.storageClass }} + storageClassName: {{ $.Values.persistence.storageClass }} + {{- end }} + resources: + requests: + storage: {{ $.Values.persistence.size }} diff --git a/charts/avalanche/values.yaml b/charts/avalanche/values.yaml new file mode 100644 index 0000000..ce327b0 --- /dev/null +++ b/charts/avalanche/values.yaml @@ -0,0 +1,121 @@ +## Set default image, imageTag, and imagePullPolicy. +## +image: + repository: avaplatform/avalanchego + tag: v1.7.4 + pullPolicy: IfNotPresent + +## Additional arguments to pass to avalanchego +extraArgs: [] + # - --api-admin-enabled=true + # - --http-host=0.0.0.0 + +updateStrategy: RollingUpdate + +mountPath: "/root/.avalanchego" + +replicas: 1 + +persistence: + storageClass: "" + VolumeName: "" + accessMode: ReadWriteOnce + size: 10Gi + +service: + type: ClusterIP + http: + port: "9650" + staking: + port: "9651" + + annotations: {} + # prometheus.io/scrape: 'true' + # prometheus.io/path: '/ext/metrics' + # prometheus.io/port: '9650' + +## Configure sidecarContainers based on the documentation here: https://kubernetes.io/docs/concepts/workloads/pods/ +## + +sidecarContainers: {} + +## Enable proxy +## + +proxy: + enabled: false + port: "8080" + image: "nginx:1.20.2" + pullPolicy: IfNotPresent + resources: {} + logFormat: [] + #- '"$remote_addr" - "$remote_user" [$time_iso8601] "$request" ' + #- '"$status" "$body_bytes_sent" "$http_referer" ' + #- '"$http_user_agent" ' + #- 'rt="$request_time" urt="$upstream_response_time" ' + serverConfig: [] + #- proxy_read_timeout 3600; + #- client_body_in_single_buffer on; + #- client_body_buffer_size 16k; + #- proxy_buffers 16 16k; + #- proxy_buffer_size 16k; + + +## Configure Ingress based on the documentation here: https://kubernetes.io/docs/concepts/services-networking/ingress/ +## + +ingress: + enabled: false + labels: {} + # node-role.kubernetes.io/ingress: platform + + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # kubernetes.io/ingress.allow-http: "false" + # kubernetes.io/ingress.global-static-ip-name: "" + # nginx.ingress.kubernetes.io/secure-backends: "true" + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0 + path: / + hosts: + - chart-example.local + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +## Node labels for pod assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +## +nodeSelector: {} +tolerations: [] +affinity: {} + +# Additational pod annotations +podAnnotations: {} + +# Additional pod labels +podLabels: {} + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 16Gi + cpu: 8 + +# Environment +environment: + +serviceAccount: + create: true + ## The name of the service account to use. If 'create' is 'true', a service account with that name + ## will be created. Otherwise, a name will be auto-generated. + name: + +## Pod priority settings +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: ""