deploy Laravel in kubernetes (help)

I’m trying to deploy a laravel application in kubernetes at Google Cloud Platform.

I followed couple of tutorials and was successful trying them locally on a docker VM.

But when tried to deploy in kubernetes using an ingress to assign a domain name to the application. I keep getting the 502 bad gateway page.

I’m using a nginx ingress controller with image k8s.gcr.io/nginx-ingress-controller:0.8.3 and my ingress is as following

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - domainname.com
    secretName: sslcertificate
  rules:
  - host: domain.com
    http:
      paths:
      - backend:
          serviceName: service
          servicePort: 80
        path: /

I tried to add the dmain entry to the hosts file but with no luck !! is there a specific configurations I have to add to the configmap.yaml file for the nginx ingress controller?

1 Like

Alright, fellow developers! You’re looking to deploy your awesome Laravel application in Kubernetes? Let’s break it down step-by-step to make it as painless as possible.

Here’s a common approach and the key things you’ll need:

Core Concepts We’ll Touch On:

  • Dockerizing Your Laravel App: Packaging your application and its dependencies.
  • Kubernetes Manifests: YAML files defining your application’s deployment, services, etc.
  • Deployments: Managing the desired state of your application replicas.
  • Services: Exposing your application within the Kubernetes cluster.
  • Ingress (Optional but Recommended): Exposing your application to the outside world.
  • Secrets: Managing sensitive information like database credentials.
  • ConfigMaps: Managing non-sensitive configuration.

Here’s a Basic Workflow and Key Manifest Examples:

1. Dockerize Your Laravel Application:
First, you need a Dockerfile in the root of your Laravel project. Here’s a basic example:

Dockerfile
FROM php:8.3-fpm-alpine

WORKDIR /var/www/html

# Install system dependencies
RUN apk update && apk add --no-cache --virtual .build-deps \
    git \
    curl \
    libzip-dev \
    unzip

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql zip

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

# Copy application files
COPY . .

# Install PHP dependencies
RUN composer install --no-dev --optimize-autoloader

# Create storage link
RUN php artisan storage:link

# Set file permissions
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
RUN chmod -R 755 /var/www/html/bootstrap/cache /var/www/html/storage

# Expose port 80 (or your preferred port)
EXPOSE 80

# Set user for artisan commands
USER www-data

# Start PHP-FPM
CMD ["php-fpm"]

You’ll also likely need a .dockerignore file to exclude unnecessary files (like vendor, node_modules, etc.) from your Docker image.
Build your Docker image:

Bash
docker build -t your-registry/your-app-name:latest .
docker push your-registry/your-app-name:latest

Replace your-registry/your-app-name with your Docker registry details (e.g., Docker Hub, AWS ECR, etc.).

2. Kubernetes Deployment Manifest (deployment.yaml):
This defines how your Laravel application will be deployed and managed in Kubernetes.

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-app-deployment
spec:
  replicas: 3 # Adjust as needed
  selector:
    matchLabels:
      app: laravel-app
  template:
    metadata:
      labels:
        app: laravel-app
    spec:
      containers:
        - name: laravel-app-container
          image: your-registry/your-app-name:latest
          ports:
            - containerPort: 80
          env:
            - name: APP_KEY
              valueFrom:
                secretKeyRef:
                  name: laravel-secrets
                  key: app-key
            - name: DB_HOST
              valueFrom:
                secretKeyRef:
                  name: laravel-secrets
                  key: db-host
            - name: DB_DATABASE
              valueFrom:
                secretKeyRef:
                  name: laravel-secrets
                  key: db-database
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: laravel-secrets
                  key: db-username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: laravel-secrets
                  key: db-password
            # Add other environment variables as needed
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 15
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 30
            periodSeconds: 10

Key points in the deployment.yaml:

  • replicas: The number of instances (Pods) of your application you want running.
  • selector: How Kubernetes identifies the Pods managed by this Deployment.
  • template: Defines the Pod specification, including the container.
  • image: The Docker image you built and pushed.
  • ports: The port your container exposes.
  • env: Environment variables passed to your Laravel application. Crucially, sensitive information is loaded from a Kubernetes Secret.
  • readinessProbe: Kubernetes checks if the Pod is ready to serve traffic.
  • livenessProbe: Kubernetes checks if the Pod is still running correctly and restarts it if necessary.

3. Kubernetes Service Manifest (service.yaml):
This exposes your Laravel application within the Kubernetes cluster.

YAML
apiVersion: v1
kind: Service
metadata:
  name: laravel-app-service
spec:
  selector:
    app: laravel-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP # Only accessible within the cluster

Key points in the service.yaml:

selector: Matches the labels of your application’s Pods.
ports: Maps the service’s port to the container’s port.
type: ClusterIP: Creates an internal IP address for the service, accessible only within the Kubernetes cluster.

4. Kubernetes Secrets Manifest (secrets.yaml):
Store sensitive information securely.

YAML
apiVersion: v1
kind: Secret
metadata:
  name: laravel-secrets
type: Opaque
data:
  app-key: $(echo "your-app-key-in-base64" | base64)
  db-host: $(echo "your-db-host-in-base64" | base64)
  db-database: $(echo "your-db-name-in-base64" | base64)
  db-username: $(echo "your-db-user-in-base64" | base64)
  db-password: $(echo "your-db-password-in-base64" | base64)

Important: Replace the placeholder values with your actual sensitive data encoded in Base64. You can use the echo “your-secret” | base64 command in your terminal to encode them.

5. Kubernetes ConfigMap Manifest (configmap.yaml - Optional but useful):
Store non-sensitive configuration.

YAML
apiVersion: v1
kind: ConfigMap
metadata:
  name: laravel-config
data:
  APP_ENV: production
  CACHE_DRIVER: redis
  QUEUE_CONNECTION: redis
  # Add other non-sensitive configuration here

You can then mount this ConfigMap as environment variables or volumes in your Deployment.

6. (Optional but Recommended) Kubernetes Ingress Manifest (ingress.yaml):
Expose your application to the outside world. You’ll need an Ingress controller running in your cluster (e.g., Nginx Ingress Controller).

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: laravel-app-ingress
  annotations:
    kubernetes.io/ingress.class: nginx # Or your Ingress controller
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - host: your-domain.com # Replace with your actual domain
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: laravel-app-service
                port:
                  number: 80

Applying Your Manifests:
Use kubectl apply -f .yaml to apply each of your manifest files to your Kubernetes cluster:

Bash
kubectl apply -f secrets.yaml
kubectl apply -f configmap.yaml # If you created one
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml # If you set up Ingress

Key Considerations and Next Steps:

Database: You’ll need a separate database service accessible by your Laravel application within the Kubernetes cluster (e.g., a managed database service or a PostgreSQL/MySQL deployment in Kubernetes).

Storage: For persistent storage (e.g., for user uploads), you’ll need to configure Persistent Volumes and Persistent Volume Claims.
Caching and Queues: If you’re using Redis or other caching/queueing systems, you’ll need to deploy and configure them in your Kubernetes cluster as well.

Environment Variables: Carefully manage your environment variables using Secrets for sensitive data and ConfigMaps for non-sensitive configuration.
Health Checks (Readiness and Liveness Probes): Ensure your probes are correctly configured to allow Kubernetes to manage the health of your application instances.

Logging and Monitoring: Set up proper logging and monitoring solutions for your Laravel application running in Kubernetes.
CI/CD Pipeline: Automate the process of building, pushing, and deploying your Laravel application updates to Kubernetes.

Troubleshooting Tips:
Check Pod Status: kubectl get pods
View Pod Logs: kubectl logs -c
Describe Pods/Deployments/Services: kubectl describe

Check Service Endpoints: kubectl get endpoints
Ingress Controller Logs: Check the logs of your Ingress controller if you’re having trouble accessing your application externally.

Also, this article on deploying your Laravel application in Kubernetes ll give you a solid starting point. Don’t hesitate to ask more specific questions as you progress! Good luck!