Mengekspos aplikasi Laravel ke dunia luar: membuat Service ClusterIP, memasang NGINX Ingress dengan aturan host-path, mengonfigurasi alias /storage di Nginx untuk menyajikan media dari volume, dan menguji end-to-end upload sampai URL publik

Deployment sudah sehat dan data berbagi antar replica. Sekarang, apa gunanya aplikasi kalau tidak bisa diakses? Di episode 11 kita membangun jalur masuk: Service menstabilkan alamat internal, Ingress membawa traffic dari internet ke Service, dan konfigurasi Nginx memastikan media di volume tampil di URL publik.
Episod ini adalah titik validation paling menyenangkan: pada akhirnya kalian upload foto, lalu membuka https://laravel.example.com/storage/uploads/foto.jpg di browser dan file itu benar-benar muncul.
Pod bisa datang dan pergi; IP-nya berubah. Service memberi alamat stabil (ClusterIP) yang mem-forward traffic ke Pod sehat:
apiVersion: v1
kind: Service
metadata:
name: laravel
spec:
selector:
app: laravel
ports:
- port: 80
targetPort: 80kubectl apply -f service-laravel.yaml
kubectl get svc laravelJika nginx dan php-fpm di container terpisah, buat juga Service internal untuk FPM (port 9000) supaya nginx bisa memakai hostname stabil:
apiVersion: v1
kind: Service
metadata:
name: laravel-fpm
spec:
selector:
app: laravel
ports:
- port: 9000
targetPort: 9000Traffic eksternal butuh pintu masuk. Di cluster kita memakai NGINX Ingress Controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.1/deploy/static/provider/metal/nginx-ingress.yaml(Alternatif: Traefik atau Gateway API. Logikanya sama: objek yang memetakan host/path ke Service.)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: laravel
spec:
ingressClassName: nginx
rules:
- host: laravel.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: laravel
port:
number: 80kubectl apply -f ingress-laravel.yaml
kubectl get ingressTambahkan host laravel.example.com ke /etc/hosts workstation atau DNS agar alamat mengarah ke IP Ingress.
File media publik berada di storage/app/public — di Pod kita ter-mount di /var/www/public/storage. Agar URL /storage/... langsung melayani file dari volume, Nginx perlu alias:
server {
listen 80;
server_name _;
root /var/www/public;
location /storage/ {
alias /var/www/public/storage/;
expires 30d;
access_log off;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}Pastikan symlink storage dibuat — di episode 12 kita buat lewat init container (untuk volume pertama kali). Untuk sekarang, verifikasi folder mount ada:
kubectl exec deploy/laravel -- ls -la /var/www/public/curl -F "photo=@/path/ke/foto.jpg" \
https://laravel.example.com/api/uploadcurl -I https://laravel.example.com/storage/uploads/foto.jpgJika docker/curl mengembalikan HTTP/1.1 200 OK pada file media, seluruh jalur berfungsi: browser → Ingress → Service → Pod → NFS server → file yang sama terlihat semua user.
Tip
Cache selama 30 hari (expires 30d) besar artinya untuk performa: media di NFS hanya dibaca sekali dari server, sisanya disajikan dari cache nginx/ingress. Kombinasi ini mengurangi beban NFS secara signifikan di episode 19 saat replica bertambah.
Pada episode 11 ini, aplikasi kalian sudah hidup dan media publiknya berfungsi:
Inti yang harus dibawa pulang:
ClusterIP memberi alamat stabil ke Pod (dan Service internal untuk FPM bila terpisah).laravel.example.com ke Service./storage/ menyajikan file dari volume RWX di public/storage.https://.../storage/uploads/foto.jpg.Di episode 12 selanjutnya kita akan mengurus data awal: seed & migrate — init container untuk menyiapkan folder dan symlink, Job php artisan migrate --force, serta menjaga idempotensi agar data yang ada tidak tertimpa. Sampai jumpa di episode 12!