Finished site
The Requirements
The requirements of the challenge were as follows:
- Get an Azure Foundation Certification
- Front-end: Create a resume website
- HTML, CSS, JavaScript
- Host on Azure Static Sites
- Use HTTPS for security
- Custom domain name
- Set Azure DNS
- Use JavaScript to call Azure Counter Function
- Back-end
- Set up a Cosmos database to store the hit counter
- Azure Function that serves as an API to connect web app to cosmos db.
- Write tests that validate API tests
- Infrastructure-as-code
- Pulumi - Web site, azure function, cosmos db, DNS
- Add source control for the site via Azure Devops
- Implement automated CI/CD for the front-end
- Implement automated CI/CD for the back-end
- Write a blog post detailing the experience
Implementation
There are quite a few requirements listed above but they basically boils down to a 4 main areas, a front-end, a back-end, infrastructure as code and two CI/CD pipelines for publishing front and back-ends.
Front-end
I wanted to keep the front-end straight forward so grabbed the bootstrap album template and used it to create a basic CV site. I choose Azure Static Web App as the site host because it can be easily integrated with Azure Devops pipelines.
First up I will the infrasturcture as code that creates
The following segment of code is taken pulumi and will create a resource group called "cvfrontend". A static site is created first.
import pulumi
from pulumi_azure_native import resources
import pulumi_azure_native as azure_native
import pulumi_azure_native.documentdb as documentdb
import pulumi_azure_native.resources as resources
import pulumi_azure_native.storage as storage
# Create an Azure Resource Group
resource_group = resources.ResourceGroup('cvfrontend')
site_name = "cvsitefrontend"
static_site = azure_native.web.StaticSite("staticSite",
branch="master",
build_properties=azure_native.web.StaticSiteBuildPropertiesArgs(
api_location="api",
app_artifact_location="build",
app_location="app",
),
location="West Europe",
name=site_name,
repository_token="add your token",
repository_url="add your git url to repo",
resource_group_name=resource_group.name,
sku=azure_native.web.SkuDescriptionArgs(
name="Free",
tier="Free",
))
I registered a Domain name "cvoregan.com" using Azure Portal which created two resources in the image below. A domain name and DNS Zone associated with the domain.
Once these domain name resources were available I then wrote some pulumi code to create a CNAME record. The record points the static site host Url and bind it to www.cvoregan.com.
record_set = azure_native.network.RecordSet("cvStaticSiteRecordSet",
cname_record=azure_native.network.CnameRecordArgs(
cname=static_site.default_hostname,
),
record_type="CNAME",
relative_record_set_name="www",
resource_group_name=resource_group.name,
ttl=3600,
zone_name="cvoregan.com")
static_site_custom_domain = azure_native.web.StaticSiteCustomDomain("cvStaticSiteCustomDomain",
domain_name="www.cvoregan.com",
name=site_name,
resource_group_name=resource_group.name)
The site would have a Javascript call that retrieved and updated the counter and displayed
Where the front-end became more interesting to me was implementing the
# Create an Azure resource (Storage Account)
storage_account = storage.StorageAccount(
"cvcosmostr",
resource_group_name=resource_group.name,
sku=storage.SkuArgs(
name=storage.SkuName.STANDARD_LRS,
),
kind=storage.Kind.STORAGE_V2)
# Cosmos DB Account
cosmosdb_account = documentdb.DatabaseAccount(
"sqladminacc",
resource_group_name=resource_group.name,
database_account_offer_type=documentdb.DatabaseAccountOfferType.STANDARD,
locations=[documentdb.LocationArgs(
location_name=resource_group.location,
failover_priority=0,
)],
consistency_policy=documentdb.ConsistencyPolicyArgs(
default_consistency_level=documentdb.DefaultConsistencyLevel.SESSION,
))
# Cosmos DB Database
db = documentdb.SqlResourceSqlDatabase(
"AzureCVDB",
resource_group_name=resource_group.name,
account_name=cosmosdb_account.name,
resource=documentdb.SqlDatabaseResourceArgs(
id="AzureCVDB",
))
# Cosmos DB SQL Container
db_container = documentdb.SqlResourceSqlContainer(
"container",
resource_group_name=resource_group.name,
account_name=cosmosdb_account.name,
database_name=db.name,
resource=documentdb.SqlContainerResourceArgs(
id="counter",
partition_key=documentdb.ContainerPartitionKeyArgs(
paths=["/count"],
kind="Hash",
)
))
account_keys = pulumi.Output.all(cosmosdb_account.name, resource_group.name).apply(
lambda arg: documentdb.list_database_account_keys(account_name=arg[0], resource_group_name=arg[1]))
Back-end resources
The back-end is an HTTP triggered Azure Functions with Cosmos DB input and output binding. The Function is triggered, it retrieves the CosmosDB item, adds 1 to it, and saves it and returns its value to the caller. CORS
Top comments (0)