diff --git a/.projen/deps.json b/.projen/deps.json index a13da43..619b554 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -48,7 +48,7 @@ }, { "name": "eslint", - "version": "^8", + "version": "8.22.0", "type": "build" }, { diff --git a/.projen/tasks.json b/.projen/tasks.json index 0d336e7..d3fb2a1 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -267,19 +267,19 @@ "exec": "yarn upgrade npm-check-updates" }, { - "exec": "npm-check-updates --dep dev --upgrade --target=minor --reject='aws-cdk-lib,constructs'" + "exec": "npm-check-updates --dep dev --upgrade --target=minor --reject='aws-cdk-lib,constructs,eslint'" }, { - "exec": "npm-check-updates --dep optional --upgrade --target=minor --reject='aws-cdk-lib,constructs'" + "exec": "npm-check-updates --dep optional --upgrade --target=minor --reject='aws-cdk-lib,constructs,eslint'" }, { - "exec": "npm-check-updates --dep peer --upgrade --target=minor --reject='aws-cdk-lib,constructs'" + "exec": "npm-check-updates --dep peer --upgrade --target=minor --reject='aws-cdk-lib,constructs,eslint'" }, { - "exec": "npm-check-updates --dep prod --upgrade --target=minor --reject='aws-cdk-lib,constructs'" + "exec": "npm-check-updates --dep prod --upgrade --target=minor --reject='aws-cdk-lib,constructs,eslint'" }, { - "exec": "npm-check-updates --dep bundle --upgrade --target=minor --reject='aws-cdk-lib,constructs'" + "exec": "npm-check-updates --dep bundle --upgrade --target=minor --reject='aws-cdk-lib,constructs,eslint'" }, { "exec": "yarn install --check-files" diff --git a/.projenrc.ts b/.projenrc.ts index 78d5b83..5009388 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -6,7 +6,7 @@ const project = new awscdk.AwsCdkConstructLibrary({ author: 'Yohta Kimura', authorAddress: 'kitakita7617@gmail.com', name: 'easy-cerver', - description: 'test', + description: 'Easy and low-cost ECS on EC2 server without a load balancer', repositoryUrl: 'https://github.com/rajyan/easy-cerver.git', license: 'MIT', cdkVersion: '2.37.0', @@ -14,8 +14,10 @@ const project = new awscdk.AwsCdkConstructLibrary({ keywords: [ 'cdk', 'ecs', + 'stepfunctions', + 'route53', 'certbot', - 'low-cost', + 'loadbalancer', ], devDeps: [ 'aws-cdk', @@ -41,4 +43,7 @@ const project = new awscdk.AwsCdkConstructLibrary({ projenrcTs: true, }); +// workaround until fixed https://youtrack.jetbrains.com/issue/WEB-57089/ESLint823-TypeError-thislibOptionsparse-is-not-a-function +project.addDevDeps('eslint@8.22.0'); + project.synth(); \ No newline at end of file diff --git a/README.md b/README.md index ff7dd3a..4454bfd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,117 @@ +[![NPM version](https://badge.fury.io/js/easy-cerver.svg)](https://www.npmjs.com/package/easy-cerver) +[![PyPI version](https://badge.fury.io/py/easy-cerver.svg)](https://pypi.org/project/easy-cerver/0.0.4/) +[![Release](https://github.com/rajyan/easy-cerver/workflows/release/badge.svg)](https://github.com/rajyan/easy-cerver/actions/workflows/release.yml) +[](https://constructs.dev/packages/easy-cerver) + # Easy Cerver -Easy ssl certificated server. +A CDK construct that provides easy and low-cost ECS on EC2 server setup without a load balancer. +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/). + +**This construct is for development purposes only** see [Limitations](#Limitations). + +# Try it out! + +The easiest way to see what this construct creates is to clone this repository and deploying sample server. +Edit settings in `bin/easy-cerver.ts` and deploy cdk construct. [Public hosted zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/AboutHZWorkingWith.html) with your own domain is required. + +``` +git clone https://github.com/rajyan/easy-cerver.git +# edit settings in bin/easy-cerver.ts +npx cdk deploy +``` + +Access to configured `recordDomainNames` and see that the nginx sample server has been deployed. + +# Installation + +To use this construct in your own cdk stack as a library, + +``` +npm install easy-cerver +``` + +```ts +import { Stack, StackProps } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import { EasyCerver } from 'easy-cerver'; + +class SampleStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const vpc = /** Your VPC */ + const securityGroup = /** Your security group */ + const serverTaskDefinition = /** Your task definition */ + + new EasyCerver(this, 'EasyCerver', { + hostedZoneDomain: "rajyan.net", + email: "kitakita7617@gmail.com", + vpc: vpc, + securityGroup: securityGroup, + serverTaskDefinition: serverTaskDefinition + }); + } +} +``` + +The required fields are `hostedZoneDomain` and `email`. +Set your own task definition, and other props. Read [`EasyCerverProps` documentation](https://github.com/rajyan/easy-cerver/blob/main/API.md#easy-cerver.EasyCerverProps) for details. + +# Why + +ECS may often seem expensive when used for personal development purposes, because of the cost of load balancer. +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, +but it is over-featured for running 1 ECS service. + +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. +This construct aims to automate these work and deploying resources to run low-cost ECS server. + +[//]: # (# Overview) + +# Cost + +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) +***if you are in the 12 Months Free period***. +After your 12 Months Free period, setting [`hostInstanceSpotPrice`](https://github.com/rajyan/easy-cerver/blob/main/API.md#easy-cerver.EasyCerverProps.property.hostInstanceSpotPrice) to use spot instances is recommended. + +* EC2 + * t2,micro 750 instance hours (12 Months Free Tier) + * 30GB EBS volume (12 Months Free Tier) +* ECS + * No additional charge because using ECS on EC2 +* EFS + * Usage is very small, it should be free +* Cloud Watch + * Usage is very small, and it should be included in the free tier + * Enabling [`containerInsights`](https://github.com/rajyan/easy-cerver/blob/main/API.md#easy-cerver.EasyCerverProps.property.containerInsights) will charge for custom metrics + +# Debugging + +* SSM Session Manager + +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 +to access and debug in your host instance. + +``` +aws ssm start-session --target $INSTANCE_ID +``` + +* ECS Exec + +Service ECS Exec is enabled, so execute commands can be used to debug in your server task container. + +``` +aws ecs execute-command \ +--cluster $CLUSTER_ID \ +--task $TASK_ID \ +--container nginx \ +--command bash \ +--interactive +``` + +# Limitations + +The ecs service occupies the host port, only one service can be run at a time. +The old task must be terminated before the new task launches, and this causes downtime on release. +Also, if you make changes that require recreating service, you may need to manually terminate the task of old the service. diff --git a/package.json b/package.json index 93e7b2a..0df2af7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "easy-cerver", - "description": "test", + "description": "Easy and low-cost ECS on EC2 server without a load balancer", "repository": { "type": "git", "url": "https://github.com/rajyan/easy-cerver.git" @@ -44,7 +44,7 @@ "aws-cdk": "^2.39.0", "aws-cdk-lib": "2.37.0", "constructs": "10.0.5", - "eslint": "^8", + "eslint": "8.22.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.0", "eslint-plugin-import": "^2.26.0", @@ -70,7 +70,9 @@ "cdk", "certbot", "ecs", - "low-cost" + "loadbalancer", + "route53", + "stepfunctions" ], "main": "lib/index.js", "license": "MIT", diff --git a/todo.md b/todo.md index 57a2555..e7ed3d0 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,4 @@ # todo -* Deploy as package -* update README +* update Overview +* add properties to expose \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 383175b..2fb4d63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -302,7 +302,7 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@eslint/eslintrc@^1.3.1": +"@eslint/eslintrc@^1.3.0": version "1.3.1" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.1.tgz#de0807bfeffc37b964a7d0400e0c348ce5a2543d" integrity sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ== @@ -336,11 +336,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d" integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA== -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" @@ -2403,15 +2398,14 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8: - version "8.23.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.23.0.tgz#a184918d288820179c6041bb3ddcc99ce6eea040" - integrity sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA== +eslint@8.22.0: + version "8.22.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.22.0.tgz#78fcb044196dfa7eef30a9d65944f6f980402c48" + integrity sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA== dependencies: - "@eslint/eslintrc" "^1.3.1" + "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.10.4" "@humanwhocodes/gitignore-to-minimatch" "^1.0.2" - "@humanwhocodes/module-importer" "^1.0.1" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2421,7 +2415,7 @@ eslint@^8: eslint-scope "^7.1.1" eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.4.0" + espree "^9.3.3" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -2447,8 +2441,9 @@ eslint@^8: strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" + v8-compile-cache "^2.0.3" -espree@^9.4.0: +espree@^9.3.3, espree@^9.4.0: version "9.4.0" resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== @@ -6191,6 +6186,11 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + v8-to-istanbul@^8.1.0: version "8.1.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"