Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ The testing flow is:
- Docker with buildx support for multi-platform builds
- AWS ECR repository access

### For EC2 Native Deployments
- AWS S3 bucket access for application package storage

### Build and Push Images to ECR

```bash
Expand Down Expand Up @@ -60,20 +63,53 @@ docker buildx build --platform linux/amd64,linux/arm64 \
| Language-Framework | App Directory | ECR Repo |
|--------------------|-------------------------------|-------------------|
| dotnet-aspnetcore | docker-apps/dotnet/aspnetcore | dotnet-aspnetcore |
| dotnet-framework | docker-apps/dotnet/framework | dotnet-framework |
| python-flask | docker-apps/python/flask | python-flask |
| python-django | docker-apps/python/django | python-django |
| java-springboot | docker-apps/java/spring-boot | java-springboot |
| nodejs-express | docker-apps/nodejs/express | nodejs-express |

### Build and Push Images to S3

```bash
# Navigate to app directory (see table above)
cd <app-directory>

# Create zip file of all contents
zip -r app.zip .

# Set variables
export AWS_REGION=$(aws configure get region || echo "us-east-1")
export S3_BUCKET_NAME="<your-bucket-name>" # Choose your bucket name

# Create S3 bucket (if it doesn't exist)
aws s3 mb s3://$S3_BUCKET_NAME --region $AWS_REGION 2>/dev/null || true

# Upload zip file to S3
aws s3 cp app.zip s3://$S3_BUCKET_NAME/

# Clean up local zip file
rm app.zip
```

| Language-Framework | App Directory |
|--------------------|-------------------------------|
| dotnet-aspnetcore | docker-apps/dotnet/aspnetcore |
| dotnet-framework | docker-apps/dotnet/framework |

## Deployment Platforms

### EC2 Deployment

#### Using CDK

```bash
# For containerized EC2 deployments:
cd infrastructure/ec2/cdk

# For native EC2 deployments:
cd infrastructure/ec2/cdk-native

# Install dependencies (first time only)
npm install

Expand All @@ -82,34 +118,59 @@ cdk deploy <stack-name>
cdk destroy <stack-name>
```

Below are the available stacks for Containerized EC2 deployments:

| Language-Framework | Stack Name |
|--------------------|--------------------------|
| dotnet-aspnetcore | DotnetAspnetcoreCdkStack |
| dotnet-framework | DotnetFrameworkCdkStack |
| python-flask | PythonFlaskCdkStack |
| python-django | PythonDjangoCdkStack |
| java-springboot | JavaSpringBootCdkStack |
| nodejs-express | NodejsExpressCdkStack |

Below are the available stacks for Native EC2 deployments:

| Language-Framework | Stack Name |
|----------------------------|------------------------------------|
| dotnet-aspnetcore-windows | DotnetAspnetcoreWindowsNativeStack |
| dotnet-framework-windows | DotnetFrameworkWindowsNativeStack |


#### Using Terraform

```bash
# For containerized EC2 deployments:
cd infrastructure/ec2/terraform

# For native EC2 deployments:
cd infrastructure/ec2/terraform-native

terraform init

terraform apply -var-file="<var-file>"

terraform destroy -var-file="<var-file>"
```

Below are the available variables files for Containerized EC2 deployments:

| Language-Framework | Variables File |
|--------------------|----------------------------------|
| dotnet-aspnetcore | config/dotnet-aspnetcore.tfvars |
| dotnet-framework | config/dotnet-framework.tfvars |
| python-flask | config/python-flask.tfvars |
| python-django | config/python-django.tfvars |
| java-springboot | config/java-springboot.tfvars |
| nodejs-express | config/nodejs-express.tfvars |

Below are the available variables files for Native EC2 deployments:

| Language-Framework | Variables File |
|----------------------------|-------------------------------------------|
| dotnet-aspnetcore-windows | config/dotnet-aspnetcore-windows.tfvars |
| dotnet-framework-windows | config/dotnet-aspnetcore-framework.tfvars |

### EKS Deployment

#### Using CDK
Expand All @@ -131,6 +192,7 @@ cdk destroy <stack-name>
| Language-Framework | Stack Name |
|--------------------|------------------------------|
| dotnet-aspnetcore | DotnetAspnetcoreEksCdkStack |
| dotnet-framework | DotnetFrameworkEksCdkStack |
| python-flask | PythonFlaskEksCdkStack |
| python-django | PythonDjangoEksCdkStack |
| java-springboot | JavaSpringBootEksCdkStack |
Expand Down Expand Up @@ -182,6 +244,7 @@ terraform destroy -var-file="<var-file>"
| Language-Framework | Variables File |
|--------------------|----------------------------------|
| dotnet-aspnetcore | config/dotnet-aspnetcore.tfvars |
| dotnet-framework | config/dotnet-framework.tfvars |
| python-flask | config/python-flask.tfvars |
| python-django | config/python-django.tfvars |
| java-springboot | config/java-springboot.tfvars |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022 AS build-env
WORKDIR /app
COPY . ./
RUN dotnet publish AspNetCoreApp.csproj -c Release -o out

FROM mcr.microsoft.com/dotnet/aspnet:9.0-windowsservercore-ltsc2022
WORKDIR /app

ENV ASPNETCORE_URLS=http://+:5000

EXPOSE 5000

COPY --from=build-env /app/out .
COPY --from=build-env /app/generate-traffic.ps1 .

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD powershell -command "try { Invoke-WebRequest -Uri http://localhost:5000/health -UseBasicParsing | Out-Null; exit 0 } catch { exit 1 }"

ENTRYPOINT ["dotnet", "AspNetCoreApp.dll"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Traffic generator script for ASP.NET Core application
$Port = if ($env:PORT) { $env:PORT } else { "5000" }
$BaseUrl = "http://localhost:$Port"

Write-Host "Starting continuous traffic generation to $BaseUrl"

while ($true) {
$timestamp = Get-Date -Format "HH:mm:ss"
Write-Host "[$timestamp] Generating traffic..."

try {
# Health check
$response = Invoke-WebRequest -Uri "$BaseUrl/health" -UseBasicParsing -TimeoutSec 5
if ($response.StatusCode -ne 200) {
Write-Host "[$timestamp] ERROR: Health check failed with status $($response.StatusCode)!"
}
}
catch {
Write-Host "[$timestamp] ERROR: Health check failed - $($_.Exception.Message)"
}

try {
# API call (S3 buckets)
$response = Invoke-WebRequest -Uri "$BaseUrl/api/buckets" -UseBasicParsing -TimeoutSec 10
if ($response.StatusCode -ne 200) {
Write-Host "[$timestamp] ERROR: API call to /api/buckets failed with status $($response.StatusCode)!"
}
}
catch {
Write-Host "[$timestamp] ERROR: API call to /api/buckets failed - $($_.Exception.Message)"
}

# Sleep between requests
Start-Sleep -Seconds 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using Newtonsoft.Json;

namespace FrameworkApp
{
// Change the base class to HttpTaskAsyncHandler
public class ApiHandler : HttpTaskAsyncHandler
{
// HttpTaskAsyncHandler uses ProcessRequestAsync instead of ProcessRequest
public override async Task ProcessRequestAsync(HttpContext context)
{
var path = context.Request.Path.ToLower();

if (path.EndsWith("/api/buckets"))
{
await ProcessBucketsRequestAsync(context); // Await the async method
}
else
{
context.Response.StatusCode = 404;
context.Response.Write("Not Found");
}
}

private async Task ProcessBucketsRequestAsync(HttpContext context) // Make this method async Task
{
try
{
var awsRegion = Environment.GetEnvironmentVariable("AWS_REGION") ?? "us-east-1";
var regionEndpoint = RegionEndpoint.GetBySystemName(awsRegion) ?? RegionEndpoint.USEast1;

// Use 'await' instead of '.Result'
using (var s3Client = new AmazonS3Client(regionEndpoint))
{
var response = await s3Client.ListBucketsAsync();
// ... rest of the logic remains mostly the same ...
if (response == null) { throw new Exception("S3 response is null"); }
if (response.Buckets == null) { throw new Exception("S3 response.Buckets is null"); }

var buckets = response.Buckets.Select(b => b.BucketName).ToList();
var result = new
{
bucket_count = buckets.Count,
buckets = buckets
};

context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(result));
}
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
// Your comprehensive error logging structure (works well for debugging)
var innerException = ex.InnerException != null ? ex.InnerException.Message : "No inner exception";
var errorDetails = new
{
error = "Failed to retrieve S3 buckets",
details = ex.Message,
innerException = innerException,
type = ex.GetType().Name
};
context.Response.Write(JsonConvert.SerializeObject(errorDetails));
}
}

// IHttpHandler requires IsReusable
public bool IsReusable { get { return false; } }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="FrameworkApp.Default" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>.NET Framework Sample App</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>.NET Framework Sample Application</h1>
<p>Status: <asp:Label ID="StatusLabel" runat="server" Text="Healthy" /></p>
</div>
</form>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Web.UI;

namespace FrameworkApp
{
public partial class Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
StatusLabel.Text = "Healthy";
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading