Deploying a Serverless Laravel Application in AWS using Bref

Serverless deployment is a new service that AWS is offering to help face the challenge of scaling applications, expenses etc. Developers who want to decrease their go-to-market time and build lightweight, flexible applications that can be expanded or updated quickly, benefit greatly from serverless computing. It offers greater scalability, more flexibility, and quicker time to release, all at a reduced cost.

Advantages:

  • No server management is necessary
  • Only charged for the server space they use
  • Scalable
  • Quick deployments and updates are possible
  • Low latency

Disadvantages:

  • Testing are debugging become difficult
  • Security concerns
  • Serverless architectures are not built for long running processes
  • Performance may be affected

Environments used:

  • Linux machine
  • AWS IAM user
  • PHP
  • Composer

You can place the directory containing the application file in whichever location.

  1. Create an AWS account. Then, create an IAM user with programmatic access and get the access key ID and secret access key.
  2. Ensure that the php extensions curl and xml are enabled. You can check using the following command.
php -m | grep xml

php -m | grep curl

If not enabled, install using the command,

sudo apt-get install php-xml

sudo apt-get install php-curl

Enable them in the file ‘/etc/php/8.1/cli/php.ini’ and restart apache using ‘service apache2 restart’

  1. Now, we have to install and configure the serverless framework as a global dependency.
npm install -g serverless

Now, we have to add the AWS IAM user credentials using the following commad.

serverless config credentials --provider aws –key <key>  --secret <secret>
  1. Install the latest version of Laravel and also create new project in it.
composer global require laravel/installer

Get the path and add it to the PATH variable.

composer global config bin-dir –absolute
/root/.config/composer/vendor/bin (This is the path I obtained). Add it using the below command.
echo 'export PATH="$PATH:/root/.config/composer/vendor/bin"' >> ~/.bashrc

Now, check the laravel version using,

laravel --version

Laravel Installer 4.5.0
  1. To create new app,
laravel new serverless-app

To have Bref configured with Laravel we also need to install the laravel-bridge component.

composer require bref/bref bref/laravel-bridge --with-all-dependencies
  1. Now, we have to create a serverless.yaml file.
php artisan vendor:publish --tag=serverless-config

Following is its contents.

 

service: laravel                                                                                                                                                                                          

provider:

    name: aws

    # The AWS region in which to deploy (us-east-1 is the default)

    region: us-east-1

    # The stage of the application, e.g. dev, production, staging… ('dev' is the default)

    stage: dev

    runtime: provided.al2

package:

    # Directories to exclude from deployment

    exclude:

        - node_modules/**

        - public/storage

        - resources/assets/**

        - storage/**

        - tests/**

functions:

    # This function runs the Laravel website/API

    web:

        handler: public/index.php

        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)

        layers:

            - ${bref:layer.php-74-fpm}

        events:

            -   httpApi: '*'

    # This function lets us run artisan commands in Lambda

    artisan:

        handler: artisan

        timeout: 120 # in seconds

        layers:

            - ${bref:layer.php-74} # PHP

            - ${bref:layer.console} # The "console" layer

plugins:

    # We need to include the Bref plugin

    - ./vendor/bref/bref

 

  1. Before deploying, we need to clear any configuration change generated on our machine.
php artisan config:cache

php artisan config:clear
  1. In case if your application requires database, you can deploy it in a server or in AWS RDS.
  2. Next we need to change the location of compiled view and a few other things like changing session driver to cookie and log channel to standard error in environment (.env) file.

Open .env file and add following:

CACHE_DRIVER =array
VIEW_COMPILED_PATH =/tmp/storage/framework/views 
SESSION_DRIVER =array 
LOG_CHANNEL =stderr
  1. Next we need to make changes in app service provider so that if compiled view directory is not present then it should recreate it automatically.

So copy and paste below section in boot method of app/Providers/AppServiceProvider.php

public function boot()
{
// Make sure the directory for compiled views exist
if (! is_dir(config('view.compiled'))) {
mkdir(config('view.compiled'), 0755, true);
}
}

11. After that, we’re ready to deploy.

serverless deploy

Deploying a Spring Boot microservice using Helm charts

In this blog,we explain the steps to deploy a Spring Boot microservice using Helm Charts.First we will build a docker image using a Docker file.This docker image is pushed to a repository.Then we will use Helm Charts to deploy our application to a Kubernetes cluster.An Nginx Ingress Controller is configured to expose our application to the outside world and manage traffic flow in a more flexible and scalable way.

Java Spring Boot is an open-source tool that makes it easier to use Java-based frameworks to create microservices and web apps.

Managing kubernetes cluster consists of checking cluster, pods, nodes, application deployment, replicas, load-balancer etc is a hectic task.So inorder to manage a Kubernetes cluster more efficiently and easily, one can use a package manager like Helm. Helm provides several advantages for managing Kubernetes applications,including:

  1. Simplified Deployment: With Helm, you can easily package and deploy complex applications with a single command, reducing the need for manual configuration and deployment steps.
  2. Version Control: Helm allows you to manage and track the version history of your Kubernetes applications, making it easier to roll back to previous versions in case of issues or bugs.
  3. Modular Architecture: Helm uses a modular architecture that allows you to break down your applications into smaller, reusable components that can be easily deployed and managed.

Overall, Helm provides a powerful and flexible solution for managing Kubernetes applications, making it easier to deploy, manage, and scale complex applications on Kubernetes clusters.

Prerequisites:
Docker Instance : To build the spring boot docker image and push to repository

Docker Hub Account/Any other Repository service for Docker Images

Basic Git Commands

Kubernetes Cluster: We used AWS’s EKS cluster.Bastion Host configured to manage K8’s.

First,let’s login to Docker Instance and build a docker image for our sample spring boot application.Clone the Sample Spring Boot Application : https://github.com/Keyshelltechs/sample_spring_boot

DockerFile

FROM maven:3.8.5-openjdk-18-slim AS build

WORKDIR /usr/src/app

COPY . /usr/src/app

RUN mvn package

FROM openjdk:18-jdk-slim

EXPOSE 8080

ARG JAR_FILE=spring-boot-ecs.jar

WORKDIR /opt/app

COPY --from=build /usr/src/app/target/${JAR_FILE} /opt/app/

ENTRYPOINT ["java","-jar","spring-boot-ecs.jar"] In this Dockerfile we use Multi-Stage build for creating a jar file in the first build and copying that jar file in the second build.

Let’s login to our Docker Hub Account.

$ docker login

Now let’s build the docker image using the docker command:

$ docker build -t keyshelltechs/sample_spring_boot:latest .

Here ‘keyshelltechs’ is my dockerhub’s username and ‘sample_spring_boot’ is the repository name and ‘latest’ is the tag.

Now let’s push this image to our Docker Hub repository using this command:

$ docker push keyshelltechs/sample_spring_boot:latest

Now let’s install Helm in our Bastion Host.I’m using Amazon Linux 2 for my Bastion Host.

$ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh

$ chmod 700 get_helm.sh

$ ./get_helm.sh

You can refer to this link for helm installation : https://docs.aws.amazon.com/eks/latest/userguide/helm.html

To check helm version : $ helm version

 

After the helm is installed,let’s install Ingress Controller using Helm charts.

For that, first we have to add the Helm Repository :

$ helm repo add nginx-stable https://helm.nginx.com/stable

Now update the repository for ensuring that you have access to the latest versions of Helm charts and managing the repositories from which you install charts. 

$ helm repo update

Now let’s install the chart from the repository:

$ helm install my-release nginx-stable/nginx-ingress

You can refer to this link for Ingress Controller installation :

https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-helm

Now let’s check whether this ingress controller is working or not.
For that, let’s check our K8’s pods and services.

$ kubectl get pods
$ kubectl get svc

We can get the External IP of our ingress controller from $ kubectl get svc

 

Now,let’s create the helm chart for our spring boot application.

$ helm create springboot

Here “springboot” is custom name given by us.This will create basic Helm Chart skeleton with the name springboot.

Run the following command to see the tree structure of our Springboot Helm Chart:

$ tree springboot

Of these files,we have to edit Chart.yaml,values.yaml & deployment.yaml

Chart.yaml

apiVersion: v2

name: springboot

description: A Helm chart for Kubernetes

type: application

version: 0.1.0

appVersion: "latest"

Here keep in mind that “appVersion” should be the tag which you are using for the Docker image.

values.yaml

In a Helm chart, values.yaml is a file that allows users to customize the deployment of the chart. It contains a set of key-value pairs that define the configuration settings for the chart. These values can be used to override the default configuration settings defined in the chart’s templates.

replicaCount: 3

image:

 repository: keyshelltechs/sample_spring_boot

 pullPolicy: Always

imagePullSecrets: []

nameOverride: ""

fullnameOverride: "springboot"

serviceAccount

 create: true 

 name: "springboot"

podAnnotations: {}

podSecurityContext: {}

securityContext: {}

service:

 type: ClusterIP

 port: 80

 targetPort: 8080

ingress:

 enabled: true

 annotations:

   kubernetes.io/ingress.class: nginx

   kubernetes.io/tls-acme: "true"

 hosts:

   - host: External_IP_of_ingress_controller

     paths:

     - path: /

       pathType: Prefix

       backend:

         serviceName: springboot-starterkit-svc

         servicePort: 80

 tls: []

resources: {}

autoscaling:

 enabled: false

 minReplicas: 1

 maxReplicas: 100

 targetCPUUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

Image’s repository value as  keyshelltechs/sample_spring_boot (without tag) which is the name of the image we have pushed earlier.Tag for this image is mentioned in Chart.yaml file.

Ingress is enabled here and we should replace External_IP_of_ingress_controller with External IP of our ingress controller which we have obtained in the earlier step.

deployment.yaml

In a Helm chart, deployment.yaml is a file that defines the Kubernetes Deployment resource used to manage the deployment of an application.

The deployment.yaml file defines the desired state of the Kubernetes Deployment resource. It specifies the containers and other resources that make up the application.This file can be customized using the values provided in the values.yaml file to enable parameterized deployment.

     containers:

       - name: {{ .Chart.Name }}

         securityContext:

           {{- toYaml .Values.securityContext | nindent 12 }}

         image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"

         imagePullPolicy: {{ .Values.image.pullPolicy }}

         ports:

           - name: http

             containerPort: {{ .Values.service.targetPort }}

             protocol: TCP

         livenessProbe:

           httpGet:

             path: /

             port: http

         readinessProbe:

           httpGet:

             path: /

             port: http

         resources:

           {{- toYaml .Values.resources | nindent 12 }}

In this file we have only edited the container: portion.

 

Now let’s run the install command.

Make sure you are in the parent directory of our ‘springboot’ folder to run this command.

$ helm install your-release-name springboot

Here you can give your custom release name instead of ‘your-release-name’ and ‘springboot’ is our folder which was created during the earlier step.

If everything goes right we can see release notes of the helm deployment.

Also check all our pods are running by :

$ kubectl get pods

We can access our site through this URL.

You can also refer our repo by :

$ helm repo add keyshell http://keyshelltechs.github.io/sample_helm_charts/charts

(github link : https://github.com/Keyshelltechs/sample_helm_charts)

 

To fetch the chart use:

$ helm fetch keyshell/springboot

 

Thanks for reading. Happy Helming.

If you have any queries contact us at 📲 +91-81295 71359 or email us at support@keyshell.net