feat: add Rancher Helm deployments

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Daniel Noulet 2026-09-20 10:49:09 +02:00
parent d4be4f47e4
commit 3364eacbcc
20 changed files with 924 additions and 1 deletions

View file

@ -0,0 +1,5 @@
.git/
.github/
.idea/
.vscode/
*.tgz

View file

@ -0,0 +1,6 @@
apiVersion: v2
name: go-guess
description: Go Guess recruitment workspace
type: application
version: 0.1.0
appVersion: "0.1.0"

View file

@ -0,0 +1,11 @@
Go Guess has been installed in namespace {{ .Release.Namespace }}.
{{- if .Values.ingress.enabled }}
Open {{ .Values.app.frontendURL }}
{{- else if eq .Values.service.type "NodePort" }}
Open a cluster node on port {{ .Values.service.nodePort }}.
{{- else }}
Run:
kubectl -n {{ .Release.Namespace }} port-forward service/{{ include "go-guess.fullname" . }} 8080:{{ .Values.service.port }}
Then open http://127.0.0.1:8080.
{{- end }}

View file

@ -0,0 +1,41 @@
{{- define "go-guess.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "go-guess.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 }}
{{- define "go-guess.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }}
app.kubernetes.io/name: {{ include "go-guess.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{- define "go-guess.selectorLabels" -}}
app.kubernetes.io/name: {{ include "go-guess.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{- define "go-guess.secretName" -}}
{{- printf "%s-secrets" (include "go-guess.fullname" .) }}
{{- end }}
{{- define "go-guess.postgresqlName" -}}
{{- printf "%s-postgresql" (include "go-guess.fullname" .) }}
{{- end }}
{{- define "go-guess.rabbitmqName" -}}
{{- printf "%s-rabbitmq" (include "go-guess.fullname" .) }}
{{- end }}

View file

@ -0,0 +1,105 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "go-guess.fullname" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
strategy:
type: {{ .Values.strategy.type }}
selector:
matchLabels:
{{- include "go-guess.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: application
template:
metadata:
annotations:
checksum/secrets: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "go-guess.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: application
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
automountServiceAccountToken: false
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: go-guess
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
env:
- name: APP_ENV
value: {{ .Values.app.environment | quote }}
- name: FRONTEND_URL
value: {{ .Values.app.frontendURL | quote }}
- name: TOKEN_TTL
value: {{ .Values.app.tokenTTL | quote }}
- name: MAX_UPLOAD_MB
value: {{ .Values.app.maxUploadMB | quote }}
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ include "go-guess.secretName" . }}
key: database-url
- name: RABBITMQ_URL
valueFrom:
secretKeyRef:
name: {{ include "go-guess.secretName" . }}
key: rabbitmq-url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: {{ include "go-guess.secretName" . }}
key: jwt-secret
ports:
- name: http
containerPort: 8080
protocol: TCP
readinessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 12
livenessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: temporary-files
mountPath: /tmp
volumes:
- name: temporary-files
emptyDir: {}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View file

@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "go-guess.fullname" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "go-guess.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: application
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
{{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
nodePort: {{ .Values.service.nodePort }}
{{- end }}

View file

@ -0,0 +1,35 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "go-guess.fullname" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
{{- with .Values.ingress.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "go-guess.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if .Values.postgresql.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "go-guess.postgresqlName" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
app.kubernetes.io/component: postgresql
spec:
clusterIP: None
selector:
{{- include "go-guess.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: postgresql
ports:
- name: postgresql
port: 5432
targetPort: postgresql
{{- end }}

View file

@ -0,0 +1,92 @@
{{- if .Values.postgresql.enabled }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "go-guess.postgresqlName" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
app.kubernetes.io/component: postgresql
spec:
serviceName: {{ include "go-guess.postgresqlName" . }}
replicas: 1
selector:
matchLabels:
{{- include "go-guess.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: postgresql
template:
metadata:
labels:
{{- include "go-guess.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: postgresql
spec:
automountServiceAccountToken: false
securityContext:
fsGroup: 70
fsGroupChangePolicy: OnRootMismatch
containers:
- name: postgresql
image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}"
imagePullPolicy: {{ .Values.postgresql.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 70
env:
- name: POSTGRES_DB
value: {{ .Values.postgresql.auth.database | quote }}
- name: POSTGRES_USER
value: {{ .Values.postgresql.auth.username | quote }}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "go-guess.secretName" . }}
key: postgresql-password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- name: postgresql
containerPort: 5432
readinessProbe:
exec:
command:
- sh
- -ec
- pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
exec:
command:
- sh
- -ec
- pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"
initialDelaySeconds: 20
periodSeconds: 10
resources:
{{- toYaml .Values.postgresql.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
{{- if not .Values.postgresql.persistence.enabled }}
volumes:
- name: data
emptyDir: {}
{{- end }}
{{- if .Values.postgresql.persistence.enabled }}
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
{{- with .Values.postgresql.persistence.storageClass }}
storageClassName: {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.postgresql.persistence.size }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,18 @@
{{- if .Values.rabbitmq.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "go-guess.rabbitmqName" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
app.kubernetes.io/component: rabbitmq
spec:
clusterIP: None
selector:
{{- include "go-guess.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: rabbitmq
ports:
- name: amqp
port: 5672
targetPort: amqp
{{- end }}

View file

@ -0,0 +1,90 @@
{{- if .Values.rabbitmq.enabled }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "go-guess.rabbitmqName" . }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
app.kubernetes.io/component: rabbitmq
spec:
serviceName: {{ include "go-guess.rabbitmqName" . }}
replicas: 1
selector:
matchLabels:
{{- include "go-guess.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: rabbitmq
template:
metadata:
labels:
{{- include "go-guess.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: rabbitmq
spec:
automountServiceAccountToken: false
securityContext:
fsGroup: 100
fsGroupChangePolicy: OnRootMismatch
containers:
- name: rabbitmq
image: "{{ .Values.rabbitmq.image.repository }}:{{ .Values.rabbitmq.image.tag }}"
imagePullPolicy: {{ .Values.rabbitmq.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 100
env:
- name: RABBITMQ_DEFAULT_USER
value: {{ .Values.rabbitmq.auth.username | quote }}
- name: RABBITMQ_DEFAULT_PASS
valueFrom:
secretKeyRef:
name: {{ include "go-guess.secretName" . }}
key: rabbitmq-password
ports:
- name: amqp
containerPort: 5672
readinessProbe:
exec:
command:
- rabbitmq-diagnostics
- -q
- ping
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 5
livenessProbe:
exec:
command:
- rabbitmq-diagnostics
- -q
- ping
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
resources:
{{- toYaml .Values.rabbitmq.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /var/lib/rabbitmq
{{- if not .Values.rabbitmq.persistence.enabled }}
volumes:
- name: data
emptyDir: {}
{{- end }}
{{- if .Values.rabbitmq.persistence.enabled }}
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
{{- with .Values.rabbitmq.persistence.storageClass }}
storageClassName: {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.rabbitmq.persistence.size }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,34 @@
{{- $name := include "go-guess.secretName" . -}}
{{- $existing := lookup "v1" "Secret" .Release.Namespace $name -}}
{{- $jwt := .Values.secrets.jwtSecret -}}
{{- $postgresPassword := .Values.secrets.postgresqlPassword -}}
{{- $rabbitmqPassword := .Values.secrets.rabbitmqPassword -}}
{{- if and (not $jwt) $existing }}{{ $jwt = index $existing.data "jwt-secret" | b64dec }}{{ end -}}
{{- if and (not $postgresPassword) $existing }}{{ $postgresPassword = index $existing.data "postgresql-password" | b64dec }}{{ end -}}
{{- if and (not $rabbitmqPassword) $existing }}{{ $rabbitmqPassword = index $existing.data "rabbitmq-password" | b64dec }}{{ end -}}
{{- if not $jwt }}{{ $jwt = randAlphaNum 48 }}{{ end -}}
{{- if not $postgresPassword }}{{ $postgresPassword = randAlphaNum 32 }}{{ end -}}
{{- if not $rabbitmqPassword }}{{ $rabbitmqPassword = randAlphaNum 32 }}{{ end -}}
{{- $databaseURL := .Values.secrets.databaseURL -}}
{{- if and (not $databaseURL) .Values.postgresql.enabled -}}
{{- $databaseURL = printf "postgres://%s:%s@%s:5432/%s?sslmode=disable" .Values.postgresql.auth.username ($postgresPassword | urlquery) (include "go-guess.postgresqlName" .) .Values.postgresql.auth.database -}}
{{- end -}}
{{- if not $databaseURL }}{{ fail "secrets.databaseURL is required when postgresql.enabled is false" }}{{ end -}}
{{- $rabbitmqURL := .Values.secrets.rabbitmqURL -}}
{{- if and (not $rabbitmqURL) .Values.rabbitmq.enabled -}}
{{- $rabbitmqURL = printf "amqp://%s:%s@%s:5672/" .Values.rabbitmq.auth.username ($rabbitmqPassword | urlquery) (include "go-guess.rabbitmqName" .) -}}
{{- end -}}
{{- if not $rabbitmqURL }}{{ fail "secrets.rabbitmqURL is required when rabbitmq.enabled is false" }}{{ end -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ $name }}
labels:
{{- include "go-guess.labels" . | nindent 4 }}
type: Opaque
data:
jwt-secret: {{ $jwt | b64enc | quote }}
database-url: {{ $databaseURL | b64enc | quote }}
rabbitmq-url: {{ $rabbitmqURL | b64enc | quote }}
postgresql-password: {{ $postgresPassword | b64enc | quote }}
rabbitmq-password: {{ $rabbitmqPassword | b64enc | quote }}

View file

@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "go-guess.fullname" . }}-test-connection"
labels:
{{- include "go-guess.labels" . | nindent 4 }}
annotations:
helm.sh/hook: test
helm.sh/hook-delete-policy: before-hook-creation
spec:
automountServiceAccountToken: false
restartPolicy: Never
containers:
- name: wget
image: busybox:1.37
command:
- wget
args:
- -qO-
- "http://{{ include "go-guess.fullname" . }}:{{ .Values.service.port }}/api/health"

View file

@ -0,0 +1,44 @@
image:
tag: latest
pullPolicy: Always
app:
environment: development
frontendURL: http://localhost:30080
service:
type: NodePort
nodePort: 30080
ingress:
enabled: false
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 300m
memory: 384Mi
postgresql:
persistence:
enabled: false
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 300m
memory: 384Mi
rabbitmq:
persistence:
enabled: false
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 300m
memory: 384Mi

View file

@ -0,0 +1,41 @@
image:
tag: latest
pullPolicy: IfNotPresent
app:
environment: production
frontendURL: https://go-guess.example.com
service:
type: ClusterIP
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 10m
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
hosts:
- host: go-guess.example.com
paths:
- path: /
pathType: Prefix
tls: []
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: "1"
memory: 768Mi
postgresql:
persistence:
enabled: true
size: 20Gi
rabbitmq:
persistence:
enabled: true
size: 8Gi

View file

@ -0,0 +1,112 @@
nameOverride: ""
fullnameOverride: ""
replicaCount: 1
image:
repository: batty1039.startdedicated.net:5000/go-guess
tag: latest
pullPolicy: IfNotPresent
imagePullSecrets: []
app:
environment: production
frontendURL: http://localhost:8080
tokenTTL: 8h
maxUploadMB: 10
secrets:
jwtSecret: ""
databaseURL: ""
rabbitmqURL: ""
postgresqlPassword: ""
rabbitmqPassword: ""
service:
type: ClusterIP
port: 80
nodePort: null
ingress:
enabled: false
className: nginx
annotations: {}
hosts:
- host: go-guess.local
paths:
- path: /
pathType: Prefix
tls: []
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
podAnnotations: {}
podLabels: {}
podSecurityContext:
fsGroup: 10001
fsGroupChangePolicy: OnRootMismatch
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 10001
strategy:
type: Recreate
postgresql:
enabled: true
image:
repository: postgres
tag: 18-alpine
pullPolicy: IfNotPresent
auth:
username: go_guess
database: go_guess
persistence:
enabled: true
size: 8Gi
storageClass: ""
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
rabbitmq:
enabled: true
image:
repository: rabbitmq
tag: 4-alpine
pullPolicy: IfNotPresent
auth:
username: go_guess
persistence:
enabled: true
size: 4Gi
storageClass: ""
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
nodeSelector: {}
tolerations: []
affinity: {}