feat(deploy): add Helm chart for k3s and production Kubernetes
Include values profiles, secrets handling, TLS hooks, HPA/PDB, and in-cluster data services.
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
# Pargar deploy
|
||||||
|
|
||||||
|
Full deployment guide and production checklist: **[`docs/deployment.md`](../docs/deployment.md)**
|
||||||
|
Security & secrets: [`docs/security.md`](../docs/security.md) · Ops / backup: [`docs/operations.md`](../docs/operations.md)
|
||||||
|
|
||||||
|
Edge: **Traefik v3.7** (Compose needs Traefik ≥3.6.1 on Docker Engine 29+).
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```text
|
||||||
|
deploy/
|
||||||
|
compose/
|
||||||
|
compose.yaml # shared app + data + Traefik labels
|
||||||
|
compose.dev.yaml # laptop TLS default, DB ports on 127.0.0.1
|
||||||
|
compose.prod.yaml # Let's Encrypt, no host DB ports
|
||||||
|
traefik/dynamic/ # middlewares
|
||||||
|
helm/pargar/ # chart + values-k3s / values-prod
|
||||||
|
scripts/
|
||||||
|
compose-dev.sh compose-prod.sh k3s-load-images.sh helm-k3s.sh backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compose — development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
./scripts/compose-dev.sh up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
- App: https://localhost
|
||||||
|
- Traefik dashboard: http://127.0.0.1:8088
|
||||||
|
|
||||||
|
## Compose — production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.prod.example .env.prod
|
||||||
|
./scripts/compose-prod.sh up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
## k3s + Helm
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/k3s-load-images.sh
|
||||||
|
./scripts/helm-k3s.sh
|
||||||
|
curl -k https://pargar.local/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n pargar get secret pargar-app -o jsonpath='{.data.admin-password}' | base64 -d; echo
|
||||||
|
```
|
||||||
|
|
||||||
|
Values: `values.yaml` · `values-k3s.yaml` · `values-prod.yaml`
|
||||||
|
Lint: `helm lint ./deploy/helm/pargar -f ./deploy/helm/pargar/values-k3s.yaml`
|
||||||
|
|
||||||
|
## Routing
|
||||||
|
|
||||||
|
| Path | Service |
|
||||||
|
|------|---------|
|
||||||
|
| `/api/*`, `/media/*` | backend |
|
||||||
|
| `/api/certificates/*`, `/c/*` | backend + noindex |
|
||||||
|
| else | frontend |
|
||||||
|
|
||||||
|
WS: `/api/ws` via Traefik.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
.git
|
||||||
|
*.md
|
||||||
|
*.tgz
|
||||||
|
secrets*.yaml
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: pargar
|
||||||
|
description: Pargar gated LMS - Go API, Next.js frontend, Postgres, Redis, S3-compatible storage
|
||||||
|
type: application
|
||||||
|
version: 0.2.0
|
||||||
|
appVersion: "0.1.0"
|
||||||
|
keywords:
|
||||||
|
- lms
|
||||||
|
- pargar
|
||||||
|
- traefik
|
||||||
|
maintainers:
|
||||||
|
- name: Pargar
|
||||||
|
home: https://github.com/example/pargar
|
||||||
|
sources:
|
||||||
|
- https://github.com/example/pargar
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
Pargar {{ .Chart.AppVersion }} installed as release "{{ .Release.Name }}" in namespace "{{ .Release.Namespace }}".
|
||||||
|
|
||||||
|
Public URL: {{ .Values.global.publicUrl }}
|
||||||
|
Domain: {{ .Values.global.domain }}
|
||||||
|
|
||||||
|
1) Ensure DNS /hosts points to your Traefik entrypoint:
|
||||||
|
{{ .Values.global.domain }} → Traefik LoadBalancer / node IP
|
||||||
|
|
||||||
|
2) Images must exist on the cluster nodes (k3s local):
|
||||||
|
docker compose -f deploy/compose/compose.yaml -f deploy/compose/compose.dev.yaml build
|
||||||
|
docker save pargar-backend:local pargar-frontend:local | sudo k3s ctr images import -
|
||||||
|
|
||||||
|
3) Upgrade / install:
|
||||||
|
helm upgrade --install {{ .Release.Name }} ./deploy/helm/pargar \
|
||||||
|
-n {{ .Release.Namespace }} --create-namespace \
|
||||||
|
-f deploy/helm/pargar/values-k3s.yaml
|
||||||
|
|
||||||
|
4) Health:
|
||||||
|
kubectl -n {{ .Release.Namespace }} get pods,ingressroute,svc
|
||||||
|
curl -k {{ .Values.global.publicUrl }}/api/health
|
||||||
|
|
||||||
|
{{- if not .Values.ingress.tls.existingSecret }}
|
||||||
|
|
||||||
|
TLS: chart-managed self-signed certificate (browser warning expected).
|
||||||
|
For production set ingress.tls.existingSecret (cert-manager).
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "pargar.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.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 "pargar.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "pargar.chart" . }}
|
||||||
|
{{ include "pargar.selectorLabels" . }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "pargar.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "pargar.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.appSecretName" -}}
|
||||||
|
{{- if .Values.backend.existingSecret }}
|
||||||
|
{{- .Values.backend.existingSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-app" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.postgresSecretName" -}}
|
||||||
|
{{- if .Values.postgres.existingSecret }}
|
||||||
|
{{- .Values.postgres.existingSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-postgres" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.redisSecretName" -}}
|
||||||
|
{{- if .Values.redis.existingSecret }}
|
||||||
|
{{- .Values.redis.existingSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-redis" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.rustfsSecretName" -}}
|
||||||
|
{{- if .Values.rustfs.existingSecret }}
|
||||||
|
{{- .Values.rustfs.existingSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-rustfs" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.tlsSecretName" -}}
|
||||||
|
{{- if .Values.ingress.tls.existingSecret }}
|
||||||
|
{{- .Values.ingress.tls.existingSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-tls" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.postgresHost" -}}
|
||||||
|
{{- printf "%s-postgres" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.redisHost" -}}
|
||||||
|
{{- printf "%s-redis" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pargar.rustfsHost" -}}
|
||||||
|
{{- printf "%s-rustfs" (include "pargar.fullname" .) }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Resolve container image: optional global.imageRegistry + repository:tag
|
||||||
|
Usage: {{ include "pargar.image" (dict "root" . "image" .Values.backend.image) }}
|
||||||
|
*/}}
|
||||||
|
{{- define "pargar.image" -}}
|
||||||
|
{{- $registry := .root.Values.global.imageRegistry | default "" -}}
|
||||||
|
{{- $repo := .image.repository -}}
|
||||||
|
{{- $tag := .image.tag | default .root.Chart.AppVersion | toString -}}
|
||||||
|
{{- if $registry -}}
|
||||||
|
{{- printf "%s/%s:%s" (trimSuffix "/" $registry) $repo $tag -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s:%s" $repo $tag -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
{{- if .Values.backend.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .Values.backend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
selector:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
{{- if not .Values.backend.autoscaling.enabled }}
|
||||||
|
replicas: {{ .Values.backend.replicaCount }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "pargar.serviceAccountName" . }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: {{ include "pargar.image" (dict "root" . "image" .Values.backend.image) | quote }}
|
||||||
|
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.backend.service.port }}
|
||||||
|
env:
|
||||||
|
- name: PORT
|
||||||
|
value: {{ .Values.backend.service.port | quote }}
|
||||||
|
- name: PUBLIC_URL
|
||||||
|
value: {{ .Values.global.publicUrl | quote }}
|
||||||
|
- name: FRONTEND_ORIGINS
|
||||||
|
value: {{ .Values.global.frontendOrigins | quote }}
|
||||||
|
- name: TRUSTED_PROXY_CIDRS
|
||||||
|
value: {{ .Values.global.trustedProxyCIDRs | quote }}
|
||||||
|
- name: DEV_MODE
|
||||||
|
value: {{ .Values.backend.env.devMode | quote }}
|
||||||
|
- name: SEED_CURRICULUM
|
||||||
|
value: {{ .Values.backend.env.seedCurriculum | quote }}
|
||||||
|
- name: ADMIN_NAME
|
||||||
|
value: {{ .Values.backend.admin.name | quote }}
|
||||||
|
- name: ADMIN_USERNAME
|
||||||
|
value: {{ .Values.backend.admin.username | quote }}
|
||||||
|
- name: ADMIN_EMAIL
|
||||||
|
value: {{ .Values.backend.admin.email | quote }}
|
||||||
|
- name: JWT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: jwt-secret
|
||||||
|
- name: ADMIN_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: admin-password
|
||||||
|
- name: METRICS_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: metrics-token
|
||||||
|
optional: true
|
||||||
|
- name: DONATION_ENABLED
|
||||||
|
value: {{ .Values.backend.env.donationEnabled | quote }}
|
||||||
|
- name: PHYSICAL_CERT_ENABLED
|
||||||
|
value: {{ .Values.backend.env.physicalCertEnabled | quote }}
|
||||||
|
- name: PHYSICAL_CERT_PRICE_IRR
|
||||||
|
value: {{ .Values.backend.env.physicalCertPriceIrr | quote }}
|
||||||
|
- name: PHYSICAL_CERT_WINDOW_DAYS
|
||||||
|
value: {{ .Values.backend.env.physicalCertWindowDays | quote }}
|
||||||
|
- name: OTEL_EXPORTER_OTLP_ENDPOINT
|
||||||
|
value: {{ .Values.backend.env.otelEndpoint | quote }}
|
||||||
|
- name: OTEL_SERVICE_NAME
|
||||||
|
value: {{ .Values.backend.env.otelServiceName | quote }}
|
||||||
|
- name: STORAGE_DRIVER
|
||||||
|
value: s3
|
||||||
|
- name: STORAGE_REGION
|
||||||
|
value: {{ .Values.rustfs.region | quote }}
|
||||||
|
- name: STORAGE_BUCKET
|
||||||
|
value: {{ .Values.rustfs.bucket | quote }}
|
||||||
|
{{- if .Values.postgres.enabled }}
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: {{ .Values.postgres.auth.username | quote }}
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: {{ .Values.postgres.auth.database | quote }}
|
||||||
|
- name: POSTGRES_HOST
|
||||||
|
value: {{ include "pargar.postgresHost" . | quote }}
|
||||||
|
- name: POSTGRES_PORT
|
||||||
|
value: "5432"
|
||||||
|
- name: POSTGRES_SSLMODE
|
||||||
|
value: "disable"
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.postgresSecretName" . }}
|
||||||
|
key: postgres-password
|
||||||
|
{{- else }}
|
||||||
|
- name: DATABASE_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: database-url
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.redis.enabled }}
|
||||||
|
- name: REDIS_HOST
|
||||||
|
value: {{ include "pargar.redisHost" . | quote }}
|
||||||
|
- name: REDIS_PORT
|
||||||
|
value: "6379"
|
||||||
|
- name: REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.redisSecretName" . }}
|
||||||
|
key: redis-password
|
||||||
|
{{- else }}
|
||||||
|
- name: REDIS_URL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: redis-url
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.rustfs.enabled }}
|
||||||
|
- name: STORAGE_ENDPOINT
|
||||||
|
value: {{ printf "http://%s:9000" (include "pargar.rustfsHost" .) | quote }}
|
||||||
|
- name: STORAGE_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.rustfsSecretName" . }}
|
||||||
|
key: access-key
|
||||||
|
- name: STORAGE_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.rustfsSecretName" . }}
|
||||||
|
key: secret-key
|
||||||
|
{{- else }}
|
||||||
|
- name: STORAGE_ENDPOINT
|
||||||
|
value: {{ required "external.storageEndpoint required when rustfs.enabled=false" .Values.external.storageEndpoint | quote }}
|
||||||
|
- name: STORAGE_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: storage-access-key
|
||||||
|
- name: STORAGE_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.appSecretName" . }}
|
||||||
|
key: storage-secret-key
|
||||||
|
{{- end }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 10
|
||||||
|
{{- with .Values.backend.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
{{- if and .Values.postgres.enabled .Values.backup.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-backups
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backup
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
{{- if .Values.backup.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.backup.persistence.storageClass | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.backup.persistence.size | quote }}
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-pg-backup
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backup
|
||||||
|
spec:
|
||||||
|
schedule: {{ .Values.backup.schedule | quote }}
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 3
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 12 }}
|
||||||
|
app.kubernetes.io/component: backup
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 999
|
||||||
|
containers:
|
||||||
|
- name: pg-dump
|
||||||
|
image: {{ .Values.backup.image | quote }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: PGHOST
|
||||||
|
value: {{ include "pargar.postgresHost" . | quote }}
|
||||||
|
- name: PGPORT
|
||||||
|
value: "5432"
|
||||||
|
- name: PGUSER
|
||||||
|
value: {{ .Values.postgres.auth.username | quote }}
|
||||||
|
- name: PGDATABASE
|
||||||
|
value: {{ .Values.postgres.auth.database | quote }}
|
||||||
|
- name: RETENTION_DAYS
|
||||||
|
value: {{ .Values.backup.retentionDays | quote }}
|
||||||
|
- name: PGPASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.postgresSecretName" . }}
|
||||||
|
key: postgres-password
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -ec
|
||||||
|
- |
|
||||||
|
set -euo pipefail
|
||||||
|
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||||
|
OUT="/backups/pargar-${STAMP}.sql.gz"
|
||||||
|
echo "Writing ${OUT}"
|
||||||
|
pg_dump --no-owner --no-acl | gzip -c > "${OUT}"
|
||||||
|
find /backups -type f -name 'pargar-*.sql.gz' -mtime +"${RETENTION_DAYS}" -print -delete || true
|
||||||
|
ls -lh /backups || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: backups
|
||||||
|
mountPath: /backups
|
||||||
|
volumes:
|
||||||
|
- name: backups
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "pargar.fullname" . }}-backups
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.tls.enabled .Values.certManager.enabled }}
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-tls
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
secretName: {{ include "pargar.tlsSecretName" . }}
|
||||||
|
duration: {{ .Values.certManager.duration | default "2160h" | quote }}
|
||||||
|
renewBefore: {{ .Values.certManager.renewBefore | default "360h" | quote }}
|
||||||
|
issuerRef:
|
||||||
|
name: {{ required "certManager.issuerRef.name required when certManager.enabled" .Values.certManager.issuerRef.name | quote }}
|
||||||
|
kind: {{ .Values.certManager.issuerRef.kind | default "ClusterIssuer" | quote }}
|
||||||
|
{{- if .Values.certManager.issuerRef.group }}
|
||||||
|
group: {{ .Values.certManager.issuerRef.group | quote }}
|
||||||
|
{{- end }}
|
||||||
|
dnsNames:
|
||||||
|
- {{ .Values.global.domain | quote }}
|
||||||
|
{{- range .Values.certManager.extraDnsNames }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
{{- if .Values.frontend.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .Values.frontend.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
selector:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
{{- if not .Values.frontend.autoscaling.enabled }}
|
||||||
|
replicas: {{ .Values.frontend.replicaCount }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "pargar.serviceAccountName" . }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
image: {{ include "pargar.image" (dict "root" . "image" .Values.frontend.image) | quote }}
|
||||||
|
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
- name: NODE_ENV
|
||||||
|
value: production
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.frontend.service.port }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 10
|
||||||
|
{{- with .Values.frontend.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
{{- if and .Values.backend.enabled .Values.backend.autoscaling.enabled }}
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: {{ include "pargar.fullname" . }}-backend
|
||||||
|
minReplicas: {{ .Values.backend.autoscaling.minReplicas }}
|
||||||
|
maxReplicas: {{ .Values.backend.autoscaling.maxReplicas }}
|
||||||
|
metrics:
|
||||||
|
{{- if .Values.backend.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.backend.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.autoscaling.targetMemoryUtilizationPercentage }}
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: memory
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.backend.autoscaling.targetMemoryUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .Values.frontend.enabled .Values.frontend.autoscaling.enabled }}
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: {{ include "pargar.fullname" . }}-frontend
|
||||||
|
minReplicas: {{ .Values.frontend.autoscaling.minReplicas }}
|
||||||
|
maxReplicas: {{ .Values.frontend.autoscaling.maxReplicas }}
|
||||||
|
metrics:
|
||||||
|
{{- if .Values.frontend.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.frontend.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.autoscaling.targetMemoryUtilizationPercentage }}
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: memory
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.frontend.autoscaling.targetMemoryUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{{- if and .Values.ingress.enabled (not .Values.ingress.useIngressRoute) }}
|
||||||
|
{{- $fullName := include "pargar.fullname" . }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.middlewares: {{ .Release.Namespace }}-{{ $fullName }}-security-headers@kubernetescrd,{{ .Release.Namespace }}-{{ $fullName }}-compress@kubernetescrd
|
||||||
|
{{- if .Values.ingress.tls.clusterIssuer }}
|
||||||
|
cert-manager.io/cluster-issuer: {{ .Values.ingress.tls.clusterIssuer | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
ingressClassName: {{ .Values.ingress.className | quote }}
|
||||||
|
{{- if .Values.ingress.tls.enabled }}
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- {{ .Values.global.domain | quote }}
|
||||||
|
secretName: {{ include "pargar.tlsSecretName" . }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.global.domain | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /api
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}-backend
|
||||||
|
port:
|
||||||
|
number: {{ .Values.backend.service.port }}
|
||||||
|
- path: /media
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}-backend
|
||||||
|
port:
|
||||||
|
number: {{ .Values.backend.service.port }}
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}-frontend
|
||||||
|
port:
|
||||||
|
number: {{ .Values.frontend.service.port }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.useIngressRoute }}
|
||||||
|
{{- $fullName := include "pargar.fullname" . }}
|
||||||
|
{{- $domain := .Values.global.domain }}
|
||||||
|
{{- $tlsSecret := include "pargar.tlsSecretName" . }}
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-http
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
routes:
|
||||||
|
- match: Host(`{{ $domain }}`)
|
||||||
|
kind: Rule
|
||||||
|
{{- if .Values.middlewares.redirectHttps }}
|
||||||
|
middlewares:
|
||||||
|
- name: {{ $fullName }}-redirect-https
|
||||||
|
{{- end }}
|
||||||
|
services:
|
||||||
|
- name: {{ $fullName }}-frontend
|
||||||
|
port: {{ .Values.frontend.service.port }}
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-https
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
# Certificate public API — highest priority + noindex
|
||||||
|
- match: Host(`{{ $domain }}`) && PathPrefix(`/api/certificates`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 110
|
||||||
|
middlewares:
|
||||||
|
{{- if .Values.middlewares.securityHeaders }}
|
||||||
|
- name: {{ $fullName }}-security-headers
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.middlewares.compress }}
|
||||||
|
- name: {{ $fullName }}-compress
|
||||||
|
{{- end }}
|
||||||
|
- name: {{ $fullName }}-noindex
|
||||||
|
services:
|
||||||
|
- name: {{ $fullName }}-backend
|
||||||
|
port: {{ .Values.backend.service.port }}
|
||||||
|
# API + media (+ WebSocket /api/ws)
|
||||||
|
- match: Host(`{{ $domain }}`) && (PathPrefix(`/api`) || PathPrefix(`/media`))
|
||||||
|
kind: Rule
|
||||||
|
priority: 100
|
||||||
|
middlewares:
|
||||||
|
{{- if .Values.middlewares.securityHeaders }}
|
||||||
|
- name: {{ $fullName }}-security-headers
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.middlewares.compress }}
|
||||||
|
- name: {{ $fullName }}-compress
|
||||||
|
{{- end }}
|
||||||
|
services:
|
||||||
|
- name: {{ $fullName }}-backend
|
||||||
|
port: {{ .Values.backend.service.port }}
|
||||||
|
# Unlisted certificate pages
|
||||||
|
- match: Host(`{{ $domain }}`) && PathPrefix(`/c`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 50
|
||||||
|
middlewares:
|
||||||
|
{{- if .Values.middlewares.securityHeaders }}
|
||||||
|
- name: {{ $fullName }}-security-headers
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.middlewares.compress }}
|
||||||
|
- name: {{ $fullName }}-compress
|
||||||
|
{{- end }}
|
||||||
|
- name: {{ $fullName }}-noindex
|
||||||
|
services:
|
||||||
|
- name: {{ $fullName }}-frontend
|
||||||
|
port: {{ .Values.frontend.service.port }}
|
||||||
|
# Frontend catch-all
|
||||||
|
- match: Host(`{{ $domain }}`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 1
|
||||||
|
middlewares:
|
||||||
|
{{- if .Values.middlewares.securityHeaders }}
|
||||||
|
- name: {{ $fullName }}-security-headers
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.middlewares.compress }}
|
||||||
|
- name: {{ $fullName }}-compress
|
||||||
|
{{- end }}
|
||||||
|
services:
|
||||||
|
- name: {{ $fullName }}-frontend
|
||||||
|
port: {{ .Values.frontend.service.port }}
|
||||||
|
{{- if .Values.ingress.tls.enabled }}
|
||||||
|
tls:
|
||||||
|
secretName: {{ $tlsSecret }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
{{- if .Values.middlewares.securityHeaders }}
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-security-headers
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
headers:
|
||||||
|
stsSeconds: 31536000
|
||||||
|
stsIncludeSubdomains: true
|
||||||
|
contentTypeNosniff: true
|
||||||
|
browserXssFilter: true
|
||||||
|
frameDeny: true
|
||||||
|
referrerPolicy: strict-origin-when-cross-origin
|
||||||
|
permissionsPolicy: "camera=(), microphone=(), geolocation=()"
|
||||||
|
customResponseHeaders:
|
||||||
|
Server: ""
|
||||||
|
Content-Security-Policy: >-
|
||||||
|
default-src 'self'; base-uri 'self'; form-action 'self';
|
||||||
|
frame-ancestors 'none'; object-src 'none';
|
||||||
|
script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';
|
||||||
|
img-src 'self' data: blob:; font-src 'self' data:;
|
||||||
|
media-src 'self' blob:; connect-src 'self' ws: wss:;
|
||||||
|
worker-src 'self' blob:
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.middlewares.compress }}
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-compress
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
compress: {}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-noindex
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
headers:
|
||||||
|
customResponseHeaders:
|
||||||
|
X-Robots-Tag: "noindex, nofollow, noarchive"
|
||||||
|
---
|
||||||
|
{{- if and .Values.ingress.useIngressRoute .Values.middlewares.redirectHttps }}
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-redirect-https
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
redirectScheme:
|
||||||
|
scheme: https
|
||||||
|
permanent: true
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
{{- if .Values.networkPolicy.enabled }}
|
||||||
|
{{- $fullName := include "pargar.fullname" . }}
|
||||||
|
# Default deny all ingress/egress in the release namespace, then allow required paths.
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-default-deny
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
podSelector: {}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
---
|
||||||
|
{{- if .Values.backend.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
{{- range .Values.networkPolicy.ingressNamespaces }}
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: {{ . | quote }}
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- toYaml $.Values.networkPolicy.ingressPodLabels | nindent 14 }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: {{ .Values.backend.service.port }}
|
||||||
|
egress:
|
||||||
|
# DNS
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: kube-system
|
||||||
|
ports:
|
||||||
|
- protocol: UDP
|
||||||
|
port: 53
|
||||||
|
- protocol: TCP
|
||||||
|
port: 53
|
||||||
|
{{- if .Values.postgres.enabled }}
|
||||||
|
- to:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 14 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 5432
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.redis.enabled }}
|
||||||
|
- to:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 14 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 6379
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.rustfs.enabled }}
|
||||||
|
- to:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 14 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 9000
|
||||||
|
{{- else }}
|
||||||
|
# External S3 / managed data when in-cluster rustfs is off
|
||||||
|
- to:
|
||||||
|
- ipBlock:
|
||||||
|
cidr: 0.0.0.0/0
|
||||||
|
except:
|
||||||
|
- 10.0.0.0/8
|
||||||
|
- 172.16.0.0/12
|
||||||
|
- 192.168.0.0/16
|
||||||
|
- 169.254.0.0/16
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 443
|
||||||
|
- protocol: TCP
|
||||||
|
port: 5432
|
||||||
|
- protocol: TCP
|
||||||
|
port: 6379
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
{{- range .Values.networkPolicy.ingressNamespaces }}
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: {{ . | quote }}
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- toYaml $.Values.networkPolicy.ingressPodLabels | nindent 14 }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: {{ .Values.frontend.service.port }}
|
||||||
|
egress:
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: kube-system
|
||||||
|
ports:
|
||||||
|
- protocol: UDP
|
||||||
|
port: 53
|
||||||
|
- protocol: TCP
|
||||||
|
port: 53
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.postgres.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-postgres
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 14 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 5432
|
||||||
|
egress: []
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.redis.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-redis
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 14 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 6379
|
||||||
|
egress: []
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.rustfs.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}-rustfs
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 14 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 9000
|
||||||
|
egress: []
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{{- if and .Values.backend.enabled .Values.backend.podDisruptionBudget.enabled }}
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-backend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
spec:
|
||||||
|
{{- if .Values.backend.podDisruptionBudget.minAvailable }}
|
||||||
|
minAvailable: {{ .Values.backend.podDisruptionBudget.minAvailable }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.backend.podDisruptionBudget.maxUnavailable }}
|
||||||
|
maxUnavailable: {{ .Values.backend.podDisruptionBudget.maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: backend
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .Values.frontend.enabled .Values.frontend.podDisruptionBudget.enabled }}
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-frontend
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
spec:
|
||||||
|
{{- if .Values.frontend.podDisruptionBudget.minAvailable }}
|
||||||
|
minAvailable: {{ .Values.frontend.podDisruptionBudget.minAvailable }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.frontend.podDisruptionBudget.maxUnavailable }}
|
||||||
|
maxUnavailable: {{ .Values.frontend.podDisruptionBudget.maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: frontend
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
{{- if .Values.postgres.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.postgresHost" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: 5432
|
||||||
|
targetPort: postgres
|
||||||
|
selector:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-postgres
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
serviceName: {{ include "pargar.postgresHost" . }}
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: postgres
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: {{ .Values.postgres.image }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: 5432
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: {{ .Values.postgres.auth.username | quote }}
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: {{ .Values.postgres.auth.database | quote }}
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.postgresSecretName" . }}
|
||||||
|
key: postgres-password
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", {{ .Values.postgres.auth.username | quote }}, "-d", {{ .Values.postgres.auth.database | quote }}]
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", {{ .Values.postgres.auth.username | quote }}, "-d", {{ .Values.postgres.auth.database | quote }}]
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 10
|
||||||
|
{{- with .Values.postgres.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
{{- if not .Values.postgres.persistence.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.postgres.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
{{- if .Values.postgres.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.postgres.persistence.storageClass | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.postgres.persistence.size }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
{{- if .Values.redis.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.redisHost" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
port: 6379
|
||||||
|
targetPort: redis
|
||||||
|
selector:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-redis
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
serviceName: {{ include "pargar.redisHost" . }}
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: redis
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: {{ .Values.redis.image }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command: ["sh", "-c", "exec redis-server --requirepass \"$REDIS_PASSWORD\" --appendonly yes"]
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
containerPort: 6379
|
||||||
|
env:
|
||||||
|
- name: REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.redisSecretName" . }}
|
||||||
|
key: redis-password
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", "redis-cli -a \"$REDIS_PASSWORD\" ping | grep -q PONG"]
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", "redis-cli -a \"$REDIS_PASSWORD\" ping | grep -q PONG"]
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 10
|
||||||
|
{{- with .Values.redis.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
{{- if not .Values.redis.persistence.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.redis.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
{{- if .Values.redis.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.redis.persistence.storageClass | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.redis.persistence.size }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
{{- if .Values.rustfs.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.rustfsHost" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- name: s3
|
||||||
|
port: 9000
|
||||||
|
targetPort: s3
|
||||||
|
selector:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.fullname" . }}-rustfs
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
spec:
|
||||||
|
serviceName: {{ include "pargar.rustfsHost" . }}
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: rustfs
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: rustfs
|
||||||
|
image: {{ .Values.rustfs.image }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
args: ["/data"]
|
||||||
|
ports:
|
||||||
|
- name: s3
|
||||||
|
containerPort: 9000
|
||||||
|
env:
|
||||||
|
- name: RUSTFS_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.rustfsSecretName" . }}
|
||||||
|
key: access-key
|
||||||
|
- name: RUSTFS_SECRET_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "pargar.rustfsSecretName" . }}
|
||||||
|
key: secret-key
|
||||||
|
- name: RUSTFS_ADDRESS
|
||||||
|
value: ":9000"
|
||||||
|
- name: RUSTFS_CONSOLE_ADDRESS
|
||||||
|
value: ":9001"
|
||||||
|
- name: RUSTFS_CONSOLE_ENABLE
|
||||||
|
value: {{ .Values.rustfs.consoleEnable | ternary "true" "false" | quote }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: s3
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: s3
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 10
|
||||||
|
{{- with .Values.rustfs.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
{{- if not .Values.rustfs.persistence.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.rustfs.persistence.enabled }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
{{- if .Values.rustfs.persistence.storageClass }}
|
||||||
|
storageClassName: {{ .Values.rustfs.persistence.storageClass | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.rustfs.persistence.size }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{{- if and .Values.backend.enabled (not .Values.backend.existingSecret) }}
|
||||||
|
{{- $name := include "pargar.appSecretName" . }}
|
||||||
|
{{- $existing := lookup "v1" "Secret" .Release.Namespace $name }}
|
||||||
|
{{- $jwt := "" }}
|
||||||
|
{{- $admin := "" }}
|
||||||
|
{{- $metrics := .Values.backend.secrets.metricsToken | default "" }}
|
||||||
|
{{- if and $existing $existing.data }}
|
||||||
|
{{- /* Reuse existing secrets so upgrades do not invalidate sessions / bootstrap. */}}
|
||||||
|
{{- if index $existing.data "jwt-secret" }}
|
||||||
|
{{- $jwt = index $existing.data "jwt-secret" | b64dec }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if index $existing.data "admin-password" }}
|
||||||
|
{{- $admin = index $existing.data "admin-password" | b64dec }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (not $metrics) (index $existing.data "metrics-token") }}
|
||||||
|
{{- $metrics = index $existing.data "metrics-token" | b64dec }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not $jwt }}
|
||||||
|
{{- if and .Values.backend.secrets.jwtSecret (not (hasPrefix "change-me" .Values.backend.secrets.jwtSecret)) (ne .Values.backend.secrets.jwtSecret "") }}
|
||||||
|
{{- $jwt = .Values.backend.secrets.jwtSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $jwt = randAlphaNum 48 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not $admin }}
|
||||||
|
{{- if and .Values.backend.secrets.adminPassword (not (hasPrefix "change-me" .Values.backend.secrets.adminPassword)) (ne .Values.backend.secrets.adminPassword "") }}
|
||||||
|
{{- $admin = .Values.backend.secrets.adminPassword }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $admin = randAlphaNum 24 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ $name }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
pargar.io/secret-source: generated-or-values
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
jwt-secret: {{ $jwt | quote }}
|
||||||
|
admin-password: {{ $admin | quote }}
|
||||||
|
metrics-token: {{ $metrics | quote }}
|
||||||
|
{{- if not .Values.postgres.enabled }}
|
||||||
|
database-url: {{ required "external.databaseUrl required when postgres.enabled=false and existingSecret is empty" .Values.external.databaseUrl | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not .Values.redis.enabled }}
|
||||||
|
redis-url: {{ required "external.redisUrl required when redis.enabled=false and existingSecret is empty" .Values.external.redisUrl | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not .Values.rustfs.enabled }}
|
||||||
|
storage-access-key: {{ required "external.storageAccessKey required when rustfs.enabled=false and existingSecret is empty" .Values.external.storageAccessKey | quote }}
|
||||||
|
storage-secret-key: {{ required "external.storageSecretKey required when rustfs.enabled=false and existingSecret is empty" .Values.external.storageSecretKey | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{{- if and .Values.postgres.enabled (not .Values.postgres.existingSecret) }}
|
||||||
|
{{- $pgName := include "pargar.postgresSecretName" . }}
|
||||||
|
{{- $pgExisting := lookup "v1" "Secret" .Release.Namespace $pgName }}
|
||||||
|
{{- $pgPass := "" }}
|
||||||
|
{{- if and $pgExisting $pgExisting.data (index $pgExisting.data "postgres-password") }}
|
||||||
|
{{- /* Never rotate an existing DB password — Postgres data dir is bound to it. */}}
|
||||||
|
{{- $pgPass = index $pgExisting.data "postgres-password" | b64dec }}
|
||||||
|
{{- else if and .Values.postgres.auth.password (not (hasPrefix "change-me" .Values.postgres.auth.password)) (ne .Values.postgres.auth.password "") }}
|
||||||
|
{{- $pgPass = .Values.postgres.auth.password }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $pgPass = randAlphaNum 32 }}
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ $pgName }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
postgres-password: {{ $pgPass | quote }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .Values.redis.enabled (not .Values.redis.existingSecret) }}
|
||||||
|
{{- $rdName := include "pargar.redisSecretName" . }}
|
||||||
|
{{- $rdExisting := lookup "v1" "Secret" .Release.Namespace $rdName }}
|
||||||
|
{{- $rdPass := "" }}
|
||||||
|
{{- if and $rdExisting $rdExisting.data (index $rdExisting.data "redis-password") }}
|
||||||
|
{{- $rdPass = index $rdExisting.data "redis-password" | b64dec }}
|
||||||
|
{{- else if and .Values.redis.auth.password (not (hasPrefix "change-me" .Values.redis.auth.password)) (ne .Values.redis.auth.password "") }}
|
||||||
|
{{- $rdPass = .Values.redis.auth.password }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $rdPass = randAlphaNum 32 }}
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ $rdName }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
redis-password: {{ $rdPass | quote }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .Values.rustfs.enabled (not .Values.rustfs.existingSecret) }}
|
||||||
|
{{- $rsName := include "pargar.rustfsSecretName" . }}
|
||||||
|
{{- $rsExisting := lookup "v1" "Secret" .Release.Namespace $rsName }}
|
||||||
|
{{- $access := .Values.rustfs.auth.accessKey | default "pargar" }}
|
||||||
|
{{- $secret := "" }}
|
||||||
|
{{- if and $rsExisting $rsExisting.data (index $rsExisting.data "secret-key") }}
|
||||||
|
{{- $secret = index $rsExisting.data "secret-key" | b64dec }}
|
||||||
|
{{- if index $rsExisting.data "access-key" }}
|
||||||
|
{{- $access = index $rsExisting.data "access-key" | b64dec }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else if and .Values.rustfs.auth.secretKey (not (hasPrefix "change-me" .Values.rustfs.auth.secretKey)) (ne .Values.rustfs.auth.secretKey "") }}
|
||||||
|
{{- $secret = .Values.rustfs.auth.secretKey }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $secret = randAlphaNum 40 }}
|
||||||
|
{{- end }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ $rsName }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
access-key: {{ $access | quote }}
|
||||||
|
secret-key: {{ $secret | quote }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pargar.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.tls.enabled (not .Values.ingress.tls.existingSecret) (not .Values.certManager.enabled) }}
|
||||||
|
{{- $secretName := include "pargar.tlsSecretName" . }}
|
||||||
|
{{- $existing := lookup "v1" "Secret" .Release.Namespace $secretName }}
|
||||||
|
{{- $cn := .Values.global.domain }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ $secretName }}
|
||||||
|
labels:
|
||||||
|
{{- include "pargar.labels" . | nindent 4 }}
|
||||||
|
type: kubernetes.tls
|
||||||
|
data:
|
||||||
|
{{- if $existing }}
|
||||||
|
tls.crt: {{ index $existing.data "tls.crt" }}
|
||||||
|
tls.key: {{ index $existing.data "tls.key" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $cert := genSelfSignedCert $cn nil (list $cn) 3650 }}
|
||||||
|
tls.crt: {{ $cert.Cert | b64enc }}
|
||||||
|
tls.key: {{ $cert.Key | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Local k3s profile — self-signed TLS, in-cluster data, single replicas.
|
||||||
|
# helm upgrade --install pargar ./deploy/helm/pargar -n pargar --create-namespace -f deploy/helm/pargar/values-k3s.yaml
|
||||||
|
#
|
||||||
|
# After install, add to /etc/hosts: <NODE_IP> pargar.local
|
||||||
|
|
||||||
|
global:
|
||||||
|
domain: pargar.local
|
||||||
|
publicUrl: https://pargar.local
|
||||||
|
frontendOrigins: "https://pargar.local"
|
||||||
|
|
||||||
|
backend:
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: pargar-backend
|
||||||
|
tag: local
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
seedCurriculum: "true"
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: pargar-frontend
|
||||||
|
tag: local
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 5Gi
|
||||||
|
|
||||||
|
redis:
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
rustfs:
|
||||||
|
enabled: true
|
||||||
|
persistence:
|
||||||
|
size: 10Gi
|
||||||
|
consoleEnable: false
|
||||||
|
|
||||||
|
backup:
|
||||||
|
enabled: true
|
||||||
|
schedule: "0 3 * * *"
|
||||||
|
retentionDays: 7
|
||||||
|
persistence:
|
||||||
|
size: 2Gi
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
useIngressRoute: true
|
||||||
|
tls:
|
||||||
|
enabled: true
|
||||||
|
existingSecret: "" # chart generates self-signed for pargar.local
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# Production profile — external data plane, registry images, HPA/PDB/NetworkPolicy, cert-manager.
|
||||||
|
# helm upgrade --install pargar ./deploy/helm/pargar -n pargar --create-namespace \
|
||||||
|
# -f deploy/helm/pargar/values-prod.yaml
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# - images pushed to ghcr.io/pargar/{backend,frontend}:<tag>
|
||||||
|
# - Secret pargar-app (jwt-secret, admin-password, metrics-token, database-url, redis-url,
|
||||||
|
# storage-access-key, storage-secret-key)
|
||||||
|
# - cert-manager ClusterIssuer letsencrypt-prod
|
||||||
|
# - imagePullSecrets if the registry is private
|
||||||
|
|
||||||
|
global:
|
||||||
|
domain: app.example.com
|
||||||
|
publicUrl: https://app.example.com
|
||||||
|
frontendOrigins: "https://app.example.com"
|
||||||
|
imageRegistry: ghcr.io/pargar
|
||||||
|
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: ghcr-pull
|
||||||
|
|
||||||
|
backend:
|
||||||
|
replicaCount: 2
|
||||||
|
image:
|
||||||
|
repository: backend
|
||||||
|
tag: "0.1.0"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
existingSecret: pargar-app
|
||||||
|
env:
|
||||||
|
devMode: "false"
|
||||||
|
seedCurriculum: "false"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 1Gi
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 8
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 1
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
replicaCount: 2
|
||||||
|
image:
|
||||||
|
repository: frontend
|
||||||
|
tag: "0.1.0"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 1Gi
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 8
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 1
|
||||||
|
|
||||||
|
# Prefer managed Postgres / Redis / object storage in real prod.
|
||||||
|
postgres:
|
||||||
|
enabled: false
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
rustfs:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
external:
|
||||||
|
databaseUrl: "" # prefer secret key database-url on pargar-app
|
||||||
|
redisUrl: ""
|
||||||
|
storageEndpoint: "https://s3.example.com"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
useIngressRoute: true
|
||||||
|
tls:
|
||||||
|
enabled: true
|
||||||
|
existingSecret: "" # Certificate CR owns the secret below
|
||||||
|
clusterIssuer: letsencrypt-prod
|
||||||
|
|
||||||
|
certManager:
|
||||||
|
enabled: true
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
||||||
|
|
||||||
|
networkPolicy:
|
||||||
|
enabled: true
|
||||||
|
ingressNamespaces:
|
||||||
|
- kube-system
|
||||||
|
ingressPodLabels:
|
||||||
|
app.kubernetes.io/name: traefik
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
# Default values — safe for local k3s. Override with values-k3s.yaml / values-prod.yaml.
|
||||||
|
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
global:
|
||||||
|
# Public hostname (Ingress / TLS / PUBLIC_URL)
|
||||||
|
domain: pargar.local
|
||||||
|
# Full public origin browsers use (must match Ingress TLS host)
|
||||||
|
publicUrl: https://pargar.local
|
||||||
|
frontendOrigins: "https://pargar.local"
|
||||||
|
# Docker/k8s pod+service CIDRs — Traefik peer is trusted for X-Forwarded-*
|
||||||
|
trustedProxyCIDRs: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8,::1/128"
|
||||||
|
# Optional registry prefix, e.g. ghcr.io/pargar → images become ghcr.io/pargar/<repository>:<tag>
|
||||||
|
imageRegistry: ""
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
backend:
|
||||||
|
enabled: true
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: pargar-backend
|
||||||
|
tag: local
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
service:
|
||||||
|
port: 8080
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 512Mi
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 6
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
minAvailable: 1
|
||||||
|
env:
|
||||||
|
devMode: "false"
|
||||||
|
seedCurriculum: "false"
|
||||||
|
donationEnabled: "true"
|
||||||
|
# Offline payment only — leave off until ops process is ready; enable in admin settings.
|
||||||
|
physicalCertEnabled: "false"
|
||||||
|
physicalCertPriceIrr: "2500000"
|
||||||
|
physicalCertWindowDays: "30"
|
||||||
|
otelEndpoint: ""
|
||||||
|
otelServiceName: pargar-api
|
||||||
|
# Created only when admin user is missing (see seed.ensureBootstrapAdmin)
|
||||||
|
admin:
|
||||||
|
name: Admin
|
||||||
|
username: admin
|
||||||
|
email: admin@example.com
|
||||||
|
# Prefer existingSecret in production. When empty, chart generate-once (lookup + rand).
|
||||||
|
existingSecret: ""
|
||||||
|
# Optional overrides; leave empty to auto-generate strong values (placeholders like change-me-* are ignored).
|
||||||
|
secrets:
|
||||||
|
jwtSecret: ""
|
||||||
|
adminPassword: ""
|
||||||
|
metricsToken: ""
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
enabled: true
|
||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: pargar-frontend
|
||||||
|
tag: local
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
service:
|
||||||
|
port: 3000
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: 512Mi
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 6
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
minAvailable: 1
|
||||||
|
|
||||||
|
# In-cluster data plane (k3s / small clusters). Disable and point to managed services in prod.
|
||||||
|
postgres:
|
||||||
|
enabled: true
|
||||||
|
image: postgres:16.4-alpine
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 10Gi
|
||||||
|
storageClass: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
auth:
|
||||||
|
username: pargar
|
||||||
|
database: pargar
|
||||||
|
# Empty → chart generate-once; placeholders change-me-* are ignored.
|
||||||
|
password: ""
|
||||||
|
existingSecret: ""
|
||||||
|
|
||||||
|
redis:
|
||||||
|
enabled: true
|
||||||
|
image: redis@sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 2Gi
|
||||||
|
storageClass: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
auth:
|
||||||
|
password: ""
|
||||||
|
existingSecret: ""
|
||||||
|
|
||||||
|
rustfs:
|
||||||
|
enabled: true
|
||||||
|
image: rustfs/rustfs@sha256:1803faef57627e2d9c2e7d89d655d712ddded5389040054987163043fecb6a3c
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 20Gi
|
||||||
|
storageClass: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
auth:
|
||||||
|
accessKey: "pargar-rustfs"
|
||||||
|
secretKey: ""
|
||||||
|
bucket: pargar
|
||||||
|
region: us-east-1
|
||||||
|
consoleEnable: false
|
||||||
|
existingSecret: ""
|
||||||
|
|
||||||
|
# Postgres dump CronJob (in-cluster postgres only).
|
||||||
|
backup:
|
||||||
|
enabled: false
|
||||||
|
schedule: "0 3 * * *"
|
||||||
|
retentionDays: 7
|
||||||
|
persistence:
|
||||||
|
size: 5Gi
|
||||||
|
storageClass: ""
|
||||||
|
image: postgres:16.4-alpine
|
||||||
|
|
||||||
|
# External endpoints when in-cluster postgres/redis/rustfs are disabled.
|
||||||
|
# Prefer putting these in backend.existingSecret in production.
|
||||||
|
external:
|
||||||
|
databaseUrl: ""
|
||||||
|
redisUrl: ""
|
||||||
|
storageEndpoint: ""
|
||||||
|
storageAccessKey: ""
|
||||||
|
storageSecretKey: ""
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
# k3s ships Traefik; use IngressRoute CRDs (recommended) or standard Ingress
|
||||||
|
className: traefik
|
||||||
|
# Use Traefik IngressRoute + Middleware CRDs (true) vs networking.k8s.io/Ingress (false)
|
||||||
|
useIngressRoute: true
|
||||||
|
annotations: {}
|
||||||
|
tls:
|
||||||
|
enabled: true
|
||||||
|
# When empty and certManager.enabled=false, chart creates a self-signed Secret for k3s/dev.
|
||||||
|
# Prefer certManager.enabled=true in prod, or set existingSecret to a pre-created TLS secret.
|
||||||
|
existingSecret: ""
|
||||||
|
# cert-manager ClusterIssuer name (annotation helper when useIngressRoute=false)
|
||||||
|
clusterIssuer: ""
|
||||||
|
|
||||||
|
# cert-manager Certificate CR (writes TLS secret used by IngressRoute)
|
||||||
|
certManager:
|
||||||
|
enabled: false
|
||||||
|
duration: 2160h
|
||||||
|
renewBefore: 360h
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
||||||
|
group: ""
|
||||||
|
extraDnsNames: []
|
||||||
|
|
||||||
|
# Restrict pod traffic (off for local k3s; on in values-prod.yaml)
|
||||||
|
networkPolicy:
|
||||||
|
enabled: false
|
||||||
|
# Namespaces whose pods may reach frontend/backend (Traefik)
|
||||||
|
ingressNamespaces:
|
||||||
|
- kube-system
|
||||||
|
ingressPodLabels:
|
||||||
|
app.kubernetes.io/name: traefik
|
||||||
|
|
||||||
|
middlewares:
|
||||||
|
securityHeaders: true
|
||||||
|
compress: true
|
||||||
|
redirectHttps: true
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
name: ""
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 10001
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 10001
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: false
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
Reference in New Issue
Block a user