From 144e80997c344a2591b5b7cfeecebd1caaab52e8 Mon Sep 17 00:00:00 2001 From: Said Sef Date: Tue, 13 Oct 2026 11:04:04 +0100 Subject: [PATCH 1/5] fix(k8s): stop the liveness probe restarting a healthy pod The liveness probe in the base Deployment ran pgrep for geocode. Linux cuts a process name to 15 characters, which leaves faas-reverse-ge, so the probe never matched and the kubelet restarted a pod that was serving requests. A match on faas-reverse-geocoding works, and the Helm chart probe uses that name. - deployment/base/deployment.yml names the full binary in the probe. - A pod from the base runs for five minutes with no restarts. --- deployment/base/deployment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/base/deployment.yml b/deployment/base/deployment.yml index ebe0d71..8ff5783 100644 --- a/deployment/base/deployment.yml +++ b/deployment/base/deployment.yml @@ -59,7 +59,7 @@ spec: exec: command: - pgrep - - geocode + - faas-reverse-geocoding initialDelaySeconds: 5 periodSeconds: 30 failureThreshold: 2 From 28e8eee2b6fcc9016166433bf08d035cf7b5b474 Mon Sep 17 00:00:00 2001 From: Said Sef Date: Tue, 13 Oct 2026 11:04:04 +0100 Subject: [PATCH 2/5] fix(docker): probe the health endpoint with wget The image healthcheck called curl, which the Alpine runtime image does not have, and single quotes kept ${PORT} from expanding, so every check failed. Busybox wget now requests / on port 8080. PORT leaves the image too, because the binary takes its port from the -port flag. - Dockerfile swaps curl for wget and exposes 8080 directly. - A container from the new image reports healthy after its first check. --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 10b804a..d0c3cc9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,14 +9,14 @@ RUN apk add --no-cache curl git && \ FROM docker.io/alpine:3.24 LABEL maintainer="Said Sef (saidsef.co.uk/)" -ENV PORT=${PORT:-8080} USER nobody COPY --from=builder /app/faas-reverse-geocoding /usr/bin/ -HEALTHCHECK --interval=60s --timeout=10s CMD curl --fail 'http://localhost:${PORT}/' || exit 1 +# The final image has busybox wget but no curl. +HEALTHCHECK --interval=60s --timeout=10s CMD wget -q -O /dev/null http://localhost:8080/ || exit 1 -EXPOSE ${PORT} +EXPOSE 8080 CMD ["/usr/bin/faas-reverse-geocoding"] From 5971a6800b68e234297596c5912952d1440f01df Mon Sep 17 00:00:00 2001 From: Said Sef Date: Tue, 13 Oct 2026 11:04:04 +0100 Subject: [PATCH 3/5] fix(k8s): make the ingress-nginx overlay build The ingress-nginx overlay carried a replacement that copied the Ingress host onto the same Ingress without naming a target field. Kustomize refused to build it, reporting that fieldPath spec.rules[0].host is missing for the replacement source. The overlay needs no replacement, so the block goes. - deployment/ingress-nginx/kustomization.yml lists its resources and nothing else. - Every overlay builds, and the API server accepts the ingress-nginx one. --- deployment/ingress-nginx/kustomization.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/deployment/ingress-nginx/kustomization.yml b/deployment/ingress-nginx/kustomization.yml index 22e9ec2..05150d7 100644 --- a/deployment/ingress-nginx/kustomization.yml +++ b/deployment/ingress-nginx/kustomization.yml @@ -5,17 +5,3 @@ kind: Kustomization resources: - ../base - ingress.yml - -replacements: -- source: - fieldPath: spec.rules[0].host - group: networking.k8s.io - kind: Ingress - name: geocode - version: v1 - targets: - - select: - kind: Ingress - name: geocode - version: v1 - group: networking.k8s.io From 48239aa0413e60213e0cd0b8909d8b505b1b943a Mon Sep 17 00:00:00 2001 From: Said Sef Date: Tue, 13 Oct 2026 11:04:04 +0100 Subject: [PATCH 4/5] chore(k8s): remove settings that nothing reads Two settings in the Kustomize manifests had no effect. An image override targeted an image called geocode, which no resource uses, so the base kept deploying :latest. PORT sat in the container environment, where the binary never reads it. - The images block comes out of deployment/kustomization.yml. - deployment/base/deployment.yml drops the PORT variable. - Rendered output differs only by that variable, and the image stays :latest. --- deployment/base/deployment.yml | 3 --- deployment/kustomization.yml | 5 ----- 2 files changed, 8 deletions(-) diff --git a/deployment/base/deployment.yml b/deployment/base/deployment.yml index 8ff5783..2b37592 100644 --- a/deployment/base/deployment.yml +++ b/deployment/base/deployment.yml @@ -29,9 +29,6 @@ spec: - name: geocode image: ghcr.io/saidsef/faas-reverse-geocoding:latest imagePullPolicy: Always - env: - - name: "PORT" - value: "8080" securityContext: runAsNonRoot: true runAsGroup: 65534 diff --git a/deployment/kustomization.yml b/deployment/kustomization.yml index 7c001d5..1bd9a8f 100644 --- a/deployment/kustomization.yml +++ b/deployment/kustomization.yml @@ -4,10 +4,5 @@ kind: Kustomization resources: - ./base -images: -- name: geocode - newName: ghcr.io/saidsef/faas-reverse-geocoding - newTag: "2023.12" - commonAnnotations: app.kubernetes.io/part-of: geocode From ebe29514235956d0cdd6f10492179c1f72f82e7b Mon Sep 17 00:00:00 2001 From: Said Sef Date: Tue, 13 Oct 2026 11:04:04 +0100 Subject: [PATCH 5/5] fix(flags): stop the cache flag help claiming a 30-minute default The -cache help text ended in a hand-written "(default 30)", and the flag package appended the real "(default 60)" after it. The usage string now reads "Cache duration in minutes", so -h shows one default. - geocode.go drops the stale default from the usage string. - Help output shows "(default 60)" once, and nothing else changed. --- geocode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geocode.go b/geocode.go index 564c504..c573875 100644 --- a/geocode.go +++ b/geocode.go @@ -41,7 +41,7 @@ func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc { func main() { flag.IntVar(&port, "port", 8080, "HTTP listening PORT") flag.BoolVar(&verbose, "verbose", false, "Enable verbose logging") - flag.IntVar(&cache, "cache", 60, "Cache duration minutes (default 30)") + flag.IntVar(&cache, "cache", 60, "Cache duration in minutes") flag.Parse() // Set the verbosity level in the utils package