Skip to content

Commit 3e6fe28

Browse files
authored
Merge pull request #25 from aws-samples/ecs-workshop
feat: Updated based on ECS workshop experience
2 parents 9d35fc7 + 3fd0006 commit 3e6fe28

37 files changed

+1282
-798
lines changed

README.kr.md

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Amazon ECS SaaS - Reference Architecture
2+
3+
**[Developer Documentation](DEVELOPER_GUIDE.md)**
4+
5+
## 소개
6+
조직은 소프트웨어 비즈니스에서 최적화된 비용, 운영 효율성 및 전반적인 민첩성을 달성하기 위해 SaaS(Software-as-a-Service) 제공 모델로 이동하고 있습니다. SaaS는 고객(테넌트)을 솔루션의 중앙 호스팅 버전에 온보딩하고 단일 창을 통해 관리하는 데 도움이 됩니다. 이러한 SaaS 솔루션은 테넌트 간에 기본 인프라 구성 요소를 공유할 수 있게 하는 동시에 사용 사례에서 요구하는 전반적인 보안, 성능 및 기타 비기능적 요구 사항을 유지하기 위해 아키텍처에서 멀티테넌시를 구현할 수 있는 메커니즘을 요구합니다. 종종 이러한 전략과 구현은 사용 중인 기본 기술과 AWS 매니지드 서비스에 크게 의존합니다.
7+
8+
이 Github 솔루션은 Amazon Elastic Container Service(ECS)를 활용하여 멀티테넌트 SaaS 레퍼런스 아키텍처를 구현하는 데 도움이 되는 코드 샘플, 구성 및 모범 사례를 제공합니다.
9+
10+
여기서의 목표는 필요한 기술적 측면을 포함하는 ECS SaaS 레퍼런스 솔루션을 구축하는 데 있어 설계 원칙과 구현 세부 사항을 더 자세히 살펴보는 것입니다. 테넌트 온보딩, 사용자 관리, 관리자 포털과 같은 공유(Shared) 서비스와 함께 SaaS Control Plane 기능과 ECS 컴퓨팅 격리 전략, 대규모 요청 라우팅, 서비스 검색, 스토리지 격리 패턴, API 제한 및 Usage Plan과 같은 SaaS Application Plane 기능과 보안 및 확장성을 보장하는 다양한 방법에 대해 논의합니다.
11+
12+
## ECS SaaS 레퍼런스 솔루션 개요
13+
다음 다이어그램은 ECS SaaS의 핵심 구성 요소를 개략적으로 설명하는 솔루션의 상위 수준 아키텍처를 보여줍니다. 이는 티어에 기반한 SaaS이며, 세 계층은 Amazon ECS를 사용하는 세 가지 다른 테넌트 격리 전략을 나타냅니다. 이를 통해 SaaS 프로바이더는 티어에 따른 요구 사항에 따라 SaaS 솔루션을 모델링하기 위한 광범위한 기술 옵션을 갖게 됩니다.
14+
15+
1. Basic 티어: 모든 테넌트에서 공유되는 ECS 서비스 (Pool 모델)
16+
2. Advanced 티어 : 공유 ECS 클러스터, 테넌트당 전용 ECS 서비스 (Silo 모델)
17+
3. Premium 티어: 테넌트당 전용 ECS 클러스터 (Silo 모델)
18+
19+
<p align="center">
20+
<img src="images/archi-high-level.png" alt="High-level Architecture"/>
21+
Fig 1: ECS SaaS - High-level infrastructure
22+
</p>
23+
24+
25+
이 레퍼런스 아키텍처는 [AWS SaaS Factory](https://aws.amazon.com/partners/programs/saas-factory)에서 개발한 최신 [AWS SaaS Builder Toolkit](https://github.com/awslabs/sbt-aws)(SBT)을 채택합니다. SBT는 테넌트 온보딩, 오프보딩, 테넌트 및 사용자 관리, 청구 등과 같은 SaaS Control Plane 서비스를 솔루션으로 원활하게 확장하는 데 도움이 됩니다. 또한 SaaS 운영을 위한 양방향 통신을 가능하게 하는 ECS Application Plane에 이벤트 기반 통합을 제공합니다. AWS SBT에 대한 자세한 내용은 [여기](https://github.com/awslabs/sbt-aws/blob/main/docs/public/README.kr.md)에서 확인할 수 있습니다.
26+
27+
## 사전 요구사항
28+
이 솔루션은 AWS 계정의 [AWS Cloud9](https://aws.amazon.com/pm/cloud9/) 환경을 통해 배포하거나 랩탑에서 직접 배포할 수 있습니다.
29+
30+
Cloud9를 사용하는 경우 최소 t3.large 인스턴스 크기를 사용하여 EC2에 `Amazon Linux 2023` AMI를 사용해야 합니다. 또한 `./scripts/resize-cloud9.sh` 스크립트를 사용하여 기본 EC2 인스턴스의 볼륨 크기를 50GB(기본 10GB 대신)로 늘립니다. 이는 솔루션을 빌드하는 데 충분한 컴퓨팅과 공간이 있는지 확인하기 위한 것입니다.
31+
32+
- 이 레퍼런스 아키텍처는 Python을 사용합니다. Python 3.8 이상이 설치되어 있는지 확인하세요.
33+
- [AWS CLI 2.14](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)의 같거나 상위버전이 설치되어 있는지 확인하세요.
34+
- [Docker Engine](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-docker.html)이 설치되어 있는지 확인하세요.
35+
- [AWS CDK CLI](https://docs.aws.amazon.com/cdk/latest/guide/cli.html)의 최신 버전이 설치되어 있는지 확인하세요. CDK의 릴리스 버전이 없으면 배포 문제가 발생합니다.
36+
- Node 18 이상이 설치되어 있는지 확인하세요.
37+
- Git이 설치되어 있는지 확인하세요.
38+
39+
## 배포 단계
40+
41+
이 ECS SaaS 레퍼런스 솔루션을 배포하려면 아래 명령을 실행할 수 있습니다. ```admin_email```을 솔루션에서 SaaS 프로바이더 관리자를 만들고 새 테넌트 온보딩과 같은 관리 작업을 수행할 수 있는 관리자 자격 증명을 공유하는 데 사용될 실제 이메일 주소로 바꾸세요.
42+
43+
```bash
44+
git clone this_repo_url
45+
cd saas-reference-architecture-ecs/scripts
46+
./build-application.sh
47+
./install.sh admin_email
48+
```
49+
50+
```build-application.sh```는 Order, Product 및 User 마이크로서비스로 샘플 SaaS 애플리케이션의 Docker 이미지를 빌드하고 Amazon ECR에 푸시합니다.
51+
52+
그리고 ```install.sh```는 다음을 배포합니다:
53+
54+
- AWS 계정에서 AWS S3 버킷을 만들고 이 레퍼런스 솔루션 코드를 버킷에 업로드합니다.
55+
- 업로든 된 소스는 Advanced 티어를 위한 마이크로서비스 프로비저닝 과 Premium 티어를 위한 ECS 와 마이크로서비스 프로비저닝에 사용.
56+
- 프로비저닝하는 CDK 스택 `controlplane-stack`
57+
- 인프라가 테넌트를 프로비저닝/프로비저닝 해제할 수 있는 SaaS Builder Toolkit(SBT) Control Plane 구성 요소 설치.
58+
- 프로비저닝하는 CDK 스택 `coreappplane-stack`
59+
- Control Plane 메시지를 수신하면 임의의 작업을 정의하고 실행할 수 있는 선택적 유틸리티인 SaaS Builder Toolkit(SBT) Core Application Plane 설치.
60+
- 이 레퍼런스 솔루션은 이 유틸리티를 사용하여 테넌트를 온보딩 및 오프보딩하기 위한 AWS CodeBuild 프로젝트를 시작.
61+
- 프로비저닝하는 CDK 스택 `shared-infra-stack`
62+
- Amazon VPC, Amazon API Gateway 및 Load Balancer와 같은 공유 애플리케이션 인프라.
63+
- 프로비저닝하는 CDK 스택 `tenant-template-stack`
64+
- `tenant-template-basic`: Basic 티어를 위한 ECS 클러스터 및 ECS 서비스 Order, Product 및 User 마이크로서비스를 설치.
65+
- `tenant-template-advanced`: Advanced 티어를 위한 ECS 클러스터를 설치.(마이크로 서비스들은 테넌트 온보딩시에 전용으로 설치)
66+
67+
## 리소스 정리
68+
69+
다음 스크립트를 실행하여 AWS 계정에서 레퍼런스 솔루션 리소스를 정리하세요. 아래 스크립트를 호출하기 전에 환경에 [jq](https://jqlang.github.io/jq/download/) JSON 프로세서 도구가 설치되어 있는지 확인하세요.
70+
71+
```bash
72+
cd scripts
73+
./cleanup.sh
74+
```
75+
## 라이선스
76+
77+
이 라이브러리는 MIT-0 라이선스에 따라 라이선스가 부여됩니다. [LICENSE](LICENSE) 파일을 참조하세요.
78+
79+
## 보안
80+
81+
자세한 내용은 [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications)을 참조하세요.

README.md

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
**[Developer Documentation](DEVELOPER_GUIDE.md)**
44

55
## Introduction
6-
Organisations are moving to the SaaS (Software-as-a-service) delivery model to achieve optimized cost, operational efficiency and overall agility in their software business. SaaS helps to onboard their customers (tenants) into a centrally hosted version of the solution, and manage them via a single pane of glass. These SaaS solutions allow the underneath infrastructure components to be shared across tenants, while demanding mechanisms that can implement the multi-tenancy in the architecture to preserve overall security, performance and other non-functional requirements demanded by the use-case. Often, these strategies and their implementation heavily depend on the underneath technologies and AWS managed services that are being used.
6+
Organizations are moving to the SaaS (Software-as-a-service) delivery model to achieve optimized cost, operational efficiency and overall agility in their software business. SaaS helps to onboard their customers (tenants) into a centrally hosted version of the solution, and manage them via a single pane of glass. These SaaS solutions allow the underneath infrastructure components to be shared across tenants, while demanding mechanisms that can implement the multi-tenancy in the architecture to preserve overall security, performance and other non-functional requirements demanded by the use-case. Often, these strategies and their implementation heavily depend on the underneath technologies and AWS managed services that are being used.
77

88
This github solution provides code samples, configurations and best practices that help to implement multi-tenant SaaS reference architecture leveraging Amazon Elastic Container Service (ECS).
99

1010
The objective here is to dive deeper into design principals and implementation details in building ECS SaaS reference solution covering necessary technical aspects. We will discuss SaaS control plane functionalities with shared services such as tenant onboarding, user management, admin portals, along with the SaaS application plane capabilities such as ECS compute isolation strategies, request routing at scale, service discovery, storage isolation patterns, API throttling and usage plans, and different ways to ensure security and scalability.
1111

1212
## ECS SaaS Reference Solution Overview
13-
The following diagram shows the high-level architecture of the solution that outlines the core components of ECS SaaS. It is a tier-based SaaS, and the two tiers represent two different tenant isolation strategies using Amazon ECS. This would help SaaS providers to have a wide range of technical options to model their SaaS solution based on their tiering requirements.
13+
The following diagram shows the high-level architecture of the solution that outlines the core components of ECS SaaS. It is a tier-based SaaS, and the three tiers represent three different tenant isolation strategies using Amazon ECS. This would help SaaS providers to have a wide range of technical options to model their SaaS solution based on their tiering requirements.
1414

1515
1. Basic Tier: Shared ECS Services across all the tenants (Pool model)
1616
2. Advanced Tier : Shared ECS Cluster, dedicated ECS services per tenant (Silo model)
@@ -40,7 +40,7 @@ If you are using Cloud9, make sure to use `Amazon Linux 2023` AMI for the EC2 wi
4040

4141
## Deployment Steps
4242

43-
To deploy this ECS SaaS reference solution, you can run below commands. Replace the ```admin_email``` with a real email address that will be used to create an admin user in the solution, and to share the admin credentials that allow to perform administrative tasks such as onboarding new tenants.
43+
To deploy this ECS SaaS reference solution, you can run the below commands. Replace the ```admin_email``` with a real email address that will be used to create an admin user in the solution, and to share the admin credentials that allow to perform administrative tasks such as onboarding new tenants.
4444

4545

4646
```bash
@@ -50,11 +50,12 @@ cd saas-reference-architecture-ecs/scripts
5050
./install.sh admin_email
5151
```
5252

53-
Note that, ```build-application.sh``` builds docker images of sample SaaS application with order, product & user microservices and pushes to Amazon ECR
53+
Note that, ```build-application.sh``` builds docker images of sample SaaS application with order, product & user microservices and pushes to Amazon ECR.
5454

5555
And, ```install.sh``` deploys the following:
5656

5757
- Creates an AWS S3 bucket in your AWS account and pushes this reference solution code to the bucket
58+
- Uploaded sources are used for microservices provisioning for the Advanced tier and each ECS and microservices provisioning for the Premium tier.
5859
- Cdk stack `controlplane-stack` which provisions
5960
- SaaS Builder Toolkit(SBT) control plane components which allows infrastructure to provision/de-provision a tenant.
6061
- Cdk stack `coreappplane-stack` which provisions
@@ -63,6 +64,8 @@ And, ```install.sh``` deploys the following:
6364
- Shared application infrastructure like Amazon VPC, Amazon API Gateway, and Load balancers.
6465
- Cdk stack `tenant-template-stack`, which provisions
6566
- ECS Cluster and ECS services order, product & user microservices.
67+
- `tenant-template-basic`: ECS cluster and ECS service Order, Product, and User microservices for the Basic tier.
68+
- `tenant-template-advanced`: ECS cluster for the Advanced tier (Microservices are installed exclusively when a tenant onboard.)
6669

6770
## Steps to Clean-up
6871

client/AdminWeb/src/app/views/tenants/create/create.component.html

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
required
1313
/>
1414
<mat-error *ngIf="tenantName?.invalid">Name is required</mat-error>
15+
<mat-error *ngIf="tenantName?.errors?.['lowercaseAndNumbers']">Must start with a lowercase, and only lowercase, numbers, and hyphen</mat-error>
1516
</mat-form-field>
1617
<mat-form-field>
1718
<mat-label>Enter email</mat-label>

client/AdminWeb/src/app/views/tenants/create/create.component.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component, OnInit } from '@angular/core';
2-
import { FormControl, FormGroup, Validators } from '@angular/forms';
2+
import { FormControl, FormGroup, Validators, ValidatorFn, ValidationErrors, AbstractControl } from '@angular/forms';
33
import { Router } from '@angular/router';
44
import { TenantsService } from '../tenants.service';
55
import { v4 as guid } from 'uuid';
@@ -12,8 +12,8 @@ import { v4 as guid } from 'uuid';
1212
export class CreateComponent implements OnInit {
1313
submitting = false;
1414
tenantForm = new FormGroup({
15-
tenantName: new FormControl('', [Validators.required]),
16-
email: new FormControl('', [Validators.required]),
15+
tenantName: new FormControl('', [Validators.required, this.lowercaseAndNumberValidator() ]),
16+
email: new FormControl('', [Validators.email, Validators.required]),
1717
tier: new FormControl('', [Validators.required]),
1818
});
1919
constructor(
@@ -43,6 +43,16 @@ export class CreateComponent implements OnInit {
4343
});
4444
}
4545

46+
lowercaseAndNumberValidator(): ValidatorFn {
47+
return (control: AbstractControl): ValidationErrors | null => {
48+
const value = control.value;
49+
if (value && !/^[a-z][a-z0-9-]*$/.test(value)) {
50+
return { lowercaseAndNumbers: 'Must start with a lowercase, and only lowercase, numbers, and hyphen' };
51+
}
52+
return null;
53+
}
54+
}
55+
4656
public get tenantName() {
4757
return this.tenantForm.get('tenantName');
4858
}

images/archi-high-level.png

521 KB
Loading

scripts/build-application.sh

+40-21
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,62 @@
44

55
export DOCKER_DEFAULT_PLATFORM=linux/amd64
66

7-
service_repos=("user" "product" "order" "rproxy")
7+
SERVICE_REPOS=("user" "product" "order" "rproxy")
8+
# RPROXY_VERSIONS=("v1" "v2")
9+
10+
REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]')
11+
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
12+
13+
REGISTRY="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com"
14+
aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin $REGISTRY
815

916
deploy_service () {
1017

1118
local SERVICE_NAME="$1"
19+
local VERSION="$2"
1220

1321
if [[ -z "$SERVICE_NAME" ]]; then
1422
echo "Please provide a SERVICE NAME"
1523
exit 1
1624
fi
1725

18-
local REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]')
19-
local ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
2026
local SERVICEECR="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/$SERVICE_NAME"
21-
22-
CWD=$(pwd)
23-
cd ../server/application
24-
local REGISTRY=$(echo $SERVICEECR| cut -d'/' -f 1)
25-
26-
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $REGISTRY
27+
# Docker Image Build
2728
docker build -t $SERVICEECR -f Dockerfile.$SERVICE_NAME .
28-
docker push $SERVICEECR:latest
29+
# Docker Image Tag
30+
docker tag "$SERVICEECR" "$SERVICEECR:$VERSION"
31+
# Docker Image Push to ECR
32+
docker push "$SERVICEECR:$VERSION"
2933

30-
cd $CWD
31-
echo '************************'
3234
echo '************************'
33-
echo ""
34-
echo "$SERVICE_NAME SERVICE_ECR_REPO:" $SERVICEECR
3535
echo "AWS_REGION:" $REGION
36+
echo "$SERVICE_NAME SERVICE_ECR_REPO: $SERVICEECR VERSION: $VERSION"
37+
3638

3739
}
3840

39-
##export service_repos;
40-
for repository in "${service_repos[@]}"
41-
do
42-
echo $repository
43-
aws ecr describe-repositories --repository-names "$repository" 2>/dev/null || echo "ECR Repository '$repository' does not exist. Creating..." &&
44-
aws ecr create-repository --repository-name "$repository"
45-
deploy_service $repository
41+
42+
CWD=$(pwd)
43+
cd ../server/application
44+
45+
for SERVICE in "${SERVICE_REPOS[@]}"; do
46+
echo "➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤➤"
47+
echo "Repository [$SERVICE] checking..."
48+
REPO_EXISTS=$(aws ecr describe-repositories --repository-names "$SERVICE" --query 'repositories[0].repositoryUri' --output text)
49+
50+
if [ "$REPO_EXISTS" == "${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/$SERVICE" ]; then
51+
echo "Repository [$SERVICE] already exists."
52+
else
53+
echo "Repository [$SERVICE] does not exist, creating it..."
54+
aws ecr create-repository --repository-name "$SERVICE" | cat
55+
echo "Repository [$SERVICE] created."
56+
fi
57+
58+
VERSION="latest"
59+
deploy_service $SERVICE $VERSION
4660
done
61+
62+
cd $CWD
63+
64+
# cloud9 SSM plugins to connect to the inside of Container
65+
# sudo dnf install -y https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm

scripts/cleanup.sh

+12
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,15 @@ for i in $(aws s3 ls | awk '{print $3}' | grep -E "^tenant-update-stack-*|^contr
152152
aws s3 rb --force "s3://${i}" #delete in stack
153153
done
154154

155+
#delete ecr repositories
156+
SERVICE_REPOS=("user" "product" "order" "rproxy")
157+
for SERVICE in "${SERVICE_REPOS[@]}"; do
158+
echo "Repository [$SERVICE] checking..."
159+
REPO_EXISTS=$(aws ecr describe-repositories --repository-names "$SERVICE" --query 'repositories[0].repositoryUri' --output text)
160+
if [ "$REPO_EXISTS" == "${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/$SERVICE" ]; then
161+
echo "Repository [$REPO_EXISTS] is deleting..."
162+
aws ecr delete-repository --repository-name "$SERVICE" --force | cat
163+
else
164+
echo "Repository [$SERVICE] does not exist"
165+
fi
166+
done

scripts/deprovision-tenant.sh

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ sudo yum install -y npm
77
sudo npm install -g aws-cdk
88
sudo yum install -y jq
99
sudo yum install -y python3-pip
10-
sudo python3 -m pip install --upgrade setuptools
10+
sudo python3 -m pip install --upgrade --ignore-installed setuptools
1111

1212
# Enable nocasematch option
1313
shopt -s nocasematch
1414

15-
1615
# Parse tenant details from the input message from step function
1716
export CDK_PARAM_TENANT_ID=$tenantId
1817
export TIER=$tier

0 commit comments

Comments
 (0)