Sistema de Apoio ao Processo Legislativo
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

6.0 KiB

SAPL — Kubernetes Redis

Manifests for the shared Redis instance used by all SAPL pods for cross-pod rate limiting (DB 1) and view/static-file caching (DB 0).


Directory layout

docker/k8s/
├── redis-configmap.yaml    # redis.conf — no persistence, allkeys-lru, 5 GB ceiling
├── redis-deployment.yaml   # Deployment (1 replica, redis:7-alpine)
├── redis-service.yaml      # ClusterIP service on port 6379
└── README.md               # this file

Prerequisites

  • kubectl configured to talk to the target cluster.
  • A redis namespace (created below if it doesn't exist).

Deploy

# 1. Create the namespace (idempotent)
kubectl create namespace redis --dry-run=client -o yaml | kubectl apply -f -

# 2. Apply all three manifests
kubectl apply -f docker/k8s/redis-configmap.yaml
kubectl apply -f docker/k8s/redis-deployment.yaml
kubectl apply -f docker/k8s/redis-service.yaml

# 3. Verify the pod is Running
kubectl -n redis get pods -l app=sapl-redis

Expected output:

NAME                          READY   STATUS    RESTARTS   AGE
sapl-redis-6d9f8b7c4d-xk2lm   1/1     Running   0          30s

Wire a SAPL namespace to Redis

# Create the per-namespace Secret (one-off per tenant)
kubectl create secret generic sapl-redis \
  --namespace=<NAMESPACE> \
  --from-literal=REDIS_URL="redis://sapl-redis.redis.svc.cluster.local:6379" \
  --dry-run=client -o yaml | kubectl apply -f -

# Ensure the waffle switch row exists (starts OFF)
kubectl exec -n <NAMESPACE> deploy/sapl -- \
  python manage.py waffle_switch REDIS_CACHE off --create

# Enable Redis for this namespace
kubectl exec -n <NAMESPACE> deploy/sapl -- \
  python manage.py waffle_switch REDIS_CACHE on

# Rolling restart so start.sh picks up the new switch value
kubectl rollout restart deployment/sapl -n <NAMESPACE>
kubectl rollout status  deployment/sapl -n <NAMESPACE>

Fleet-wide rollout

kubectl get namespaces -l app=sapl -o name | sed 's|namespace/||' | \
  xargs -P 10 -I{} kubectl exec -n {} deploy/sapl -- \
    python manage.py waffle_switch REDIS_CACHE on --create

kubectl get namespaces -l app=sapl -o name | sed 's|namespace/||' | \
  xargs -P 5 -I{} kubectl rollout restart deployment/sapl -n {}

Roll back (without removing the Secret)

kubectl exec -n <NAMESPACE> deploy/sapl -- \
  python manage.py waffle_switch REDIS_CACHE off
kubectl rollout restart deployment/sapl -n <NAMESPACE>

Monitor

Pod and events

# Pod status
kubectl -n redis get pods -l app=sapl-redis -o wide

# Deployment events (useful right after apply)
kubectl -n redis describe deployment sapl-redis

# Pod events (OOMKill, restarts, etc.)
kubectl -n redis describe pod -l app=sapl-redis

Logs

# Tail live logs
kubectl -n redis logs -f deploy/sapl-redis

# Last 100 lines
kubectl -n redis logs deploy/sapl-redis --tail=100

Redis INFO

# Memory usage
kubectl exec -n redis deploy/sapl-redis -- \
  redis-cli info memory \
  | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'

# Connection pressure
kubectl exec -n redis deploy/sapl-redis -- \
  redis-cli info stats \
  | grep -E 'rejected_connections|instantaneous_ops_per_sec'

# Key distribution per DB
kubectl exec -n redis deploy/sapl-redis -- redis-cli info keyspace

# Recent slow queries
kubectl exec -n redis deploy/sapl-redis -- redis-cli slowlog get 10

# Live command sampling (1-second window)
kubectl exec -n redis deploy/sapl-redis -- redis-cli --latency-history -i 1

Rate-limiter keys (DB 1)

kubectl exec -n redis deploy/sapl-redis -- \
  redis-cli -n 1 dbsize

kubectl exec -n redis deploy/sapl-redis -- \
  redis-cli -n 1 --scan --pattern 'rl:ip:*' | head -20

Seed the UA deny list (once after first deploy)

kubectl exec -n redis deploy/sapl-redis -- redis-cli -n 1 \
  SADD rl:bot:ua:blocked \
    "$(echo -n 'GPTBot'             | sha256sum | cut -d' ' -f1)" \
    "$(echo -n 'ClaudeBot'          | sha256sum | cut -d' ' -f1)" \
    "$(echo -n 'PerplexityBot'      | sha256sum | cut -d' ' -f1)" \
    "$(echo -n 'Bytespider'         | sha256sum | cut -d' ' -f1)" \
    "$(echo -n 'AhrefsBot'          | sha256sum | cut -d' ' -f1)" \
    "$(echo -n 'meta-externalagent' | sha256sum | cut -d' ' -f1)"

# Add a new offender at runtime (no restart required)
kubectl exec -n redis deploy/sapl-redis -- redis-cli -n 1 \
  SADD rl:bot:ua:blocked "$(echo -n 'NewBot/1.0' | sha256sum | cut -d' ' -f1)"

Local standalone Redis (development / testing)

No Kubernetes? Run Redis directly with Docker:

sudo docker run --rm -p 6379:6379 redis:7-alpine \
  redis-server --save "" --appendonly no

Then point Django at it by exporting the env var before starting the dev server:

export REDIS_URL="redis://localhost:6379"
export CACHE_BACKEND="redis"
python manage.py runserver

Or add them to your local .env file:

REDIS_URL=redis://localhost:6379
CACHE_BACKEND=redis

Note: the waffle switch REDIS_CACHE must also be on in your local database for start.sh to activate the Redis backend. Run:

python manage.py waffle_switch REDIS_CACHE on --create

Update redis.conf without redeploying

# Edit the ConfigMap
kubectl -n redis edit configmap redis-config

# Restart the pod to pick up the new config
kubectl -n redis rollout restart deployment/sapl-redis

Key schema reference

DB Use case Key pattern TTL
0 Page / view cache sapl:cache:* 60 – 3 600 s
0 Static file cache (logos) static:{ns}:{sha256} 3 – 24 h
0 PDF cache (≤ 360 KB) file:{ns}:{sha256} 1 h
1 IP rate-limit counter rl:ip:{ip}:reqs 60 s
1 IP blocked marker rl:ip:{ip}:blocked 300 s
1 User rate-limit counter rl:{ns}:user:{id}:reqs 60 s
1 Path counter rl:{ns}:path:{sha256}:reqs 60 s
1 UA deny list rl:bot:ua:blocked permanent SET
2 Django Channels (future) channels:* session TTL