Kubernetes Deployment

PackyTrace has a local Kubernetes reference under deployment/k8s. It runs the backend and supporting stack on kind and provides a starting point for a future cloud deployment. The public application currently runs on AWS with Docker Compose; kind provides a local path for exercising the same services under Kubernetes.

How It Is Implemented

The deployment uses plain Kubernetes manifests managed by Kustomize:

deployment/k8s/
├── kind-config.yaml          # local cluster and host port mappings
├── base/                     # shared workloads, networking, config, and autoscaling
├── overlays/kind/            # settings for the local kind environment
└── jobs/measurement-seed.yaml

The main implementation choices are:

Kubernetes feature PackyTrace use
Namespace Keeps all PackyTrace resources together
Deployments and Services Run and connect the eight services and four brand simulators
StatefulSets and persistent volumes Preserve Postgres and Kafka data across pod restarts
Jobs Initialize database schemas and Kafka topics
ConfigMaps Load the Keycloak realm, SQL, Prometheus rules, and Grafana configuration from shared Compose files
Secrets Provide a separate database connection to each service
Ingress NGINX Exposes the gateway and local administration endpoints
Health probes Restart unhealthy containers and send traffic only to ready pods
Resource controls Reserve CPU and memory and prevent uncontrolled memory use
Security contexts Run containers as non-root with reduced Linux privileges
Horizontal Pod Autoscaler Scales passport-service from 1 to 5 replicas at a 60% CPU target

The API gateway starts with two replicas so a pod can restart without removing the public edge. Postgres, Kafka, and Keycloak use one replica because this is a local demonstration, not a highly available production data platform.

Kustomize keeps reusable definitions in base/ and environment-specific changes in an overlay. The current overlay targets kind; a future managed-cluster overlay can patch image locations, ingress, storage classes, secrets, and replica counts while retaining the same service definitions.

Scope and production gaps

The autoscaler is attached to passport-service because barcode scans are the main public, SLO-bearing path. CPU is a local demonstration signal, not validation that replicas preserve the SLO. Passport currently applies migrations at process startup, so scaling above one replica can race migrations; the HPA must remain a demonstration artifact until deployment serializes migration as the startup-migration policy requires. A production design must also select a scaling signal from load tests and observed bottlenecks.

The manifests are an orchestration reference, not a production-ready or scaling-ready baseline. A production cluster would still need managed secrets, TLS and DNS, backups, network policies, and highly available Postgres and Kafka deployments.

Run It Locally

Prerequisites are Docker, kubectl, and kind. Start the whole stack with:

make k8s-up

This creates the cluster, installs ingress-nginx and metrics-server, builds and loads the local images, applies the Kustomize overlay, and waits for the workloads. First startup can take a few minutes while the initialization Jobs and Keycloak complete.

Command Purpose
make k8s-status Show pods, Jobs, and autoscaler state
make k8s-logs Follow logs from the PackyTrace pods
make k8s-seed Publish the demo analytics data
make k8s-check Verify that Kustomize renders valid manifests
make k8s-down Delete the local cluster and its data

The gateway is available at http://localhost:8080. Local ingress also exposes Grafana at http://grafana.localhost, Prometheus at http://prometheus.localhost, and Keycloak at http://keycloak.localhost. The consumer and brand web applications continue to run on the host with make web and make brand.

After changing service code, rebuild and load the images, then restart the changed deployment. For example:

make k8s-build k8s-load
kubectl --context kind-packytrace -n packytrace rollout restart deployment/passport-service

To watch automatic scaling:

kubectl --context kind-packytrace -n packytrace get hpa -w

Common Problems

  • ErrImageNeverPull or ImagePullBackOff: run make k8s-build k8s-load.
  • CrashLoopBackOff immediately after startup: wait for the postgres-init and kafka-init Jobs, then check make k8s-status.
  • An HPA target of '': wait for metrics-server or rerun make k8s-kind.
  • An ingress webhook error: rerun make k8s-apply after ingress-nginx is ready.