?? Deploying a Laravel Application with MySQL and Nginx on Kubernetes! ??

?? Deploying a Laravel Application with MySQL and Nginx on Kubernetes! ??


1. Introduction

"Deploying modern web applications on Kubernetes can be challenging, but it's incredibly rewarding once you get it right. I recently completed deploying a Laravel application with MySQL and Nginx on Kubernetes using MicroK8"

2. Project Overview

  • Deploy a Laravel application in Kubernetes.
  • Use Nginx as a reverse proxy.
  • Set up MySQL with persistent storage.
  • Configure Kubernetes components for scalability and high availability.

3. Kubernetes Components Used

? Namespace – Isolated environment for better resource management

? Deployment – Managed app lifecycle with replica scaling

? ConfigMap & Secret – Centralized app configuration and sensitive data handling

? Persistent Volume (PV) & Persistent Volume Claim (PVC) – Ensured data persistence for MySQL

? Service – Facilitated internal communication between pods

? Ingress – Managed external access and routing

4 .?? How to Install MicroK8s on Ubuntu

? 4.1: Update System Packages

sudo apt update
sudo apt upgrade -y        

? 4.2 : Install Snap (if not installed)

Ensure that Snap is installed (MicroK8s is installed via Snap):

sudo apt install snapd -y        

? 4.3: Install MicroK8s

sudo snap install microk8s --classic        

install a specific version:

sudo snap install microk8s --classic --channel=1.30/stable
        

? 4.4 : Add User to MicroK8s Group

Add your user to the MicroK8s group to avoid needing sudo for every command:

udo usermod -aG microk8s $USER
newgrp microk8s        

? 4.5 : Verify Installation

microk8s status --wait-ready
        

? 4.6: Enable Core Add-ons

Enable some essential Kubernetes components:

microk8s enable dns storage ingress        

For other add-ons, you can list them with:

microk8s enable --help
        

? Step 4.7: Check Kubernetes Nodes

microk8s kubectl get nodes        

? Step 4.8: Start and Stop MicroK8s

microk8s start
microk8s stop        
microk8s start
microk8s stop        
alias kubectl="microk8s kubect        

To make this alias permanent, add it to your ~/.bashrc

echo 'alias kubectl="microk8s kubectl"' >> ~/.bashrc
source ~/.bashrc        

Now MicroK8s is installed and ready to use! You can deploy applications, create services, and manage Kubernetes resources. ??


? Step 5: Create Namespace:

Create a Namespace YAML file:Create a file named Namespace.yml

apiVersion: v1
kind: Namespace
metadata:
  name: laravel-app        

Apply the Namespace file:

kubectl apply -f Namespace.yml        

Verify the Namespace

microk8s kubectl get namespaces
        

If you want to set the namespace as the default for all future commands

 kubectl config set-context --current --namespace=laravel-app

        

? Step 6: Create PV and PVC for MySQL

You can create the directory under /data/mysql or any other suitable location:

sudo mkdir -p /data/mysql        

Set Permissions: Ensure that Kubernetes has permission to read and write to this directory:

sudo chown -R $USER:$USER /data/mysql
sudo chmod -R 775 /data/mysql

        

Create a file named pv.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce 
  hostPath:
    path: /data/mysql

        

create a file named pvc.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: laravel-app
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

        

? Apply the Changes:

kubectl apply -f pv.yml  -f pvc.yml 

        

Check the pv and pvc status

kubectl get pvc -n laravel-app 
kubectl get pv         

? Step 7: Create MySQL ConfigMap

Create a file named mysql-configmap.yml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: laravel-app
data:
  MYSQL_DATABASE: "laravel"
  MYSQL_USER: "laravel_user"        


? Step 7.1: Create MySQL Secret

Create a file named mysql-secret.yml:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: laravel-app
type: Opaque
data:
  MYSQL_PASSWORD: cGFzc3dvcmQ=         # base64 encoded value of 'password'
  MYSQL_ROOT_PASSWORD: cm9vdHBhc3N3b3Jk # base64 encoded value of 'rootpassword'        

? Step 7.2: Create MySQL Deployment

Create a file named Deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  namespace: laravel-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8
          ports:
            - containerPort: 3306
          envFrom:
            - configMapRef:
                name: mysql-config
          env:
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_PASSWORD
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_ROOT_PASSWORD
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
      volumes:
        - name: mysql-data
          persistentVolumeClaim:
            claimName: mysql-pvc        
? Apply the Changes:
#kubectl apply -f  mysql-configmap.yml -f mysql-secret.yml -f Deployment.yml        

Check the status of the MySQL ConfigMap, Secret, and Deployment.

? Step 7.3: check the mysql pod running or not

kubectl get pods  -n laravel-app        

Access the MySQL container and import the SQL file into the database. The SQL file is present in the db_backup directory.

? Step 7.4: Create MySQL Service

Create a file named Service.yml

apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: laravel-app
spec:
  ports:
    - port: 3306
      targetPort: 3306
  selector:
    app: mysql        

Check status of t mysql service.

? Step 8: Create pv and pvc for the laravel application and nginx

Create a file named pv.yml and pvc.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: laravel-pv
  namespace: laravel-app
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: "/data/laravel"

        
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: laravel-pvc
  namespace: laravel-app
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
        

Check Status

? Step 9: Create Deployment, Service, ConfigMap, and Secret for the Laravel application.

laravel-configmap.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: laravel-config
  namespace: laravel-app
data:
  DB_CONNECTION: "mysql"
  DB_HOST: "mysql"
  DB_PORT: "3306"
  DB_DATABASE: "laravel"
  DB_USERNAME: "laravel_user"
  APP_ENV: "production"
  APP_DEBUG: "false"
  APP_KEY: "base64:H2b7fzOGniGCzfQDF2DlCvTPpcU00QOoplmbP3F8SqA="        

laravel-secret.yml

apiVersion: v1
kind: Secret
metadata:
  name: laravel-secret
  namespace: laravel-app
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQ= # base64 encoded value of 'password'
#cGFzc3dvcmQ=           

Service.yml

apiVersion: v1
kind: Service
metadata:
  name: laravel
  namespace: laravel-app
spec:
  selector:
    app: laravel
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 9000        

Deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel
  namespace: laravel-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: laravel
  template:
    metadata:
      labels:
        app: laravel
    spec:
      containers:
        - name: laravel
          image: akhileshpatel123/simple-laravel_application:v2
          imagePullPolicy: Always
          ports:
            - containerPort: 9000
          envFrom:
            - configMapRef:
                name: laravel-config
            - secretRef:
                name: laravel-secret 
          volumeMounts:
            - name: app-data
              mountPath: /var/www/html
      volumes:
        - name: app-data
          persistentVolumeClaim:
            claimName: laravel-pvc        

Apply the YAML files and check the status.

Access the Laravel app container. No need to clear the cache because it is already cleared in the Dockerfile.


? Step 10 :Create Deployment, Service, Nginx ConfigMap, and Ingress for Nginx.

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: laravel-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: nginx.conf
            - name: laravel-code
              mountPath: /var/www/   # 
      volumes:
        - name: nginx-config
          configMap:
            name: nginx-config
        - name: laravel-code
          persistentVolumeClaim:
            claimName: laravel-pvc   # 

        

nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: laravel-app
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080
  selector:
    app: nginx        

nginx-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: laravel-app
data:
  nginx.conf: |
    server {
        listen 80;
        server_name example.local;

        root /var/www/public;
        index index.php index.html;

        # Handle static files and routes
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }

        # ? Forward API requests to Laravel service (now `/resume`)
        location /resume {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            fastcgi_pass laravel:9000;
            fastcgi_param SCRIPT_FILENAME $document_root/index.php;
            include fastcgi_params;
        }

        # Forward PHP files to PHP-FPM
        location ~ \.php$ {
            include fastcgi_params;
            fastcgi_pass laravel:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param DOCUMENT_ROOT $document_root;
            fastcgi_param SERVER_NAME $host;
            fastcgi_param SERVER_PORT $server_port;
            fastcgi_param SERVER_ADDR $server_addr;
        }

        # Deny access to .htaccess files
        location ~ /\.ht {
            deny all;
        }
    }        

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-path-ingress
  namespace: laravel-app
spec:
  rules:
    - host: example.local
      http:
        paths:
          - path: /resume     
                 
            pathType: Prefix
            backend:
              service:
                name: nginx
                port:
                  number: 80
          - path: /     
            pathType: Prefix
            backend:
              service:
                name: laravel
                port:
                  number: 9000        

Apply the YAML files and check the status.

? Step 11: Add the domain name on the host machine in the /etc/hosts file with the Nginx service Cluster IP for the Ingress.


Now you can access the application using your local domain example.local. I have configured the register page as the default.







? Step 12:Now we can check it our Ingress is working or not.


  • If you open https://example.local/resume, traffic will be directed to the nginx service.
  • If you open https://example.local/, traffic will be directed to the laravel service.

The full path is https://example.local/resume.

We can see our Ingress is working properly.



I am not experienced in controller services in a Laravel application. I have just demonstrated the Kubernetes service by creating a Laravel application. In the future, I will better optimize the Laravel controller service. For now, I have only created a registration page and another controller named ResumeController.php. The application is definitely not perfect, but I am trying my best. After login, it should ideally redirect to another page, but I am currently redirecting it to the home page.


Thank You !!





Hari Shankar

Fellow MT@SCEH | IM-BHU | PGDHCM | Healthcare

40 分钟前

Great work ??

要查看或添加评论,请登录

Akhilesh Patel的更多文章