Skip to content

Commit

Permalink
feature: add serverless template for closed network system workloads
Browse files Browse the repository at this point in the history
Add CDK code to build an environment to run serverless sample applications.

If the number of accesses is low or there is a time period where there is almost no access, running servers all the time using ECS/Fargate costs a lot compared to the actual usage amount. There are also operating costs for container images.

In such cases, reduce costs and operational troubles by using serverless by S3 and Lambda.

Hosting an internal HTTPS static website using ALB, S3, and PrivateLink in a closed network is described in this blog.

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Amazon GitHub Automation <[email protected]>
Co-authored-by: Yozo Suzuki <[email protected]>
Co-authored-by: suzukyz <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ray Oshikawa <[email protected]>
  • Loading branch information
6 people authored Mar 7, 2024
1 parent 0b6d0a3 commit bfbaf9c
Show file tree
Hide file tree
Showing 80 changed files with 27,780 additions and 111 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*/.DS_Store
.DS_Store
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ In local government systems that require a high level security and network restr
We will adopt REPLATFORM, one of the 6Rs, which is AWS's migration strategy, and aims to migrate from an existing on-premise environment to computing and managed DB using containers. REPLATFORM has advantages such as improving performance and reducing costs. The template uses several AWS managed services that will help us to reduce cost and operational workload.
(Ref:[Migrating to AWS Best Practices and Strategies](https://pages.awscloud.com/rs/112-TZM-766/images/Migrating-to-AWS_Best-Practices-and-Strategies_eBook.pdf)

And we added serverless application version of infra that uses AWS Lambda and React application instead of container.
Please see here you want to know how to deploy serverless application version.

## Scope

### What the template provides
Expand All @@ -20,6 +23,12 @@ We will adopt REPLATFORM, one of the 6Rs, which is AWS's migration strategy, and
- A sample Dockerfile to turn that sample application into a container image
- For sample applications, see [`Webapp-java/readme.md`](./webapp-java/README.md)

- Serverless application environment for running React application hosted on Amazon S3 and REST API on API Gateway and AWS Lambda.(\*)

- A sample application using React
- For sample react application, see [`Webapp-react/readme.md`](./webapp-react/README.md).
- Sample REST APIs code is in `functions/`

- CI/CD environment for continuous application development

- Pipeline for building and deploying the above sample applications using CodePipeline, CodeCommit, and CodeBuild
Expand Down Expand Up @@ -94,6 +103,7 @@ This is the architecture diagram that is slightly modified by using private link
## How to Deploy

Please see the following document: [infra/README.md](./infra/README.md)
If you want to deploy serverless application version, please see the following document: [infra/README_serverless.md](./infra/README_serverless.md)

## Security

Expand Down
14 changes: 12 additions & 2 deletions README_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@ AWS のマイグレーション戦略である 6R の一つ、REPLATFORM を採
)
REPLATFORM では、サーバの運用負荷の軽減などがメリットになります。本テンプレートでも、AWS のマネージドサービスを活用した形で運用コストの軽減を目指しました。

また、Container の代わりに、AWS Lambda を利用して API を構築し、React アプリケーションを利用した、サーバーレスアプリケーション版を追加しました。
デプロイ方法については、[こちら](./infra/README_serverless_ja.md)を参照ください。

## テンプレートのスコープ

### テンプレートで提供されるもの

- Java アプリケーション(Spring boot)を Amazon ECS/Fargate 上で稼働させるためのコンテナ実行環境
- Java アプリケーション(Spring boot)を Amazon ECS/Fargate 上で稼働させるためのコンテナ実行環境(\*)
- これに加え、上記環境下で動作する Spring boot を利用したサンプルアプリケーション
- そのサンプルアプリケーションをコンテナイメージにするためのサンプル Dockerfile
- サンプルアプリケーションについては、[`webapp-java/README.md`](../webapp-java/README_ja.md)をご参照ください
- 閉域網で SPA + REST API を動かすための、Amazon S3、Amazon API Gateway、AWS Lambda を利用したサーバーレスな実行環境(\*)
- React のサンプルアプリケーション
- 詳しくは、[`Webapp-react/readme_ja.md`](./webapp-react/README_ja.md)を参照ください
- React サンプルアプリケーションから呼び出される REST API のサンプルコード
- アプリケーションを継続開発するための CI/CD 環境
- AWS CodePipeline や AWS CodeCommit, AWS CodeBuild を利用した、上記サンプルアプリケーションをビルド、デプロイするためのパイプライン
- 簡易なジョブフローが実行できる、AWS Step Functions、Amazon ECS/Fargate を組み合わせたジョブ実行基盤
Expand All @@ -29,6 +36,8 @@ REPLATFORM では、サーバの運用負荷の軽減などがメリットにな
- SystemsManager と EC2 を組み合わせたアプリケーションのテストや DB の管理を実施できる環境
- リモートデスクトップ接続(Windows Server Instance)と コンソール接続(Amazon Linux Instance)を提供

\* コンテナ実行環境とサーバーレスな実行環境は、どちらか選んでデプロイしていただく手順をそれぞれの README に記載しています。

### テンプレートで提供されないもの

- AWS Direct Connect(DX)や AWS Site-to-Site VPN(VPN) といったオンプレとの接続に関わる AWS 側の設定や実装
Expand Down Expand Up @@ -83,7 +92,8 @@ Private Link を利用する場合には、[“共有型”AWS DirectConnect で

## テンプレートのデプロイ方法

[infra/README.md](./infra/README_ja.md)を参照ください
[infra/README.md](./infra/README_ja.md)を参照ください。
サーバーレスアプリケーション版を利用したい方は、[infra/README_serverless_ja.md](./infra/README_serverless_ja.md)を参照ください。

## Security

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions functions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
34 changes: 34 additions & 0 deletions functions/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Connection from "./lib/connect";
import { Logger } from "@aws-lambda-powertools/logger";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";

const logger = new Logger({ serviceName: "getLambda" });

export const handler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
try {
const client = await Connection();
// Connection
await client.connect();
logger.info("connected");

// Query
const res = await client.query(
"SELECT * FROM sampleapp_table WHERE id = 1"
);
const response = {
statusCode: 200,
body:
res.rows.length > 0 ? JSON.stringify(res.rows[0]) : JSON.stringify(""),
};
return response;
} catch (e) {
logger.error(e.toString());
const response = {
statusCode: 500,
body: JSON.stringify("Server error"),
};
return response;
}
};
51 changes: 51 additions & 0 deletions functions/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Connection from "./lib/connect";
import { Logger } from "@aws-lambda-powertools/logger";
import cfnResponse from "cfn-response";

const logger = new Logger({ serviceName: "initLambda" });

export const handler = async (event: any, context: any): Promise<any> => {
if (event.RequestType == "Create" || event.RequestType == "Update") {
try {
const client = await Connection();
// Connection
await client.connect();
logger.info("connected");

// Query
const res1 = await client.query("DROP TABLE IF EXISTS sampleapp_table;");
logger.info(res1);
const res2 = await client.query(
'CREATE TABLE IF NOT EXISTS sampleapp_table(id serial NOT NULL,name text COLLATE pg_catalog."default" NOT NULL,job0001_flag boolean NOT NULL DEFAULT false,job0002_flag boolean NOT NULL DEFAULT false,job0003_flag boolean NOT NULL DEFAULT false,job0004_flag boolean NOT NULL DEFAULT false,job0005_flag boolean NOT NULL DEFAULT false,CONSTRAINT sample_app_pkey PRIMARY KEY (id));'
);
logger.info(res2);
const res3 = await client.query(
"INSERT INTO sampleapp_table(name, job0001_flag, job0002_flag, job0003_flag, job0004_flag, job0005_flag) VALUES ('test record 1',true,true,true,true,true);"
);
logger.info(res3);
return cfnResponse.send(
event,
context,
cfnResponse.SUCCESS,
{ message: Date.now().toString() },
event.PhysicalResourceId
);
} catch (e) {
logger.error(e.toString());
return cfnResponse.send(
event,
context,
cfnResponse.SUCCESS,
{ message: Date.now().toString() },
event.PhysicalResourceId
);
}
}
return cfnResponse.send(
event,
context,
cfnResponse.SUCCESS,
{ message: Date.now().toString() },
event.PhysicalResourceId
);
};
36 changes: 36 additions & 0 deletions functions/lib/connect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const referSecrets = async () => {
const { SecretsManagerClient, GetSecretValueCommand } = await import(
"@aws-sdk/client-secrets-manager"
);
const secretsManager = new SecretsManagerClient({
region: process.env.REGION!,
});
const response = await secretsManager.send(
new GetSecretValueCommand({
SecretId: process.env.SECRET_NAME!,
})
);
return JSON.parse(response.SecretString!);
};

export default async function Connection() {
const { Client } = await import("pg");
const secrets = await referSecrets();
const { Signer } = await import("@aws-sdk/rds-signer");
const signer = new Signer({
region: process.env.REGION!,
username: secrets.username,
hostname: process.env.HOST!,
port: secrets.port,
});
const token = await signer.getAuthToken();
// client settings
const client = new Client({
host: process.env.HOST!,
port: secrets.port,
user: secrets.username,
password: token, //secrets.password,
ssl: true,
});
return client;
}
Loading

0 comments on commit bfbaf9c

Please sign in to comment.