Showing posts with label GitHub Actions. Show all posts
Showing posts with label GitHub Actions. Show all posts

Saturday, March 26, 2022

Deploy DB driven Laravel web app to Azure App Service running on Linux NGINX web server through GitHub Actions

Laravel is an open-source PHP framework designed to make developing web apps mush easier and faster through built-in features. It is based on the MVC design pattern.

In this article, I will show you how to deploy a Laravel application to Azure App Services. The Azure web server is NGINX running on Linux version "Debian GNU/Linux 10 (buster)".

Assumptions

The following is assumed:

  • You have Git, PHP and Composer installed on your computer.
  • You have an Azure subscription
  • You have a GitHub account

Getting Started

We will start our journey with a very simple Laravel application that lists some data from a SQLite database. Go into a working directory on your computer and run the following command from a terminal window to clone a GitHub repo:

git clone https://github.com/medhatelmasry/laravel-azure.git

It is a good idea to delete the .git folder on your computer.

Once the application is cloned, change directory to the cloned app and start your app as shown below:

cd laravel-azure
composer install
php artisan serve --port=8888

The web server will start on your computer listening on port 8888.

Starting Laravel development server: http://127.0.0.1:8888
[Sat Mar 26 15:36:29 2022] PHP 8.1.2 Development Server (http://127.0.0.1:8888) started

Point your browser to http://localhost:8888/ and you will see the following page:


For demo purposes, data is pulled from a SQLite database file at database/autos.db

Disclaimer: It is normal practice that the .env file is excluded from being pushed to source control. If you look at the .gitignore file, the line pertaining to .env is commented out because there is really no confidential information in this file.

Create a repository in your GitHub account and push the source code to it.

Create Azure App Service

Login to your Azure account by visiting https://portal.azure.com. Enter "app services" in the filter field, then click on "App Services".



Click on "+ Create" on the top left-side.

On the "Create Web App Page", choose. your subscription then create new resource group.



Give your app a suitable host name that is unique.


Next, ensure these settings for Publish, Runtime stack and Operating System:


Choose suitable values for the remaining settings based on your individual preference then click on the blue "Review + create" button:


Click on Create button after you have reviewed your. choices.


Once your app service is successfully provisioned, you can click on the "Go to resource" button.


You can see a default web page to your web app be clicking on the URL link on the top right-side.


The default page looks like this.

\

CI/CD pipeline

Of course, we want to deploy our Laravel PHP site from our GitHub repo. An easy way to achieve this is to use Azure's "Deployment Center". Click on "Deployment Center" in the left-side navigation.

In the "Deployment Center" blade, select GitHub.


If this is your first time to connect Azure to your GitHub account, you will be asked to go through the GitHub authentication process. Thereafter, select the appropriate GitHub Organization, Repository and Branch. My experience was:


Once you click on Save, the deployment process commences.


To go to your GitHub repo, click on the main link under Branch.

To see the deployment in action, click on Actions in your GitHub repository.


Click on the workflow in progress.


The workflow will be going through a build and deploy process. 


Be patient as it takes about 15 minutes to complete. This is because during build the command "composer install" is executed. This produces a multitude of files under the vendors folder, which are thereafter sent to Azure. Once the workflow is completed, your GitHub workflow page will look like this:


The workflow files were automatically generated and placed a .yml file in the .github/workflows folder with your source code.


You can click on the .yml file to see what the file looks like.


At this point, it is worth going back to the code on your computer and doing a pull of your code so that you get a copy of the .yml file that was added to your source code.

Configuring app on Azure

Back on the Azure portal, if you refresh the default page of our web app, you will experience a "403 Forbidden" message, which typically means that the root directory has no welcome page.




This is understandable because the main index.php page in Laravel resides in the /public folder. THis means that we need to do some configuration work on Azure. 

In Azure, enter the term advanced in the search input field then click on "Advanced Tools".


Click "Go -->".


A page opens up in a new browser tab. Click on SSH on the top menu.


A Linux terminal window is open.



If you are interested to know what version of Linux this is, enter the following terminal command:

cat /etc/os-release

The value beside PRETTY_NAME is the Linux distribution and version.

PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

We will make a copy of the existing nginx configuration and place the file inside the /home/site directory with the following command:

cp /etc/nginx/sites-available/default /home/site/default

Once copied, edit the /home/site/default file with nano or vi. I will use nano.

nano /home/site/default

Make the following changes:

FromToAround Line #
root /home/site/wwwrootroot /home/site/wwwroot/public6
location / {
   index  index.php index.html index.htm hostingstart.html;
}
      
location / {
   index  index.php index.html index.htm hostingstart.html;
   try_files $uri $uri/ /index.php?$query_string;
}
      
10


In nano, hit CTRL X to save, enter Y then hit return.

We need to create a bash script file that overrides the existing default file with our customized version, then restart the server. Change directory to the site folder.

cd site

Inside the site directory, using vi or nano, create a file named startup.sh. To create a file with nano, type "nano startup.sh". Otherwise,  to create a file with vi, type "vi startup.sh". Add the following content to startup.sh:

#!/bin/bash

cp /home/site/default /etc/nginx/sites-available/default
service nginx reload

We will make our bash script file executable with:

chmod u+x startup.sh

While in the terminal window on Azure, let's visit the folder that contains our Laravel application. Do this by going to the wwwroot folder.

cd wwwroot
ls -a

This reveals the existence of all the files that we had on GitHub plus files in the vendor folder.


Navigate back to your App Service via the Azure Portal. Select Configuration in the Settings section.


Click on the "General Settings" tab, enter "/home/site/startup.sh" for the "Startup Command", then click on Save.


Click on blue Continue button the the "Save changes" prompt.


Now, when you refresh the website, you should see that our web app is working as expected.

Conclusion

We have successfully deployed a database driven Laravel PHP application to Azure App Services through GitHub. I hope you use the principles you learned in this tutorial to deploy much more interesting Laravel applications.

Saturday, March 5, 2022

Deploy ReactJS app to Azure Blob Storage through GitHub Actions

This tutorial will show you how easy it is to deploy a simple ReactJS single page application to Azure Blob Storage.

Source code: https://github.com/medhatelmasry/react2az.gitPre-requisites

The following pre-requisites are assumed:

  • The latest versions of Node.js & npm are installed on your computer
  • You have an Azure subscription
  • You have git installed on your computer
  • You have a GitHub account
  • You have some basic knowledge of ReactJS

Create a simple React app

Choose a suitable working folder and then execute the following command in a terminal window to create a ReactJS app named react2az:

npx create-react-app react2az --use-npm
cd react2az 
npm start

The app will display in your default browser as shown below:

Let us make this application more interesting. 

Install the following client-side packages for bootstrap support:

npm install react-bootstrap bootstrap

Visit React-Bootstrap · React-Bootstrap Documentation for documentation on how to use Bootstrap with ReactJS.

Create /src/pages folder, then add to this new folder a file named home-page.js with content:

import React from "react";
import { useState, useEffect } from "react";
import { Card, Col, Row } from "react-bootstrap";

const HomePage = () => {
  const [toonInfo, setToonInfo] = useState({});

  useEffect(() => {
    const fetchData = async () => {
      const result = await fetch(
        `https://api4all.azurewebsites.net/api/people/`
      );
      const body = await result.json();
      setToonInfo(body);
    };
    fetchData();
  }, []);

  const renderCard = (card, index) => {
    return (
      <Col>
        <Card style={{ width: "50%" }} key={index}>
          <Card.Img variant="top" src={card.pictureUrl} />
          <Card.Body>
            <Card.Title style={{ fontSize: "12px" }}>
              {card.firstName} {card.lastName}
            </Card.Title>
            <Card.Text style={{ fontSize: "10px" }}>
              {card.occupation}
            </Card.Text>
          </Card.Body>
        </Card>
      </Col>
    );
  };

  return (
    <React.Fragment>
      <Row xs={1} sm={2} md={3} lg={5} className="g-4">
        {Array.from(toonInfo).map((item, key) => renderCard(item, key))}
      </Row>
    </React.Fragment>
  );
};

export default HomePage;

The above code accesses an API at https://api4all.azurewebsites.net/api/people/ and renders the images of some cartoon characters in a bootstrap grid of cards.

Open src/App.js in your favourite editor and made the following changes:
  • Delete the first two import lines and replace them with the following:
import HomePage from './pages/home-page';
import 'bootstrap/dist/css/bootstrap.min.css';
  • Delete the content inside return (. . . ); and replace with:
<div className="container">
  <HomePage />
</div>

This means that your src/App.js will look like this:

import HomePage from './pages/home-page';
import 'bootstrap/dist/css/bootstrap.min.css';

function App() {
  return (
    <div className="container">
      <HomePage />
    </div>
  );
}

export default App;

Run your application and you should experience the following web page:

Push ReactJS app to GitHub

Note that your application already contains a .gitignore file. This means that the node_modules folder will be excluded for being pushed to GitHub.

Create a local git repo by running the following command in the root of your application:

git init
git add .
git commit -m "1st commit"

Login into your GitHub account and create a repository. In my case I created a repository by the same name of the application react2az. After you create a new repository, you will see a page that looks like this:



Copy the instructions under "…or push an existing repository from the command line" and execute them in the root of your application. This pushes your code to GitHub.

If you refresh the previous GitHub page, you will see your code had indeed been pushed to GitHub:

Create Storage Account on Azure

Visit https://portal.azure.com/ and login into your Azure subscription. Click on "Create a resource":

In the search field, enter the word storage, hit ENTER, then click on "Storage account".

Click on the blue Create button:



Beside "Resource group", click on "Create new" and give your resource group a suitable name. 


Meantime, change the other settings so that they are similar to the following:


Click on "Review + create":


On the next screen, click on Create. After a short while, your storage account will be provisioned and your page will look like this:

Click on "Go to resource".  In the search field, enter the word static then click on "Static website". 

Click on Enabled.

Enter index.html and 404.html then click on Save at the top.


Your static website will be placed into a folder named $web. You can go ahead and click on it to see that it contains nothing:

Click on your browser back button, clear the search field, then select "Access keys".



Click on "Show keys", copy the connection string, then temporarily paste it in a a text editor.

GitHub Actions

In GitHub, click on Settings:


Click on Secrets followed by Actions:


Click on "New repository secret".

Create a key named AZURE_STORAGE then paste the connection string that you previously saved in a text editor. Click on "Add secret".


Add a folder .github/workflows to your source code. Inside that folder, create a text file named react2az.yml with the following content:

name: Deploy React App to Azure Storage

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - '*'
defaults:
  run:
    working-directory: ./
env:
  NODE_VERSION: '17'                # set this to the node version to use
  CI: false
jobs:
  build-and-deploy:
    name: Build and Deploy
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ env.NODE_VERSION }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ env.NODE_VERSION }}
    - name: npm install & build
      run: |
        # Build and test the project, then
        # deploy to Azure Web App.
        npm install
        npm run build
    - name: 'Deploy react app to Azure blob storage'
      uses: bacongobbler/azure-blob-storage-upload@main
      with:
          source_dir: './build'
          container_name: '$web'
          connection_string: ${{ secrets.AZURE_STORAGE }} 
          sync: 'true'

Once this file gets pushed or created on GitHub, you can see that the workflow gets kicked off. Click on Actions and you will see a workflow running. This workflow will likely have a different name than "workflow". 



If all goes well, the workflow will turn green, meaning that it completed successfully:

Viewing our web application

You must be dying to view the application hosted on Azure. Return to the Azure portal then go to "static websites". The URL for accessing your application is beside "Primary endpoint".

Visit the primary endpoint URL and you will see that your ReactJS app is happily hosted on Azure:


In Azure, if you click on $web you will see your files on Azure Blob Storage.

Happy coding and deploying.