├── demo-app ├── .prettierrc ├── src │ ├── app.service.ts │ ├── main.ts │ ├── app.module.ts │ ├── app.controller.ts │ └── app.controller.spec.ts ├── test │ ├── jest-e2e.json │ └── app.e2e-spec.ts ├── Dockerfile ├── tslint.json ├── .gitignore ├── package.json └── README.md ├── deploy ├── terraform │ ├── versions.tf │ ├── ecs.tf │ ├── outputs.tf │ ├── provider.tf │ ├── webcore-logs.tf │ ├── templates │ │ └── demoapp_app.json.tpl │ ├── roles.tf │ ├── webcore-alb.tf │ ├── security.tf │ ├── network.tf │ ├── variables.tf │ ├── webcore-ecs-service.tf │ └── webcore-auto-scaling.tf ├── create_repo_in_ecr.sh └── push_image_to_ecr_&_deploy_ecs.sh └── README.md /demo-app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /deploy/terraform/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | -------------------------------------------------------------------------------- /deploy/terraform/ecs.tf: -------------------------------------------------------------------------------- 1 | # ecs.tf 2 | resource "aws_ecs_cluster" "main" { 3 | name = "${var.prefix}-api-cluster" 4 | } 5 | -------------------------------------------------------------------------------- /deploy/terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | # outputs.tf 2 | 3 | output "demoapp_alb_hostname" { 4 | value = aws_alb.demoapp_lb.dns_name 5 | } 6 | 7 | -------------------------------------------------------------------------------- /demo-app/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /demo-app/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /deploy/terraform/provider.tf: -------------------------------------------------------------------------------- 1 | # provider.tf 2 | 3 | # Specify the provider and access details 4 | provider "aws" { 5 | shared_credentials_file = "$HOME/.aws/credentials" 6 | profile = "dev" 7 | region = var.aws_region 8 | } 9 | 10 | -------------------------------------------------------------------------------- /demo-app/src/main.ts: -------------------------------------------------------------------------------- 1 | import {NestFactory} from '@nestjs/core'; 2 | import {AppModule} from './app.module'; 3 | 4 | const APP_PORT = 80; 5 | 6 | async function bootstrap() { 7 | const app = await NestFactory.create(AppModule); 8 | await app.listen(APP_PORT); 9 | } 10 | 11 | bootstrap(); 12 | -------------------------------------------------------------------------------- /demo-app/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [AppController], 8 | providers: [AppService], 9 | }) 10 | export class AppModule {} 11 | -------------------------------------------------------------------------------- /demo-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.3.0-buster-slim 2 | 3 | RUN mkdir -p /demo-app 4 | 5 | WORKDIR /demo-app 6 | 7 | COPY package*.json ./ 8 | 9 | COPY yarn.lock ./ 10 | 11 | RUN yarn install 12 | 13 | COPY . . 14 | 15 | RUN yarn build 16 | 17 | WORKDIR ./ 18 | 19 | # EXPOSE 9001 20 | EXPOSE 80 21 | 22 | RUN mkdir /var/logs 23 | 24 | CMD ["node" , "./dist/main.js", "2>server.log"] 25 | -------------------------------------------------------------------------------- /demo-app/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | @Get('api/index') 13 | getIndex(): string { 14 | return this.appService.getHello(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /deploy/terraform/webcore-logs.tf: -------------------------------------------------------------------------------- 1 | # logs.tf 2 | # Set up CloudWatch group and log stream and retain logs for 30 days 3 | resource "aws_cloudwatch_log_group" "demoapp_log_group" { 4 | name = "/ecs/demoapp" 5 | retention_in_days = 30 6 | 7 | tags = { 8 | Name = "demoapp-log-group" 9 | } 10 | } 11 | 12 | resource "aws_cloudwatch_log_stream" "cb_log_stream" { 13 | name = "demoapp-log-stream" 14 | log_group_name = aws_cloudwatch_log_group.demoapp_log_group.name 15 | } 16 | -------------------------------------------------------------------------------- /demo-app/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended"], 4 | "jsRules": { 5 | "no-unused-expression": true 6 | }, 7 | "rules": { 8 | "quotemark": [true, "single"], 9 | "member-access": [false], 10 | "ordered-imports": [false], 11 | "max-line-length": [true, 150], 12 | "member-ordering": [false], 13 | "interface-name": [false], 14 | "arrow-parens": false, 15 | "object-literal-sort-keys": false 16 | }, 17 | "rulesDirectory": [] 18 | } 19 | -------------------------------------------------------------------------------- /demo-app/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Deploy a dockerized Application in Aws ECS with new vpc 2 | 3 | ###demo-app 4 | A simple nodejs based application build on nestjs framework. 5 | 6 | ###deploy 7 | It contains script to deploy the application in ECS fargate by pushing your docker conainter into ECR and then 8 | deploy from there to ECS. 9 | 10 | Script were written on terraform & some shell script. 11 | 12 | ####Uninstall 13 | After deploy, to remove or uninstall everything from AWS, just go to terraform folder & run destroy command. 14 | ``` 15 | terraform destroy 16 | ``` 17 | -------------------------------------------------------------------------------- /deploy/terraform/templates/demoapp_app.json.tpl: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "${container_name}", 4 | "image": "${app_image}", 5 | "cpu": ${fargate_cpu}, 6 | "memory": ${fargate_memory}, 7 | "networkMode": "awsvpc", 8 | "logConfiguration": { 9 | "logDriver": "awslogs", 10 | "options": { 11 | "awslogs-group": "/ecs/demoapp", 12 | "awslogs-region": "${aws_region}", 13 | "awslogs-stream-prefix": "ecs" 14 | } 15 | }, 16 | "portMappings": [ 17 | { 18 | "containerPort": ${app_port}, 19 | "hostPort": ${app_port} 20 | } 21 | ] 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /demo-app/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /demo-app/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /deploy/create_repo_in_ecr.sh: -------------------------------------------------------------------------------- 1 | export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX 2 | export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXX 3 | export AWS_REGION=ap-southeast-1 4 | export AWS_PROFILE=DEV 5 | export ECR_REPO_NAME=demo_app_repo 6 | 7 | 8 | # aws configure set varname value [--profile profile-name] 9 | aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile "$AWS_PROFILE" 10 | aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile "$AWS_PROFILE" 11 | aws configure set region "$AWS_REGION" --profile "$AWS_PROFILE" 12 | aws configure set output json --profile "$AWS_PROFILE" 13 | 14 | 15 | # create repository 16 | aws ecr create-repository --repository-name "$ECR_REPO_NAME" 17 | 18 | # after created repo, it will print the repo path in console. 19 | #978267824871.dkr.ecr.ap-southeast-1.amazonaws.com/demo_app_repo 20 | -------------------------------------------------------------------------------- /deploy/terraform/roles.tf: -------------------------------------------------------------------------------- 1 | # ECS task execution role data 2 | data "aws_iam_policy_document" "demoapp_ecs_task_execution_role" { 3 | version = "2012-10-17" 4 | statement { 5 | sid = "" 6 | effect = "Allow" 7 | actions = ["sts:AssumeRole"] 8 | 9 | principals { 10 | type = "Service" 11 | identifiers = ["ecs-tasks.amazonaws.com"] 12 | } 13 | } 14 | } 15 | 16 | # ECS task execution role 17 | resource "aws_iam_role" "demoapp_ecs_task_execution_role" { 18 | name = var.ecs_task_execution_role_name 19 | assume_role_policy = data.aws_iam_policy_document.demoapp_ecs_task_execution_role.json 20 | } 21 | 22 | # ECS task execution role policy attachment 23 | resource "aws_iam_role_policy_attachment" "demoapp_task_execution_role" { 24 | role = aws_iam_role.demoapp_ecs_task_execution_role.name 25 | policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" 26 | } 27 | -------------------------------------------------------------------------------- /deploy/terraform/webcore-alb.tf: -------------------------------------------------------------------------------- 1 | # alb.tf 2 | resource "aws_alb" "demoapp_lb" { 3 | name = "dev-demoapp" 4 | subnets = aws_subnet.public.*.id 5 | security_groups = [aws_security_group.lb.id] 6 | } 7 | 8 | resource "aws_alb_target_group" "demoapp_target" { 9 | name = "demoapp-target-group" 10 | port = 80 11 | protocol = "HTTP" 12 | vpc_id = aws_vpc.main.id 13 | target_type = "ip" 14 | 15 | health_check { 16 | healthy_threshold = "3" 17 | interval = "30" 18 | protocol = "HTTP" 19 | matcher = "200" 20 | timeout = "3" 21 | path = var.demoapp_health_check_path 22 | unhealthy_threshold = "2" 23 | } 24 | } 25 | 26 | # Redirect all traffic from the ALB to the target group 27 | resource "aws_alb_listener" "front_end_demoapp" { 28 | load_balancer_arn = aws_alb.demoapp_lb.id 29 | port = var.app_port 30 | protocol = "HTTP" 31 | 32 | default_action { 33 | target_group_arn = aws_alb_target_group.demoapp_target.id 34 | type = "forward" 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /deploy/terraform/security.tf: -------------------------------------------------------------------------------- 1 | # security.tf 2 | 3 | # ALB Security Group: Edit to restrict access to the application 4 | resource "aws_security_group" "lb" { 5 | name = "${var.prefix}-load-balancer-security-group" 6 | description = "controls access to the ALB" 7 | vpc_id = aws_vpc.main.id 8 | 9 | ingress { 10 | protocol = "tcp" 11 | from_port = var.app_port 12 | to_port = var.app_port 13 | cidr_blocks = ["0.0.0.0/0"] 14 | } 15 | 16 | egress { 17 | protocol = "-1" 18 | from_port = 0 19 | to_port = 0 20 | cidr_blocks = ["0.0.0.0/0"] 21 | } 22 | } 23 | 24 | # Traffic to the ECS cluster should only come from the ALB 25 | resource "aws_security_group" "ecs_tasks" { 26 | name = "${var.prefix}-ecs-tasks-security-group" 27 | description = "allow inbound access from the ALB only" 28 | vpc_id = aws_vpc.main.id 29 | 30 | ingress { 31 | protocol = "tcp" 32 | from_port = var.app_port 33 | to_port = var.app_port 34 | security_groups = [aws_security_group.lb.id] 35 | } 36 | 37 | egress { 38 | protocol = "-1" 39 | from_port = 0 40 | to_port = 0 41 | cidr_blocks = ["0.0.0.0/0"] 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /deploy/terraform/network.tf: -------------------------------------------------------------------------------- 1 | # network.tf without elastic ip 2 | 3 | # Fetch AZs in the current region 4 | data "aws_availability_zones" "available" { 5 | } 6 | 7 | resource "aws_vpc" "main" { 8 | cidr_block = "192.10.0.0/16" 9 | tags = { 10 | Name = "${var.prefix}-vpc" 11 | } 12 | } 13 | 14 | 15 | # Create var.az_count public subnets, each in a different AZ 16 | resource "aws_subnet" "public" { 17 | count = var.az_count 18 | cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, var.az_count + count.index) 19 | availability_zone = data.aws_availability_zones.available.names[count.index] 20 | vpc_id = aws_vpc.main.id 21 | map_public_ip_on_launch = true 22 | tags = { 23 | Name = "${var.prefix}-public-subnet" 24 | } 25 | } 26 | 27 | # Internet Gateway for the public subnet 28 | resource "aws_internet_gateway" "gw" { 29 | vpc_id = aws_vpc.main.id 30 | tags = { 31 | Name = "${var.prefix}-ig" 32 | } 33 | } 34 | 35 | # Route the public subnet traffic through the IGW 36 | resource "aws_route" "internet_access" { 37 | route_table_id = aws_vpc.main.main_route_table_id 38 | destination_cidr_block = "0.0.0.0/0" 39 | gateway_id = aws_internet_gateway.gw.id 40 | } 41 | -------------------------------------------------------------------------------- /deploy/terraform/variables.tf: -------------------------------------------------------------------------------- 1 | # variables.tf 2 | 3 | variable "prefix" { 4 | description = "Prefix for all envirnoments" 5 | default = "demoapp" 6 | } 7 | 8 | variable "aws_region" { 9 | description = "The AWS region things are created in" 10 | default = "ap-southeast-1" 11 | } 12 | 13 | variable "ecs_task_execution_role_name" { 14 | description = "ECS task execution role name" 15 | default = "demoappEcsTaskExecutionRole" 16 | } 17 | 18 | variable "az_count" { 19 | description = "Number of AZs to cover in a given region" 20 | default = "3" 21 | } 22 | 23 | variable "app_port" { 24 | description = "Port exposed by the docker image to redirect traffic to" 25 | default = 80 26 | } 27 | 28 | variable "app_count" { 29 | description = "Number of docker containers to run" 30 | default = 2 31 | } 32 | 33 | #### Commented becoz of it uses Envirnoment variable. 34 | variable "demoapp_image" { 35 | description = "Docker image to run in the ECS cluster" 36 | // default = "XXXXXXXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/dev-demoapp:0.0.4" 37 | } 38 | 39 | variable "demoapp_health_check_path" { 40 | default = "/api/index" 41 | } 42 | 43 | variable "fargate_cpu" { 44 | description = "Fargate instance CPU units to provision (1 vCPU = 1024 CPU units)" 45 | default = "1024" 46 | } 47 | 48 | variable "fargate_memory" { 49 | description = "Fargate instance memory to provision (in MiB)" 50 | default = "2048" 51 | } 52 | 53 | variable "demoapp_container_name" { 54 | description = "Application container name" 55 | default = "demoapp-app" 56 | } 57 | -------------------------------------------------------------------------------- /deploy/terraform/webcore-ecs-service.tf: -------------------------------------------------------------------------------- 1 | data "template_file" "demoapp_app" { 2 | template = file("./templates/demoapp_app.json.tpl") 3 | 4 | vars = { 5 | app_image = "${var.demoapp_image}" 6 | # its env variable 7 | app_port = var.app_port 8 | fargate_cpu = var.fargate_cpu 9 | fargate_memory = var.fargate_memory 10 | aws_region = var.aws_region 11 | prefix = var.prefix 12 | container_name = var.demoapp_container_name 13 | } 14 | } 15 | 16 | 17 | resource "aws_ecs_task_definition" "demoapp_task_def" { 18 | family = "demoapp-task" 19 | execution_role_arn = aws_iam_role.demoapp_ecs_task_execution_role.arn 20 | network_mode = "awsvpc" 21 | requires_compatibilities = [ 22 | "FARGATE"] 23 | cpu = var.fargate_cpu 24 | memory = var.fargate_memory 25 | container_definitions = data.template_file.demoapp_app.rendered 26 | } 27 | 28 | 29 | resource "aws_ecs_service" "demoapp_main" { 30 | name = "demoapp-service" 31 | cluster = aws_ecs_cluster.main.id 32 | task_definition = aws_ecs_task_definition.demoapp_task_def.arn 33 | desired_count = var.app_count 34 | launch_type = "FARGATE" 35 | 36 | network_configuration { 37 | security_groups = [ 38 | aws_security_group.ecs_tasks.id] 39 | subnets = aws_subnet.public.*.id 40 | assign_public_ip = true 41 | } 42 | 43 | load_balancer { 44 | target_group_arn = aws_alb_target_group.demoapp_target.id 45 | container_name = var.demoapp_container_name 46 | container_port = var.app_port 47 | } 48 | 49 | depends_on = [ 50 | aws_alb_listener.front_end_demoapp, 51 | aws_iam_role_policy_attachment.demoapp_task_execution_role] 52 | } 53 | -------------------------------------------------------------------------------- /demo-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-nestjs-kafka", 3 | "version": "0.0.1", 4 | "description": "

\"Nest

", 5 | "author": "", 6 | "license": "MIT", 7 | "scripts": { 8 | "prebuild": "rimraf dist", 9 | "build": "nest build", 10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 11 | "start": "nest start", 12 | "start:dev": "nest start --watch", 13 | "start:debug": "nest start --debug --watch", 14 | "start:prod": "node dist/main", 15 | "lint": "tslint -p tsconfig.json -c tslint.json", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:cov": "jest --coverage", 19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 20 | "test:e2e": "jest --config ./test/jest-e2e.json" 21 | }, 22 | "dependencies": { 23 | "@nestjs/common": "^6.7.2", 24 | "@nestjs/core": "^6.7.2", 25 | "@nestjs/platform-express": "^6.7.2", 26 | "kafkajs": "^1.12.0", 27 | "reflect-metadata": "^0.1.13", 28 | "rimraf": "^3.0.0", 29 | "rxjs": "^6.5.3" 30 | }, 31 | "devDependencies": { 32 | "@nestjs/cli": "^6.9.0", 33 | "@nestjs/schematics": "^6.7.0", 34 | "@nestjs/testing": "^6.7.1", 35 | "@types/express": "^4.17.1", 36 | "@types/jest": "^24.0.18", 37 | "@types/node": "^12.7.5", 38 | "@types/supertest": "^2.0.8", 39 | "jest": "^24.9.0", 40 | "prettier": "^1.18.2", 41 | "supertest": "^4.0.2", 42 | "ts-jest": "^24.1.0", 43 | "ts-loader": "^6.1.1", 44 | "ts-node": "^8.4.1", 45 | "tsconfig-paths": "^3.9.0", 46 | "tslint": "^5.20.0", 47 | "typescript": "^3.6.3" 48 | }, 49 | "jest": { 50 | "moduleFileExtensions": [ 51 | "js", 52 | "json", 53 | "ts" 54 | ], 55 | "rootDir": "src", 56 | "testRegex": ".spec.ts$", 57 | "transform": { 58 | "^.+\\.(t|j)s$": "ts-jest" 59 | }, 60 | "coverageDirectory": "./coverage", 61 | "testEnvironment": "node" 62 | }, 63 | "main": "index.js", 64 | "directories": { 65 | "test": "test" 66 | }, 67 | "keywords": [] 68 | } 69 | -------------------------------------------------------------------------------- /deploy/push_image_to_ecr_&_deploy_ecs.sh: -------------------------------------------------------------------------------- 1 | echo "*************************************************************************" 2 | echo "TO DEPLOY THE CODE, YOU NEED TO HAVE AWS CLI & TERRAFORM CLI INSTALLED." 3 | echo "*************************************************************************" 4 | cd .. 5 | 6 | #it can be any version, depends on user choice either hardcoded version or from war/jar file or packaage.json 7 | PACKAGE_VERSION=$(node -p -e "require('./demo-app/package.json').version") 8 | #PACKAGE_VERSION=1.0.0 9 | 10 | #Update parameters before running 11 | # AWS configuration details 12 | export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX 13 | export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXX 14 | export AWS_REGION=ap-southeast-1 15 | export AWS_PROFILE=DEV 16 | 17 | #Custom ECR REPO Name. any name for repo 18 | ECR_REPO_NAME=demo_app_repo 19 | #Application Name 20 | APP_NAME=demo-app 21 | # first create ECR repo with create_repo_in_ecr sh file and give the path here 22 | ECR_REPO_PATH=XXXXXXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/demo_app_repo 23 | #Application Folder location 24 | APP_LOCATION=./demo-app/ 25 | 26 | cd $APP_LOCATION 27 | 28 | # go to inside application folder 29 | #docker build -t dev-webcore:"$PACKAGE_VERSION" . 30 | docker build -t "$APP_NAME":"$PACKAGE_VERSION" . 31 | 32 | # aws configure set varname value [--profile profile-name] 33 | aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" --profile "$AWS_PROFILE" 34 | aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" --profile "$AWS_PROFILE" 35 | aws configure set region "$AWS_REGION" --profile "$AWS_PROFILE" 36 | aws configure set output json --profile "$AWS_PROFILE" 37 | 38 | 39 | # create repository 40 | aws ecr create-repository --repository-name "$ECR_REPO_NAME" 41 | 42 | 43 | echo "docker image created with package version :$PACKAGE_VERSION" 44 | 45 | # tag doker image for ecr image 46 | echo "$APP_NAME:$PACKAGE_VERSION" "$ECR_REPO_PATH:$PACKAGE_VERSION" 47 | docker tag "$APP_NAME:$PACKAGE_VERSION" "$ECR_REPO_PATH:$PACKAGE_VERSION" 48 | 49 | $(aws ecr get-login --no-include-email --no-include-email | sed 's|https://||') 50 | 51 | #push tagged image to ecr 52 | docker push "$ECR_REPO_PATH:$PACKAGE_VERSION" 53 | 54 | 55 | 56 | # Deploy code thru terraform 57 | cd .. 58 | 59 | cd deploy/terraform 60 | 61 | # envirnoment variable demoapp_image for terraform 62 | #export TF_VAR_webcore_image="XXXXX.dkr.ecr.ap-southeast-1.amazonaws.com/demo-app:$PACKAGE_VERSION" 63 | export TF_VAR_demoapp_image="$ECR_REPO_PATH:$PACKAGE_VERSION" 64 | 65 | terraform init 66 | 67 | terraform plan 68 | 69 | terraform apply -auto-approve 70 | -------------------------------------------------------------------------------- /deploy/terraform/webcore-auto-scaling.tf: -------------------------------------------------------------------------------- 1 | # auto_scaling.tf 2 | 3 | resource "aws_appautoscaling_target" "demoapp_target" { 4 | service_namespace = "ecs" 5 | resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.demoapp_main.name}" 6 | scalable_dimension = "ecs:service:DesiredCount" 7 | min_capacity = 1 8 | max_capacity = 6 9 | } 10 | 11 | # Automatically scale capacity up by one 12 | resource "aws_appautoscaling_policy" "demoapp_up" { 13 | name = "demoapp_scale_up" 14 | service_namespace = "ecs" 15 | resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.demoapp_main.name}" 16 | scalable_dimension = "ecs:service:DesiredCount" 17 | 18 | step_scaling_policy_configuration { 19 | adjustment_type = "ChangeInCapacity" 20 | cooldown = 60 21 | metric_aggregation_type = "Maximum" 22 | 23 | step_adjustment { 24 | metric_interval_lower_bound = 0 25 | scaling_adjustment = 1 26 | } 27 | } 28 | 29 | depends_on = [aws_appautoscaling_target.demoapp_target] 30 | } 31 | 32 | # Automatically scale capacity down by one 33 | resource "aws_appautoscaling_policy" "demoapp_down" { 34 | name = "demoapp_scale_down" 35 | service_namespace = "ecs" 36 | resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.demoapp_main.name}" 37 | scalable_dimension = "ecs:service:DesiredCount" 38 | 39 | step_scaling_policy_configuration { 40 | adjustment_type = "ChangeInCapacity" 41 | cooldown = 60 42 | metric_aggregation_type = "Maximum" 43 | 44 | step_adjustment { 45 | metric_interval_upper_bound = 0 46 | scaling_adjustment = -1 47 | } 48 | } 49 | 50 | depends_on = [aws_appautoscaling_target.demoapp_target] 51 | } 52 | 53 | # CloudWatch alarm that triggers the autoscaling up policy 54 | resource "aws_cloudwatch_metric_alarm" "demoapp_service_cpu_high" { 55 | alarm_name = "demoapp_cpu_utilization_high" 56 | comparison_operator = "GreaterThanOrEqualToThreshold" 57 | evaluation_periods = "2" 58 | metric_name = "CPUUtilization" 59 | namespace = "AWS/ECS" 60 | period = "60" 61 | statistic = "Average" 62 | threshold = "85" 63 | 64 | dimensions = { 65 | ClusterName = aws_ecs_cluster.main.name 66 | ServiceName = aws_ecs_service.demoapp_main.name 67 | } 68 | 69 | alarm_actions = [aws_appautoscaling_policy.demoapp_up.arn] 70 | } 71 | 72 | # CloudWatch alarm that triggers the autoscaling down policy 73 | resource "aws_cloudwatch_metric_alarm" "demoapp_service_cpu_low" { 74 | alarm_name = "demoapp_cpu_utilization_low" 75 | comparison_operator = "LessThanOrEqualToThreshold" 76 | evaluation_periods = "2" 77 | metric_name = "CPUUtilization" 78 | namespace = "AWS/ECS" 79 | period = "60" 80 | statistic = "Average" 81 | threshold = "10" 82 | 83 | dimensions = { 84 | ClusterName = aws_ecs_cluster.main.name 85 | ServiceName = aws_ecs_service.demoapp_main.name 86 | } 87 | 88 | alarm_actions = [aws_appautoscaling_policy.demoapp_down.arn] 89 | } 90 | 91 | -------------------------------------------------------------------------------- /demo-app/README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master 6 | [travis-url]: https://travis-ci.org/nestjs/nest 7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux 8 | [linux-url]: https://travis-ci.org/nestjs/nest 9 | 10 |

A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.

11 |

12 | NPM Version 13 | Package License 14 | NPM Downloads 15 | Travis 16 | Linux 17 | Coverage 18 | Gitter 19 | Backers on Open Collective 20 | Sponsors on Open Collective 21 | 22 | 23 |

24 | 26 | 27 | ## Description 28 | 29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 30 | 31 | ## Installation 32 | 33 | ```bash 34 | $ npm install 35 | ``` 36 | 37 | ## Running the app 38 | 39 | ```bash 40 | # development 41 | $ npm run start 42 | 43 | # watch mode 44 | $ npm run start:dev 45 | 46 | # production mode 47 | $ npm run start:prod 48 | ``` 49 | 50 | ## Test 51 | 52 | ```bash 53 | # unit tests 54 | $ npm run test 55 | 56 | # e2e tests 57 | $ npm run test:e2e 58 | 59 | # test coverage 60 | $ npm run test:cov 61 | ``` 62 | 63 | ## Support 64 | 65 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 66 | 67 | ## Stay in touch 68 | 69 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) 70 | - Website - [https://nestjs.com](https://nestjs.com/) 71 | - Twitter - [@nestframework](https://twitter.com/nestframework) 72 | 73 | ## License 74 | 75 | Nest is [MIT licensed](LICENSE). 76 | --------------------------------------------------------------------------------