Commit graph

28 commits

Author SHA1 Message Date
5152ceac8b
fix: simplify Redis host to just 'valkey' for same-namespace service 2026-01-18 12:06:44 -06:00
7e9940c619
fix(k8s): use ClusterIP service and FQDN for Valkey connection
Changed Valkey service from headless to ClusterIP and updated
REDIS_HOST to use full FQDN for more reliable DNS resolution.

Changes:
- valkey-service.yaml: Changed from headless (clusterIP: None) to ClusterIP
- deployment.yaml: Changed REDIS_HOST from "valkey" to "valkey.towerops.svc.cluster.local"

This ensures stable ClusterIP and explicit DNS resolution for Redis connections.
2026-01-18 11:23:51 -06:00
bac286ee1b
feat(k8s): move Valkey to standalone StatefulSet
Previously Valkey ran as a sidecar container in the main deployment,
causing it to restart every time the web app deployed. This resulted
in connection errors and cache loss during deployments.

Changes:
- Created valkey-statefulset.yaml with StatefulSet resource (1 replica)
- Created valkey-service.yaml with headless service
- Removed Valkey sidecar container from deployment.yaml
- Updated REDIS_HOST from 127.0.0.1 to valkey-0.valkey.towerops.svc.cluster.local
- Added new resources to kustomization.yaml

Benefits:
- Valkey persists across web app deployments
- No connection errors during rolling updates
- Cache data preserved
- Independent scaling and resource management
2026-01-18 11:10:36 -06:00
cafca82dd4
scale: increase production replicas to 4 pods
With Horde's distributed supervision, devices will automatically
distribute ~25% per pod across all 4 replicas.

Benefits:
- 4x horizontal scaling for device monitoring and SNMP polling
- Better fault tolerance (can lose 3 pods and still operate)
- Automatic load balancing via consistent hashing
- Each device still polls from exactly ONE pod (no duplicates)
2026-01-18 10:15:59 -06:00
3b4fd98b21
Update debug script to select only running pods
Changed pod selection to use --field-selector=status.phase=Running
to avoid selecting Terminating pods during rollout
2026-01-17 17:23:36 -06:00
77562cafb5
Add Redis/Valkey debugging script for production
Script checks:
- Container status in pod
- Valkey logs
- Network connectivity from towerops to Valkey
- Environment variables
- Valkey health

Usage: ./k8s/debug-redis.sh [namespace]
2026-01-17 17:20:37 -06:00
5836925166
Fix Redis connection in production with startup probe and explicit 127.0.0.1
Changes:
- Added startupProbe to towerops container to allow up to 70s for startup
  (gives Valkey sidecar time to be ready)
- Changed REDIS_HOST from 'localhost' to '127.0.0.1' for explicit loopback
- Removed initialDelaySeconds from liveness/readiness probes (handled by startup)
- Added comment clarifying Redis connects to Valkey sidecar

This ensures the app waits for Valkey to be ready before accepting traffic.
2026-01-17 17:20:14 -06:00
eb7b57aa42
feat: add Valkey as k8s sidecar for Redis compatibility
- Add Valkey 8.0 alpine container as sidecar in k8s deployment
- Configure with appropriate security context (non-root, no privilege escalation)
- Add resource limits (256Mi memory, 200m CPU) and requests (128Mi, 50m)
- Add health probes using valkey-cli ping command
- Configure Redis connection via REDIS_HOST and REDIS_PORT environment variables
- Add Redis config to runtime.exs, dev.exs, and test.exs
- Valkey runs on localhost:6379 within the same pod as Phoenix app
2026-01-17 16:30:38 -06:00
9c2d95b55a
Add zero-downtime deployment configuration
Prevent WebSocket disconnections during deployments by:

1. Rolling Update Strategy:
   - maxSurge: 1 (allow 1 extra pod during rollout)
   - maxUnavailable: 0 (keep all pods running)
   - minReadySeconds: 10 (wait before continuing rollout)

2. Graceful Shutdown:
   - terminationGracePeriodSeconds: 30 (allow Phoenix to drain connections)

3. PodDisruptionBudget:
   - minAvailable: 1 (ensure at least 1 pod always available)
   - Prevents all pods from being terminated simultaneously

4. Improved Health Checks:
   - Faster readiness probe (5s initial, 3s period)
   - More aggressive success/failure thresholds
   - New pods marked ready faster

This ensures new pods are fully ready and serving traffic before old
pods are terminated, maintaining WebSocket connections and preventing
'something went wrong' errors during deployments.
2026-01-17 12:44:22 -06:00
07b0ddb67d
Set DEPLOY_TIMESTAMP from GitLab CI instead of pod metadata
- Update GitLab CI deploy job to set DEPLOY_TIMESTAMP when deploying
- Use 'kubectl set env' to update all pods with same timestamp
- Change deployment.yaml to use static placeholder value
- Update documentation to explain GitLab CI timestamp approach

This ensures all pods show the same deployment time, regardless of:
- Which pod handles the request (with replicas=2)
- When individual pods were created or restarted
- Pod restarts from crashes or rolling updates

The timestamp now represents when the deployment was initiated by GitLab CI,
not when individual pods were created.
2026-01-17 11:17:07 -06:00
9fcf19b304
Use Kubernetes pod creation timestamp for deploy time in footer
- Read DEPLOY_TIMESTAMP environment variable for actual deploy time
- Fall back to compile time in development when env var not set
- Add Kubernetes Downward API to inject metadata.creationTimestamp
- Update k8s/deployment.yaml to set DEPLOY_TIMESTAMP env var
- Document deployment timestamp mechanism in k8s/README.md

This ensures the footer shows when the pod was deployed to the cluster,
not when the Docker image was built in CI/CD.
2026-01-17 11:14:15 -06:00
ae949b4a0b
Remove secretGenerator from kustomization for GitOps compatibility
Secrets are now managed directly in the cluster rather than generated
from .envrc files. This fixes FluxCD reconciliation errors since .envrc
is gitignored and cannot be used in GitOps workflows.

All secrets have been backed up to 1Password for disaster recovery.
2026-01-14 13:09:19 -06:00
1b8017dd98
change replicas 2026-01-12 10:43:24 -06:00
d382f6a46e
update gitlab ci 2026-01-11 13:33:54 -06:00
0f238ac33d
set up ses 2026-01-09 16:52:11 -06:00
fd317770fe
Fix health check logging with dynamic log level in endpoint
Use Plug.Telemetry's dynamic log level feature to disable logging for
/health requests. This is the proper Phoenix way to exclude specific
endpoints from request logs.

- Add log_level/1 function to endpoint that returns false for /health
- Configure Plug.Telemetry to use dynamic log level
- Remove log: false from router (handled by endpoint now)

This prevents Kubernetes health probe spam in application logs.
2026-01-06 13:57:32 -06:00
40d699716e
Increase pod memory to 2GB
- Set memory request to 1Gi
- Set memory limit to 2Gi
2026-01-04 12:47:57 -06:00
25b82848d6
Run migrations on app start instead of separate job
- Migrations now run in Application.start/2 before starting services
- Ecto's advisory locks prevent concurrent migrations in clustered setup
- Simplified deployment - no separate migration job needed
- Removed migrate-job.yaml manifest
2026-01-03 16:09:31 -06:00
66ed55d78e
Add security context to meet PodSecurity restricted standard
- Set runAsNonRoot and runAsUser to 65534 (nobody)
- Disable privilege escalation
- Drop all Linux capabilities
- Use RuntimeDefault seccomp profile
- Applies to both migration job and main deployment
2026-01-03 16:02:27 -06:00
d7481dc0fd
Silence debconf warnings in Docker builds
Set DEBIAN_FRONTEND=noninteractive for all apt-get operations
to prevent interactive frontend warnings in build logs
2026-01-03 16:00:54 -06:00
1ea4496e95
Add BuildKit cache mounts to speed up Docker builds
- Cache Hex packages across builds
- Cache Mix archives across builds
- Cache npm packages for asset tooling
- Speeds up dependency installation significantly
2026-01-03 15:55:24 -06:00
7339ac7eec
Add automatic database migrations on deployment
- Create Kubernetes Job to run migrations before deployment
- Update GitLab CI to execute migration job and wait for completion
- Ensures migrations run once per deployment in clustered environment
- Migration job uses PostgreSQL advisory locks to prevent race conditions
2026-01-03 15:50:01 -06:00
570c6d03b3
Dockerfile improvements 2026-01-03 15:38:14 -06:00
80cc5e937e
add sendgrid 2026-01-03 15:26:48 -06:00
da42d64494
cluster 2026-01-02 15:29:02 -06:00
faffc050c2
Add imagePullSecrets for GitLab registry 2026-01-02 15:10:47 -06:00
a8bcd4d411
Remove www subdomain from certificate and IngressRoute 2026-01-02 15:06:21 -06:00
92c5160f6e
Add Kubernetes deployment manifests for towerops.net 2026-01-02 14:38:52 -06:00