Deploy a Laravel Application to Kubernetes using Gitlab CI

Prerequisites

This article assumes you have a basic understanding of Docker and Kubernetes, Gitlab CI and that you have already set up a Kubernetes Cluster.

Start a Laravel Project

The first thing you’ll need is a Laravel application, use composer to start a new project.

Dockerize your Laravel Project

There’s a number of ways to dockerize your Laravel project. You may use the official Nginx and PHP images form dockerhub, but I found it’s a bit troublesome to set them up.

So instead of messing around with all the different kinds of docker images, I came across thecodingmachine/docker-images-php, a set of production-ready docker images.

To build a production-ready image, we will use thecodingmachine/php:7.3-v2-slim-apache as our base image. The Dockerfile looks like this:

We will configure Gitlab CI to build the docker image automatically later.

Create Kubernetes Deployment Files

Here are all the yaml files we need to deploy our Laravel Application.

Deployment

Out deployment.yaml contains two deployments actually. One is for our main Laravel application, while the other one is for Laravel Horizon. If you do not plan to use Horizon, you can simply remove it.

There’s an init container to optimize configuration and route loading. To share the application code between init container and app container, it uses an emptyDir.

There’s also affinity setting to tell Kubernetes to try it best to schedule the pods among different nodes as to avoid downtime.

CronJob

We use cronjob.yaml that leverage Kubernete’s CronJob to run php artisan schedule:run every minute. We feel like this is a more robust way of scheduling cron by fine-tuning activeDeadlineSeconds , backoffLimit and startingDeadlingSeconds to make sure our cron gets scheduled.

ConfigMap, Ingress & Service

Our ingress.yaml and service.yaml is pretty standard, we use CloudFlare DNS verification to obtain HTTPS certificates from Let’s Encrypt (It’s commented).

As for configmap, it’s recommended to use secret to store sensitive information like the database password.

Here’s a GitHub Repo in case you would like to clone it. Merge request is also appreciated!

Set up Gitlab CI

Now that we have our app and kubernetes config ready, we can go ahead to setup Gitlab CI to automate our deployment. (We assume you are using Kubernetes token authentication)

Setup CI/CD Environment Variables

Within Repo > Settings > CI / CD, we need to store our Kubernetes Cluster credentials into Gitlab CI’s environment variables.

Move the Dockerfile to your project’s root directory, then create a folder called k8 and store all the kubernetes yaml files inside. Create a file called .gitlab-ci.yml that contains the folllowing.

The CI/CD script contains two steps. First is to build our Laravel Application and push to Amazon ECR (you may configure it to another Docker Image Repo as you like). Then it moves on to deploy our Laravel Application image to our Kubernetes cluster.

In line 36 and 37, the $KUBE_URL and $KUBE_TOKEN are the two environment variables that we set up above.

In line 40, we ask kubectl to apply our k8s configuration files.

In line 41, it a hack to trigger redeployment of pods. Since we have set the imagePullPolicy to always, Kubernetes will automatically re-pull our docker image to the latest version. Combine with our deployment’s rolling update strategy, there’s should be no downtime in deployment updates.

In production, we actually use Kustomize to maintain deployment of multiple Git branches and environment. But we are looking to switch to Helm as it seems to be an easier and more popular deployment method.

img_6067

The joy of CI/CD. Push your code, wait for 4 minutes and it’s deployed automatically, without downtime.

And that’s it! the joy of CI/CD. Just push your code, wait for 4 minutes and it’s deployed automatically, without downtime.

laravel-k8s-master