# 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 AND by the HTTPRoute below, 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). # # Mutually exclusive with httpRoute.enabled below: with both true the render # aborts, naming both values. 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. # # NO COUNTERPART IN GATEWAY MODE. The Gateway API has no annotation channel # for controller behaviour, so everything set here is gone when # httpRoute.enabled is used instead. rewrite-target has an equivalent (the # URLRewrite filter in an HTTPRoute rule); an upload limit # (proxy-body-size) has none at all, and a chart that depends on one must say # so in its NOTES.txt for that mode. annotations: {} # Gateway-API alternative to the Ingress above (Gitea #114). Off by default, so # adding it to an existing chart is additive; exactly one of ingress.enabled # and httpRoute.enabled may be true. # # The chart renders ONLY an HTTPRoute with parentRefs - no Gateway, no # gatewayClassName, no Certificate and no implementation-specific policy # object. Class and certificate belong to the Gateway and therefore to the # platform, which is what keeps a chart independent of whether the cluster runs # nginx-gateway-fabric, Cilium, Envoy Gateway or Istio. # # The Gateway-API CRDs must be installed in the cluster: the chart does not and # cannot detect them (.Capabilities.APIVersions is unreliable at template # time), so with httpRoute.enabled: true and no CRDs the INSTALL fails. httpRoute: enabled: false # The Gateway(s) this route attaches to - a platform object, usually in # another namespace, which must allow this namespace in its listener's # allowedRoutes. One entry per parent; the fields are the Gateway API's # ParentReference (name, and optionally namespace, sectionName, port, group, # kind), passed through unchanged: # # parentRefs: # - name: public # namespace: gateway # sectionName: https # # REQUIRED while httpRoute.enabled is true - the render aborts on an empty # list, because a route without a parent is created, is valid and routes # nothing, with no event to say so. parentRefs: [] # Empty means [ingress.domain], so the hostname has one source of truth. Set # explicitly only to publish under a different or an additional name - which # is how a migration from the Ingress runs: the HTTPRoute takes a second # hostname while the Ingress keeps ingress.domain. hostnames: []