Skip to content

Commit

Permalink
feat: infrastructure as code (#187)
Browse files Browse the repository at this point in the history
* feat: infrastructure as code backend

* feat: infrastructure as code frontend

* fix: serverless db

* fix: use node

* revert: wrong db use

* docs: readme

* fix: spell check

* feat: free tier cosmosDB

* feat: distable rate limit response

* fix: use serverless over free tier due to capacity issues
  • Loading branch information
edalholt authored Aug 22, 2023
1 parent 8953a94 commit 0ff062e
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 0 deletions.
43 changes: 43 additions & 0 deletions infrastructure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Infrastructure

##### The [bicep-template](./azureInfrastructure.bicep) contains the infrastructure to run a production and development environment for this application in [Microsoft Azure](https://azure.microsoft.com/).

For deploying the app you have to follow these steps:

1. Download the Azure CLI (guide [here](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli))
2. Log in to your preferred account using `az login`
3. Create a Resource Group for the application by the command (Change the name and the location if another is preferred):
`az group create --name vote --location "Norway East"`
4. Deploy the bicep template into the newly created Resource group by entering this command from this folder (replace name of resource group if another is used):
5. `az deployment group create --resource-group test --template-file ./infrastructure/azureInfrastructure.bicep`

Now you have all the resources set up, but there are still some manual steps:

1. Set up a custom domain

The application has to be hosted on the same domain/subdomain for cookies and CORS to behave correctly.
For example, the frontend can be assigned to vote.ntnui.no, then the backend has to run on a subdomain of the frontend. For example, api.vote.ntnui.no. This has to be configured manually in Azure.
(In the future this could probably be automated as well?)

2. Allow only the backend IP to access the database.

Because the backend is dependent on the database to exist to obtain the database connection string, the database is created before the backend. Therefore the bicep script won't know the backend IP because it does not exist yet. By default, it there allows all IPs, which is not ideal security-wise.
(You obviously still need the URI, username, and password)

### Deploying code from GitHub

##### Now that the infrastructure is up and running it's time to add some content ✨

This repository contains some [workflows](../.github/workflows/). The ones containing "deploy" deploys either the backend or the frontend to the development or the production environment.

In the backend workflows, you have to add the correct `app-name` and `slot-name`.
The backend workflows also contain an `publish-profile`. The publish profiles are stored in the secrets section of this GitHub repository. These secrets have to be updated with the new ones for the workflows to function.

![Image](azure-publish-profile.png)
The secret can be downloaded from here or by using Azure CLI.

It is almost the same for the frontend workflows, except here the workflow contains a `azure_static_web_apps_api_token`. You find this token almost the same way as the publish profile, but it is named `deployment token` in the Static Web App settings.

##### When all the above steps are completed, your next commit will automagically deploy to Azure, and the service are ready for production! 🚀

(If one day you do not need the service anymore, you only need to delete the resource group, and you are back to where you started 🧹)
Binary file added infrastructure/azure-publish-profile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
180 changes: 180 additions & 0 deletions infrastructure/azureInfrastructure.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
param appName string = 'vote'
param location string = 'Norway East'
param staticWebAppLocation string = 'westeurope'

/*
Using a S1 plan to support development slots.
Also using a S1 plan to support more than 350 concurrent web socket connections.
If downgrading to a cheaper plan, such as B1, you could run into issues with the number of concurrent web socket connections under peak load.
Also you have to remove the dev slot, and give it a separate Web App.
*/
resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = {
name: '${appName}-plan'
location: location
sku: {
name: 'S1'
tier: 'Standard'
}
properties: {
reserved: true
}
}

resource voteDB 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
name: '${appName}-db'
location: location
tags: {
defaultExperience: 'Azure Cosmos DB for MongoDB API'
'hidden-cosmos-mmspecial': ''
}
kind: 'MongoDB'
identity: {
type: 'None'
}
properties: {
enableFreeTier: false
databaseAccountOfferType: 'Standard'
apiProperties: {
serverVersion: '4.2'
}
locations: [
{
locationName: location
failoverPriority: 0
isZoneRedundant: false
}
]
capabilities: [
{
name: 'EnableMongo'
}
{
name: 'DisableRateLimitingResponses'
}
{
name: 'EnableServerless'
}
]
backupPolicy: {
type: 'Continuous'
continuousModeProperties: {
tier: 'Continuous7Days'
}
}
}
}

resource databaseAccounts_production 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2023-04-15' = {
parent: voteDB
name: 'production'
properties: {
resource: {
id: 'production'
}
}
}

resource databaseAccounts_development 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2023-04-15' = {
parent: voteDB
name: 'development'
properties: {
resource: {
id: 'development'
}
}
}

resource backend 'Microsoft.Web/sites@2022-09-01' = {
name: '${appName}-backend'
location: location
kind: 'app,linux'
properties: {
serverFarmId: appServicePlan.id
httpsOnly: true
siteConfig: {
numberOfWorkers: 1
linuxFxVersion: 'NODE|18-lts'
appSettings: [
{
name: 'DB_URI'
value: voteDB.listConnectionStrings().connectionStrings[0].connectionString
}
{
name: 'BACKEND_PORT'
value: '8080'
}
{
name: 'NODE_ENV'
value: 'production'
}
{
name: 'NTNUI_TOOLS_API_URL'
value: 'https://api.ntnui.no/'
}
]
}
}
}

resource backendDevSlot 'Microsoft.Web/sites/slots@2022-09-01' = {
parent: backend
location: location
name: 'dev'
properties: {
httpsOnly: true
siteConfig: {
numberOfWorkers: 1
linuxFxVersion: 'NODE|18-lts'
appSettings: [
{
name: 'DB_URI'
value: voteDB.listConnectionStrings().connectionStrings[0].connectionString
}
{
name: 'BACKEND_PORT'
value: '8080'
}
{
name: 'NODE_ENV'
value: 'development'
}
{
name: 'NTNUI_TOOLS_API_URL'
value: 'https://dev.api.ntnui.no/'
}
]
}
}
}

resource frontend 'Microsoft.Web/staticSites@2022-09-01' = {
name: '${appName}-frontend'
location: staticWebAppLocation
properties: {
repositoryUrl: 'https://github.com/NTNUI/vote2/'
branch: 'main'
buildProperties: {
appLocation: '/frontend'
}
}
sku: {
tier: 'Free'
name: 'Free'
}
}

resource frontendDev 'Microsoft.Web/staticSites@2022-09-01' = {
name: '${appName}-frontend-dev'
location: staticWebAppLocation
properties: {
repositoryUrl: 'https://github.com/NTNUI/vote2/'
branch: 'dev'
buildProperties: {
appLocation: '/frontend'
}
}
sku: {
tier: 'Free'
name: 'Free'
}
}

0 comments on commit 0ff062e

Please sign in to comment.