Single Repo: AWS CDK, Route53, APIGateway, Lambda, Cloudfront, Flask & Nuxt

Velocity

Shift left the deployment pipeline

AWSCDK

Fullstack

Init

  1. Install AWS CDK
npm install -g aws-cdk
git clone https://gitlab.com/eilon2/spa-flask-aws-cdk
python3 -m venv awscdk
. awscdk/bin/activate
pip install -r requirements.txt

Code Walkthrough

Directory tree

  • The term ‘AWSGEN’ references to file that generated automatically by AWSCDK
.
├── app.py # AWSGEN
├── backend # The backend code of the project
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
├── cdk.json # AWSGEN
├── cdk.out # AWSGEN
├── frontend # The frontend code of the project
│ ├── package.json
│ └── pages
│ ├── about.vue
│ └── index.vue
├── package-lock.json
├── README.md
├── requirements.txt
├── setup.py # AWSGEN
├── source.bat # AWSGEN
└── spa_flask_aws_cdk # AWSGEN
├── __init__.py
├── spa_flask_aws_cdk.egg-info
│ ├── dependency_links.txt
│ ├── PKG-INFO
│ ├── requires.txt
│ ├── SOURCES.txt
│ └── top_level.txt
└── spa_flask_aws_cdk_stack.py
6 directories, 20 files

DNS & Certificates

# File: spa_flask_aws_cdk_stack.pyROOT_ZONE = 'saasment'# Create interface to already existing hosted zone
root_hosted_zone = route53.HostedZone.from_hosted_zone_attributes(self,
'RootHostedZone',
hosted_zone_id='Z05422531LZAQAHZETW5S',
zone_name=ROOT_ZONE)
  1. Creating a new hosted zone ‘demo.saasment.com’
  2. Creating an NS record in the root hosted zone to point our new hosted zone
  3. Creating & validating certificates in ACM for both frontend ‘cdk-spa.demo.saasment.com’ and backend ‘cdk-spa-api.demo.saasment.com’ domains
# File: spa_flask_aws_cdk_stack.pyZONE = 'demo.saasment.com'
DOMAIN_NAME_FRONT = 'cdk-spa.demo.saasment.com'
DOMAIN_NAME_BACKEND = 'cdk-spa-api.demo.saasment.com'
# Create a new zone
hosted_zone = route53.HostedZone(self,
'HostedZone',
zone_name=ZONE)
# Create NS record in the root zone, it will point to our new zone
route53.NsRecord(self,
'HostedZoneNS',
values=hosted_zone.hosted_zone_name_servers,
zone=root_hosted_zone,
record_name=ZONE)
# Create & validate SSL certificates for frontend & backend domains
front_certificate = acm.Certificate(self,
'staticWebCert',
domain_name=DOMAIN_NAME_FRONT,
validation=acm.CertificateValidation.from_dns(hosted_zone))
backend_certificate = acm.Certificate(self,
'apiCert',
domain_name=DOMAIN_NAME_BACKEND,
validation=acm.CertificateValidation.from_dns(hosted_zone))

Static Frontend

Our frontend infro + app layers
# File: spa_flask_aws_cdk_stack.py# Create bucket for static pagesstatic_bucket = s3.Bucket(self,
'staticWebBucket',
website_index_document='index.html',
website_error_document='index.html',
public_read_access=True)
# Upload nuxt static pages to S3
core_image=core.BundlingDockerImage.from_registry(image='node:lts')
build_cmd=['bash', '-c', ' && '.join(['ls -la ', 'npm install', 'npm run build', 'npm run generate', 'cp -r /asset-input/dist/* /asset-output/'])]
s3deployment = s3deploy.BucketDeployment(self,
'staticDeployment',
destination_bucket=static_bucket,
sources=[s3deploy.Source.asset('./frontend',
bundling=core.BundlingOptions(image=core_image,
command=build_cmd))])
# Init view policy
view_policy = cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS
# Init error responses
error_403 = cloudfront.ErrorResponse(http_status=403, response_http_status=200, response_page_path='/index.html')
error_404 = cloudfront.ErrorResponse(http_status=404, response_http_status=200, response_page_path='/index.html')distribution = cloudfront.Distribution(self,
'staticWebBucketDistribution',
default_behavior={
'origin': origins.S3Origin(static_bucket),
'viewer_protocol_policy': view_policy
},
domain_names=[DOMAIN_NAME_FRONT],
certificate=front_certificate,
error_responses=[error_403, error_404])
# Init alias
front_target = route53.RecordTarget.from_alias(targets.CloudFrontTarget(distribution))
# Create A & AAA records to point cloudfront and serves frontend
frond_r53_record = route53.AaaaRecord(self,
'frontendAlias',
zone=hosted_zone,
target=front_target,
record_name=DOMAIN_NAME_FRONT)

Serverless Backend

Our backend infra + app layers
# File: spa_flask_aws_cdk_stack.py# Pack backend code as docker
backend = lambda_.DockerImageFunction(self,
"ECRFunction",
code=lambda_.DockerImageCode.from_image_asset("./backend")
)
# Create API Gateway instance
apigwdomain = apigateway.DomainNameOptions(
certificate=backend_certificate,
domain_name=DOMAIN_NAME_BACKEND)
# Trigger lambda by APIGateway
apigw = apigateway.LambdaRestApi(self,
"myapi",
handler=backend,
domain_name=apigwdomain)
backend_target = route53.RecordTarget.from_alias(targets.ApiGateway(apigw))backend_alias = route53.AaaaRecord(self,
'backendAlias',
zone=hosted_zone,
target=backend_target,
record_name=DOMAIN_NAME_BACKEND)

Leapfrogging

--

--

--

You live at least once

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to run Android Emulator without Android Studio?

Tricks to code ealthy and Robust in Magento 2?

I like to move it move it!

Dockerfile : Best practices for building an image

It Becomes Easier With Time

Github clone with password is expiring

ScandiPWA Developer Certification has been Launched!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Tech Rap

Tech Rap

You live at least once

More from Medium

Automate tasks with SMS via Amazon Pinpoint

Setting up Serverless Framework with AWS

Configuring APIGateway VTL to store JSON object directly on S3 —With Lambda authorizer enabled

Hosting a CDN securely with Amazon S3 and Cloudfront while maintaining SOC2 compliance