Init Helm chart (#255)

* Initial chart version

* Add CI/CD for chart

* Fix admin creds template

* Add command, args, env, envFrom

* Render volumes and volumeMounts with tpl

* Change persistance accessMode type

* Add update strategy config

* Use custom types in docs

* Add startup probe config

* Fix web.external_url config
This commit is contained in:
Dmytro Bondar
2024-07-04 22:37:30 +02:00
committed by GitHub
parent 85381121ee
commit 6f52cb2ada
19 changed files with 981 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
{{- $serviceName := printf "%s-web" (include "wg-portal.fullname" .) -}}
{{- $servicePort := .Values.service.web.port }}
{{- if not .Values.ingress.enabled }}
Get the application URL by running these commands:
{{- if eq "ClusterIP" .Values.service.web.type }}
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ $serviceName }} {{ $servicePort }}:{{ $servicePort }}
Visit http://127.0.0.1:{{ $servicePort }} to use your application
{{- else if eq "LoadBalancer" .Values.service.web.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 {{ $serviceName }}'
export SERVICE_IP=$(kubectl get --namespace {{ .Release.Namespace }} svc {{ $serviceName }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ $servicePort }}
{{- else if eq "NodePort" .Values.service.web.type }}
export NODE_IP=$(kubectl get --namespace {{ .Release.Namespace }} nodes -o jsonpath="{.items[0].status.addresses[0].address}")
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} svc {{ $serviceName }} -o jsonpath="{.spec.ports[0].nodePort}" )
echo http://$NODE_IP:$NODE_PORT
{{- end }}
{{- else }}
Visit http{{ if .Values.ingress.tls }}s{{ end }}://{{ .Values.ingress.host }}{{ .Values.ingress.path }} to use your application
{{- end }}

View File

@@ -0,0 +1,100 @@
{{/*
Expand the name of the chart
*/}}
{{- define "wg-portal.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 "wg-portal.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 "wg-portal.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "wg-portal.labels" -}}
helm.sh/chart: {{ include "wg-portal.chart" . }}
{{ include "wg-portal.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "wg-portal.selectorLabels" -}}
app.kubernetes.io/name: {{ include "wg-portal.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "wg-portal.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "wg-portal.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Define default admin credentials
If external auth is enabled and has admin group mappings,
the admin_user and admin_password values are not used.
*/}}
{{- define "wg-portal.admin" -}}
{{- $externalAdmin := false -}}
{{- with .Values.config.auth -}}
{{- range (default list .ldap) -}}
{{- if hasKey . "admin_group" -}}
{{- $externalAdmin = true -}}
{{- end -}}
{{- end }}
{{- range (concat (default list .oidc) (default list .oauth)) -}}
{{- if hasKey .field_map "is_admin" -}}
{{- $externalAdmin = true -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- if not $externalAdmin -}}
admin_user: admin@wgportal.local
admin_password: {{ printf "%s/%s" .Release.Name .Release.Namespace | b64enc }}
{{- end -}}
{{- end -}}
{{/*
Define PersistentVolumeClaim spec
*/}}
{{- define "wg-portal.pvc" -}}
accessModes: [{{ .Values.persistence.accessMode }}]
{{- with .Values.persistence.storageClass }}
storageClassName: {{ . }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- end -}}

View File

@@ -0,0 +1,111 @@
{{- define "wg-portal.podTemplate" -}}
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
kubectl.kubernetes.io/default-container: {{ .Chart.Name }}
{{- with .Values.podAnnotations }}
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
labels:
{{- include "wg-portal.labels" . | nindent 4 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.affinity }}
affinity: {{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
containers:
{{- with .Values.sidecarContainers }}
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag}}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- with .Values.command }}
command: {{ . }}
{{- end }}
{{- with .Values.args }}
args: {{ . }}
{{- end }}
{{- with .Values.env }}
env: {{- tpl (toYaml .) $ | nindent 8 }}
{{- end }}
{{- with .Values.envFrom }}
envFrom: {{- tpl (toYaml .) $ | nindent 8 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.web.port }}
protocol: TCP
{{- range $index, $port := .Values.service.wireguard.ports }}
- name: wg{{ $index }}
containerPort: {{ $port }}
protocol: UDP
{{- end }}
{{- with .Values.livenessProbe }}
livenessProbe: {{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe: {{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.startupProbe }}
startupProbe: {{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.securityContext }}
securityContext: {{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.resources}}
resources: {{- toYaml . | nindent 8 }}
{{- end }}
volumeMounts:
- name: config
mountPath: /app/config
readOnly: true
- name: data
mountPath: /app/data
{{- with .Values.volumeMounts }}
{{- tpl (toYaml .) $ | nindent 8 }}
{{- end }}
{{- with .Values.dnsPolicy }}
dnsPolicy: {{ . }}
{{- end }}
{{- with .Values.hostNetwork }}
hostNetwork: {{ . }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.initContainers }}
initContainers: {{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.restartPolicy }}
restartPolicy: {{ . }}
{{- end }}
serviceAccountName: {{ include "wg-portal.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext: {{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations: {{- toYaml . | nindent 4 }}
{{- end }}
volumes:
- name: config
secret:
secretName: {{ include "wg-portal.fullname" . }}
{{- if not .Values.persistence.enabled }}
- name: data
emptyDir: {}
{{- else if eq .Values.workloadType "Deployment" }}
- name: data
persistentVolumeClaim:
claimName: {{ include "wg-portal.fullname" . }}
{{- end }}
{{- with .Values.volumes }}
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
{{- end -}}

View File

@@ -0,0 +1,17 @@
{{- if eq .Values.workloadType "Deployment" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "wg-portal.fullname" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
{{- with .Values.revisionHistoryLimit }}
revisionHistoryLimit: {{ . }}
{{- end }}
{{- with .Values.strategy }}
strategy: {{- toYaml . | nindent 4 }}
{{- end }}
selector:
matchLabels: {{- include "wg-portal.selectorLabels" . | nindent 6 }}
template: {{- include "wg-portal.podTemplate" . | nindent 4 }}
{{- end -}}

View File

@@ -0,0 +1,4 @@
{{- range .Values.extraDeploy -}}
{{- tpl (toYaml .) $ }}
---
{{- end -}}

View File

@@ -0,0 +1,47 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{- with .Values.ingress.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "wg-portal.fullname" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
ingressClassName: {{ .Values.ingress.className }}
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: {{ default "ImplementationSpecific" .pathType }}
backend:
service:
name: {{ include "wg-portal.fullname" . }}-web
port:
name: http
{{- range .Values.ingress.extraHosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ default "ImplementationSpecific" .pathType }}
backend:
service:
name: {{ include "wg-portal.fullname" . }}-web
port:
name: http
{{- end }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,11 @@
{{- if and .Values.persistence.enabled (eq .Values.workloadType "Deployment") -}}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
{{- with .Values.persistence.annotations }}
annotations: {{- toYaml . | nindent 4}}
{{- end }}
name: {{ include "wg-portal.fullname" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec: {{- include "wg-portal.pvc" . | nindent 2 }}
{{- end -}}

View File

@@ -0,0 +1,41 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ include "wg-portal.fullname" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
stringData:
config.yml: |
advanced:
start_listen_port: {{ .Values.service.wireguard.ports | sortAlpha | first }}
{{- with .Values.config.advanced }}
{{- tpl (toYaml (omit . "start_listen_port")) $ | nindent 6 }}
{{- end }}
{{- with .Values.config.auth }}
auth: {{- tpl (toYaml .) $ | nindent 6 }}
{{- end }}
{{- with mustMerge .Values.config.core (include "wg-portal.admin" . | fromYaml) }}
core: {{- tpl (toYaml .) $ | nindent 6 }}
{{- end }}
{{- with .Values.config.database }}
database: {{- tpl (toYaml .) $ | nindent 6 }}
{{- end }}
{{- with .Values.config.mail }}
mail: {{- tpl (toYaml .) $ | nindent 6 }}
{{- end }}
{{- with .Values.config.statistics }}
statistics: {{- tpl (toYaml .) $ | nindent 6 }}
{{- end }}
web:
listening_address: :{{ .Values.service.web.port }}
{{- if and .Values.ingress.enabled (not (hasKey .Values.config.web "external_url")) }}
{{- $proto := ternary "http" "https" (empty .Values.ingress.tls) }}
external_url: {{ trimSuffix "/" (printf "%s://%s%s" $proto .Values.ingress.host .Values.ingress.path) }}
{{- end }}
{{- with .Values.config.web }}
{{- tpl (toYaml (omit . "listening_address")) $ | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
{{- with .Values.service.web.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "wg-portal.fullname" . }}-web
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
ports:
- port: {{ .Values.service.web.port }}
targetPort: http
protocol: TCP
name: http
selector: {{- include "wg-portal.selectorLabels" . | nindent 4 }}
type: {{ .Values.service.web.type }}

View File

@@ -0,0 +1,27 @@
apiVersion: v1
kind: Service
metadata:
{{- with .Values.service.wireguard.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "wg-portal.fullname" . }}-wireguard
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
{{- with .Values.service.wireguard.externalTrafficPolicy }}
externalTrafficPolicy: {{ . }}
{{- end }}
{{- with .Values.service.wireguard.loadBalancerSourceRanges }}
loadBalancerSourceRanges: {{- toYaml . | nindent 4 }}
{{- end }}
ports:
{{- range $index, $port := .Values.service.wireguard.ports }}
- port: {{ $port }}
targetPort: wg{{ $index }}
protocol: UDP
name: wg{{ $index }}
{{- end }}
selector: {{- include "wg-portal.selectorLabels" . | nindent 4 }}
{{- with .Values.service.wireguard.sessionAffinity }}
sessionAffinity: {{ . }}
{{- end }}
type: {{ .Values.service.wireguard.type }}

View File

@@ -0,0 +1,10 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "wg-portal.serviceAccountName" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,24 @@
{{- if eq .Values.workloadType "StatefulSet" -}}
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "wg-portal.fullname" . }}
labels: {{- include "wg-portal.labels" . | nindent 4 }}
spec:
{{- with .Values.revisionHistoryLimit }}
revisionHistoryLimit: {{ . }}
{{- end }}
{{- with .Values.strategy }}
updateStrategy: {{- toYaml . | nindent 4 }}
{{- end }}
serviceName: {{ template "wg-portal.fullname" . }}-web
selector:
matchLabels: {{- include "wg-portal.selectorLabels" . | nindent 6 }}
template: {{- include "wg-portal.podTemplate" . | nindent 4 }}
{{- if .Values.persistence.enabled }}
volumeClaimTemplates:
- metadata:
name: data
spec: {{- include "wg-portal.pvc" . | nindent 8 }}
{{- end -}}
{{- end -}}