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/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
+ [![NPM version](https://badge.fury.io/js/low-cost-ecs.svg)](https://www.npmjs.com/package/low-cost-ecs)
2
+ [![PyPI version](https://badge.fury.io/py/low-cost-ecs.svg)](https://pypi.org/project/low-cost-ecs/0.0.4/)
3
+ [![Release](https://github.com/rajyan/low-cost-ecs/workflows/release/badge.svg)](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,3 @@
1
+ {
2
+ "app": "npx ts-node --prefer-ts-exts bin/low-cost-ecs.ts"
3
+ }
@@ -0,0 +1,3 @@
1
+ FROM nginx:stable
2
+
3
+ COPY ./templates /etc/nginx/templates
@@ -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,6 @@
1
+ server {
2
+ listen 80;
3
+ listen [::]:80;
4
+ server_name ${SERVER_NAME};
5
+ return 301 https://$host$request_uri;
6
+ }
@@ -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
+ }