Only the newest Java line is maintained from now on. Publishing the chart once per line out of one directory is what made the lines drift apart (#158): a change reached whichever line happened to lie in the directory. java8 and java17 stay published as frozen artifacts at 4.0.0, java21 at 4.1.0, and none of them gets another chart change. Running an older JVM is now a decision at rollout time instead of a chart version: image.tagOverride replaces the tag that otherwise comes from appVersion. It is not called image.tag because it decouples the running image from the chart version, and it is deliberately outside Renovate's reach - renovate.json5 keeps tracking appVersion only. The pairing of tag and minecraft.version is now checked at render time and fails with both values named, the line each one belongs to, and where the tag came from. Until now nothing checked it: a mismatch installed silently and only the container failed afterwards. The boundaries are Mojang's, swept over all 102 releases of the piston-meta manifest (javaVersion.majorVersion): up to 1.16.5 Java 8, 1.17-1.17.1 Java 16, 1.18-1.20.4 Java 17, 1.20.5-1.21.11 Java 21, 26.1 and later Java 25. The 1.17 line was the one gap the chart's own notes did not cover. Two cases pass unchecked on purpose, documented in values.yaml and NOTES.txt: a tag without a recognizable java<N> part, and a minecraft.version that is not a plain numeric x[.y[.z]]. A guard that rejects what it does not understand gets worked around instead of respected. Major, because an installation that already runs a mismatched pair stops rendering. It does not run today either - it now fails earlier and visibly.
244 lines
11 KiB
YAML
244 lines
11 KiB
YAML
{{- include "minecraft-server.validateModpackSources" . }}
|
|
{{- include "minecraft-server.validateJavaLine" . }}
|
|
apiVersion: apps/v1
|
|
kind: StatefulSet
|
|
metadata:
|
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
labels:
|
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
spec:
|
|
replicas: {{ include "minecraft-server.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.server.replicas) }}
|
|
selector:
|
|
matchLabels:
|
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
serviceName: {{ .Release.Name }}-{{ .Chart.Name }}-service
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
annotations:
|
|
# Rolls the pod whenever the rendered ConfigMap changes. init.sh is
|
|
# mounted with subPath (kubelet never refreshes those in a running
|
|
# container) and the init container only reads it at pod start, so
|
|
# without this a changed download URL or working directory would stay
|
|
# inert while the release still reported success.
|
|
checksum/config: {{ include (print $.Template.BasePath "/minecraft-server.configmap.yaml") . | sha256sum }}
|
|
# Deliberately a SEPARATE annotation, and deliberately NOT a hash of the
|
|
# secret's content: the Kubernetes Secret is materialized by the
|
|
# 1Password operator, so Helm never sees what is in it. This hash covers
|
|
# the rendered OnePasswordItem, i.e. the op:// item path - repointing
|
|
# secrets.minecraftServerRef at a different item now takes effect
|
|
# instead of silently leaving the old credentials in the running pod.
|
|
# A change of the item's CONTENT inside the vault is not covered; see
|
|
# the comment on secrets in values.yaml for why that gap cannot be
|
|
# closed here and what it means operationally.
|
|
checksum/secret-ref: {{ include (print $.Template.BasePath "/minecraft-server.secret.yaml") . | sha256sum }}
|
|
spec:
|
|
automountServiceAccountToken: false
|
|
securityContext:
|
|
{{- include "minecraft-server.podSecurityContext" .Values.securityContext | nindent 8 }}
|
|
{{- if .Values.curseforgeServerpack.enabled }}
|
|
initContainers:
|
|
- name: download-serverpack
|
|
image: {{ .Values.server.initImage }}
|
|
command: [ 'sh', '/init/init.sh' ]
|
|
securityContext:
|
|
{{- include "minecraft-server.containerSecurityContext" .Values.securityContext | nindent 12 }}
|
|
volumeMounts:
|
|
- name: "mc-volume"
|
|
mountPath: /modpacks
|
|
subPath: mc-modpacks/
|
|
- name: "mc-volume"
|
|
mountPath: /data
|
|
subPath: mc-data/
|
|
- name: init-script
|
|
mountPath: /init/init.sh
|
|
subPath: init.sh
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
{{- end }}
|
|
containers:
|
|
- name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
|
{{- /* Tag from .Chart.AppVersion unless image.tagOverride replaces
|
|
it; validateJavaLine above rejects a tag whose Java line does
|
|
not fit minecraft.version. Template comment on purpose - a
|
|
YAML comment here would change the rendered manifest. */}}
|
|
image: "itzg/minecraft-server:{{ include "minecraft-server.imageTag" . }}"
|
|
imagePullPolicy: IfNotPresent
|
|
securityContext:
|
|
{{- include "minecraft-server.containerSecurityContext" .Values.securityContext | nindent 12 }}
|
|
ports:
|
|
- name: mc-port
|
|
containerPort: {{ .Values.server.port }}
|
|
protocol: TCP
|
|
{{- if .Values.server.rcon.enabled }}
|
|
- name: minecraft-rcon
|
|
containerPort: {{ .Values.server.rcon.port }}
|
|
protocol: TCP
|
|
{{- end }}
|
|
- name: metrics
|
|
containerPort: 19565
|
|
protocol: TCP
|
|
env:
|
|
- name: EULA
|
|
value: "true"
|
|
- name: DUMP_SERVER_PROPERTIES
|
|
value: "true"
|
|
- name: MOTD
|
|
value: "{{ .Values.server.motd }}"
|
|
- name: DIFFICULTY
|
|
value: {{ .Values.minecraft.difficulty }}
|
|
- name: SERVER_PORT
|
|
value: "{{ .Values.server.port }}"
|
|
# ENABLE_WHITELIST is set in both positions on purpose - it is the
|
|
# only variable that can switch the whitelist OFF again. The image
|
|
# enables the whitelist when WHITELIST/WHITELIST_FILE is non-empty
|
|
# OR ENABLE_WHITELIST is true, and disables it (white-list=false)
|
|
# when ENABLE_WHITELIST is false, rewriting an existing
|
|
# server.properties on the volume. Because a non-empty WHITELIST
|
|
# wins over ENABLE_WHITELIST=false, players must stay unset while
|
|
# disabled - hence the guard below rather than emitting both.
|
|
- name: ENABLE_WHITELIST
|
|
value: "{{ .Values.minecraft.whitelist.enabled }}"
|
|
# enforce-whitelist is mapped from ENFORCE_WHITELIST in the image's
|
|
# property-definitions.json. The image only ever sets it to true (in
|
|
# its enable branch) and never resets it, so without this line a
|
|
# server that once had the whitelist on keeps enforce-whitelist=true
|
|
# in its persisted server.properties after switching off. It is
|
|
# inert while white-list=false, but leaving stale state behind is
|
|
# exactly what this chart version fixes, so it follows the switch.
|
|
- name: ENFORCE_WHITELIST
|
|
value: "{{ .Values.minecraft.whitelist.enabled }}"
|
|
{{- if .Values.minecraft.whitelist.enabled }}
|
|
- name: EXISTING_WHITELIST_FILE
|
|
value: {{ .Values.minecraft.whitelist.overridePolicy }}
|
|
{{- with .Values.minecraft.whitelist.players }}
|
|
- name: WHITELIST
|
|
value: "{{ . }}"
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- with .Values.minecraft.management.opPlayers }}
|
|
- name: OPS
|
|
value: "{{ . }}"
|
|
{{- end }}
|
|
- name: EXISTING_OPS_FILE
|
|
value: "SYNCHRONIZE"
|
|
- name: MAX_PLAYERS
|
|
value: "{{ .Values.minecraft.management.maxPlayers }}"
|
|
- name: FORCE_GAMEMODE
|
|
value: "{{ .Values.minecraft.management.forceGameMode }}"
|
|
- name: SNOOPER_ENABLED
|
|
value: "false"
|
|
- name: MODE
|
|
value: "{{ .Values.minecraft.management.gameMode }}"
|
|
- name: LEVEL
|
|
value: "{{ .Values.minecraft.management.worldSaveName }}"
|
|
- name: SERVER_NAME
|
|
value: "{{ .Values.minecraft.management.serverName }}"
|
|
- name: VERSION
|
|
value: "{{ .Values.minecraft.version }}"
|
|
- name: ENABLE_RCON
|
|
value: "{{ .Values.server.rcon.enabled }}"
|
|
{{- if .Values.server.rcon.enabled }}
|
|
- name: RCON_PORT
|
|
value: "{{ .Values.server.rcon.port }}"
|
|
- name: RCON_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
key: rcon-password
|
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-secret
|
|
{{- end }}
|
|
- name: ENABLE_AUTOPAUSE
|
|
value: "false"
|
|
- name: MEMORY
|
|
value: "{{ .Values.minecraft.resources.memory }}G"
|
|
{{- if .Values.curseforge.enabled }}
|
|
- name: TYPE
|
|
value: "AUTO_CURSEFORGE"
|
|
- name: CF_API_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
key: curseforge-api-key
|
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-secret
|
|
- name: CF_SLUG
|
|
value: "{{ .Values.curseforge.modpack.slug }}"
|
|
- name: CF_FILE_ID
|
|
value: "{{ .Values.curseforge.modpack.versionId }}"
|
|
- name: CF_EXCLUDE_MODS
|
|
value: "{{ .Values.curseforge.modpack.exclude }}"
|
|
- name: CF_OVERRIDES_EXCLUSIONS
|
|
value: "{{ .Values.curseforge.modpack.excludeOverride }}"
|
|
- name: CF_FORCE_INCLUDE_MODS
|
|
value: "{{ .Values.curseforge.modpack.include }}"
|
|
- name: CF_FORCE_SYNCHRONIZE
|
|
value: "{{ .Values.curseforge.forceReload }}"
|
|
{{- end }}
|
|
{{- if .Values.curseforgeServerpack.enabled }}
|
|
- name: TYPE
|
|
value: "CURSEFORGE"
|
|
- name: CF_SERVER_MOD
|
|
value: "/modpacks/serverpack.zip"
|
|
- name: CF_BASE_DIR
|
|
value: "{{ .Values.curseforgeServerpack.workingDirectory }}"
|
|
{{- end }}
|
|
{{- if .Values.ftb.enabled }}
|
|
- name: TYPE
|
|
value: FTBA
|
|
- name: FTB_MODPACK_ID
|
|
value: "{{ .Values.ftb.modpackId }}"
|
|
- name: FTB_MODPACK_VERSION_ID
|
|
value: "{{ .Values.ftb.versionId }}"
|
|
{{- end }}
|
|
{{- range $value := .Values.env }}
|
|
{{- if $value.value }}
|
|
- name: {{ $value.name }}
|
|
value: {{ tpl $value.value $ }}
|
|
{{- else if $value.valueFrom }}
|
|
{{- if $value.valueFrom.secretKeyRef }}
|
|
- name: {{ $value.name }}
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ tpl $value.valueFrom.secretKeyRef.name $ }}
|
|
key: {{ tpl $value.valueFrom.secretKeyRef.key $ }}
|
|
{{- else if $value.valueFrom.configMapKeyRef }}
|
|
- name: {{ $value.name }}
|
|
valueFrom:
|
|
configMapKeyRef:
|
|
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ }}
|
|
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
livenessProbe:
|
|
{{- include "minecraft-server.livenessProbe" .Values.livenessProbe | nindent 12 }}
|
|
readinessProbe:
|
|
{{- include "minecraft-server.readinessProbe" .Values.readinessProbe | nindent 12 }}
|
|
startupProbe:
|
|
{{- include "minecraft-server.startupProbe" .Values.startupProbe | nindent 12 }}
|
|
resources:
|
|
{{- include "minecraft-server.serverResources" . | nindent 12 }}
|
|
volumeMounts:
|
|
- name: "mc-volume"
|
|
mountPath: /data
|
|
subPath: mc-data/
|
|
- name: "mc-volume"
|
|
mountPath: /modpacks
|
|
subPath: mc-modpacks/
|
|
# Writable path required by readOnlyRootFilesystem: the image writes
|
|
# its server-icon scratch file and mc-server-runner's console named
|
|
# pipe to /tmp. Everything else goes to the PVC at /data.
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
volumes:
|
|
- name: "mc-volume"
|
|
persistentVolumeClaim:
|
|
# Deliberate exception from the naming scheme: renaming the PVC
|
|
# would make Kubernetes provision a new, empty volume and orphan
|
|
# the existing world (see README, naming exceptions).
|
|
claimName: {{ .Release.Name }}-mc-volume-claim
|
|
- name: init-script
|
|
configMap:
|
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-configmap
|
|
- name: tmp
|
|
emptyDir: {}
|