Merge pull request #188 from jk-cluster/feat/minecraft-router-notes-and-157
minecraft-router: NOTES.txt und Exponential-Schreibweise in multiplyQuantity (4.1.0+up1.46.4)
This commit is contained in:
3 files changed
+160
-3
No files matched your search
@@ -5,7 +5,7 @@ icon: https://avatars.githubusercontent.com/u/988985
|
||||
|
||||
type: application
|
||||
|
||||
version: 4.0.0+up1.46.4
|
||||
version: 4.1.0+up1.46.4
|
||||
appVersion: "1.46.4"
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
{{- $replicas := include "minecraft-router.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.server.replicas) -}}
|
||||
{{- $outward := .Values.server.outwardPort | default 25565 -}}
|
||||
{{- $port := .Values.server.port | default 25565 -}}
|
||||
{{- $backendPort := .Values.server.backendPort | default 25565 -}}
|
||||
{{- $apiPort := .Values.server.apiPort | default 8080 -}}
|
||||
{{- $deploy := printf "%s-%s-deployment" .Release.Name .Chart.Name -}}
|
||||
{{- $svc := printf "%s-%s-service" .Release.Name .Chart.Name -}}
|
||||
{{- $cm := printf "%s-%s-configmap" .Release.Name .Chart.Name -}}
|
||||
{{- $mappings := .Values.mappings | default list -}}
|
||||
mc-router {{ .Chart.AppVersion }} — release {{ .Release.Name }} in namespace {{ .Release.Namespace }}.
|
||||
|
||||
ACCESS — A TCP PROXY, NOT A WEB SERVICE
|
||||
This release has no Ingress, no certificate and no URL. Minecraft clients
|
||||
speak raw TCP to the NodePort Service {{ $svc }}:
|
||||
|
||||
<any-node-ip>:{{ $outward }}
|
||||
|
||||
server.outwardPort ({{ $outward }}) is the port on the node and the one that goes into
|
||||
the client. server.port ({{ $port }}) is what mc-router listens on inside the pod and
|
||||
what the Service publishes cluster-internally; changing it does not change
|
||||
what a player dials.
|
||||
|
||||
Which backend a connection reaches is decided by the HOSTNAME the client
|
||||
typed, not by the port: mc-router reads the server address out of the
|
||||
Minecraft handshake and looks it up in the routing table below. Every mapped
|
||||
name therefore has to resolve to a node of this cluster (or to whatever sits
|
||||
in front of it), and the player has to enter that name. Connecting to the
|
||||
node's bare IP address carries no matching hostname and is routed nowhere.
|
||||
{{- if or (lt (int $outward) 30000) (gt (int $outward) 32767) }}
|
||||
|
||||
{{ $outward }} IS OUTSIDE THE DEFAULT NODE-PORT RANGE (30000-32767)
|
||||
This install needs a cluster whose API server runs with an extended
|
||||
--service-node-port-range; without it the API server rejects the Service and
|
||||
the release fails on that one object while everything else applies. The
|
||||
choice is deliberate — 25565 is the port Minecraft clients dial by default.
|
||||
Confirm the Service actually exists:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} get svc {{ $svc }}
|
||||
{{- end }}
|
||||
|
||||
ROUTING TABLE — {{ len $mappings }} MAPPING(S) ACTIVE IN THIS RELEASE
|
||||
{{ range $mapping := $mappings }} {{ $mapping.domain }} → {{ $mapping.internalUrl }}:{{ $mapping.port | default $backendPort }}{{ if $mapping.port }} (own port, overrides server.backendPort {{ $backendPort }}){{ end }}
|
||||
{{ end }}
|
||||
mappings is the ONLY source of routes here. The chart does not run mc-router
|
||||
in its Kubernetes auto-discovery mode — there is no ServiceAccount and
|
||||
automountServiceAccountToken is false, so the router cannot watch the API and
|
||||
never reads routing annotations on a backend Service. A server announced that
|
||||
way stays unreachable through this router until its name stands in mappings,
|
||||
and a name that is in mappings routes there no matter what any annotation
|
||||
elsewhere says. Where both exist, this table wins.
|
||||
|
||||
The table is rendered into the ConfigMap {{ $cm }}
|
||||
(key custom-routing-config.json) and mounted with subPath at
|
||||
/data/custom-routing-config.json. Two consequences:
|
||||
|
||||
- mc-router reads that file once at startup, and the kubelet never
|
||||
refreshes a subPath mount, so a routing change takes effect only through
|
||||
a pod restart. The Deployment carries a checksum/config annotation, so
|
||||
helm upgrade performs that restart for you — at the price of a few
|
||||
seconds in which no client can connect and open sessions are dropped.
|
||||
Treat a routing change as a short, planned outage.
|
||||
- internalUrl is dialed by name. Point it at the backend's Service
|
||||
(survival-service.minecraft.svc.cluster.local), not at a pod IP: the
|
||||
Service name survives a restart of the Minecraft server, the pod IP does
|
||||
not.
|
||||
|
||||
There is no fallback backend. The chart configures no default route, so a
|
||||
client arriving with a hostname outside the table is not connected to
|
||||
anything. mc-router itself knows the concept (its API has POST /defaultRoute)
|
||||
and parses every flag equally as an environment variable, so server.env is
|
||||
where you would set one.
|
||||
|
||||
WHAT A READY ROUTER DOES NOT PROVE
|
||||
All three probes call mc-router's own API — GET /routes on container port
|
||||
api-port ({{ $apiPort }}) — which answers as soon as the config file has been read. It
|
||||
answers just as happily when every backend behind it is down, and when a
|
||||
domain or an internalUrl in the table is misspelled: the router is up, the
|
||||
mapping is loaded, and the player still cannot connect. A green rollout here
|
||||
is a statement about the proxy, never about a Minecraft server. Nothing in
|
||||
this release watches the backends.
|
||||
|
||||
A backend that is unreachable also does not restart the router: mc-router
|
||||
accepts the client, fails to dial the target and closes the connection, which
|
||||
the player sees as an ordinary connection failure. The router's log is the
|
||||
only place that names the address it tried:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} logs deploy/{{ $deploy }}
|
||||
|
||||
The API is not published by the Service (which carries proxy-port only), so
|
||||
ask the pod directly:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} port-forward deploy/{{ $deploy }} {{ $apiPort }}:{{ $apiPort }}
|
||||
curl -s -H 'Accept: application/json' http://127.0.0.1:{{ $apiPort }}/routes
|
||||
|
||||
That is the same endpoint the probes use; it returns the live table, and
|
||||
/metrics returns the Prometheus metrics. The API also writes: POST /routes,
|
||||
POST /defaultRoute and DELETE /routes/{addr} change the routing of the
|
||||
RUNNING PROCESS only. Nothing written that way survives a restart — the
|
||||
mounted ConfigMap is the source of truth and the next rollout silently
|
||||
reinstates it. Fix routing in mappings, not over the API.
|
||||
|
||||
NO SECRETS, NO VOLUMES, NO STATE
|
||||
This chart creates no OnePasswordItem and mounts no Secret, so there is no
|
||||
1Password item to prepare and no field names to get right. The only mounted
|
||||
object is the routing ConfigMap, rendered entirely from mappings:
|
||||
"helm uninstall {{ .Release.Name }}" destroys nothing that is not already in your values
|
||||
file. The worlds live in the backend releases, not here.
|
||||
{{- if eq $replicas "0" }}
|
||||
|
||||
SCALED TO ZERO
|
||||
{{ if .Values.scaleDown }}scaleDown: true{{ else }}server.replicas: 0{{ end }} — no router pod runs, so every hostname above stops
|
||||
connecting although the Service and the ConfigMap stay in place. The backend
|
||||
Minecraft servers keep running and stay reachable through their own Services;
|
||||
only the way in through this router is gone.
|
||||
{{- end }}
|
||||
{{- if gt (atoi $replicas) 1 }}
|
||||
|
||||
MORE THAN ONE ROUTER REPLICA
|
||||
server.replicas is {{ $replicas }}. mc-router keeps no state between connections and every
|
||||
replica mounts the same routing ConfigMap, so the Service can spread clients
|
||||
across them. Two things change: an established connection is pinned to the
|
||||
replica that accepted it, so a rollout drops the open sessions pod by pod;
|
||||
and a runtime change through the API reaches only the one pod you forwarded
|
||||
to, leaving the replicas disagreeing until the next restart.
|
||||
{{- end }}
|
||||
{{- if .Values.server.env }}
|
||||
|
||||
server.env IS APPENDED TO WHAT THE CHART SETS
|
||||
The entries land after ROUTES_CONFIG and are rendered through tpl, so a value
|
||||
may contain template expressions. Because mc-router parses its flags with
|
||||
go-flagsfiller, this is also the place for every option the chart does not
|
||||
model explicitly — LOG_LEVEL, BACKEND_DIAL_TIMEOUT, CONNECTION_RATE_LIMIT.
|
||||
|
||||
Two things it will not do. The chart passes --port and --api-binding as
|
||||
command-line arguments, and those take precedence over the matching
|
||||
environment variables, so PORT or API_BINDING set here change nothing — use
|
||||
server.port and server.apiPort. And a plain "value" is stored in the pod spec
|
||||
in clear text, readable by everyone who can read pods in {{ .Release.Namespace }}; anything
|
||||
sensitive belongs in valueFrom.secretKeyRef.
|
||||
{{- end }}
|
||||
@@ -67,7 +67,7 @@ Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary
|
||||
results are printed without a decimal point.
|
||||
*/}}
|
||||
{{- define "minecraft-router.multiplyQuantity" -}}
|
||||
{{- $quantity := printf "%v" .quantity -}}
|
||||
{{- $quantity := include "minecraft-router.formatNumber" .quantity -}}
|
||||
{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}}
|
||||
{{- if not $number -}}
|
||||
{{- fail (printf "cannot parse resource quantity %q" $quantity) -}}
|
||||
@@ -80,7 +80,24 @@ results are printed without a decimal point.
|
||||
{{- if eq $product (floor $product) -}}
|
||||
{{- printf "%d%s" (int64 $product) $suffix -}}
|
||||
{{- else -}}
|
||||
{{- printf "%v%s" $product $suffix -}}
|
||||
{{- printf "%s%s" (include "minecraft-router.formatNumber" $product) $suffix -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Render a number as a plain decimal string, never in exponential notation.
|
||||
|
||||
Why this exists (issue #157): the null-safe fallback helpers pass values
|
||||
through fromYaml, which parses every number as float64. Go's "%v" switches
|
||||
float64 to exponential notation from about 1e6 upwards, so a bare byte count
|
||||
like 1048576 became "1.048576e+06" - not a valid Kubernetes quantity, and the
|
||||
render aborted. Strings ("512Mi") are passed through untouched.
|
||||
*/}}
|
||||
{{- define "minecraft-router.formatNumber" -}}
|
||||
{{- if kindIs "float64" . -}}
|
||||
{{- regexReplaceAll "\\.?0+$" (printf "%.10f" .) "" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%v" . -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
Reference in new issue
Block a user