From ee7c6c2669462c8cd98e8a42e102acc53995a162 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Sun, 3 May 2026 18:45:51 +0200 Subject: [PATCH 1/4] Initiate trackboard chart --- charts/trackboard/CONTRIBUTING.md | 38 ++++++++ charts/trackboard/Chart.yaml | 14 +++ charts/trackboard/README.md | 34 +++++++ charts/trackboard/templates/NOTES.txt | 20 ++++ charts/trackboard/templates/_helpers.tpl | 49 ++++++++++ charts/trackboard/templates/deployment.yaml | 91 ++++++++++++++++++ charts/trackboard/templates/hpa.yaml | 28 ++++++ charts/trackboard/templates/ingress.yaml | 33 +++++++ .../trackboard/templates/networkpolicy.yaml | 33 +++++++ charts/trackboard/templates/pdb.yaml | 11 +++ charts/trackboard/templates/pvc.yaml | 11 +++ charts/trackboard/templates/secret.yaml | 12 +++ charts/trackboard/templates/service.yaml | 15 +++ charts/trackboard/values.yaml | 92 +++++++++++++++++++ 14 files changed, 481 insertions(+) create mode 100644 charts/trackboard/CONTRIBUTING.md create mode 100644 charts/trackboard/Chart.yaml create mode 100644 charts/trackboard/README.md create mode 100644 charts/trackboard/templates/NOTES.txt create mode 100644 charts/trackboard/templates/_helpers.tpl create mode 100644 charts/trackboard/templates/deployment.yaml create mode 100644 charts/trackboard/templates/hpa.yaml create mode 100644 charts/trackboard/templates/ingress.yaml create mode 100644 charts/trackboard/templates/networkpolicy.yaml create mode 100644 charts/trackboard/templates/pdb.yaml create mode 100644 charts/trackboard/templates/pvc.yaml create mode 100644 charts/trackboard/templates/secret.yaml create mode 100644 charts/trackboard/templates/service.yaml create mode 100644 charts/trackboard/values.yaml diff --git a/charts/trackboard/CONTRIBUTING.md b/charts/trackboard/CONTRIBUTING.md new file mode 100644 index 0000000..aafa5c1 --- /dev/null +++ b/charts/trackboard/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# Contribution guide + +## Validate on a test cluster + +Create the chart configuration file: + +```bash +# example for an Instruqt track, with a Traefik ingress controller, with cert-manager and Let's Encrypt +cat > values.mine.yaml << 'EOF' +ingress: + enabled: true + className: "traefik" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + tls: + enabled: true +EOF +``` + +Install the chart: + +```bash +helm upgrade --install trackboard . -f values.yaml -f values.mine.yaml \ + --set ingress.domain=trackboard.server.$SANDBOX_ID.instruqt.io \ + --namespace trackboard --create-namespace +``` + +Wait for all pods to be ready: + +```bash +kubectl get all -n trackboard +``` + +Open the web application in a browser. + +```bash +echo "https://trackboard.server.${SANDBOX_ID}.instruqt.io" +``` diff --git a/charts/trackboard/Chart.yaml b/charts/trackboard/Chart.yaml new file mode 100644 index 0000000..154aae9 --- /dev/null +++ b/charts/trackboard/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: trackboard +description: Trackboard web application +type: application +version: 0.1.0 +appVersion: "0.1.0" +keywords: + - event + - ctf + - dashboard + - live +maintainers: + - name: devpro + email: bertrand@devpro.fr diff --git a/charts/trackboard/README.md b/charts/trackboard/README.md new file mode 100644 index 0000000..944e5d4 --- /dev/null +++ b/charts/trackboard/README.md @@ -0,0 +1,34 @@ +# Trackboard Helm Chart + +Helm chart for [Trackboard Web Application](https://github.com/devpro/container-images/tree/main/src/trackboard) — designed for container security workshops. + +## Quick Start + +Add the chart repository: + +```bash +helm repo add devpro https://devpro.github.io/helm-charts +helm repo update +``` + +Create the `values.yaml` file to override [default values](values.yaml). + +Install the chart: + +```bash +helm upgrade --install trackboard devpro/trackboard -f values.yaml --namespace trackboard --create-namespace +``` + +## Uninstall + +```bash +helm uninstall trackboard -n trackboard +kubectl delete namespace trackboard +``` + +## Going further + +Check the [contribution guide](CONTRIBUTING.md). + +--- +> ⚠️ **FOR WORKSHOP USE ONLY** — intentionally vulnerable, never expose to the internet. diff --git a/charts/trackboard/templates/NOTES.txt b/charts/trackboard/templates/NOTES.txt new file mode 100644 index 0000000..567b9b9 --- /dev/null +++ b/charts/trackboard/templates/NOTES.txt @@ -0,0 +1,20 @@ +1. Trackboard web application has been deployed. + +{{- if .Values.ingress.enabled }} + URL: https://{{ .Values.ingress.domain }} + + TLS certificate will be issued automatically by cert-manager. + Watch progress with: + kubectl get certificate -n {{ .Release.Namespace }} + kubectl describe certificaterequest -n {{ .Release.Namespace }} +{{- else }} + Port-forward to access locally: + kubectl port-forward svc/{{ include "trackboard.fullname" . }} 3000:3000 -n {{ .Release.Namespace }} + then open http://localhost:3000 +{{- end }} + +2. Check pod status: + kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "trackboard.name" . }} + +3. View logs: + kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "trackboard.name" . }} -f diff --git a/charts/trackboard/templates/_helpers.tpl b/charts/trackboard/templates/_helpers.tpl new file mode 100644 index 0000000..4379db8 --- /dev/null +++ b/charts/trackboard/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "trackboard.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "trackboard.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 }} + +{{/* +Chart label. +*/}} +{{- define "trackboard.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels. +*/}} +{{- define "trackboard.labels" -}} +helm.sh/chart: {{ include "trackboard.chart" . }} +{{ include "trackboard.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels. +*/}} +{{- define "trackboard.selectorLabels" -}} +app.kubernetes.io/name: {{ include "trackboard.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/trackboard/templates/deployment.yaml b/charts/trackboard/templates/deployment.yaml new file mode 100644 index 0000000..c1fb4ca --- /dev/null +++ b/charts/trackboard/templates/deployment.yaml @@ -0,0 +1,91 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + # Because state is on a PVC with `ReadWriteOnce`, keep `replicas: 1`. The app is stateful — multiple replicas would race on the file. + type: Recreate + selector: + matchLabels: + {{- include "trackboard.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + # forces a rollout when values change even if the image tag is the same + checksum/config: {{ toYaml .Values.env | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "trackboard.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + automountServiceAccountToken: false + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.containerSecurityContext }} + securityContext: + {{- toYaml .Values.containerSecurityContext | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: 3000 + protocol: TCP + env: + - name: DATA_FILE + value: /app/data/state.json + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + envFrom: + - secretRef: + name: {{ include "trackboard.fullname" . }} + {{- with .Values.envFrom }} + {{- toYaml . | nindent 12 }} + {{- end }} + startupProbe: + {{- toYaml .Values.startupProbe | nindent 12 }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /app/data + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ include "trackboard.fullname" . }} + restartPolicy: Always diff --git a/charts/trackboard/templates/hpa.yaml b/charts/trackboard/templates/hpa.yaml new file mode 100644 index 0000000..8a469d2 --- /dev/null +++ b/charts/trackboard/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "trackboard.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 +{{- end }} diff --git a/charts/trackboard/templates/ingress.yaml b/charts/trackboard/templates/ingress.yaml new file mode 100644 index 0000000..204a49b --- /dev/null +++ b/charts/trackboard/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + - host: {{ .Values.ingress.domain | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "trackboard.fullname" $ }} + port: + name: http + {{- if .Values.ingress.tls.enabled }} + tls: + - secretName: trackboard-tls + hosts: + - {{ .Values.ingress.domain | quote }} + {{- end }} +{{- end }} diff --git a/charts/trackboard/templates/networkpolicy.yaml b/charts/trackboard/templates/networkpolicy.yaml new file mode 100644 index 0000000..800cf5c --- /dev/null +++ b/charts/trackboard/templates/networkpolicy.yaml @@ -0,0 +1,33 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + {{- include "trackboard.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + # Allow traffic only from the ingress controller namespace + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: traefik + ports: + - protocol: TCP + port: 3000 + egress: + # Allow DNS resolution + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + # Allow outbound HTTPS (for Google Fonts CDN) + - ports: + - protocol: TCP + port: 443 diff --git a/charts/trackboard/templates/pdb.yaml b/charts/trackboard/templates/pdb.yaml new file mode 100644 index 0000000..e5c3cf6 --- /dev/null +++ b/charts/trackboard/templates/pdb.yaml @@ -0,0 +1,11 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +spec: + minAvailable: 1 + selector: + matchLabels: + {{- include "trackboard.selectorLabels" . | nindent 6 }} diff --git a/charts/trackboard/templates/pvc.yaml b/charts/trackboard/templates/pvc.yaml new file mode 100644 index 0000000..22e5938 --- /dev/null +++ b/charts/trackboard/templates/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 100Mi diff --git a/charts/trackboard/templates/secret.yaml b/charts/trackboard/templates/secret.yaml new file mode 100644 index 0000000..14b4691 --- /dev/null +++ b/charts/trackboard/templates/secret.yaml @@ -0,0 +1,12 @@ + +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +type: Opaque +stringData: + ADMIN_PASSWORD: "your-strong-password" + EVENT_NAME: "DevOpsDay Geneva" + EVENT_DATE: "May 2026" diff --git a/charts/trackboard/templates/service.yaml b/charts/trackboard/templates/service.yaml new file mode 100644 index 0000000..ac38825 --- /dev/null +++ b/charts/trackboard/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "trackboard.fullname" . }} + labels: + {{- include "trackboard.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + selector: + {{- include "trackboard.selectorLabels" . | nindent 4 }} + ports: + - name: http + port: {{ .Values.service.port }} + targetPort: http + protocol: TCP diff --git a/charts/trackboard/values.yaml b/charts/trackboard/values.yaml new file mode 100644 index 0000000..a59c739 --- /dev/null +++ b/charts/trackboard/values.yaml @@ -0,0 +1,92 @@ +image: + repository: ghcr.io/devpro/trackboard + tag: "1.0.0" + pullPolicy: IfNotPresent + +imagePullSecrets: [] + # - name: "" + +replicaCount: 1 + +podAnnotations: {} + +resources: {} + # requests: + # cpu: 100m + # memory: 128Mi + # limits: + # cpu: 500m + # memory: 512Mi + +service: + type: ClusterIP + port: 3000 + +ingress: + enabled: false + # e.g. traefik + className: "" + domain: "" + annotations: {} + # cert-manager.io/cluster-issuer: "letsencrypt-prod" + # traefik.ingress.kubernetes.io/router.entrypoints: websecure + # traefik.ingress.kubernetes.io/router.tls: "true" + # traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd + tls: + enabled: false + +startupProbe: + httpGet: + path: /healthz + port: http + failureThreshold: 10 + periodSeconds: 3 + +livenessProbe: + httpGet: + path: /healthz + port: 3000 + initialDelaySeconds: 15 + periodSeconds: 20 + failureThreshold: 3 + +readinessProbe: + httpGet: + path: /healthz + port: 3000 + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + +podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + seccompProfile: + type: RuntimeDefault + +containerSecurityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + capabilities: + drop: + - ALL + +autoscaling: + enabled: false + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 + +nodeSelector: {} +tolerations: [] +affinity: {} + +env: + NODE_ENV: production + NEXT_TELEMETRY_DISABLED: "1" + +# envFrom: +# - secretRef: +# name: "" From 4477743f4af84da64d72fb66efe1fa01805fd6cc Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Sun, 3 May 2026 22:21:37 +0200 Subject: [PATCH 2/4] Update chart --- charts/trackboard/CONTRIBUTING.md | 9 ++++- charts/trackboard/templates/deployment.yaml | 6 +++- .../trackboard/templates/networkpolicy.yaml | 14 ++++---- charts/trackboard/templates/secret.yaml | 7 ++-- charts/trackboard/values.yaml | 36 +++++++++++-------- 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/charts/trackboard/CONTRIBUTING.md b/charts/trackboard/CONTRIBUTING.md index aafa5c1..5686f72 100644 --- a/charts/trackboard/CONTRIBUTING.md +++ b/charts/trackboard/CONTRIBUTING.md @@ -5,7 +5,7 @@ Create the chart configuration file: ```bash -# example for an Instruqt track, with a Traefik ingress controller, with cert-manager and Let's Encrypt +# example with Traefik ingress controller, cert-manager and Let's Encrypt cat > values.mine.yaml << 'EOF' ingress: enabled: true @@ -17,11 +17,18 @@ ingress: EOF ``` + + Install the chart: ```bash helm upgrade --install trackboard . -f values.yaml -f values.mine.yaml \ --set ingress.domain=trackboard.server.$SANDBOX_ID.instruqt.io \ + --set admin.password=mysecretpassword \ --namespace trackboard --create-namespace ``` diff --git a/charts/trackboard/templates/deployment.yaml b/charts/trackboard/templates/deployment.yaml index c1fb4ca..4ad6d9b 100644 --- a/charts/trackboard/templates/deployment.yaml +++ b/charts/trackboard/templates/deployment.yaml @@ -53,12 +53,16 @@ spec: - name: {{ $key }} value: {{ $val | quote }} {{- end }} + {{- if or .Values.admin.password .Values.envFrom }} envFrom: + {{- if .Values.admin.password }} - secretRef: - name: {{ include "trackboard.fullname" . }} + name: {{ include "trackboard.fullname" . }} + {{- end }} {{- with .Values.envFrom }} {{- toYaml . | nindent 12 }} {{- end }} + {{- end }} startupProbe: {{- toYaml .Values.startupProbe | nindent 12 }} livenessProbe: diff --git a/charts/trackboard/templates/networkpolicy.yaml b/charts/trackboard/templates/networkpolicy.yaml index 800cf5c..8e9ccc1 100644 --- a/charts/trackboard/templates/networkpolicy.yaml +++ b/charts/trackboard/templates/networkpolicy.yaml @@ -1,4 +1,5 @@ -apiVersion: networking.k8s.io/v1 +{{- if .Values.networkpolicy.enabled -}} +apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: {{ include "trackboard.fullname" . }} @@ -12,22 +13,23 @@ spec: - Ingress - Egress ingress: - # Allow traffic only from the ingress controller namespace + # allow traffic only from the ingress controller namespace - from: - namespaceSelector: matchLabels: - kubernetes.io/metadata.name: traefik + kubernetes.io/metadata.name: kube-system ports: - protocol: TCP - port: 3000 + port: {{ .Values.service.port }} egress: - # Allow DNS resolution + # allows DNS resolution - ports: - protocol: UDP port: 53 - protocol: TCP port: 53 - # Allow outbound HTTPS (for Google Fonts CDN) + # allows outbound HTTPS (for Google Fonts CDN) - ports: - protocol: TCP port: 443 +{{- end }} diff --git a/charts/trackboard/templates/secret.yaml b/charts/trackboard/templates/secret.yaml index 14b4691..5b603ca 100644 --- a/charts/trackboard/templates/secret.yaml +++ b/charts/trackboard/templates/secret.yaml @@ -1,4 +1,4 @@ - +{{- if .Values.admin.password -}} apiVersion: v1 kind: Secret metadata: @@ -7,6 +7,5 @@ metadata: {{- include "trackboard.labels" . | nindent 4 }} type: Opaque stringData: - ADMIN_PASSWORD: "your-strong-password" - EVENT_NAME: "DevOpsDay Geneva" - EVENT_DATE: "May 2026" + ADMIN_PASSWORD: {{ .Values.admin.password }} +{{- end }} diff --git a/charts/trackboard/values.yaml b/charts/trackboard/values.yaml index a59c739..a836e57 100644 --- a/charts/trackboard/values.yaml +++ b/charts/trackboard/values.yaml @@ -58,20 +58,20 @@ readinessProbe: periodSeconds: 10 failureThreshold: 3 -podSecurityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - -containerSecurityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: false - capabilities: - drop: - - ALL +podSecurityContext: {} + # runAsNonRoot: true + # runAsUser: 1000 + # runAsGroup: 1000 + # fsGroup: 1000 + # seccompProfile: + # type: RuntimeDefault + +containerSecurityContext: {} + # allowPrivilegeEscalation: false + # readOnlyRootFilesystem: false + # capabilities: + # drop: + # - ALL autoscaling: enabled: false @@ -86,7 +86,15 @@ affinity: {} env: NODE_ENV: production NEXT_TELEMETRY_DISABLED: "1" + EVENT_NAME: "DevOpsDay Geneva" + EVENT_DATE: "May 2026" # envFrom: # - secretRef: # name: "" + +networkpolicy: + enabled: false + +admin: + password: "" From 97afb8773c42991258267d321dd986d5c1aa8f3b Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Sun, 3 May 2026 22:23:31 +0200 Subject: [PATCH 3/4] Add comment --- charts/trackboard/CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/charts/trackboard/CONTRIBUTING.md b/charts/trackboard/CONTRIBUTING.md index 5686f72..e5a3467 100644 --- a/charts/trackboard/CONTRIBUTING.md +++ b/charts/trackboard/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contribution guide +# Contribution guide ## Validate on a test cluster @@ -20,6 +20,7 @@ EOF From 365e3af65ee6e8c80ff7f0c983e4aeeddf2a5c00 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Sun, 3 May 2026 23:46:22 +0200 Subject: [PATCH 4/4] Update charts --- .kube-linter.yaml | 1 + charts/drupal/CONTRIBUTING.md | 37 ++++++++++++++++++--- charts/drupal/Chart.yaml | 4 +-- charts/drupal/templates/deployment.yaml | 37 ++++++++++++++++++++- charts/drupal/templates/ingress.yaml | 2 ++ charts/drupal/templates/pvc.yaml | 17 ++++++++++ charts/drupal/values.yaml | 8 +++++ charts/trackboard/templates/deployment.yaml | 2 -- charts/trackboard/templates/hpa.yaml | 28 ---------------- charts/trackboard/templates/pdb.yaml | 11 ------ charts/trackboard/values.yaml | 6 ---- 11 files changed, 99 insertions(+), 54 deletions(-) create mode 100644 charts/drupal/templates/pvc.yaml delete mode 100644 charts/trackboard/templates/hpa.yaml delete mode 100644 charts/trackboard/templates/pdb.yaml diff --git a/.kube-linter.yaml b/.kube-linter.yaml index 81dd88e..271f02b 100644 --- a/.kube-linter.yaml +++ b/.kube-linter.yaml @@ -20,6 +20,7 @@ - run-as-non-root - sorted-keys - privileged-ports + - no-rolling-update-strategy ignorePaths: - charts/**/charts/** # disable for now (too many issues for something to rework from the container image) diff --git a/charts/drupal/CONTRIBUTING.md b/charts/drupal/CONTRIBUTING.md index 58b3762..3d476d7 100644 --- a/charts/drupal/CONTRIBUTING.md +++ b/charts/drupal/CONTRIBUTING.md @@ -5,6 +5,9 @@ Create a `values.mine.yaml` file: ```yaml +image: drupal +tag: 8.9.20 + ingress: enabled: true className: "traefik" @@ -12,23 +15,49 @@ ingress: cert-manager.io/cluster-issuer: "letsencrypt-prod" tls: enabled: true + +persistence: + enabled: true + initImage: ghcr.io/devpro/drupal:8.5.0-postinstall + dbType: sqlite ``` Install the chart: ```bash -helm upgrade --install drupal . -f values.yaml -f values.mine.yaml --namespace drupal --create-namespace \ - --set ingress.domain="drupal.console.$SANDBOX_ID.instruqt.io" +helm upgrade --install drupal . -f values.yaml -f values.mine.yaml \ + --set ingress.domain="drupal.server.$SANDBOX_ID.instruqt.io" \ + --namespace drupal --create-namespace ``` Wait for all pods to be ready: ```bash -kubectl get pod,rs,deploy,svc,ingress,certificate -n drupal +kubectl get pod,rs,deploy,svc,ingress,certificate,pvc,pv -n drupal +``` + +Check init container logs: + +```bash +kubectl logs -n drupal -l app=drupal -c init-sites ``` Open the web application in a browser: ```bash -echo https://drupal.console.$SANDBOX_ID.instruqt.io +echo https://drupal.server.$SANDBOX_ID.instruqt.io +``` + +Cleanup: + +```bash +helm uninstall drupal -n drupal +kubectl get pv --watch +kubectl delete namespace drupal +kubectl get pv | grep drupal ``` + + diff --git a/charts/drupal/Chart.yaml b/charts/drupal/Chart.yaml index 996097a..4ced60f 100644 --- a/charts/drupal/Chart.yaml +++ b/charts/drupal/Chart.yaml @@ -2,8 +2,8 @@ name: drupal description: Drupal Web Application - for container security workshops type: application -version: 1.0.0 -appVersion: "1.0.0" +version: 1.0.1 +appVersion: "8.5.0" keywords: - security - vulnerable diff --git a/charts/drupal/templates/deployment.yaml b/charts/drupal/templates/deployment.yaml index fe39a44..465825c 100644 --- a/charts/drupal/templates/deployment.yaml +++ b/charts/drupal/templates/deployment.yaml @@ -2,10 +2,12 @@ kind: Deployment metadata: name: drupal + labels: + app: drupal spec: replicas: {{ .Values.replicaCount }} strategy: - type: RollingUpdate + type: {{ if eq .Values.persistence.dbType "sqlite" }}Recreate{{ else }}RollingUpdate{{ end }} selector: matchLabels: app: drupal @@ -14,6 +16,27 @@ spec: labels: app: drupal spec: + {{- if and .Values.persistence.enabled .Values.persistence.initImage }} + initContainers: + - name: init-sites + image: {{ .Values.persistence.initImage }} + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - | + # only copy if the PVC is empty (first boot) + if [ -z "$(ls -A /mnt/sites)" ]; then + echo "PVC is empty — seeding from image..." + cp -a /var/www/html/sites/. /mnt/sites/ + echo "Done." + else + echo "PVC already has data — skipping copy." + fi + volumeMounts: + - name: sites + mountPath: /mnt/sites + {{- end }} containers: - name: drupal image: {{ .Values.image }}:{{ .Values.tag }} @@ -28,3 +51,15 @@ spec: port: 80 initialDelaySeconds: 10 periodSeconds: 10 + {{- if .Values.persistence.enabled }} + volumeMounts: + - name: sites + mountPath: /var/www/html/sites + {{- end }} + {{- if .Values.persistence.enabled }} + volumes: + - name: sites + persistentVolumeClaim: + claimName: drupal + {{- end }} + restartPolicy: Always diff --git a/charts/drupal/templates/ingress.yaml b/charts/drupal/templates/ingress.yaml index fcac4a1..164ba3a 100644 --- a/charts/drupal/templates/ingress.yaml +++ b/charts/drupal/templates/ingress.yaml @@ -3,6 +3,8 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: drupal + labels: + app: drupal {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/drupal/templates/pvc.yaml b/charts/drupal/templates/pvc.yaml new file mode 100644 index 0000000..bfac030 --- /dev/null +++ b/charts/drupal/templates/pvc.yaml @@ -0,0 +1,17 @@ +{{- if .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: drupal + labels: + app: drupal +spec: + accessModes: + - ReadWriteOnce + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- end }} diff --git a/charts/drupal/values.yaml b/charts/drupal/values.yaml index e6b1b61..a5a2267 100644 --- a/charts/drupal/values.yaml +++ b/charts/drupal/values.yaml @@ -1,6 +1,7 @@ replicaCount: 1 image: vulhub/drupal tag: 8.5.0 + ingress: enabled: false className: "" # traefik @@ -9,3 +10,10 @@ ingress: # cert-manager.io/cluster-issuer: letsencrypt-prod tls: enabled: false + +persistence: + enabled: false + storageClass: "" + size: 500Mi + initImage: "" + dbType: "" diff --git a/charts/trackboard/templates/deployment.yaml b/charts/trackboard/templates/deployment.yaml index 4ad6d9b..18756e7 100644 --- a/charts/trackboard/templates/deployment.yaml +++ b/charts/trackboard/templates/deployment.yaml @@ -5,9 +5,7 @@ metadata: labels: {{- include "trackboard.labels" . | nindent 4 }} spec: - {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} - {{- end }} strategy: # Because state is on a PVC with `ReadWriteOnce`, keep `replicas: 1`. The app is stateful — multiple replicas would race on the file. type: Recreate diff --git a/charts/trackboard/templates/hpa.yaml b/charts/trackboard/templates/hpa.yaml deleted file mode 100644 index 8a469d2..0000000 --- a/charts/trackboard/templates/hpa.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "trackboard.fullname" . }} - labels: - {{- include "trackboard.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "trackboard.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: 80 -{{- end }} diff --git a/charts/trackboard/templates/pdb.yaml b/charts/trackboard/templates/pdb.yaml deleted file mode 100644 index e5c3cf6..0000000 --- a/charts/trackboard/templates/pdb.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: {{ include "trackboard.fullname" . }} - labels: - {{- include "trackboard.labels" . | nindent 4 }} -spec: - minAvailable: 1 - selector: - matchLabels: - {{- include "trackboard.selectorLabels" . | nindent 6 }} diff --git a/charts/trackboard/values.yaml b/charts/trackboard/values.yaml index a836e57..d2eac54 100644 --- a/charts/trackboard/values.yaml +++ b/charts/trackboard/values.yaml @@ -73,12 +73,6 @@ containerSecurityContext: {} # drop: # - ALL -autoscaling: - enabled: false - minReplicas: 2 - maxReplicas: 10 - targetCPUUtilizationPercentage: 70 - nodeSelector: {} tolerations: [] affinity: {}