# Scale the whole chart down without uninstalling it: scaleDown: true renders # every Deployment/StatefulSet with replicas: 0 (and suspends CronJobs) and # takes precedence over any per-workload replicas value. PVCs, Secrets and # Services stay in place; scaleDown: false brings the workloads back up. scaleDown: false secrets: xxxSecretRef: null xxx: # Replica count for this workload; 0 is allowed and scales it down. # The chart-global scaleDown flag takes precedence. replicas: 1 resources: # Limits are optional: memory and ephemeral-storage limits default to # limitFactor x the request, an explicitly set limit always wins, and a # CPU limit is only set when configured explicitly under "limits". limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeral-storage: 10Mi livenessProbe: httpGet: path: / port: http periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: / port: http periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 # The startup probe gates liveness/readiness, so those need no initialDelaySeconds. # Startup budget = periodSeconds * failureThreshold = 150s. startupProbe: httpGet: path: / port: http periodSeconds: 5 timeoutSeconds: 5 failureThreshold: 30 securityContext: pod: runAsNonRoot: true runAsUser: 20000 runAsGroup: 1000 fsGroup: 1000 fsGroupChangePolicy: Always # RuntimeDefault applies the container runtime's default seccomp filter, # which blocks the syscalls a normal workload never makes. It sits in the # pod context on purpose: from here it covers every container in the pod # including init containers, while a container-level seccompProfile would # have to be repeated for each one (and silently missed on the next one # added). A container that genuinely needs a different filter can still # override it under securityContext.container, which wins over this value. seccompProfile: type: RuntimeDefault container: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsNonRoot: true capabilities: drop: - ALL add: [] ports: # An unprivileged port on purpose (AVD-KSV-0117 flags containerPort < 1024). # # Note what the reason is NOT: on current Kubernetes a non-root container # can bind port 80 just fine. The kubelet sets # net.ipv4.ip_unprivileged_port_start=0 in the pod network namespace, so # the classic "ports below 1024 need NET_BIND_SERVICE" rule does not apply # inside a pod. Measured in k3d (k3s v1.35.5): the sysctl reads 0, and a # container running as runAsUser 20000 with capabilities.drop: [ALL] binds # port 80 successfully. Anyone who "fixes" this back to 80 after testing it # once will find that it works - which is exactly why the reason is written # down here. # # The reason to stay above 1024 is that this is a runtime default, not a # guarantee: a cluster that restores ip_unprivileged_port_start=1024 (node # sysctl or a hardened distribution) breaks every workload that copied the # 80, and the failure then appears in the copied chart, not here. Every # real chart in this repo listens above 1024 (3000, 8080, 8123, 9998, ...); # the one exception is samba, which needs 139/445 and adds NET_BIND_SERVICE # with a documented justification. # # containerPort is declarative - it does not force the application onto the # port. Point the application at the same port when copying this template. - containerPort: 8080 protocol: TCP name: http env: # Reference for guideline 1: ingress.domain is read HERE, outside the # Ingress template, so it needs its own required(). Without it, switching # the Ingress off via ingress.enabled would render an empty value and the # workload would start with a broken address - silently. Copy this shape # whenever a chart uses the domain for anything but the Ingress host. - name: NORMAL_ENV value: '{{ required "A Domain/Host must be provided (ingress.domain)" .Values.ingress.domain }}' - name: ENV_FROM_SECRET valueFrom: secretKeyRef: name: "{{ .Release.Name }}-{{ .Chart.Name }}-secret" key: "secretKey" - name: ENV_FROM_CONFIGMAP valueFrom: configMapKeyRef: name: "{{ .Release.Name }}-{{ .Chart.Name }}-config-map" key: "configMapKey" storage: amount: 10Gi storageClass: null ingress: # Gates the whole Ingress template. Note that ingress.domain is ALSO read by # the env block above, so it stays required even with the Ingress switched # off; only clusterIssuer becomes unnecessary. Check this per chart instead # of assuming either way (guideline 1). enabled: true clusterIssuer: null domain: null className: nginx # Extra annotations for the Ingress; merged with the cert-manager # cluster-issuer annotation the chart always sets. annotations: {}