We will deploy the resources below using Terraform reusable modules utilizing the Azure landing zone concept, part of the Cloud Adoption Framework (CAF). In this setup, we are talking about only infra resources; if you are new to terraform, the same concept has been explained using the Azure Portal; I have spoken about Azure Management Groups and Subscription Planning in this link – Azure Management Groups and Subscriptions Design
Azure landing zone design that accounts for scale, security governance, networking, and identity, which enables seamless application migration, modernization, and innovation at the enterprise scale in Azure. This approach considers all platform resources like infrastructure (Iaas) or platform as a service.
Benefits of Azure Landing Zones –
Good Governance ( Like you can place a policy in the overall environment that no internet-exposing storage accounts can be provisioned)
Scalability (Multi Datacenter or Improving the design with Virtual WAN should be seamless)
Cost Savings (Segregated billing with subscriptions – Overall Control or like can apply Hybrid benefit using policies)
Resources Provisioned –
1. Virtual Networks (Hub – 10.50.0.0/16 – Spoke – 10.51.0.0/16) 2. VPN Gateway (10.50.1.0/24) – Not Provisioned by Default 3. Azure Firewall (10.50.2.0/24) 4. Application Gateway (10.50.3.0/24) – Not Provisioned by Default 5. Azure Bastion (10.50.4.0/24) 6. Jump Box (Windows 11) (10.50.5.0/24) 7. Windows Server 2019 Web Server (10.51.1.0/24) 8. Linux RHEL Server (10.51.2.0/24) 9. Public IP Addresses 10. Recovery Services Vault 11. Azure Key Vault – Not Provisioned by Default 12. Route Tables 13. Azure Firewall Policies
Modules are convenient to place into folders and reuse resource configurations with Terraform for multiple deployments. Also, changing/upgrading specific resource configurations becomes easier.
Utilizing Connection Strings in PHP/Nodejs/Next Js for App Service – The source code is Deployed in UAT and Production; both have different connection strings, for example. So that pipeline is deployed smoothly without any manual changes utilizing DevOps variables. Let’s take an example of using the same codebase and applying it on UAT and Prod. My UAT will apply UAT DB Connection String, and Production will apply the Production Connection string for the same Codebase.
As you can see, I am adding this MYSQLCONNSTR_ suffix for my connection string as its MYSQL; you can update the suffix accordingly. Application settings don’t need any suffixes. Also, you can retrieve secrets from the key vault to run them in the App service without exposing them.
At runtime, connection strings are available as environment variables, prefixed with the following connection types:
SQLServer: SQLCONNSTR_
MySQL: MYSQLCONNSTR_
SQLAzure: SQLAZURECONNSTR_
Custom: CUSTOMCONNSTR_
PostgreSQL: POSTGRESQLCONNSTR_
For Retrieving from Key Vault, you need to specific the URI, and it will retrieve the latest version if the below format is used.
Node Js Build Error fetch failed with undici – Run Node Js 18.0 – 18.x minor versions cause this error. (Bug)
npm install
npm run dev
npm run build
C:\Scripts\repo\azure365pro-Guide>npm install
up to date, audited 707 packages in 4s
97 packages are looking for funding
run `npm fund` for details
8 vulnerabilities (1 moderate, 3 high, 4 critical)
To address all issues, run:
npm audit fix
Run `npm audit` for details.
npm notice
npm notice New major version of npm available! 8.19.2 -> 9.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.2.0
npm notice Run npm install -g npm@9.2.0 to update!
npm notice
C:\Scripts\repo\azure365pro-Guide>npm run dev
> dev
> next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 869 ms (228 modules)
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
Terminate batch job (Y/N)? Y
C:\Scripts\repo\azure365pro-Guide>npm run build
> build
> next build
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
info - Checking validity of types
./pages/buscar.js
92:7 Warning: React Hook useEffect has a missing dependency: 'fetchFilterOptions'. Either include it or remove the dependency array. react-hooks/exhaustive-deps
./pages/colegio/[cid].js
261:65 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
278:33 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
294:60 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
318:25 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
323:25 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
328:25 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
336:25 Warning: Image elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/alt-text
./components/SearchInput.js
33:7 Warning: React Hook useEffect has a missing dependency: 'fetchFilterOptions'. Either include it or remove the dependency array. react-hooks/exhaustive-deps
info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db
Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
info - Creating an optimized production build
Failed to compile.
./public/images/banner.jpg
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11118:11)
Import trace for requested module:
./pages/index.js
./public/images/condiciones.jpg
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11118:11)
Import trace for requested module:
./pages/condiciones.js
./public/images/conoce.jpg
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11118:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Import trace for requested module:
./pages/index.js
./public/images/graduation.jpg
TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11118:11)
Import trace for requested module:
./pages/buscar.js
> Build failed because of webpack errors
C:\Scripts\repo\azure365pro-Guide>
Single Sign-on using Azure AD with Static Web Apps, let’s create a Simple Azure AD Page, Enable Single Sign-on Using Azure AD. Uploaded the same javascript below the GitHub repo.
Sign in, Redirects to Microsoft Login, and Logout Kills all the session.
In this requirement. We are using CI / CD from the GitHub repository and creating an artifact and Deploying Next Js on Azure App Service, which is using “Strapi – Open source Node.js Headless CMS” from an Azure App Service using Azure DevOps Releases. We are using staging slots, and upon Approval, it will deploy to the production slot.
Good to know – CI/CD are Continuous Integration, Continuous Delivery, and Continuous Deployment
Pipelines are integrated with GitHub Repo for CI / CD and are deployed to UAT (Azure App Service Staging Slot ), where they can be tested. If it gets approved (Approval Gates), After testing, it will be deployed to the Production Slot in the same App Service. Otherwise, the change can be rejected.
Ran the node js locally using [ npm run dev / npm run build ], which went through successfully.
A similar article for CI / CD is done for Azure App Service using Azure DevOps.
As you see below, we are using a Git hub source repository. First Deploys to a Standard UAT (Azure App Service Staging Slot ). If an approver approves changes, It’s deployed to a Production Azure App Service.
Now you can see the releases happening on UAT and Production environments without any manual steps. Let’s see how to implement the same.
Create New Pipeline – Choose Github (YAML) as I use GitHub in my case
Choosing Node.js Express Web App on Linux on Azure
Using below YAML – azure-pipelines.yml
# Node.js Express Web App to Linux on Azure
# Build a Node.js Express app and deploy it to Azure as a Linux web app.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
trigger:
- main
variables:
# Azure Resource Manager connection created during pipeline creation
azureSubscription: 'd4200000-0000-0000-0000-9bb00007d505'
# Web app name
webAppName: 'az-az365pro-pr-fc-web-rg'
# Environment name
environmentName: 'az-az365pro-pr-fc-web-rg'
# Agent VM image name
vmImageName: 'ubuntu-latest'
stages:
- stage: Build
displayName: Build stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: NodeTool@0
inputs:
versionSpec: '18.x'
displayName: 'Install Node.js'
- script: |
npm install
npm run build --if-present
# npm run test --if-present
displayName: 'npm install, build and test'
- task: ArchiveFiles@2
displayName: 'Archive files'
inputs:
rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
includeRootFolder: false
archiveType: zip
archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
replaceExistingArchive: true
- upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
artifact: drop
Having two files in my repo
Added ecosystem.config.js. We need to start this separately
Error: Cannot find module ‘../build/output/log’
Require stack:
– /home/site/wwwroot/node_modules/.bin/next
at Module._resolveFilename (node:internal/modules/cjs/loader:1077:15)
at Module._load (node:internal/modules/cjs/loader:922:27)
at Module.require (node:internal/modules/cjs/loader:1143:19)
at require (node:internal/modules/cjs/helpers:110:18)
at Object. (/home/site/wwwroot/node_modules/.bin/next:6:54)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
code: ‘MODULE_NOT_FOUND’,
requireStack: [ ‘/home/site/wwwroot/node_modules/.bin/next’ ]
}
.
Staging is set to a Staging slot.
Staging slot is created for use – Add Slot – Staging
In my next stage Production Slot is chosen with the same settings
Now my App Service URLs are ready with below
Staging – (Upon Approval, Goes to Prod) https://azure365pro-statging.azurewebsites.net/en-US Production – https://azure365pro.azurewebsites.net/en-US
Continous Deployment Trigger is enabled so that UAT is pushing on every new build.