Dec 17, 2017

Deploying a MEAN App to Azure App Services via GitHub

Do you want to setup your MEAN stack (MongoDB, Express, AngularJS and Node.js) application on Azure App Services with Continuous Integration and Delivery? Here are step by step videos to deploy a MEAN application to Azure Web Apps via GitHub and store the app's data inside Cosmos DB (a drop-in replacement for MongoDB).

Step 1:

Deploy simple Node.js + Express application via GitHub

 

It shows

- Create simple "Hello World" express application

- Setup GitHub repository and push the code

- Create Web Apps in Azure App Services

- Configure Deployment Options to set GitHub repository as deployment source.

- Run the application in web browser

If you are beginner or first time to deploy on Azure App Service, don't miss it.

Step 2:

Setup environment variable and configuration settings

 

As the best practices say to keep configuration settings out of source code then how it be configured on cloud side? The video shows in case of Azure app service:

- How to use environment variables in Node.js application.


console.log (process.env.MyEnvronmentVariable);

- How to define "App Settings" and "Connection Strings" in Application Settings

azure app settings

- These settings will also be available as environment variables at runtime, prefixed with the connection type. The environment variable prefixes are as follows:

SQL Server: SQLCONNSTR_

MySQL: MYSQLCONNSTR_

SQL Database: SQLAZURECONNSTR_

Custom: CUSTOMCONNSTR_

For example, if a Custom connection string were named MyConnectionString, it would be accessed through the environment variable CUSTOMCONNSTR_MyConnectionString.

In Node.js:


console.log (process.env.CUSTOMCONNSTR_MyConnectionString);

Step 3:

Deploy MongoDB Based App using Azure Cosmos DB

You can use Cosmos DB for MongoDB APIs with same driver (Mongoose) means you can develop your application using MongoDB and deploy to production using Cosmos DB service.

 

It shows:

- To configure simple node todo application in local environment.

- Setup Azure Cosmos DB account for MongoDB APIs

- Update node app to get connectionstring from environment variable.


mongoose.connect(process.env.CUSTOMCONNSTR_MyConnectionString || database.localUrl);

- push the changes on repository.

- Create Azure web app with Github as deployment options as done in Step-1.

- Setup connectionstring environment variable "MyConnectionString" as done in Step-2 and copy & paste connectionstring from CosmosDB settings.

- Run the application and add some items

- Check Cosmos DB Data Explorer to see collection and documents (data)

Step 4:

Deploy Angular 4 App via GitHub

 

With Microsoft Azure Web Apps, you can deploy your website by simply pushing your git repository, this will automatically deploy your website But sometimes you need to control this deployment flow (If you are using Angular 2/4+ then you want to build via Angular CLI.) you can use the custom deployment feature. For this, custom deployment script generator tool called kuduscript is used. In the video, simple Angular 4 Todo application is used and after local setup, run following command to generate default deployment script:


npm install kuduscript -g
kuduscript -y --node

It will generate the files required to deploy your site, mainly:

.deployment - Contains the command to run for deploying your site.

deploy.cmd - Contains the deployment script (or deploy.sh if running on Mac/Linux)

By default, the deployment section in the file:


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

:Deployment
echo Handling node.js deployment.

:: 1. KuduSync
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
)

:: 2. Select node version
call :SelectNodeVersion

:: 3. Install npm packages
IF EXIST "%DEPLOYMENT_TARGET%\package.json" (
  pushd "%DEPLOYMENT_TARGET%"
  call :ExecuteCmd !NPM_CMD! install --production
  IF !ERRORLEVEL! NEQ 0 goto error
  popd
)

The above will sync files from repository to target folder and run "npm install --production" command. Now, update it with following:


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

:Deployment
echo Handling node.js deployment.

:: 1. Select node version
call :SelectNodeVersion

:: 2. Install npm packages
IF EXIST "%DEPLOYMENT_SOURCE%\package.json" (
  pushd "%DEPLOYMENT_SOURCE%"
  call :ExecuteCmd !NPM_CMD! install
  IF !ERRORLEVEL! NEQ 0 goto error
  popd
)

:: 3. Angular Prod Build
IF EXIST "%DEPLOYMENT_SOURCE%/.angular-cli.json" (
echo Building App in %DEPLOYMENT_SOURCE%…
pushd "%DEPLOYMENT_SOURCE%"
call :ExecuteCmd !NPM_CMD! run build
IF !ERRORLEVEL! NEQ 0 goto error
popd
)

:: 4. Copy Web.config
IF EXIST "%DEPLOYMENT_SOURCE%\web.config" (
  pushd "%DEPLOYMENT_SOURCE%"
 :: the next line is optional to fix 404 error see section #8
  call :ExecuteCmd cp web.config dist\
  IF !ERRORLEVEL! NEQ 0 goto error
  popd
)

:: 5. KuduSync
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%/dist" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
)

In other words, the following operations will be executed

npm install //No --production because we need to build via CLI

npm run build // in package.json "build": "ng build --prod" will be executed

cp web.config dist/ // copy web.config to dist folder

At last, sync dist folder to wwwroot.

Now what about web.config?

For fixing the 404 when refreshing, you need to add a web.config on the root with this content: (via Stackoverflow)


   <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <system.webServer>
        <rewrite>
          <rules>
            <rule name="AngularJS" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
              </conditions>
              <action type="Rewrite" url="index.html" />
            </rule>
          </rules>
        </rewrite>
      </system.webServer>
    </configuration>

You can push your changes in repository, setup Azure Web App via GitHub like in previous step, run the application and enjoy it.

Similarly, if you are using Gulp, Grunt, Bower, Composer or any custom build operation, you can customize deployment script accordingly.

Conclusion:

This post covered how to setup MEAN stack on Azure App Services + Cosmos DB via GitHub. Started with very basic how to create "Hello World" application in Node.js + Express then went through how to implement configuration settings in Azure App Service and used it for connection string. Setup CosmosDB and saw how it can be used without any modification in MongoDB driver. At last saw how to customize deployment for Angular 4 build process.

Hope, It helps, Enjoy MEAN Stack!!