This repository packages the minimal Flask app in app.py into a production-ready container and provides
both raw Kubernetes manifests and a Helm chart for deployment. It also includes a metrics addon
based on a Blackbox (synthetic) probe measuring user-perceived availability and latency at the edge.
- App: minimal Flask returning “Hello World!” on
/. - Instructions: Dockerize the app, create production-grade K8s manifests (HA/scalable), incorporate a dummy URL, avoid host port pinning, and ensure reproducibility & cost efficiency for scaling to ~20+ similar apps.
hello-flask-deployable/
|-- app.py
|-- instructions.txt
|-- Dockerfile
|-- requirements.txt
|-- README.md <-- this file
|-- k8s/ # Raw Kubernetes (prod-grade)
| |-- namespace.yaml # PSA labels (restricted), app namespace
| |-- serviceaccount.yaml # Explicit SA; automount=false
| |-- deployment.yaml # 3 replicas, zone+node spread, probes, preStop
| |-- service.yaml # ClusterIP (no hostPort)
| |-- ingress.yaml # Dummy host w/ TLS + SSL redirect/HSTS
| |-- hpa.yaml # CPU-based autoscaling (3..10)
| |-- pdb.yaml # minAvailable=2
| |-- networkpolicy.yaml # Restrict ingress to ingress-nginx; allow DNS
| |-- limitrange.yaml # Default requests/limits
| |-- resourcequota.yaml # Namespace cost guardrails
| |-- monitoring/
| | |-- probe.yaml # Preferred: Prometheus Operator Probe (shared exporter)
| | |-- local-blackbox/ # Optional: per-namespace exporter
| | |-- blackbox-exporter-deployment.yaml
| | |--blackbox-exporter-service.yaml
| | |-- blackbox-exporter-servicemonitor.yaml
| |-- gateway/ # Optional: Gateway API example
| |-- gateway.yaml # Sample Gateway (edit GatewayClass)
| |-- httproute.yaml # HTTPRoute to the Service
|-- helm/
|-- hello-flask/
|-- Chart.yaml
|-- values.yaml
|-- templates/
|-- _helpers.tpl
|-- serviceaccount.yaml
|-- deployment.yaml
|-- service.yaml
|-- ingress.yaml # Auto-defaults path="/" when omitted
|-- gateway-httproute.yaml # Optional (gatewayApi.enabled)
|-- hpa.yaml
|-- pdb.yaml
|-- networkpolicy.yaml
|-- metrics-blackbox-deployment.yaml # Optional local exporter
|-- metrics-blackbox-service.yaml
|-- metrics-blackbox-servicemonitor.yaml
|-- metrics-blackbox-probe.yaml # Shared exporter via Probe CRD
|-- NOTES.txt
- No code changes to
app.py. - Measures actual user path (DNS > TLS > Ingress > Service > Pod).
- Cost-efficient across many apps: one Ingress controller; cheap per-host probe.
- Reproducible: standardized in raw YAML and Helm.
- PSA (restricted) on the Namespace; non-root, seccomp, and caps dropped at pod level.
- HA: 3 replicas + PDB; preStop (drain) + probes for graceful rollouts.
- Spread across zones and nodes via
topologySpreadConstraintsfor failure isolation.
- ClusterIP + shared Ingress (one LB, many apps).
- LimitRange sets default requests/limits > predictable bin-packing if teams forget to set resources.
- ResourceQuota caps total cores/memory and pods per namespace > prevents runaway spend.
- HPA auto-scales for actual load; stateless (no PVs).
- Helm chart drives consistent deployments; now supports image digests for immutability.
- Gateway API (HTTPRoute) if that's your platform standard-can be toggled instead of Ingress.
- Local blackbox exporter if you don't have a shared one; otherwise use Probe CRD against shared exporter (preferred for cost).
- LimitRange (
k8s/limitrange.yaml) sets defaultRequest and default limits for every container that doesn't specify them.- Effect: workloads get a small, sane footprint by default (
50m/64Mirequest;250m/256Milimit) > better bin-packing and fewer oversized pods consuming nodes.
- Effect: workloads get a small, sane footprint by default (
- ResourceQuota (
k8s/resourcequota.yaml) caps the sum of requests/limits and the pod count per namespace.- Effect: protects the cluster budget and other teams by enforcing hard ceilings (e.g.,
limits.cpu: 10,pods: 20).
Together, these provide predictable cost envelopes even as teams create "20 additional similar applications."
- Effect: protects the cluster budget and other teams by enforcing hard ceilings (e.g.,
- Container registry, K8s 1.25+, Ingress controller, cert-manager for TLS.
- For metrics addon (preferred): Prometheus Operator (kube-prometheus-stack). If your Prometheus selects
ServiceMonitor/Probevia labels, adjust labels in the manifests/values.
export IMAGE=your-registry/hello-flask
export TAG=0.1.0
docker build -t $IMAGE:$TAG .
docker push $IMAGE:$TAGImmutable images (Helm): You can use a digest instead of a tag: set
image.digest=...and omitimage.tag.
kubectl apply -f k8s/namespace.yaml
# (Optional) If using Ingress, ensure DNS hello.example.com points to your LB and cert-manager has an issuer.
# (Reqired) set the Image tag and version in the deployment manifest before deploying.
kubectl -n hello-flask apply -f k8s/Metrics addon (choose one) (REMINDER: Promethius operator (kube-promethius-stack) reqruired to be installed on the cluster first):
- Preferred (shared exporter):
- Ensure a cluster blackbox-exporter exists at
http://blackbox-exporter.monitoring.svc:9115 - Apply:
kubectl -n hello-flask apply -f k8s/monitoring/probe.yaml
- Ensure a cluster blackbox-exporter exists at
- Local exporter (if no shared exporter):
- Apply:
kubectl -n hello-flask apply -f k8s/monitoring/local-blackbox/
- Apply:
Gateway API (optional): If your cluster uses Gateway API, edit k8s/gateway/gateway.yaml to set your gatewayClassName (or omit if you already have a shared Gateway) and apply gateway.yaml + httproute.yaml.
Basic:
helm upgrade --install hello-flask ./helm/hello-flask --namespace hello-flask --create-namespace --set image.repository=your-registry/hello-flask --set image.tag=0.1.0 --set ingress.hosts[0].host=hello.example.comThe chart now defaults the path to "/" if omitted, so the above works without specifying
paths.
Immutable image (digest):
helm upgrade --install hello-flask ./helm/hello-flask --namespace hello-flask --create-namespace --set image.repository=your-registry/hello-flask --set image.digest=sha256:YOUR_DIGEST --set ingress.hosts[0].host=hello.example.comUse Gateway API instead of Ingress:
helm upgrade --install hello-flask ./helm/hello-flask --namespace hello-flask --create-namespace --set image.repository=your-registry/hello-flask --set image.tag=0.1.0 --set gatewayApi.enabled=true --set gatewayApi.gatewayRef.name=web --set gatewayApi.gatewayRef.namespace=hello-flaskMetrics addon with shared exporter (Probe CRD):
helm upgrade --install hello-flask ./helm/hello-flask --namespace hello-flask --create-namespace --set image.repository=your-registry/hello-flask --set image.tag=0.1.0 --set ingress.hosts[0].host=hello.example.com --set metrics.blackbox.enabled=true --set metrics.blackbox.useProbe=true --set metrics.blackbox.proberUrl="http://blackbox-exporter.monitoring.svc:9115" --set metrics.blackbox.targetUrl="https://hello.example.com/"Metrics addon with local exporter (if no shared one):
helm upgrade --install hello-flask ./helm/hello-flask --namespace hello-flask --create-namespace --set image.repository=your-registry/hello-flask --set image.tag=0.1.0 --set ingress.hosts[0].host=hello.example.com --set metrics.blackbox.enabled=true --set metrics.blackbox.createExporter=true --set metrics.blackbox.targetUrl="https://hello.example.com/"- App:
curl -I https://hello.example.com/> HTTP 200 - Prometheus:
probe_success{}andprobe_duration_seconds{}for your job/instance
- GitHub Actions to build/push image, lint YAML, and run
helm template+ schema validation. - Argo CD/Flux for declarative, auditable rollouts per environment (dev/staging/prod values).
- Dockerfile + K8s manifests deploy the Flask app as a web service with a dummy URL (Ingress or HTTPRoute).
- Designed for production quality, HA, and scalability (HPA, PDB, zone/node spread, security contexts).
- No hostPort; traffic via shared Ingress or Gateway.
- Reproducibility & cost: Helm chart, default resource envelopes (LimitRange), namespace guardrails (ResourceQuota), shared edge, and low-overhead metrics pattern suitable for "20 additional similar applications."