LAB10: Deployment & Autoscaling
Let's build app which computes prime numbers
Python app source
import os
import socket
import time
from typing import List
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class PrimeRequest(BaseModel):
n: int
class PrimeResponse(BaseModel):
n: int
prime_count: int
time_taken_seconds: float
pod_name: str
hostname: str
primes: List[int]
def generate_primes(limit: int) -> List[int]:
primes = []
for num in range(2, limit + 1):
is_prime = True
# naive but CPU-heavy enough for HPA testing
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
is_prime = False
break
if is_prime:
primes.append(num)
return primes
@app.post("/primes", response_model=PrimeResponse)
def compute_primes(req: PrimeRequest):
if req.n < 2:
raise HTTPException(status_code=400, detail="n must be >= 2")
start = time.perf_counter()
primes = generate_primes(req.n)
elapsed = time.perf_counter() - start
pod_name = os.environ.get("POD_NAME", "unknown-pod")
hostname = socket.gethostname()
return PrimeResponse(
n=req.n,
prime_count=len(primes),
time_taken_seconds=elapsed,
pod_name=pod_name,
hostname=hostname,
primes=primes,
)
@app.get("/info")
def info():
pod_name = os.environ.get("POD_NAME", "unknown-pod")
hostname = socket.gethostname()
return {
"message": "Prime calculator HPA lab",
"pod_name": pod_name,
"hostname": hostname,
}
:::
:::spoiler requirements.txt
fastapi
uvicorn[standard]
:::
:::spoiler Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy app code
COPY app.py .
# Run the FastAPI app with uvicorn
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Docker build and push
docker build -t openlabfree/prime-hpa-lab:v1 .
docker push openlabfree/prime-hpa-lab:v1Check if you cluster has metric-server installed or not
kubectl top nodes
kubectl top pod
kubectl get apiservices | grep metricsIf no metrics shown, then install metric server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Verify Metrics Server Pod
kubectl get pods -n kube-system | grep metrics
Test API availability
Note: try editing deployment file , and adding
--kubelet-insecure-tlsflag in container start command.
If not running, apply patch
Delete old pods
Wait 10–20 seconds. 9. Verify result
Test metrics
[Optional]
If you like to query directly to node metrics api
```bash #!/bin/bash set -euo pipefail
echo "-----------------------------------------------------" echo " 🔐 Kubernetes system:masters Client Cert Generator" echo "-----------------------------------------------------"
--- CONFIG ---
CA_FILE="/etc/kubernetes/pki/ca.crt" CA_KEY="/etc/kubernetes/pki/ca.key" WORKDIR="$(pwd)"
ADMIN_KEY="$WORKDIR/kubelet-admin.key" ADMIN_CSR="$WORKDIR/kubelet-admin.csr" ADMIN_CERT="$WORKDIR/kubelet-admin.crt" ADMIN_CNF="$WORKDIR/admin-masters.cnf" FULLCHAIN="$WORKDIR/kubelet-full-chain.crt"
--- Detect Hostname for curl Example ---
NODE_NAME="$(hostname)" echo "📌 Node hostname detected: $NODE_NAME" echo ""
--- Verify CA ---
echo "🔍 Checking Kubernetes CA..." if [[ ! -f "$CA_FILE" || ! -f "$CA_KEY" ]]; then echo "❌ Kubernetes CA files not found." echo "This script must run on a control-plane node with CA access." exit 1 fi echo " ✓ CA verified: $CA_FILE" echo ""
--- Prevent Accidental Overwrite ---
for f in "$ADMIN_KEY" "$ADMIN_CSR" "$ADMIN_CERT" "$ADMIN_CNF" "$FULLCHAIN"; do if [[ -f "$f" ]]; then echo "⚠️ Removing existing file: $f" rm -f "$f" fi done
--- Generate Key ---
echo "🔐 Generating private key..." openssl genrsa -out "$ADMIN_KEY" 2048 >/dev/null echo " ✓ $ADMIN_KEY" echo ""
--- Create CSR Config ---
echo "📄 Writing CSR configuration..." cat > "$ADMIN_CNF" <<EOF [ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn req_extensions = v3_req
[ dn ] CN = admin O = system:masters
[ v3_req ] basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuth EOF echo " ✓ CSR config: $ADMIN_CNF" echo ""
--- Generate CSR ---
echo "🔏 Generating CSR..." openssl req -new -key "$ADMIN_KEY" -out "$ADMIN_CSR" -config "$ADMIN_CNF" >/dev/null echo " ✓ CSR created: $ADMIN_CSR" echo ""
--- Sign Certificate ---
echo "🔐 Signing certificate with Kubernetes CA..." openssl x509 -req -in "$ADMIN_CSR" -CA "$CA_FILE" -CAkey "$CA_KEY" -CAcreateserial -out "$ADMIN_CERT" -days 365 -extensions v3_req -extfile "$ADMIN_CNF" >/dev/null echo " ✓ Certificate: $ADMIN_CERT" echo ""
--- Extract Full Kubelet CA chain ---
echo "🔍 Extracting kubelet CA certificate chain..." openssl s_client -showcerts -connect localhost:10250 </dev/null 2>/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > "$FULLCHAIN"
echo " ✓ Full chain written: $FULLCHAIN" echo ""
--- Show Certificate Details ---
echo "📜 Certificate details:" openssl x509 -in "$ADMIN_CERT" -noout -text | sed 's/^/ /' echo ""
--- Final Output ---
echo "-----------------------------------------------------" echo " 🎉 COMPLETED SUCCESSFULLY!" echo "-----------------------------------------------------" echo "Generated files:" echo " ✔ $ADMIN_KEY" echo " ✔ $ADMIN_CERT" echo " ✔ $ADMIN_CSR" echo " ✔ $ADMIN_CNF" echo " ✔ $FULLCHAIN" echo "" echo "You can now access kubelet securely:" echo "" echo "curl --cacert $FULLCHAIN \" echo " --cert $ADMIN_CERT \" echo " --key $ADMIN_KEY \" echo " https://$NODE_NAME:10250/stats/summary" echo "" echo "🟢 This certificate belongs to system:masters and has FULL kubelet privileges." echo "-----------------------------------------------------"
Let's deploy the app
prime-hpa-lab.yaml
```yaml apiVersion: v1 kind: Namespace metadata: name: hpa-lab --- apiVersion: apps/v1 kind: Deployment metadata: name: prime-api-deployment namespace: hpa-lab spec: replicas: 1 selector: matchLabels: app: prime-api template: metadata: labels: app: prime-api spec: containers: - name: prime-api image: openlabfree/prime-hpa-lab:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 8000 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name resources: # important: HPA uses CPU *requests* as baseline requests: cpu: "100m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" --- apiVersion: v1 kind: Service metadata: name: prime-api-service namespace: hpa-lab spec: selector: app: prime-api ports: - name: http port: 80 targetPort: 8000 type: ClusterIP
Test quickly via port-forward:
In another terminal:
Horizontal Pod Autoscaler (HPA)
Prereq: metrics-server must be installed and working
kubectl get apiservices | grep metricskubectl top pods -Ashould return data.
Create
prime-hpa.yaml:
Apply:
Generate Load via Service (to trigger autoscale)
Start launcher container
Then:
Verification inside the pod
Load generator
Example Output
Watch Autoscaling in Action Metrics:
HPA behavior:
Scaling events:
References:
Last updated