Table of contents
Laravel is a popular PHP framework that helps you build web applications with different frontend frameworks like React.js. You can also implement a decoupled application by only writing the APIs.
Whether it’s a monolith or API, leverage the power of Kubernetes so your application can perform under high traffic. By taking care of the application availability, Kubernetes efficiently utilizes resources and can scale up or down based on demand.
In this blog, you’ll learn how to deploy a Laravel application using Kubernetes.
Before we dive in, refer to this template I’ve prepared, which will help you with deployment.
We will begin by deploying the application in a local Kubernetes cluster using minikube.
With Nginx as the web server, we’ll consider a simple Laravel application that consists of a MySQL database for storing the data.
It is easy to set up if you do not have
minikube installed on your machine. Select the options based on your machine's configuration.
Execute the following command:
It will create the cluster in your machine.
We will require a few
minikube addons for this exercise.
minikube addons enable ingress minikube addons enable metrics-server
ingress allows you to route requests from your machine to the cluster, making the application available to you.
metrics-server collects metrics from the pods and exposes them to the Kubernetes API server, which is necessary for pod scheduling and autoscaling.
minikube cluster once you have enabled the addons.
minikube stop minikube start
Containerize The Application
ARG PHP_EXTENSIONS="apcu bcmath pdo_mysql redis imagick gd" FROM thecodingmachine/php:8.1-v4-fpm as php_base ENV TEMPLATE_PHP_INI=production WORKDIR /var/www/html COPY --chown=docker:docker . . COPY --chown=docker:docker .env.example .env RUN composer install --optimize-autoloader RUN php artisan key:generate
Dockerfile can vary based on your application requirements.
Build the Docker image. It ensures that the image is available to the
minikube runs its Docker environment. Therefore, we must ensure that the deployment happens in the right environment. You can point to the
minikube's Docker environment by executing the below in the terminal.
eval $(minikube -p minikube docker-env)
Followed by the command for building an image:
docker build . --tag=ci-k8s
You can choose any image name.
Enter The Kubernetes
Let’s create a few entities in Kubernetes that will deploy the application. You’ll need to make sure it’s scalable and publicly available.
You can prepare the entities one by one. However, we will use helm to prepare the boilerplate entities. It helps in packaging the application deployment and simplifies the deployment.
We will modify those boilerplate entities as per our requirements.
If you don’t have
helm, install it from here. Once done, prepare the boilerplate configuration by executing:
helm create chart
It will create a directory named
chart with the files like this. Feel free to provide any name while creating the chart.
You will notice the various entities involved in deploying the application one by one.
Helm provides a templating feature. What does that mean? It can specify configurations like the number of replicas inside a template file. The entities will use the template to get the values. You will see those template files.
values.yml contains the specifications like the resource you want to give to each pod, the number of pod replicas to maintain, etc. They will vary based on availability factors, cost, and expected traffic.
_helpers.tpl define templates that you can use in the entities.
Chart.yaml specifies the chart metadata like its name, version, etc.
Now, let's get to the entities.
We will require two volumes in this exercise—for codebase and database. In production, you might want to go with database services like AWS RDS, DigitalOcean, etc. Why? They handle the necessary tasks like maintaining backups and allocating resources.
The volume specifications are mentioned in
Specifying how to handle PHP requests in Nginx is a must. Let’s use
ConfigMap for it.
nginx_config.yml contains those specifications.
Deployment entity is responsible for deploying the application and its dependencies. We will have three deployments: phpfpm, Nginx, and database (MySQL). You’ll be able to view them in
nginx deployment relies on the configuration entity.
We will use the
Service entity to expose the container ports. The
service.yaml specifies how you can do it.
Ingress entity makes the pods publicly available. It routes the traffic from the internet to the pod and vice-versa. The
ingress.yaml file explains how you can do it.
HorizontalPodAutoscaler entity enables your application to serve under traffic. You can choose between vertical or horizontal scaling of your pods. For this, let’s go with horizontal scaling.
hpa.yaml specifies the threshold and the maximum number of replicas to maintain. The pod scheduler creates a new pod if the resource utilization crosses the threshold.
The database and the
phpfpm pods may consume more CPU and memory based on the traffic. Therefore, we have configured the autoscalers for them.
metrics will vary by application and business requirement. Also, consider the resources available in the node.
Once you create all the required entities, the
chart directory will look like this:
Let's see how we can deploy the application.
Deploying The Application
Create The Cluster
It will route the traffic from your machine to the cluster.
It will request authorization as you have exposed port 80.
Install The Chart
Installing the chart will initiate the deployment, and the API server will instantiate the entities. Before installation, replace the database secrets with the actual values. We specified them in
dbRootPassword: "test" dbName: "test" dbUser: "test" dbPassword: "test"
Specify the correct secrets as environment variables.
export DB_ROOT_PASSWORD=rootpass DB_NAME=db DB_USER=main DB_PASSWORD=password API_KEY=samplekey
To validate whether there are issues with the entities, execute the following from the project root:
helm install --set dbRootPassword=$DB_ROOT_PASSWORD --set dbName=$DB_NAME --set dbUser=$DB_USER --set dbPassword=$DB_PASSWORD --set apiKey=$API_KEY laravel-k8s chart/ --dry-run --debug
It should output the entities with the exact specifications. If you see an error, something is wrong.
It is time to install the chart.
helm install --set dbRootPassword=$DB_ROOT_PASSWORD --set dbName=$DB_NAME --set dbUser=$DB_USER --set dbPassword=$DB_PASSWORD --set apiKey=$API_KEY laravel-k8s chart/
laravel-k8s is the name of the chart. You can name it something else.
chart/ is the location of the directory that contains all the entities.
minikube comes with the Kubernetes dashboard. You can open it by executing:
It might take time to open. Once it does, you will see:
It specifies that the pods are starting up. Once the pods are ready, they are green.
To check whether the application is running, initiate a
curl request from your machine.
curl -v http://localhost/
You should see a 200 OK response.
Wondering how the pods can listen to the requests from your machine? Because you enabled the tunneling and ingress entity. It means your machine's port 80 can communicate with the cluster.
Autoscaling In Action
Let's say the application has an endpoint that does some computational tasks. We will simulate the traffic using ApacheBench.
ab -c 2 -n 5000 http://localhost/api/calc-daily-average-power-consumption
Kubernetes relies on the metrics server to gather data from the pods. Based on the data and the specified threshold, it schedules the pods.
Once you have executed the command, it takes a while for the new pod to come online.
Since it can automatically scale, once it sees that the resource consumption in a pod is within the threshold, it will destroy the newly created pod.
Debug Incorrect Templates
Helm provides many ways to find the issue in incorrect templates. In this case, execute the below command:
helm template --set dbRootPassword=$DB_ROOT_PASSWORD --set dbName=$DB_NAME --set dbUser=$DB_USER --set dbPassword=$DB_PASSWORD --set apiKey=$API_KEY laravel-k8s chart/ --debug > test.yaml
The YAML content will be output in the
test.yaml file. You can find the issue from there.
You learned the power of Kubernetes to make your applications ready to serve traffic and how cost-efficient it is.
A few things, like the dashboard, might be different, but most of the processes we undertook in this blog will stay the same. Try it out, and let us know how it went!