You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Non-breaking hardening + reliability for the Gotify deployment:
Pin the image to gotify/server:2 instead of :latest, so a pod restart
can't silently pull a new major version.
Add resource requests/limits (CPU, memory, ephemeral-storage) — the pod
currently has none, so one container can consume whatever the node has.
Add liveness and readiness probes (liveness: TCP :80; readiness: HTTP /version on :80, which Gotify serves unauthenticated).
Add a container securityContext: allowPrivilegeEscalation: false,
all capabilities dropped with only NET_BIND_SERVICE added back (Gotify
binds :80), and seccomp RuntimeDefault.
Why
Without probes, Kubernetes can't tell a wedged pod from a healthy one; without
limits a single pod can starve the node; and :latest makes "what's actually
running" ambiguous across restarts. The securityContext is defense-in-depth a
notification server doesn't need to give up.
Scope
Deliberately minimal and non-breaking. The Service, PVC, env, and data volume
are unchanged. I kept NET_BIND_SERVICE so the container can still bind :80,
and left readOnlyRootFilesystem, a non-root UID, and a NetworkPolicy out —
those depend on the image's runtime assumptions and your cluster's networking,
and are better as separate changes. The image is pinned, so imagePullPolicy
is intentionally left at the IfNotPresent default rather than Always.
Verified the manifest still parses.
The tag is the one thing holding this back. gotify/server:latest is 3.1.1 right now, so :2 would move existing installs back a major version to 2.9.1. That's not harmless: 3.0 changed how tokens are stored. In a quick test, an app token created on 3.1.1 was rejected with a 401 once the same data volume was started on 2.9.1.
Gotify publishes major-version tags, so gotify/server:3 with imagePullPolicy: Always seems like the right balance. It picks up fixes within 3.x and avoids the next breaking major. Without Always, each node keeps whatever 3.x build it pulled first, and the tag stops updating.
The rest checks out: Gotify ran fine with the dropped capabilities, no-new-privileges and the 128Mi limit, and /version serves the readiness probe without auth. Happy to merge after the tag change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Non-breaking hardening + reliability for the Gotify deployment:
gotify/server:2instead of:latest, so a pod restartcan't silently pull a new major version.
currently has none, so one container can consume whatever the node has.
/versionon :80, which Gotify serves unauthenticated).securityContext:allowPrivilegeEscalation: false,all capabilities dropped with only
NET_BIND_SERVICEadded back (Gotifybinds :80), and seccomp
RuntimeDefault.Why
Without probes, Kubernetes can't tell a wedged pod from a healthy one; without
limits a single pod can starve the node; and
:latestmakes "what's actuallyrunning" ambiguous across restarts. The securityContext is defense-in-depth a
notification server doesn't need to give up.
Scope
Deliberately minimal and non-breaking. The Service, PVC, env, and data volume
are unchanged. I kept
NET_BIND_SERVICEso the container can still bind :80,and left
readOnlyRootFilesystem, a non-root UID, and a NetworkPolicy out —those depend on the image's runtime assumptions and your cluster's networking,
and are better as separate changes. The image is pinned, so
imagePullPolicyis intentionally left at the
IfNotPresentdefault rather thanAlways.Verified the manifest still parses.