Deploy Scalable Php application in kubernetes cluster with Mysql database integration with Nginx ingress controller

Hiteshkoolwal
6 min readJan 3, 2021

Introduction

In this post, I am going to talk about How to Deploy a Scalable Php containerized application with MySQL backend database integration with nginx ingress controller. At the end of this post you should be able to understand how to deploy a scalable app with ingress controller and deploy your app in a Kubernetes cluster.

Prerequisite

  • Basic knowledge of k8s cluster and its composnets.
  • A k8s cluster minikube cluster or cluster in EKS or AKS.
  • Metrics-server should be enabled
  • helm version 3 should be installed.

Lets get started..

Github Link of code click here..

How the helm chart looks like…

[root@abc]# tree php-sql-chart/
php-sql-chart/
├── charts
├── Chart.yaml
├── templates
│ ├── asecret.yml
│ ├── hpa-php.yaml
│ ├── ingress.yaml
│ ├── mysql-deploy.yaml
│ ├── mysql-pvc.yaml
│ ├── mysql-service.yaml
│ ├── php-deploy.yaml
│ └── php-service.yaml
└── values.yaml

2 directories, 10 files

To install the Helm Chart run the following commands

cd php-sql-chart/

helm install myproject .

helm ls

PHP Pod Details

Firstly, we have to make a php-webserver yaml file describing all details of webserver pod.

apiVersion: v1
kind: Service
metadata:
name: web-service
labels:
run: web-service
spec:
type: {{ .Values.service.php.type }}
ports:
- port: {{ .Values.service.php.port }}
nodePort: 30007
protocol: TCP
selector:
app: apache
---
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-php
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: webserver
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: {{ .Values.autoscaling.memorylimit }}

Details about php.yaml file

  • Website will be available at port no 30007.
  • Default replicas is one. we can change no of replicas by

kubectl scale deploy webserver — replicas=2

  • Used a custom image to deploy the php webserver. The image is pushed to docker hub as hitman001/php-mysql:v6 The image is build using Dockerfile available in my Github Repository.
  • The other details can be seen in values.yaml file.

MySQL pod details

This file conatins all details of our mysql database.

I have already written all environment variables in this file, that are used to connect to a database.

apiVersion: v1
kind: Service
metadata:
name: mysql8-service
labels:
app: mysql8
spec:
type: {{ .Values.service.mysql.type }}
ports:
- port: {{ .Values.service.mysql.port }}
protocol: TCP
selector:
app: mysql8
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: mysql8
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi #5 GB
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: mysql8
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql8
spec:
containers:
- image: "{{ .Values.image.mysql.name }}:{{ .Values.image.mysql.tag }}"
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password # the value of MYSQL_ROOT_PASSWORD is coming from secret "mysecret"
- name: MYSQL_DATABASE
value: my_db
- name: MYSQL_USER
value: db_user
- name: MYSQL_PASSWORD
value: mypass
args: ["--default-authentication-plugin=mysql_native_password"]
ports:
- containerPort: {{ .Values.service.mysql.port }}
name: mysql8
volumeMounts:
- name: mysql-persistent-storage
mountPath: {{ .Values.mountpath.mysql }}
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim # Mysql data is stored in pvc

About mysql.yaml file

  • MySQL service is ClusterIP means, the pod cannot communicate with public world.
  • 5GiB PVC is allocated for the storage of mysql database. It is mounted to /var/lib/mysql In this directory all data of MySQL is stored.
  • A secret is made to store MYSQL_ROOT_PASSWORD

Creating Secrets

This file contains the important password of our database/cluster which we do not want to make public.

We cannot write normal text in this file. First the password has to be encoded in base64 encoding format then, we can write the encoded password in this file.

apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: LnN3ZWV0cHdkLg== # .sweetpwd. encoded in base64

Horizontal Pod AutoScaling

Horizonatal Pod AutoScaler is used to scale the pod when the load/CPU utilization is high and we need more pods to balance the load.

All the values can be seen in values.yaml file

For AutoScaling we have to first enable metrics-server

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml

The metrics-server will be installed in namespace kube-system. We can see the metrics-server by this command.

kubectl get deployment metrics-server -n kube-system

This is hpa.yaml file

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: hpa-php
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: webserver
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: {{ .Values.autoscaling.memorylimit }}

Creating nginx ingress Controller

ingress-nginx is an Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer.

use this command to enable nginx ingress controller in minikube cluster

minikube addons enable ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: web-service
servicePort: 80
  • Using this our page will be hosted at port no 80 using reverse proxy.
  • “web-service” is name of the php service used to expose php-deployment. So, in serviceName we write the name of service we want to apply reverse proxy or load balancing.
  • path / means the ingress controller will work for every page after / default path.

values.yaml

All the changeable values used in helm chart are written in values.yaml file

# Default values for php-sql.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1image:
php:
name: hitman001/php-mysql
tag: "v6"
mysql:
name: mysql
tag: "8.0"
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
service:
php:
type: LoadBalancer
port: 80
mysql:
type: ClusterIP
port: 3306
mountpath:
mysql: /var/lib/mysql #PVC will be mounted here
resources:
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
limits: # limits are set on php webserver
cpu: 100m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
# autoscaling is done on php webserver
autoscaling:
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
memorylimit: 80Mi
  • By this we can change the limits of pods.
  • change the name and tag of image used.

Output

kubectl get all

kubectl top pods

http://192.168.99.101/php-info.php

  • the above site is running at port 80 by nginx ingress controller.

http://192.168.99.101

  • index.php is the default page.
  • The Php Site already connected to MySQL database.

Github link click here…

Thank You For Reading the Blog till end (^.^)

--

--