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.
1 |
composer create-project --prefer-dist laravel/laravel blog |
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.