Deploy Laravel Application บน Kubernetes พร้อม Redis Queue
การ Deploy Laravel ไปยัง Kubernetes เป็นแนวทางที่ยอดเยี่ยมสำหรับการสร้างระบบ Production-Ready ที่มีการจัดการ PHP-FPM, Nginx, MySQL, Redis และ Queue Workers อย่างครบถ้วน บทความนี้จะแนะนำวิธีการ Deploy Laravel บน Kubernetes Cluster พร้อมกับ Redis Queue สำหรับการประมวลผลงานแบบ Asynchronous
ทำไมต้อง Deploy Laravel บน Kubernetes
- Microservices Architecture: แยก Laravel Application ออกเป็น Web Server, PHP-FPM, Worker และ Database Containers ที่เป็นอิสระ
- Scalability: ปรับจำนวน Web Server และ Queue Workers ได้อย่างอิสระตามความต้องการของระบบ
- Queue Jobs: Redis Queue สำหรับการประมวลผลงานที่ต้องเวลานาน (Long-Running Tasks)
- Data Persistence: MySQL StatefulSet สำหรับการเก็บข้อมูล และ Redis สำหรับ Caching
- High Availability: ระบบจะทำงานต่อได้หากมี Pod ตัวหนึ่งเกิดปัญหา
Architecture ของ Laravel บน Kubernetes
ระบบ Production-Ready ของ Laravel บน Kubernetes ประกอบด้วยส่วนประกอบหลัก ดังต่อไปนี้:
- Nginx Service: ทำหน้าที่เป็น Reverse Proxy และ Load Balancer สำหรับจัดการคำขอจาก Clients
- PHP-FPM Deployment: หลาย Replicas ที่รัน Laravel Application
- Queue Workers: Separate Deployment สำหรับการประมวลผล Queue Jobs
- MySQL StatefulSet: เก็บข้อมูลของ Application และรักษาความสอดคล้องของข้อมูล
- Redis Deployment: สำหรับ Caching และ Queue Storage
- ConfigMap และ Secret: เก็บ .env Configuration และ Sensitive Data อย่างปลอดภัย
1. สร้าง Namespace
kubectl create namespace laravel
kubectl config set-context --current --namespace=laravel
2. สร้าง Secret สำหรับ .env
เก็บ Laravel Configuration อย่างปลอดภัยโดยใช้ Kubernetes Secret:
cat > laravel.env << EOF
APP_KEY=base64:your-base64-encoded-key
APP_DEBUG=false
APP_URL=https://yourapp.com
DB_CONNECTION=mysql
DB_HOST=mysql.laravel.svc.cluster.local
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=your-secure-password
REDIS_HOST=redis.laravel.svc.cluster.local
REDIS_PASSWORD=your-redis-password
REDIS_PORT=6379
QUEUE_CONNECTION=redis
EOF
kubectl create secret generic laravel-env --from-file=laravel.env -n laravel
3. สร้าง MySQL StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: laravel
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "root-password"
- name: MYSQL_DATABASE
value: "laravel"
- name: MYSQL_USER
value: "laravel"
- name: MYSQL_PASSWORD
value: "your-secure-password"
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 20Gi
4. สร้าง MySQL Service
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: laravel
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
5. สร้าง Redis Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: laravel
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
command:
- redis-server
- "--requirepass"
- "your-redis-password"
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
6. สร้าง Redis Service
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: laravel
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
7. สร้าง Laravel PHP-FPM Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: laravel-app
namespace: laravel
spec:
replicas: 3
selector:
matchLabels:
app: laravel-app
template:
metadata:
labels:
app: laravel-app
spec:
containers:
- name: php-fpm
image: your-registry/laravel-app:latest
ports:
- containerPort: 9000
env:
- name: APP_ENV
value: "production"
volumeMounts:
- name: laravel-env
mountPath: /var/www/html/.env
subPath: laravel.env
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
livenessProbe:
tcpSocket:
port: 9000
initialDelaySeconds: 10
periodSeconds: 10
volumes:
- name: laravel-env
secret:
secretName: laravel-env
8. สร้าง Nginx Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: laravel
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
- name: laravel-app
mountPath: /var/www/html
volumes:
- name: nginx-config
configMap:
name: nginx-config
- name: laravel-app
emptyDir: {}
9. สร้าง Nginx ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: laravel
data:
default.conf: |
upstream php-fpm {
server laravel-app:9000;
}
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.php;
location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
10. สร้าง Queue Workers Deployment
สร้าง Separate Deployment สำหรับการประมวลผล Queue Jobs จาก Redis Queue:
apiVersion: apps/v1
kind: Deployment
metadata:
name: laravel-worker
namespace: laravel
spec:
replicas: 2
selector:
matchLabels:
app: laravel-worker
template:
metadata:
labels:
app: laravel-worker
spec:
containers:
- name: queue-worker
image: your-registry/laravel-app:latest
command: ["php", "artisan", "queue:work", "redis", "--tries=3"]
env:
- name: APP_ENV
value: "production"
volumeMounts:
- name: laravel-env
mountPath: /var/www/html/.env
subPath: laravel.env
resources:
limits:
memory: "256Mi"
cpu: "250m"
requests:
memory: "128Mi"
cpu: "100m"
volumes:
- name: laravel-env
secret:
secretName: laravel-env
11. สร้าง Nginx Service
apiVersion: v1
kind: Service
metadata:
name: laravel-app
namespace: laravel
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
ตรวจสอบและจัดการ Laravel บน Kubernetes
# สร้าง Database
kubectl exec -it mysql-0 -n laravel -- \
mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS laravel;"
# รันการ Migrate ของ Laravel
kubectl exec -it $(kubectl get pod -l app=laravel-app -n laravel -o jsonpath='{.items[0].metadata.name}') -n laravel -- \
php artisan migrate --force
# ตรวจสอบสถานะของ Pods
kubectl get pods -n laravel
# ตรวจสอบสถานะของ Services
kubectl get svc -n laravel
HorizontalPodAutoscaler สำหรับ Auto Scaling
สามารถตั้งค่า HPA เพื่อให้ระบบสามารถ Scale ได้อัตโนมัติตามการใช้งาน CPU:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: laravel-app-hpa
namespace: laravel
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: laravel-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Best Practices สำหรับ Laravel บน Kubernetes
- ใช้ Secret สำหรับเก็บข้อมูลที่มีความเสี่ยง แทนการใช้ Environment Variables โดยตรง
- กำหนด Resource Requests และ Limits เพื่อควบคุมการใช้งานทรัพยากร
- เพิ่มจำนวน Queue Workers ตามความต้องการของงาน Asynchronous
- ใช้ Health Checks (Liveness Probe และ Readiness Probe) เพื่อตรวจสอบสถานะของ Pods
- มีกลยุทธ์ Database Migration ที่ปลอดภัย เพื่อหลีกเลี่ยงข้อมูลสูญหาย
- ใช้ PersistentVolume สำหรับเก็บข้อมูลที่ต้องการเก็บรักษาอย่างยาวนาน
- ทำการ Monitor และ Logging ด้วยเครื่องมือเช่น Prometheus, ELK Stack หรือ CloudWatch
บทสรุป
การ Deploy Laravel บน Kubernetes ให้ความยืดหยุ่นและความเสถียรในการจัดการแอปพลิเคชัน ด้วยการ Scale อัตโนมัติ, Caching ด้วย Redis และการประมวลผล Queue Jobs อย่างมีประสิทธิภาพ สามารถสร้างระบบที่พร้อมสำหรับ Production และรองรับภาระงานที่สูงได้
