*The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.*

Introduction

Laravel is one of the most popular open-source PHP application frameworks today. It is commonly deployed with a MySQL database but can be configured to use a variety of backend data storage options. Laravel prides itself on taking advantage of many of PHP's modern features and extensive package ecosystem.

Kubernetes is a container orchestration platform that can be hosted on Kubernetes clusters to take much of the administration work out of setting up and running containers in production. Helm is a Kubernetes package manager that makes configuring and installing services and pods on Kubernetes easier.

In this guide, you will create a Laravel PHP application, build your app into a Docker image, and deploy that image to a Kubernetes cluster using the LAMP Helm chart. Next, you'll set up an Ingress Controller to add SSL and a custom domain name to your app. When completed, you will have a working Laravel application connected to a MySQL database that is running on a Kubernetes cluster.

Prerequisites

laravel illustration for: Prerequisites
  • An account at Docker Hub for storing Docker images you’ll create during this tutorial.
  • A fully registered domain name with an available A record. This tutorial will use <^>your_domain<^> throughout. You can purchase a domain name on Namecheap, get one for free on Freenom, or use the domain registrar of your choice. Don't worry about associating your domain's A record with an IP at this time. Once you reach Step 5 and your Ingress controller is in place, you will connect <^>your_domain<^> to the proper IP.

Step 1 &mdash; Creating a New Laravel Application

In this step, you'll use Docker to create a new Laravel 7 application, but you should be able to go through the same process with an existing Laravel application that uses MySQL as the backing database. The new application you build will verify that Laravel is connected to the database and display the name of the database.

First, move to your home directory and then create a new Laravel application using a composer Docker container:

				
					
cd ~

docker run --rm -v $(pwd):/app composer create-project --prefer-dist laravel/laravel laravel-kubernetes

				
			

Once the container is done and all the Composer packages have been installed, you should see a fresh installation of Laravel in your current directory called laravel-kubernetes/. Navigate to that folder:

				
					
cd ~/laravel-kubernetes

				
			

You'll execute the rest of this tutorial's commands from here.

The purpose of this application is to test your database connection and display its name in your browser. In order to test the database connection, open up the ./resources/views/welcome.blade.php file in a text editor:

				
					
nano ./resources/views/welcome.blade.php

				
			

Find the section <div class="links">...</div> and replace its contents with the following:

				
					
[label ./resources/views/welcome.blade.php]

...

&lt;div class="links"&gt;

   &lt;^&gt;&lt;strong&gt;Database Connected: &lt;/strong&gt;&lt;^&gt;

    &lt;^&gt;@php&lt;^&gt;

        &lt;^&gt;try {&lt;^&gt;

            &lt;^&gt;DB::connection()-&gt;getPDO();&lt;^&gt;

            &lt;^&gt;echo DB::connection()-&gt;getDatabaseName();&lt;^&gt;

            &lt;^&gt;} catch (\Exception $e) {&lt;^&gt;

            &lt;^&gt;echo 'None';&lt;^&gt;

        &lt;^&gt;}&lt;^&gt;

    &lt;^&gt;@endphp&lt;^&gt;

&lt;/div&gt;

...

				
			

Save and close the file.

That's all the customization you'll need to make to the default Laravel app for this tutorial. Once completed, this brief snippet of PHP will test your database connection and display the database's name on the Laravel splash screen in your web browser.

In the next step, you'll use Docker to build an image containing this Laravel application and Docker Compose to test that it runs locally and connects to a MySQL database.

Step 2 &mdash; Containerizing Your Laravel Application

Now that you have created a new Laravel application, you'll need to build your code into a Docker image and then test the image with Docker Compose. While the goal of this tutorial is to deploy your application to a Kubernetes cluster, Docker Compose is a convenient way to test your Docker image and configuration locally before running it in the cloud. This fast feedback loop can be useful for making and testing small changes.

First, using nano or your preferred text editor, create a file in the root of your Laravel application called Dockerfile:

				
					
nano ./Dockerfile

				
			

Add the following content. Docker will use this file to build your code into an image:

				
					
[label ./Dockerfile]

FROM php:7.4-apache



# Install packages

RUN apt-get update &amp;&amp; apt-get install -y \

    git \

    zip \

    curl \

    sudo \

    unzip \

    libicu-dev \

    libbz2-dev \

    libpng-dev \

    libjpeg-dev \

    libmcrypt-dev \

    libreadline-dev \

    libfreetype6-dev \

    g++



# Apache configuration

ENV APACHE_DOCUMENT_ROOT=/var/www/html/public

RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf

RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf

RUN a2enmod rewrite headers



# Common PHP Extensions

RUN docker-php-ext-install \

    bz2 \

    intl \

    iconv \

    bcmath \

    opcache \

    calendar \

    pdo_mysql



# Ensure PHP logs are captured by the container

ENV LOG_CHANNEL=stderr



# Set a volume mount point for your code

VOLUME /var/www/html



# Copy code and run composer

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

COPY . /var/www/tmp

RUN cd /var/www/tmp &amp;&amp; composer install --no-dev



# Ensure the entrypoint file can be run

RUN chmod +x /var/www/tmp/docker-entrypoint.sh

ENTRYPOINT ["/var/www/tmp/docker-entrypoint.sh"]



# The default apache run command

CMD ["apache2-foreground"]

				
			

Save and close the file.

This Dockerfile starts with the PHP 7.4 Apache Docker Image found on Docker Hub, then installs several Linux packages that are commonly required by Laravel applications. Next, it creates Apache configuration files and enables header rewrites. The Dockerfile installs several common PHP extensions and adds an environment variable to ensure that Laravel's logs are streamed to the container via stderr. This will allow you to see Laravel logs by tailing your Docker Compose or Kubernetes logs.

Finally, the Dockerfile copies all the code in your Laravel application to /var/www/tmp and installs the Composer dependencies. It then sets an ENTRYPOINT, but you'll need to create that file, which we will do next.

At the root directory of your project, create a new file called docker-entrypoint.sh. This file will run when your container is run locally or in the Kubernetes cluster, and it will copy your Laravel application code from the /var/www/tmp directory to /var/www/html where Apache will be able to serve it.

				
					
nano ./docker-entrypoint.sh

				
			

Now add the following script:

				
					
[label ./docker-entrypoint.sh]

#!/bin/bash



cp -R /var/www/tmp/. /var/www/html/

chown -R www-data:www-data /var/www/html



exec "$@"

				
			

The final line, exec "$@" instructs the shell to run whatever command was passed in as an input argument next. This is important because you want Docker to continue running the Apache run command (apache2-foreground) after this script executes. Save and close the file.

Next, create a .dockerignore file in your app's root directory. This file will ensure that when you build your Docker image it won't become polluted with packages or environment files that shouldn't be copied into it:

				
					
nano ./.dockerignore

				
			
				
					
[label ./.dockerignore]

.env

/vendor

				
			

Save and close the file.

The last file that you need to create before you can run your app locally using Docker Compose is a docker-compose.yml file. But during the configuration of this YAML file, you will need to enter the APP_KEY that Laravel generated during installation. Find this by opening and searching the ./.env file, or by running the following cat and grep commands:

				
					
cat .env | grep ^APP_KEY

				
			

You will see an output like this:

				
					
[secondary_label Output]

APP_KEY=&lt;^&gt;base64:0EHhVpgg ... UjGE=&lt;^&gt;

				
			

Copy your key to your clipboard. Be sure to include the base64: prefix. Now create the docker-compose.yml file in your app's root directory:

				
					
nano ./docker-compose.yml

				
			

Here we will include your Laravel application's PHP image as well as a MySQL container to run your database. Add the following content:

				
					
[label ./docker-compose.yml]

version: '3.5'

services:

  php:

    image: &lt;^&gt;your_docker_hub_username&lt;^&gt;/laravel-kubernetes:latest

    restart: always

    ports:

      - 8000:80

    environment:

      - APP_KEY="&lt;^&gt;your_laravel_app_key&lt;^&gt;"

      - APP_ENV=local

      - APP_DEBUG=true

      - DB_PORT=3306

      - DB_HOST=mysql

      - DB_DATABASE

      - DB_USERNAME

      - DB_PASSWORD

  mysql:

    image: mysql:5.7

    restart: always

    environment:

      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}

      - MYSQL_DATABASE=${DB_DATABASE}

      - MYSQL_USER=${DB_USERNAME}

      - MYSQL_PASSWORD=${DB_PASSWORD}

				
			

Use the APP_KEY variable that you copied to your clipboard for the <^>your_laravel_app_key<^> variable, and use your Docker Hub username for the <^>your_docker_hub_username<^> variable. Save and close the file.

You'll create the first image locally using docker build. The second image is the official MySQL Docker image available on Docker Hub. Both require several environment variables, which you'll include when you run the containers.

In order to build the Docker image containing your Laravel application, run the following command. Make sure to replace <^>your_docker_hub_username<^> with your username or your team's username at Docker Hub where this image will be stored:

				
					
docker build -t &lt;^&gt;your_docker_hub_username&lt;^&gt;/laravel-kubernetes:latest .

				
			

Next, you can run the two containers with Docker Compose with the required database credentials:

				
					
DB_ROOT_PASSWORD=rootpassword DB_DATABASE=local_db DB_USERNAME=admin DB_PASSWORD=password docker-compose up -d

				
			

The four environment variables used here (DB_ROOT_PASSWORD, DB_DATABASE, DB_USERNAME, DB_PASSWORD) can be modified if you'd like, but since you are only testing your application locally, you don't have to worry about securing them yet.

It may take up to 30 seconds for your MySQL database to initialize and your containers to be ready. Once they are, you can view your Laravel application on your machine at localhost:8000.

Your PHP application will connect to your MySQL database. After a successful connection, the text "Database Connected: local_db" will appear beneath the Laravel logo.

Now that you've tested your Docker image locally using Docker Compose, you can bring the containers down by running docker-compose down:

				
					
docker-compose down

				
			

In the next section, you'll push your Docker image to Docker Hub so that your Helm chart can use it to deploy your application to your Kubernetes cluster.

Step 3 &mdash; Pushing Your Docker Image to Docker Hub

The LAMP Helm Chart that you'll use to deploy your code to Kubernetes requires that your code be available in a container registry. While you can push your image to a private or self-hosted registry, for the purposes of this tutorial you'll use a publicly available and free Docker registry on Docker Hub.

Access your account on Docker Hub using your web browser and then create a new repository called laravel-kubernetes.

Next, if you haven't connected to Docker Hub from your local machine, you'll need to log into Docker Hub. You can do this through the command line:

				
					
docker login -u &lt;^&gt;your_docker_hub_username&lt;^&gt;

				
			

Enter your login credentials when prompted. This typically only needs to be done once per machine as Docker will save your credentials to the ~/.docker/config.json in your home directory.

Finally, push your image to Docker Hub:

				
					
docker push &lt;^&gt;your_docker_hub_username&lt;^&gt;/laravel-kubernetes:latest

				
			

It may take a few minutes to upload your app depending on your connecti

on speed, but once Docker is done, you'll see a final digest hash and the size of your image in the terminal. It will look something like this:

				
					
[secondary_label Output]

latest: digest: sha256:df4bdeda91484c8c26a989b13b8f27ab14d93ab2e676e3c396714cb3811c4086 size: 4918

				
			

Now that your Laravel application is containerized and you've pushed an image to Docker Hub, you can use the image in a Helm Chart or Kubernetes deployment. In the next step, you'll set custom values based on the LAMP Helm Chart and deploy it to your Kubernetes cluster.

Step 4 &mdash; Configuring and Deploying the Application with the LAMP Helm Chart

Helm provides a number of Charts to help you set up Kubernetes applications using preset combinations of tools. While you could write your own Kubernetes service files to accomplish a similar deployment, you'll see in this section that using a Helm Chart will require much less configuration.

First, you'll need a directory to store all your Helm configuration files. Create a new directory in the root of your Laravel project called helm/:

				
					
mkdir ./helm

				
			

Inside the helm/ directory, you will create two new files: values.yml and secrets.yml. First create and open values.yml:

				
					
nano ./helm/values.yml

				
			

The values.yml file will include non-secret configuration options that will override the default values in the LAMP Helm chart. Add the following configurations, making sure to replace <^>your_docker_hub_username<^> with your own username:

				
					
[label ./helm/values.yml]

php:

  repository: "&lt;^&gt;your_docker_hub_username&lt;^&gt;/laravel-kubernetes"

  tag: "latest"

  fpmEnabled: false

  envVars:

    - name: APP_ENV

      value: production

    - name: APP_DEBUG

      value: false

    - name: DB_PORT

      value: 3306

    - name: DB_HOST

      value: localhost

				
			

Save and close the file.

Now create a secrets.yml file:

				
					
nano ./helm/secrets.yml

				
			

secrets.yml will not be checked into version control. It will contain sensitive configuration information like your database password and Laravel app key. Add the following configurations, adjusting as needed to fit your credentials:

				
					
[label ./helm/secrets.yml]

mysql:

  rootPassword: "&lt;^&gt;your_database_root_password&lt;^&gt;"

  user: &lt;^&gt;your_database_user&lt;^&gt;

  password: "&lt;^&gt;your_database_password&lt;^&gt;"

  database: &lt;^&gt;your_database_name&lt;^&gt;



php:

  envVars:

    - name: APP_KEY

      value: "&lt;^&gt;your_laravel_app_key&lt;^&gt;"

    - name: DB_DATABASE

      value: &lt;^&gt;your_database_name&lt;^&gt;

    - name: DB_USERNAME

      value: &lt;^&gt;your_database_user&lt;^&gt;

    - name: DB_PASSWORD

      value: "&lt;^&gt;your_database_password&lt;^&gt;"

				
			

Be sure to use strong username and password combinations for your production database, and use the same <^>your_laravel_app_key<^> as above, or open a new terminal window and generate a new one by running the following command. You can then copy the new value Laravel sets in your .env file:

				
					
docker run --rm -v $(pwd):/app php:cli php /app/artisan key:generate

				
			

Save and close secrets.yml.

Next, in order to prevent your secrets.yml file from being built into the Docker image or saved to version control, make sure to add the following line to both your .dockerignore and .gitignore files. Open and append /helm/secrets.yml to each file, or run the following command to add both:

				
					
echo '/helm/secrets.yml' &gt;&gt; ./.dockerignore &amp;&amp; echo '/helm/secrets.yml' &gt;&gt; ./.gitignore

				
			

Now that you've created Helm configuration files for your application and the Docker image, you can install this Helm chart as a new release on your Kubernetes cluster. Install your chart from your application's root directory:

				
					
helm install laravel-kubernetes -f helm/values.yml -f helm/secrets.yml stable/lamp

				
			

You will see an output like this:

				
					
[secondary_label Output]

NAME: laravel-kubernetes

LAST DEPLOYED: Mon May 18 13:21:20 2020

NAMESPACE: default

STATUS: deployed

REVISION: 1

				
			

Your application will take a minute or two to become available, but you can run this command to monitor the Kubernetes services in your cluster:

				
					
kubectl get services -w

				
			

Look for the name of your application:

				
					
[secondary_label Output]

NAME                        TYPE            CLUSTER-IP          EXTERNAL-IP     PORT(S)

laravel-kubernetes-lamp     LoadBalancer    &lt;^&gt;your_cluster_ip&lt;^&gt;      &lt;^&gt;your_external_ip&lt;^&gt;   80:32175/TCP,3306:32243/TCP

				
			

When your new laravel-kubernetes-lamp service displays an IP address under EXTERNAL-IP, you can visit <^>your_external_ip<^> to see the application running on your Kubernetes cluster. Your app will connect to your database and you will see the name of the database below the Laravel logo, like you did when running your app locally on Docker Compose.

Running a web application on an unsecured IP address might be okay for a proof of concept, but your website isn't production-ready without an SSL certificate and a custom domain name. Before you set that up in the next step, uninstall your release via the command line:

				
					
helm delete laravel-kubernetes

				
			

In the next step you'll expand on this first Helm configuration to add an Ingress controller, SSL certificate, and custom domain to your Laravel application.

Step 5 &mdash; Adding an Ingress Controller and SSL to Your Kubernetes Cluster

In Kubernetes, an Ingress Controller is responsible for exposing your application's services to the internet. In the previous step, the LAMP Helm chart created a load balancers and exposed your application directly via the load balancer's IP address.

You could terminate SSL and your domain name directly on the load balancer, but because you're working in Kubernetes, it might be more convenient to manage it all in the same place. For much more about Ingress Controllers and details about the following steps, read How To Set Up an Nginx Ingress on Kubernetes Using Helm.

The LAMP Helm chart includes a configuration option for supporting Ingress. Open up your helm/values.yml file:

				
					
nano ./helm/values.yml

				
			

Now add the following lines:

				
					
[label ./helm/values.yml]

...

# Use Ingress Controller

service:

  type: ClusterIP

  HTTPPort: 80

ingress:

  enabled: true

  domain: &lt;^&gt;your_domain&lt;^&gt;

				
			

This instructs your deployment not to install a load balancer and instead to expose the application to the Kubernetes cluster's port 80 where the Ingress Controller will expose it to the internet. Save and close values.yml.

Now run the helm install command you ran previously to get your Laravel application running again. Make sure to run the command from your app's root directory:

				
					
helm install laravel-kubernetes -f helm/values.yml -f helm/secrets.yml stable/lamp

				
			

Next, install the nginx-ingress controller on your Kubernetes cluster using the Kubernetes-maintained Nginx Ingress Controller:

				
					
helm install nginx-ingress stable/nginx-ingress --set controller.publishService.enabled=true

				
			

After installation, you will see an output like this:

				
					
[secondary_label Output]

NAME: nginx-ingress

LAST DEPLOYED: Mon May 18 13:28:34 2020

NAMESPACE: default

STATUS: deployed

REVISION: 1

				
			

You also need an Ingress Resource to expose your Laravel app's deployment. Create a new file in your app's root directory called ingress.yml:

				
					
nano ./ingress.yml

				
			

This file defines your application's host, SSL certificate manager, and backend service and port name. Add the following configurations, replaceing <^>your_domain<^> with the domain of your choice:

				
					
[label ./ingress.yml]

apiVersion: networking.k8s.io/v1beta1

kind: Ingress

metadata:

  name: laravel-kubernetes-ingress

  annotations:

    kubernetes.io/ingress.class: nginx

    cert-manager.io/cluster-issuer: letsencrypt-prod

spec:

  tls:

    - hosts:

        - &lt;^&gt;your_domain&lt;^&gt;

      secretName: laravel-kubernetes-tls

  rules:

    - host: &lt;^&gt;your_domain&lt;^&gt;

      http:

        paths:

          - backend:

              serviceName: laravel-kubernetes-lamp

              servicePort: 80

				
			

Save and close the file.

Next, you should install Cert-Manager and create an issuer that will allow you to create production SSL certificates using Let's Encrypt. Cert-Manager requires Custom Resource Definitions that you can apply from the Cert-Manager repository using the command line:

				
					
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.15.0/cert-manager.crds.yaml

				
			

This will create a number of Kubernetes resources that will be displayed in the command line:

				
					
[secondary_label Output]

customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created

customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created

customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created

customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created

customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created

customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io create

				
			

Cert-Manager also requires a namespace to isolate it in your Kubernetes cluster:

				
					
kubectl create namespace cert-manager

				
			

You will see this output:

				
					
[secondary_label Output]

namespace/cert-manager created

				
			

Because Jetstack's Cert-Manager is not one of the Kubernetes-maintained charts, you will need to add the Jetstack Helm repository as well. Run the following command to make it available in Helm:

				
					
helm repo add jetstack https://charts.jetstack.io

				
			

A successful addition will output the following:

				
					
[secondary_label Output]

"jetstack" has been added to your repositories

				
			

Now you're ready to install Cert-Manager into the cert-manager namespace on your Kubernetes cluster:

				
					
helm install cert-manager --version v0.15.0 --namespace cert-manager jetstack/cert-manager

				
			

When complete, you'll see a summary of the deployment like this:

				
					
[secondary_label Output]

NAME: cert-manager

LAST DEPLOYED: Mon May 18 13:32:08 2020

NAMESPACE: cert-manager

STATUS: deployed

REVISION: 1

				
			

The last file you'll need to add to your Laravel application's root directory is a production_issuer.yml Kubernetes configuration file. Create the file:

				
					
nano ./production_issuer.yml

				
			

Now add the following:

				
					
apiVersion: cert-manager.io/v1alpha2

kind: ClusterIssuer

metadata:

  name: letsencrypt-prod

spec:

  acme:

    # Email address used for ACME registration

    email: &lt;^&gt;your_email_address&lt;^&gt;

    server: https://acme-v02.api.letsencrypt.org/directory

    privateKeySecretRef:

      # Name of a secret used to store the ACME account private key

      name: letsencrypt-prod-private-key

    # Add a single challenge solver, HTTP01 using nginx

    solvers:

      - http01:

          ingress:

            class: nginx

				
			

Save and close the file.

Let's Encrypt will send <^>your_email_address<^> any important notices and expiration warnings, so be sure to add an address that you'll check regularly. Save this file and create a new resource for both your Ingress resource and production issuer in your Kubernetes cluster:

				
					
kubectl create -f ingress.yml

kubectl create -f production_issuer.yml

				
			

Finally, update your domain name's DNS records to point an A record to your load balancer's IP address. To find the IP address for your Ingress Controller enter:

				
					
kubectl get service nginx-ingress-controller

				
			
				
					
[secondary_label Output]

NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE

nginx-ingress-controller   LoadBalancer   &lt;^&gt;your_cluster_ip&lt;^&gt;      &lt;^&gt;your_external_ip&lt;^&gt;   80:30187/TCP,443:31468/TCP   6m10s

				
			

Use the <^>your_external_ip<^> address as the IP address for your DNS A Record. The process for updating your DNS records varies depending on where you manage your domain names and DNS hosting, but if you're using the cloud provider you can reference our guide on How to Manage DNS Records.

Once your DNS records update and your SSL certificate is generated, your application will be available at <^>your_domain<^> and SSL will be enabled.

While your PHP application and database are already connected, you will still need to run database migrations. In the last step, you'll see how to run Artisan commands on your Kubernetes pod to perform database migrations and other common maintenance tasks.

Step 6 &mdash; Running Remote Commands

While your Laravel application is running and connected to the MySQL database in Kubernetes, there are several common operations that you should run on a new Laravel installation. One common task that you should perform is database migrations.

Before you can run an Artisan command on your Laravel application, you need to know the name of the pod that is running your Laravel application container. Using the command line, you can view all the pods in your Kubernetes cluster:

				
					
kubectl get pods

				
			

You will see an output like this:

				
					
[secondary_label Output]

NAME                                             READY   STATUS    RESTARTS   AGE

&lt;^&gt;laravel-kubernetes-lamp-77fb989b46-wczgb&lt;^&gt;         2/2     Running   0          16m

				
			

Select the pod for your laravel-kubernetes-lamp-... deployment. Make sure to use the name in your output and not the one listed above. Now you can run kubectl exec on it. For example, run a database migration using the artisan migrate command. You will add the --force flag because you're running the pod in production:

				
					
kubectl exec &lt;^&gt;laravel-kubernetes-lamp-77fb989b46-wczgb&lt;^&gt; -- php artisan migrate --force

				
			

This command will produce an output:

				
					
[secondary_label Output]

Migration table created successfully.

Migrating: 2014_10_12_000000_create_users_table

Migrated:  2014_10_12_000000_create_users_table (0.16 seconds)

Migrating: 2019_08_19_000000_create_failed_jobs_table

Migrated:  2019_08_19_000000_create_failed_jobs_table (0.05 seconds)

				
			

You have now successfully deployed Laravel 7 and MySQL to Kubernetes and performed an essential database maintenance task.

Conclusion

In this tutorial, you learned how to containerize a Laravel PHP application, connect it to a MySQL database, push a Docker image containing your code to Docker Hub, and then use a Helm chart to deploy that image to a Kubernetes cluster. Finally, you added SSL and a custom domain name and learned how to run command line tools on your running pods.

Kubernetes and Helm offer you a number of advantages over traditional LAMP stack hosting: scalability, the ability to swap out services without logging into your server directly, tools to perform rolling upgrades, and control over your hosting environment. That said, the complexity of initially containerizing and configuring your application makes the barrier to getting started quite high. With this guide as a starting point, deploying Laravel to Kubernetes becomes more attainable. From here you might consider learning more about the power of Laravel or adding monitoring tools to Kubernetes like Linkerd, which you can install manually with our guide or with a the cloud provider 1-Click.