low-cost-ecs 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +23 -0
- package/.jsii +3394 -0
- package/.projenrc.ts +49 -0
- package/API.md +1184 -0
- package/LICENSE +19 -0
- package/README.md +117 -0
- package/bin/low-cost-ecs.ts +15 -0
- package/cdk.json +3 -0
- package/containers/nginx-proxy/Dockerfile +3 -0
- package/containers/nginx-proxy/templates/default.conf.template +15 -0
- package/containers/nginx-proxy/templates/http_to_https_redirect.conf.template +6 -0
- package/containers/nginx-proxy/templates/https.conf.template +33 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +14 -0
- package/lib/low-cost-ecs.d.ts +102 -0
- package/lib/low-cost-ecs.js +273 -0
- package/package.json +139 -0
- package/todo.md +4 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2022 Yohta Kimura
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/low-cost-ecs)
|
|
2
|
+
[](https://pypi.org/project/low-cost-ecs/0.0.4/)
|
|
3
|
+
[](https://github.com/rajyan/low-cost-ecs/actions/workflows/release.yml)
|
|
4
|
+
[<img src="https://constructs.dev/badge?package=low-cost-ecs" width="150">](https://constructs.dev/packages/low-cost-ecs)
|
|
5
|
+
|
|
6
|
+
# Low-Cost ECS
|
|
7
|
+
|
|
8
|
+
A CDK construct that provides easy and low-cost ECS on EC2 server setup without a load balancer.
|
|
9
|
+
TLS/SSL certificates are installed automatically on startup of the server and renewed by a scheduled state machine using [certbot-dns-route53](https://certbot-dns-route53.readthedocs.io/en/stable/).
|
|
10
|
+
|
|
11
|
+
**This construct is for development purposes only** see [Limitations](#Limitations).
|
|
12
|
+
|
|
13
|
+
# Try it out!
|
|
14
|
+
|
|
15
|
+
The easiest way to see what this construct creates is to clone this repository and deploying sample server.
|
|
16
|
+
Edit settings in `bin/low-cost-ecs.ts` and deploy cdk construct. [Public hosted zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/AboutHZWorkingWith.html) with your own domain is required.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
git clone https://github.com/rajyan/low-cost-ecs.git
|
|
20
|
+
# edit settings in bin/low-cost-ecs.ts
|
|
21
|
+
npx cdk deploy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Access to configured `recordDomainNames` and see that the nginx sample server has been deployed.
|
|
25
|
+
|
|
26
|
+
# Installation
|
|
27
|
+
|
|
28
|
+
To use this construct in your own cdk stack as a library,
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
npm install low-cost-ecs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
36
|
+
import { Construct } from 'constructs';
|
|
37
|
+
import { LowCostECS } from 'low-cost-ecs';
|
|
38
|
+
|
|
39
|
+
class SampleStack extends Stack {
|
|
40
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
41
|
+
super(scope, id, props);
|
|
42
|
+
|
|
43
|
+
const vpc = /** Your VPC */;
|
|
44
|
+
const securityGroup = /** Your security group */;
|
|
45
|
+
const serverTaskDefinition = /** Your task definition */;
|
|
46
|
+
|
|
47
|
+
new LowCostECS(this, 'LowCostECS', {
|
|
48
|
+
hostedZoneDomain: "rajyan.net",
|
|
49
|
+
email: "kitakita7617@gmail.com",
|
|
50
|
+
vpc: vpc,
|
|
51
|
+
securityGroup: securityGroup,
|
|
52
|
+
serverTaskDefinition: serverTaskDefinition
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The required fields are `hostedZoneDomain` and `email`.
|
|
59
|
+
Set your own task definition, and other props. Read [`LowCostECSProps` documentation](https://github.com/rajyan/low-cost-ecs/blob/main/API.md#low-cost-ecs.LowCostECSProps) for details.
|
|
60
|
+
|
|
61
|
+
# Why
|
|
62
|
+
|
|
63
|
+
ECS may often seem expensive when used for personal development purposes, because of the cost of load balancer.
|
|
64
|
+
The application load balancer is a great service because it is easy to set up managed ACM certificates, it scales, and has dynamic port mapping,
|
|
65
|
+
but it is over-featured for running 1 ECS service.
|
|
66
|
+
|
|
67
|
+
However, to run a ECS sever without a load balancer, you need to associate an Elastic IP to the host instance, and install your certificate by yourself.
|
|
68
|
+
This construct aims to automate these work and deploying resources to run low-cost ECS server.
|
|
69
|
+
|
|
70
|
+
[//]: # (# Overview)
|
|
71
|
+
|
|
72
|
+
# Cost
|
|
73
|
+
|
|
74
|
+
All resources except Route53 HostedZone should be included in [AWS Free Tier](https://docs.aws.amazon.com/whitepapers/latest/how-aws-pricing-works/get-started-with-the-aws-free-tier.html)
|
|
75
|
+
***if you are in the 12 Months Free period***.
|
|
76
|
+
After your 12 Months Free period, setting [`hostInstanceSpotPrice`](https://github.com/rajyan/low-cost-ecs/blob/main/API.md#low-cost-ecs.LowCostECSProps.property.hostInstanceSpotPrice) to use spot instances is recommended.
|
|
77
|
+
|
|
78
|
+
* EC2
|
|
79
|
+
* t2,micro 750 instance hours (12 Months Free Tier)
|
|
80
|
+
* 30GB EBS volume (12 Months Free Tier)
|
|
81
|
+
* ECS
|
|
82
|
+
* No additional charge because using ECS on EC2
|
|
83
|
+
* EFS
|
|
84
|
+
* Usage is very small, it should be free
|
|
85
|
+
* Cloud Watch
|
|
86
|
+
* Usage is very small, and it should be included in the free tier
|
|
87
|
+
* Enabling [`containerInsights`](https://github.com/rajyan/low-cost-ecs/blob/main/API.md#low-cost-ecs.LowCostECSProps.property.containerInsights) will charge for custom metrics
|
|
88
|
+
|
|
89
|
+
# Debugging
|
|
90
|
+
|
|
91
|
+
* SSM Session Manager
|
|
92
|
+
|
|
93
|
+
SSM manager is pre-installed (in ECS-optimized Amazon Linux 2 AMI) in the host instance and `AmazonSSMManagedInstanceCore` is added to the host instance role
|
|
94
|
+
to access and debug in your host instance.
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
aws ssm start-session --target $INSTANCE_ID
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
* ECS Exec
|
|
101
|
+
|
|
102
|
+
Service ECS Exec is enabled, so execute commands can be used to debug in your server task container.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
aws ecs execute-command \
|
|
106
|
+
--cluster $CLUSTER_ID \
|
|
107
|
+
--task $TASK_ID \
|
|
108
|
+
--container nginx \
|
|
109
|
+
--command bash \
|
|
110
|
+
--interactive
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
# Limitations
|
|
114
|
+
|
|
115
|
+
The ecs service occupies the host port, only one service can be run at a time.
|
|
116
|
+
The old task must be terminated before the new task launches, and this causes downtime on release.
|
|
117
|
+
Also, if you make changes that require recreating service, you may need to manually terminate the task of old the service.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { App } from "aws-cdk-lib";
|
|
2
|
+
import { LowCostECS } from '../src';
|
|
3
|
+
|
|
4
|
+
const app = new App();
|
|
5
|
+
|
|
6
|
+
new LowCostECS(app, "LowCostECSStack", {
|
|
7
|
+
env: {
|
|
8
|
+
account: process.env.CDK_DEFAULT_ACCOUNT,
|
|
9
|
+
region: process.env.CDK_DEFAULT_REGION,
|
|
10
|
+
},
|
|
11
|
+
hostedZoneDomain: "rajyan.net",
|
|
12
|
+
recordDomainNames: ["test1.rajyan.net", "test2.rajyan.net"],
|
|
13
|
+
email: "kitakita7617@gmail.com",
|
|
14
|
+
hostInstanceSpotPrice: "0.0050",
|
|
15
|
+
});
|
package/cdk.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
server {
|
|
2
|
+
listen 80 default_server;
|
|
3
|
+
listen 443 ssl http2 default_server;
|
|
4
|
+
listen [::]:80 default_server;
|
|
5
|
+
listen [::]:443 ssl http2 default_server;
|
|
6
|
+
|
|
7
|
+
ssl_reject_handshake on;
|
|
8
|
+
|
|
9
|
+
error_page 497 =444 @close;
|
|
10
|
+
location @close {
|
|
11
|
+
return 444;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return 444;
|
|
15
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
server {
|
|
2
|
+
listen 443 ssl http2;
|
|
3
|
+
listen [::]:443 ssl http2;
|
|
4
|
+
|
|
5
|
+
server_name ${SERVER_NAME};
|
|
6
|
+
|
|
7
|
+
ssl_certificate /etc/letsencrypt/live/${CERT_NAME}/fullchain.pem;
|
|
8
|
+
ssl_certificate_key /etc/letsencrypt/live/${CERT_NAME}/privkey.pem;
|
|
9
|
+
ssl_session_cache shared:ssl:10m;
|
|
10
|
+
ssl_session_timeout 1d;
|
|
11
|
+
ssl_session_tickets off;
|
|
12
|
+
|
|
13
|
+
# based on https://ssl-config.mozilla.org/
|
|
14
|
+
# intermediate configuration
|
|
15
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
16
|
+
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
|
17
|
+
ssl_prefer_server_ciphers off;
|
|
18
|
+
|
|
19
|
+
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
|
|
20
|
+
add_header Strict-Transport-Security "max-age=63072000" always;
|
|
21
|
+
|
|
22
|
+
# OCSP stapling
|
|
23
|
+
ssl_stapling on;
|
|
24
|
+
ssl_stapling_verify on;
|
|
25
|
+
|
|
26
|
+
# vpc resolver https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html
|
|
27
|
+
resolver 169.254.169.253;
|
|
28
|
+
|
|
29
|
+
location / {
|
|
30
|
+
root /usr/share/nginx/html;
|
|
31
|
+
index index.html index.htm;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './low-cost-ecs';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./low-cost-ecs"), exports);
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsaURBQStCIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9sb3ctY29zdC1lY3MnO1xuIl19
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as lib from 'aws-cdk-lib';
|
|
2
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
3
|
+
import * as ecs from 'aws-cdk-lib/aws-ecs';
|
|
4
|
+
import { ILogGroup } from 'aws-cdk-lib/aws-logs';
|
|
5
|
+
import { Construct } from 'constructs';
|
|
6
|
+
export interface LowCostECSProps extends lib.StackProps {
|
|
7
|
+
/**
|
|
8
|
+
* Domain name of the hosted zone.
|
|
9
|
+
*/
|
|
10
|
+
readonly hostedZoneDomain: string;
|
|
11
|
+
/**
|
|
12
|
+
* Email for expiration emails to register to your let's encrypt account.
|
|
13
|
+
*
|
|
14
|
+
* @link https://letsencrypt.org/docs/expiration-emails/
|
|
15
|
+
*
|
|
16
|
+
* Also registered as a subscriber of the sns topic, notified on certbot task failure.
|
|
17
|
+
* Subscription confirmation email would be sent on stack creation.
|
|
18
|
+
*
|
|
19
|
+
* @link https://docs.aws.amazon.com/sns/latest/dg/sns-email-notifications.html
|
|
20
|
+
*/
|
|
21
|
+
readonly email: string;
|
|
22
|
+
/**
|
|
23
|
+
* Domain names for A records to elastic ip of ECS host instance.
|
|
24
|
+
*
|
|
25
|
+
* @default - [ props.hostedZone.zoneName ]
|
|
26
|
+
*/
|
|
27
|
+
readonly recordDomainNames?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Vpc of the ECS host instance and cluster.
|
|
30
|
+
*
|
|
31
|
+
* @default - Creates vpc with only public subnets and no NAT gateways.
|
|
32
|
+
*/
|
|
33
|
+
readonly vpc?: ec2.IVpc;
|
|
34
|
+
/**
|
|
35
|
+
* Security group of the ECS host instance
|
|
36
|
+
*
|
|
37
|
+
* @default - Creates security group with allowAllOutbound and ingress rule (ipv4, ipv6) => (tcp 80, 443).
|
|
38
|
+
*/
|
|
39
|
+
readonly securityGroup?: ec2.SecurityGroup;
|
|
40
|
+
/**
|
|
41
|
+
* Instance type of the ECS host instance.
|
|
42
|
+
*
|
|
43
|
+
* @default - t2.micro
|
|
44
|
+
*/
|
|
45
|
+
readonly hostInstanceType?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The maximum hourly price (in USD) to be paid for any Spot Instance launched to fulfill the request.
|
|
48
|
+
* Host instance asg would use spot instances if hostInstanceSpotPrice is set.
|
|
49
|
+
*
|
|
50
|
+
* @link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs.AddCapacityOptions.html#spotprice
|
|
51
|
+
* @default - undefined
|
|
52
|
+
*/
|
|
53
|
+
readonly hostInstanceSpotPrice?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Log group of the certbot task and the aws-cli task.
|
|
56
|
+
*
|
|
57
|
+
* @default - Creates default cdk log group
|
|
58
|
+
*/
|
|
59
|
+
readonly logGroup?: ILogGroup;
|
|
60
|
+
/**
|
|
61
|
+
* Docker image tag of certbot/dns-route53 to create certificates.
|
|
62
|
+
*
|
|
63
|
+
* @link https://hub.docker.com/r/certbot/dns-route53/tags
|
|
64
|
+
* @default - v1.29.0
|
|
65
|
+
*/
|
|
66
|
+
readonly certbotDockerTag?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Certbot task schedule interval in days to renew the certificate.
|
|
69
|
+
*
|
|
70
|
+
* @default - 60
|
|
71
|
+
*/
|
|
72
|
+
readonly certbotScheduleInterval?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Docker image tag of amazon/aws-cli.
|
|
75
|
+
* This image is used to associate elastic ip on host instance startup, and run certbot cfn on ecs container startup.
|
|
76
|
+
*
|
|
77
|
+
* @default - latest
|
|
78
|
+
*/
|
|
79
|
+
readonly awsCliDockerTag?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Enable container insights or not
|
|
82
|
+
*
|
|
83
|
+
* @default - undefined (container insights disabled)
|
|
84
|
+
*/
|
|
85
|
+
readonly containerInsights?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Removal policy for the file system and log group (if using default).
|
|
88
|
+
*
|
|
89
|
+
* @default - RemovalPolicy.DESTROY
|
|
90
|
+
*/
|
|
91
|
+
readonly removalPolicy?: lib.RemovalPolicy;
|
|
92
|
+
/**
|
|
93
|
+
* Task definition for the server ecs task.
|
|
94
|
+
*
|
|
95
|
+
* @default - Nginx server task definition defined in sampleServerTask()
|
|
96
|
+
*/
|
|
97
|
+
readonly serverTaskDefinition?: ecs.Ec2TaskDefinition;
|
|
98
|
+
}
|
|
99
|
+
export declare class LowCostECS extends lib.Stack {
|
|
100
|
+
constructor(scope: Construct, id: string, props: LowCostECSProps);
|
|
101
|
+
private sampleSeverTask;
|
|
102
|
+
}
|