Five changes to the scaffold every future chart is copied from: 1. seccompProfile.type: RuntimeDefault in the pod security context, in line with the rest of the seccomp series (#84). Pod context, because from there it also covers init containers and any container added later without being repeated. 2. containerPort 80 -> 8080, clearing AVD-KSV-0117. Note that the usual justification for this does not hold: a non-root container CAN bind port 80 on current Kubernetes, because the kubelet sets net.ipv4.ip_unprivileged_port_start=0 in the pod network namespace. Measured, not assumed - see the values.yaml comment. The reason to stay above 1024 is that this is a runtime default rather than a guarantee, and that every real chart here already does. 3. The ConfigMap placeholder key is renamed from the literal "key" to "example-setting", clearing AVD-KSV-01010 (secret-scanner patterns match any key named "key"). 4. The image placeholder is fully qualified as ghcr.io/ORG/IMAGE, so the template stops teaching the unqualified form that produced the repo's unqualified Docker Hub images. 5. env values are rendered through "quote". Without it a value like "8080" renders as a YAML number and the API server rejects the whole manifest ("cannot unmarshal number into Go struct field EnvVar.value of type string"). Every real chart in the repo already quotes here; only the template did not. Found by instantiating the template and installing it, not by rendering it. Verified by instantiating the scaffold into a working chart per the README procedure and installing it in k3d: the workload becomes Ready, the Service routes to the app on 8080 and an ephemeral container added to the running pod inherits Seccomp: 2 from the pod context. Refs #84
80 lines
3.8 KiB
YAML
80 lines
3.8 KiB
YAML
apiVersion: apps/v1
|
|
kind: StatefulSet
|
|
metadata:
|
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
labels:
|
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
spec:
|
|
replicas: {{ include "xxx.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.xxx.replicas) }}
|
|
serviceName: {{ .Release.Name }}-{{ .Chart.Name }}-service
|
|
selector:
|
|
matchLabels:
|
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
template:
|
|
metadata:
|
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
labels:
|
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
annotations:
|
|
# Hash of the rendered ConfigMap: a changed ConfigMap changes the pod
|
|
# template and thus restarts the pods. Without it a config change stays
|
|
# invisible to the running container - subPath mounts are never
|
|
# updated by the kubelet, and most apps read their config only at
|
|
# start. Add one line per ConfigMap the workload consumes.
|
|
checksum/config: {{ include (print $.Template.BasePath "/xxx.configmap.yaml") . | sha256sum }}
|
|
spec:
|
|
automountServiceAccountToken: false
|
|
securityContext:
|
|
{{- include "xxx.podSecurityContext" .Values.xxx.securityContext | nindent 8 }}
|
|
containers:
|
|
- name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
# Fully qualified on purpose: an unqualified "registry/image" resolves
|
|
# to Docker Hub, which is how the repo accumulated its unqualified
|
|
# images. Replace host/org/image, keep the registry host.
|
|
image: "ghcr.io/ORG/IMAGE:{{ .Chart.AppVersion }}"
|
|
imagePullPolicy: IfNotPresent
|
|
env:
|
|
{{- range $value := .Values.xxx.env }}
|
|
{{- if $value.value }}
|
|
- name: {{ $value.name | quote }}
|
|
# quote is required, not cosmetic: a value like "8080" or "true"
|
|
# renders unquoted as a YAML number/bool, and the API server then
|
|
# rejects the whole manifest with "cannot unmarshal number into
|
|
# Go struct field EnvVar.value of type string". Every chart in
|
|
# this repo quotes here.
|
|
value: {{ tpl $value.value $ | quote }}
|
|
{{- else if $value.valueFrom }}
|
|
{{- if $value.valueFrom.secretKeyRef }}
|
|
- name: {{ $value.name }}
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ tpl $value.valueFrom.secretKeyRef.name $ | quote }}
|
|
key: {{ tpl $value.valueFrom.secretKeyRef.key $ | quote }}
|
|
{{- else if $value.valueFrom.configMapKeyRef }}
|
|
- name: {{ $value.name }}
|
|
valueFrom:
|
|
configMapKeyRef:
|
|
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ | quote }}
|
|
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ | quote }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
ports:
|
|
{{- toYaml .Values.xxx.ports | nindent 12 }}
|
|
# Probes, resources and both security contexts go through the
|
|
# null-safe helpers (#99): an erased block means "chart defaults
|
|
# apply" instead of a vanished probe or an unhardened container.
|
|
# Never wrap these in an "if" - a guard hides the erased case
|
|
# completely instead of rendering a visible null.
|
|
livenessProbe:
|
|
{{- include "xxx.livenessProbe" .Values.xxx.livenessProbe | nindent 12 }}
|
|
readinessProbe:
|
|
{{- include "xxx.readinessProbe" .Values.xxx.readinessProbe | nindent 12 }}
|
|
startupProbe:
|
|
{{- include "xxx.startupProbe" .Values.xxx.startupProbe | nindent 12 }}
|
|
resources:
|
|
{{- include "xxx.effectiveResources" .Values.xxx.resources | nindent 12 }}
|
|
securityContext:
|
|
{{- include "xxx.containerSecurityContext" .Values.xxx.securityContext | nindent 12 }}
|
|
restartPolicy: Always
|