When deploying applications on Kubernetes, one of the biggest architectural challenges is handling application state, especially user sessions. Kubernetes is designed for stateless workloads, but most real-world applications are not completely stateless.
In this blog, I’ll walk through a real, end-to-end DevOps implementation where I:
- Deployed a Laravel application on Kubernetes
- Used Helm for reproducible deployments
- Integrated Redis as a centralized session store
- Configured Redis persistence using PVC
- Enabled Redis master–replica architecture
- Tested real production failure scenarios
This blog focuses on how production systems actually behave, not just how to deploy them successfully.
Problem Statement: Why File-Based Sessions Fail in Kubernetes
Laravel stores user sessions on the local filesystem by default. This approach works well in traditional single-server deployments. However, it fails in Kubernetes because Kubernetes is built for ephemeral and distributed workloads. Application pods can restart at any time. Kubernetes may also reschedule pods to different nodes or scale them horizontally based on traffic.
When Laravel stores session data inside a pod’s filesystem, the session becomes tied to that pod’s lifecycle. If Kubernetes restarts or replaces the pod, the session data disappears. This behavior causes unexpected user logouts and a poor user experience. The issue becomes more serious when multiple replicas run behind a load balancer. Each pod maintains its own local session storage. As a result, requests from the same user may hit different pods, which leads to session inconsistency and frequent logouts.
To fix this problem, session management needs to move outside the application pods. A centralized session store allows all application replicas to access the same session data. This design keeps sessions consistent, no matter which pod handles a request. The session store must also persist data independently of pod restarts to survive failures. Redis solves this problem effectively. It provides high performance, supports large concurrency, and works well as a distributed session store. By storing Laravel sessions in Redis instead of the pod filesystem, the application becomes stateless, scalable, and reliable in a Kubernetes environment.
Architecture

End To End Implementation
Step 1: Containerizing the Laravel Application
A Dockerfile is used to package the Laravel application:
FROM php:8.1-apache
WORKDIR /var/www/html
RUN apt-get update && apt-get install -y \
git unzip curl \
libpng-dev libonig-dev libxml2-dev libzip-dev \
&& docker-php-ext-install pdo_mysql mbstring zip \
&& a2enmod rewrite
COPY . .
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
RUN composer install --no-interaction --optimize-autoloader
RUN chown -R www-data:www-data storage bootstrap/cache
EXPOSE 80
CMD ["apache2-foreground"]
The image is built and pushed to Docker Hub for Kubernetes consumption.
Step 2: Deploying Redis with Persistence & Replication (Helm)
Redis is deployed using the Bitnami Redis Helm chart, which provides production-ready defaults.
Redis Helm Values (redis-values.yaml)
architecture: replication
auth:
enabled: true
password: redis123
master:
persistence:
enabled: true
size: 8Gi
replica:
replicaCount: 2
persistence:
enabled: true
size: 8GiInstall Redis
helm install inventory-redis bitnami/redis \
-n staging \
-f redis-values.yaml
Result
- 1 Redis master pod
- 2 Redis replica pods
- 1 PVC per Redis pod
This ensures high availability and persistence.
Step 3: Deploying Laravel Using Helm
Laravel is deployed using a custom Helm chart.
Kubernetes Resources
- Deployment → Laravel application
- Service (NodePort) → External access
- Environment variables → Injected via Helm values
helm install inventory-app ./inventory-app -n staging
This allows clean upgrades and rollbacks.
Step 4: Configuring Laravel to Use Redis Sessions
Laravel session configuration is injected via Helm, not hardcoded .env files.
SESSION_DRIVER=redis
CACHE_DRIVER=redis
REDIS_HOST=inventory-redis-master
REDIS_PORT=6379
REDIS_PASSWORD=redis123
SESSION_COOKIE=inventory_session
SESSION_SECURE_COOKIE=false
SESSION_SAME_SITE=lax
This makes the container immutable and environment-agnostic.

Step 5: Creating a Session Test Endpoint
To verify Redis-backed sessions, a test route is added:
Route::get('/session', function () {
session(['test_session' => 'redis_is_working']);
return response()->json([
'message' => 'Session created',
'value' => session('test_session'),
'session_id' => session()->getId(),
]);
});
Access:
http://<EC2_PUBLIC_IP>:<NODE_PORT>/session
Step 6: Verifying Sessions Inside Redis
kubectl exec -it inventory-redis-master-0 -- redis-cli -a redis123
SCAN 0
GET <session-key>
TTL <session-key>Confirmation
- Sessions are stored in Redis
- TTL is correctly applied
- Persistence is enabled via PVC
verify pvc is creted or not
kubectl get pvc -n staging
Step 7: Failure Testing (Real Production Scenarios)
Scenario 1: Application Pod Deletion
kubectl delete pod inventory-app-xxxxx
Result
- New pod is created automatically
- User remains logged in
- Session remains active
Reason:
Application pods are stateless; sessions live in Redis.
Scenario 2: Redis Master Pod Deletion
kubectl delete pod inventory-redis-master-0
Result
- Redis pod is recreated
- PVC is reattached
- Data still exists
Expected Behavior
- Some sessions may require re-login
- Redis restarts can invalidate in-memory session metadata
This is normal behavior and must be considered in production.
Conclusion
This end-to-end implementation demonstrates how to design and deploy a production-ready Laravel application on Kubernetes by following core cloud-native principles. By decoupling session management from application pods and using Redis as a centralized session store, the application achieves true statelessness, which is essential for scalability and resilience in Kubernetes environments. Helm simplifies deployments and configuration management, while Redis persistence through Persistent Volume Claims ensures that session data survives pod restarts and node failures.
Testing real failure scenarios plays a critical role in validating this architecture. Application pod deletion does not impact user sessions because Redis manages state externally. Redis pod restarts preserve data through PVC reattachment, although some session revalidation may occur, which is expected behavior in real-world systems. These tests highlight the importance of designing for failure rather than assuming ideal conditions.
Overall, this setup reflects how modern production systems operate on Kubernetes. It reinforces key DevOps concepts such as stateless application design, stateful service management, reproducible deployments, and failure-first thinking. Anyone learning Kubernetes or DevOps should go beyond successful deployments and actively test failure scenarios to truly understand system behavior under real production conditions.


