"Building a Cloud-Native Website with AWS: From Static Hosting to Dynamic Content"
I heard about the Cloud Resume Challenge while surfing reddit a few years ago. As a tech enthusiast but someone who is not working in AWS on a daily basis, the challenge intrigued me.
The Cloud Resume Challenge, created by Forrest Brazeal, is a multi-step project that involves building a full-stack application using various AWS services. It's designed to showcase cloud skills through practical implementation, making it an excellent exercise even for those of us already in the field.
In this blog post, I'll share my experience completing the Cloud Resume Challenge, detailing the AWS services I used, the architecture I implemented, and the insights I gained. Whether you're a cloud professional looking to sharpen your skills or someone curious about real-world AWS applications, I hope you'll find value in my journey through this project.
Cloud-native development leverages the power of cloud computing to build scalable and resilient applications. In this comprehensive guide, we'll walk through the process of creating a cloud-native website using various AWS services. We'll start with hosting a static website and progressively add dynamic features, including a visitor counter. This article is perfect for beginners who want to understand how different AWS services work together to create a fully functional, scalable website.
Amazon S3 (Simple Storage Service) is an object storage service that we can use to host static websites. Here's how to set it up:
Create an S3 bucket:
Upload your website files:
Configure bucket policy:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::your-bucket-name/*" } ] }
Replace "your-bucket-name" with your actual bucket name.
CloudFront is AWS's Content Delivery Network (CDN) service. We'll use it to serve our website over HTTPS and improve performance:
Create a CloudFront distribution:
Configure SSL/TLS certificate:
Set up Origin Access Identity (OAI):
Route 53 is AWS's Domain Name System (DNS) web service. We'll use it to map our domain name to our CloudFront distribution:
Create a hosted zone:
Update name servers:
Create record sets:
For our visitor counter, we'll use a serverless architecture with DynamoDB, Lambda, and API Gateway.
DynamoDB is a NoSQL database service. We'll use it to store our visitor count:
Lambda allows us to run code without provisioning servers. Our Lambda function will update the visitor count:
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb'); const client = new DynamoDBClient(); exports.handler = async (event) => { const params = { TableName: process.env.TABLE_NAME, Key: { id: { S: 'visitors' } }, UpdateExpression: 'ADD visitorCount :inc', ExpressionAttributeValues: { ':inc': { N: '1' } }, ReturnValues: 'UPDATED_NEW' }; try { const command = new UpdateItemCommand(params); const data = await client.send(command); const visitorCount = data.Attributes.visitorCount.N; return { statusCode: 200, headers: { "Access-Control-Allow-Origin": "https://yourdomain.com", "Access-Control-Allow-Headers": "Content-Type", "Access-Control-Allow-Methods": "OPTIONS,POST" }, body: JSON.stringify({ visitorCount: parseInt(visitorCount) }) }; } catch (error) { console.error('Error:', error); return { statusCode: 500, headers: { "Access-Control-Allow-Origin": "https://yourdomain.com", "Access-Control-Allow-Headers": "Content-Type", "Access-Control-Allow-Methods": "OPTIONS,POST" }, body: JSON.stringify({ error: 'Failed to update visitor count' }) }; } };
Set up environment variables:
Configure permissions:
API Gateway allows us to create, publish, and manage APIs. We'll use it to expose our Lambda function:
Create a new API:
Create a resource and method:
Enable CORS:
Deploy the API:
Now, let's integrate our backend with the frontend:
<div id="visitor-count">Visitors: <span id="count">0</span></div>
function updateVisitorCount() { fetch('https://your-api-gateway-url/visitorcount', { method: 'POST', headers: { 'Content-Type': 'application/json' }, mode: 'cors' }) .then(response => response.json()) .then(data => { document.getElementById('count').textContent = data.visitorCount; }) .catch(error => console.error('Error:', error)); } document.addEventListener('DOMContentLoaded', updateVisitorCount);
Replace 'https://your-api-gateway-url' with your actual API Gateway URL.
To ensure our JavaScript works correctly, we'll add some tests:
npm install --save-dev jest
// Mock fetch function global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ visitorCount: 5 }), }) ); // Import the function to test const { updateVisitorCount } = require('./visitorCounter'); test('updates visitor count correctly', async () => { // Set up our document body document.body.innerHTML = '<div id="count">0</div>'; // Call the function await updateVisitorCount(); // Check that the count was updated expect(document.getElementById('count').textContent).toBe('5'); });
npx jest
In this guide, we've covered how to build a cloud-native website using various AWS services. We've implemented a static website with S3, secured it with CloudFront, set up DNS with Route 53, and created a serverless backend with DynamoDB, Lambda, and API Gateway.
This architecture provides a scalable, secure, and cost-effective solution for hosting websites and web applications. As you become more comfortable with these services, you can expand on this foundation to build even more complex and feature-rich applications.
In the next article, we'll explore how to automate the deployment of this website using CI/CD practices with GitHub Actions.
The above is the detailed content of AWS Cloud Resume Challenge Blog Post Part 1. For more information, please follow other related articles on the PHP Chinese website!