avatarMohamed Gaddour

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

6235

Abstract

st-x</span> <span class="hljs-comment"># The stage of the application, e.g. dev, production, staging… ('dev' is the default)</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">dev</span> <span class="hljs-attr">runtime:</span> <span class="hljs-string">provided.al2</span> <span class="hljs-attr">stackName:</span> <span class="hljs-string">app-stack</span>

<span class="hljs-attr">package:</span> <span class="hljs-comment"># Directories to exclude from deployment </span> <span class="hljs-attr">patterns:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">'!node_modules/'</span> <span class="hljs-bullet">-</span> <span class="hljs-string">'!public/storage'</span> <span class="hljs-bullet">-</span> <span class="hljs-string">'!resources/assets/'</span> <span class="hljs-bullet">-</span> <span class="hljs-string">'!storage/'</span> <span class="hljs-bullet">-</span> <span class="hljs-string">'!tests/'</span>

<span class="hljs-attr">functions:</span> <span class="hljs-comment"># This function runs the Laravel website/API</span> <span class="hljs-attr">web:</span> <span class="hljs-attr">handler:</span> <span class="hljs-string">public/index.php</span> <span class="hljs-attr">environment:</span> <span class="hljs-attr">APP_NAME:</span> <span class="hljs-string">CHATI-BACKEND</span> <span class="hljs-attr">APP_DEBUG:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">LOG_CHANNEL:</span> <span class="hljs-string">stderr</span> <span class="hljs-attr">SESSION_DRIVER:</span> <span class="hljs-string">array</span> <span class="hljs-attr">CACHE_DRIVER:</span> <span class="hljs-string">array</span>
<span class="hljs-attr">DB_CONNECTION:</span> <span class="hljs-string">mysql</span> <span class="hljs-attr">DB_HOST:</span> <span class="hljs-string">{env:DB_HOST}</span> <span class="hljs-attr">DB_PORT:</span> <span class="hljs-string">{env:DB_PORT}</span> <span class="hljs-attr">DB_DATABASE:</span> <span class="hljs-string">{env:DB_DATABASE}</span> <span class="hljs-attr">DB_USERNAME:</span> <span class="hljs-string">{env:DB_USERNAME}</span> <span class="hljs-attr">DB_PASSWORD:</span> <span class="hljs-string">${env:DB_PASSWORD}</span>

    <span class="hljs-attr">description:</span> <span class="hljs-string">''</span>
    <span class="hljs-attr">timeout:</span> <span class="hljs-number">28</span> <span class="hljs-comment"># in seconds (API Gateway has a timeout of 29 seconds)</span>
    <span class="hljs-attr">layers:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">${bref:layer.php-82-fpm}</span>
    <span class="hljs-attr">events:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">httpApi:</span> <span class="hljs-string">'*'</span>

<span class="hljs-attr">useDotenv:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">plugins:</span> <span class="hljs-comment"># We need to include the Bref plugin</span> <span class="hljs-bullet">-</span> <span class="hljs-string">./vendor/bref/bref</span></pre></div><p id="5692"><b>useDotenv:true</b> : I added this instruction to use Laravel<b> .env</b> file to set Lambda function environment variables.</p><p id="23cb">In fact i added two .env files:<b> .env.dev</b> and <b>.env.prod</b>. Serveless plugin will search first for .env file with the same name as stage variable used.</p><p id="0c82">If stage variable used is <b>dev</b> then <b>.env.dev </b>variables are used when i set for example <b>DB_HOST: ${env:DB_HOST}</b>. that mean DB_HOST lambda env variable will be the same as DB_HOST in <b>.env.dev</b>.</p><p id="6779">if stage variable in deployment is <b>prod</b> then <b>DB_HOST </b>will get DB_HOST value<b> </b>of <b>.env.prod.</b></p><figure id="3393"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*-2WBQARX0kcJhBd280Mkqw.png"><figcaption></figcaption></figure><p id="c6a9">For the Gitlab pipelines I will :</p><p id="4203">run <b>build-dev</b> and <b>test-dev</b> for every commit on feature branchs</p><p id="d192">run <b>build-dev </b>and <b>deploy-dev</b> on each commit to <b>develop</b> branch</p><p id="4995">and finally run <b>prod-dev</b> et <b>deploy-prod</b> on each commit to <b>master</b> branch.</p><div id="658c"><pre><span class="hljs-attr">stages:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">build</span> <span class="hljs-bullet">-</span> <span class="hljs-string">test</span> <span class="hljs-bullet">-</span> <span class="hljs-string">deploy</span>

<span class="hljs-attr">image:</span> <span class="hljs-string">laravel-image:1.0</span>

<span class="hljs-attr">cache:</span> <span class="hljs-attr">key:</span> <span class="hljs-attr">files:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">composer.json</span> <span class="hljs-attr">paths:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">vendor/</span>

<span class="hljs-attr">build-dev:</span> <span class="hljs-attr">stage :</span> <span class="hljs-string">build</span> <span class="hljs-attr">before_script:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">--version</span> <span class="hljs-bullet">-</span> <span class="hljs-string">composer</span> <span class="hljs-string">--version</span> <span class="hljs-attr">script :</span> <span class="hljs-bullet">-</span> <span class="hljs-string">composer</span> <span class="hljs-string">install</span> <span class="hljs-string">--ignore-platform-req=ext-curl</span> <span class="hljs-attr">artifacts:</span> <span class="hljs-attr">paths:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">vendor</span>
<span class="hljs-attr">rules:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_COMMIT_BRANCH ==

Options

"master"'</span> <span class="hljs-attr">when:</span> <span class="hljs-string">never</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">when:</span> <span class="hljs-string">on_success</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">chati</span>

<span class="hljs-attr">build-prod:</span> <span class="hljs-attr">stage :</span> <span class="hljs-string">build</span> <span class="hljs-attr">before_script:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">--version</span> <span class="hljs-bullet">-</span> <span class="hljs-string">composer</span> <span class="hljs-string">--version</span> <span class="hljs-attr">script :</span> <span class="hljs-bullet">-</span> <span class="hljs-string">composer</span> <span class="hljs-string">install</span> <span class="hljs-string">--ignore-platform-req=ext-curl</span> <span class="hljs-string">--no-dev</span> <span class="hljs-attr">artifacts:</span> <span class="hljs-attr">paths:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">vendor</span>
<span class="hljs-attr">rules:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_COMMIT_BRANCH == "master"'</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">chati</span>

<span class="hljs-attr">test-dev:</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">test</span> <span class="hljs-attr">dependencies:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">build-dev</span> <span class="hljs-attr">script:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">cp</span> <span class="hljs-string">.env.dev</span> <span class="hljs-string">.env</span> <span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">key:generate</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">optimize</span> <span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">test</span> <span class="hljs-attr">rules:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'CI_COMMIT_BRANCH == "master"'</span> <span class="hljs-attr">when:</span> <span class="hljs-string">never</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'CI_COMMIT_BRANCH == "develop"'</span> <span class="hljs-attr">when:</span> <span class="hljs-string">never</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">when:</span> <span class="hljs-string">on_success</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">chati</span>

<span class="hljs-attr">deploy-dev:</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">deploy</span> <span class="hljs-attr">script:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">optimize</span> <span class="hljs-bullet">-</span> <span class="hljs-string">sls</span> <span class="hljs-string">deploy</span> <span class="hljs-string">--stage</span> <span class="hljs-string">dev</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">chati</span> <span class="hljs-attr">rules:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_COMMIT_BRANCH == "develop"'</span>

<span class="hljs-string">.deploy-prod:</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">deploy</span> <span class="hljs-attr">script:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">php</span> <span class="hljs-string">artisan</span> <span class="hljs-string">optimize</span> <span class="hljs-bullet">-</span> <span class="hljs-string">sls</span> <span class="hljs-string">deploy</span> <span class="hljs-string">--stage</span> <span class="hljs-string">prod</span>
<span class="hljs-attr">rules:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">if:</span> <span class="hljs-string">'$CI_COMMIT_BRANCH == "master"'</span> <span class="hljs-attr">tags:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">chati</span></pre></div><p id="e4b3">The difference between <b>deploy-dev</b> and <b>deploy-prod </b>is the stage variable ( <b>— stage</b>) used in deployment. This variable when changed from <b>dev</b> to <b>prod</b> will create different cloudformations stacks on aws for each environments and then two differents AWS APIs. Also a Specific Laravel env config will be used for each environment. In <b>deploy-dev,</b> <b>.env.dev</b> config file will be used and for <b>deploy-prod,</b> <b>.env.prod</b> config file will be used.</p><p id="0f4c">Last thing, I used a cache for Composer dependencies to speed up build job.</p><figure id="0c5a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*txeGlyFVRdmVJuPcUpjGUw.png"><figcaption></figcaption></figure><p id="1448">When<b> deploy-dev</b> job is runned with success, I will get my Laravel Application deployed in dev environment with all necessary aws ressources (API app, Lambda application , cloudwatch logs etc …). I will get also the URL for my api.</p><figure id="27f6"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*vaHxoNeWvcmsTRXekE952Q.png"><figcaption></figcaption></figure><p id="2474">And when i open API Url in browser :</p><figure id="be16"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*Z51dOgcGaIytRyPWinBd-g.png"><figcaption></figcaption></figure><p id="3db2">That is all, and welcome for comments.</p></article></body>

Complete CI/CD Gitlab pipeline for serveless Laravel Application on AWS API Gateway.

In this story we will try together to make new challenge : a complete CI/CD Gitlab pipeline for Serverless Laravel API on AWS.

The pipeline should build Laravel application dependencies using composer tool, save artifacts, test Unit and features tests and finally deploy the Laravel App to AWS.

As first step we will build together a Dockerfile for Laravel Container that will execute pipelines Jobs. I choose most optimized image based on ubuntu20.04 and contain only necessary tools for laravel and of course the aws cli. Below the Dockerfile I used in my pipeline:

FROM ubuntu:20.04

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC

# Install dependencies
RUN apt update
RUN apt install -y software-properties-common
RUN add-apt-repository -y ppa:ondrej/php
RUN apt update
RUN apt install -y php8.2\
    php8.2-cli\
    php8.2-common\
    php8.2-fpm\
    php8.2-mysql\
    php8.2-zip\
    php8.2-gd\
    php8.2-mbstring\
    php8.2-curl\
    php8.2-xml\
    php8.2-bcmath\
    php8.2-pdo

# Install php-fpm
RUN apt install -y php8.2-cli

# Install composer
RUN apt install -y curl
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Install nodejs
RUN apt install -y ca-certificates gnupg
RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
ENV NODE_MAJOR 20
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
RUN apt update
RUN apt install -y nodejs
RUN npm install -g serverless 


WORKDIR /var/www

In the last instruction of Dockerfile, I installed the serveless npm package that we will used to deploy to AWS.

Please now see my story https://readmedium.com/d018bc7e27b1 to help you to build new Laravel application and to install Laravel serveless package using npm and Bref using composer. When this is done, a file serveless.yml will be generated at the root of your Laravel Project.

I add some code to this file :

service: laravel-app

provider:
    name: aws
    # The AWS region in which to deploy (us-east-1 is the default)
    region: eu-west-x
    # The stage of the application, e.g. dev, production, staging… ('dev' is the default)
    stage: dev
    runtime: provided.al2
    stackName: app-stack   
      
          
package:
    # Directories to exclude from deployment   
    patterns:
        - '!node_modules/**'
        - '!public/storage'
        - '!resources/assets/**'
        - '!storage/**'
        - '!tests/**'

functions:
    # This function runs the Laravel website/API
    web:
        handler: public/index.php
        environment:
            APP_NAME: CHATI-BACKEND
            APP_DEBUG: true
            LOG_CHANNEL: stderr
            SESSION_DRIVER: array
            CACHE_DRIVER: array   
            DB_CONNECTION: mysql
            DB_HOST: ${env:DB_HOST}
            DB_PORT: ${env:DB_PORT}
            DB_DATABASE: ${env:DB_DATABASE}
            DB_USERNAME: ${env:DB_USERNAME}
            DB_PASSWORD: ${env:DB_PASSWORD}

        description: ''
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        layers:
            - ${bref:layer.php-82-fpm}
        events:
            - httpApi: '*'
useDotenv: true     
plugins:
    # We need to include the Bref plugin
 - ./vendor/bref/bref

useDotenv:true : I added this instruction to use Laravel .env file to set Lambda function environment variables.

In fact i added two .env files: .env.dev and .env.prod. Serveless plugin will search first for .env file with the same name as stage variable used.

If stage variable used is dev then .env.dev variables are used when i set for example DB_HOST: ${env:DB_HOST}. that mean DB_HOST lambda env variable will be the same as DB_HOST in .env.dev.

if stage variable in deployment is prod then DB_HOST will get DB_HOST value of .env.prod.

For the Gitlab pipelines I will :

run build-dev and test-dev for every commit on feature branchs

run build-dev and deploy-dev on each commit to develop branch

and finally run prod-dev et deploy-prod on each commit to master branch.

stages:
  - build
  - test
  - deploy

image: laravel-image:1.0

cache:
    key:
      files:
        - composer.json
    paths:
      - vendor/

build-dev:
  stage : build
  before_script:
    - php --version 
    - composer --version
  script :
    - composer install --ignore-platform-req=ext-curl 
  artifacts:
    paths:
      - vendor      
  rules:
    - if: '$CI_COMMIT_BRANCH == "master"'
      when: never
    - when: on_success
  tags:
    - chati

build-prod:
  stage : build
  before_script:
    - php --version 
    - composer --version
  script :
    - composer install --ignore-platform-req=ext-curl  --no-dev
  artifacts:
    paths:
      - vendor     
  rules:
    - if: '$CI_COMMIT_BRANCH == "master"'
  tags:
    - chati


test-dev:
  stage: test 
  dependencies:
      - build-dev
  script:
      - cp .env.dev .env
      - php artisan key:generate      
      - php artisan optimize 
      - php artisan test
  rules:
    - if: '$CI_COMMIT_BRANCH == "master"'
      when: never
    - if: '$CI_COMMIT_BRANCH == "develop"'
      when: never   
    - when: on_success 
  tags:
   - chati



deploy-dev:
  stage: deploy
  script:   
    - php artisan optimize
    - sls deploy --stage dev 
  tags:
    - chati
  rules:
     - if: '$CI_COMMIT_BRANCH == "develop"'



.deploy-prod:
  stage: deploy
  script:   
    - php artisan optimize
    - sls deploy --stage prod  
  rules:
     - if: '$CI_COMMIT_BRANCH == "master"'
  tags:
    - chati

The difference between deploy-dev and deploy-prod is the stage variable ( — stage) used in deployment. This variable when changed from dev to prod will create different cloudformations stacks on aws for each environments and then two differents AWS APIs. Also a Specific Laravel env config will be used for each environment. In deploy-dev, .env.dev config file will be used and for deploy-prod, .env.prod config file will be used.

Last thing, I used a cache for Composer dependencies to speed up build job.

When deploy-dev job is runned with success, I will get my Laravel Application deployed in dev environment with all necessary aws ressources (API app, Lambda application , cloudwatch logs etc …). I will get also the URL for my api.

And when i open API Url in browser :

That is all, and welcome for comments.

Gitlab
Aws Api Gateway
Serverless
DevOps
Lambda
Recommended from ReadMedium