node.js

nestjs + serverless + lambda + apiGateway ์‚ฌ์šฉํ•˜๊ธฐ

dev_summer 2022. 8. 23. 12:14

๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ๋“ค ๋ณด๋ฉด ์ด๋Ÿฐ๊ฑฐ ์ด๋ฏธ์ง€ ๊น”๋”ํ•˜๊ฒŒ ๋ถ™์ด๋˜๋ฐ ๋‚˜๋Š” ๊ทธ๋Ÿฐ ๋Šฅ๋ ฅ์ด ์—†์–ด์„œ ํผ์™”๋‹ค.

์ด ๊ท€์—ฌ์šด ๊ณ ์–‘์ด๋Š” nodejs ํ”„๋ ˆ์ž„์›Œํฌ์ธ nestjs์˜ ๊ท€์—ผ๋‘ฅ์ด ๋งˆ์Šค์ฝ”ํŠธ ๋กœ๊ณ ์ด๋‹ค. node๊ณ„์˜ ์Šคํ”„๋ง๋ถ€ํŠธ ๊ฐ™์€ ๋Š๋‚Œ์ธ๋ฐ ๊ธฐ์กด์˜ nodejs์˜ ๋Œ€ํ‘œ์ ์ธ ํ”„๋ ˆ์ž„์›Œํฌ์ธ express์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ ์˜์กด์„ฑ ์ฃผ์ž… ๊ฐœ๋…๋„ ์žˆ๊ณ  ์ด๋ฏธ ๋งˆ๋ จ๋œ ๋ฏธ๋“ค์›จ์–ด ๋“ฑ์ด ์žˆ์–ด ๊พธ์ค€ํžˆ ์ฆ๊ฐ€ํ•˜๊ณ  ์žˆ๋Š” nodejs์˜ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.  ๋‚˜๋Š” ๊ท€์—ฌ์šด ๊ณ ์–‘์ด๊ฐ€ ์ข‹์€ nestjs๊ฐ€ ์ฃผ์ข…๋ชฉ์ธ ๊ฐœ๋ฐœ ์ฃผ๊พธ๋ฏธ

์„œ๋ฒ„๋ฆฌ์Šค๋Š” ๋ง ๊ทธ๋Œ€๋กœ ์„œ๋ฒ„๊ฐ€ ์—†๋‹ค๋Š” ๋œป์ธ๋ฐ, ์ข€ ๋” ๊ฐœ๋ฐœ์ ์œผ๋กœ ์ ‘๊ทผํ•˜์ž๋ฉด ์„œ๋ฒ„๋ฅผ ๊ด€๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ผ๋Š” ๋Š๋‚Œ์œผ๋กœ ํ•ด์„์„ ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค. ์ข€ ๋” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ง‘์ค‘ํ•˜๋Š” ๋Š๋‚Œ์œผ๋กœ ์ง„์งœ ์„œ๋ฒ„๊ฐ€ ์—†๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๊ทธ์ € ์„œ๋ฒ„๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ๋œ์–ด๋‚ธ ์˜๋ฏธ์˜ ์„œ๋ฒ„๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ํ•ด๋‹นํ•˜๋Š” ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๋น ๋ฅด๊ฒŒ ๊ตฌ์„ฑ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด ์‚ฌ๋‹ค๋ฆฌ๋Š” ๋žŒ๋‹ค์ธ๋ฐ, ์ด ๋˜ํ•œ ์„œ๋ฒ„๋ฆฌ์Šค ํด๋ผ์šฐ๋“œ ๋ชจ๋ธ์˜ ํ•˜๋‚˜๋กœ ๊ฐ„๋‹จํ•œ ๋™์ž‘์„ ๋ถ„๋ฆฌ์‹œ์ผœ ํ•ด๋‹นํ•˜๋Š” ์ผ๋งŒ์„ ์‹คํ–‰ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ๋™์ž‘์ด ์•„๋‹ˆ์–ด๋„ ์ƒ๊ด€์—†๋‹ค. ์‚ฌ์šฉํ•œ ๋งŒํผ๋งŒ ๋น„์šฉ์ด ์ฒญ๊ตฌ๋˜๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

api gateway๋กœ ์ด๋ฒคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์—”๋“œํฌ์ธํŠธ๋กœ์„œ ๋žŒ๋‹ค๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผœ ์ค„ ๊ฒƒ์ด๋‹ค.

 

 

์ด๋ฒˆ ์ •๋ฆฌ ๊ธ€์€ ์•„๋ž˜์™€ ๊ฐ™์€ ์ž‘์—…์„ ์š”์•ฝํ•˜์˜€๋‹ค.

1. nestjs ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋‚ด๋ถ€์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

2. nestjs์˜ ์ „์ฒด ๋™์ž‘ ์ง„์ž… ์ „ serverlessํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๊ฐ์‹ผ ๋’ค ๋™์ž‘ ํ•˜๋‚˜ํ•˜๋‚˜๋ฅผ ๋ถ„๋ฆฌ์‹œ์ผœ lambda์— ๋ฐฐํฌํ•  ๊ฒƒ์ด๋‹ค.

3. ํ•ด๋‹นํ•˜๋Š” ๋žŒ๋‹ค๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ์ง„์ž…์ ์€ apigateway๋ฅผ ๋ถ™์—ฌ ํ•˜๋‚˜์˜ restapi ์„œ๋ฒ„๋กœ์„œ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ๊ฒƒ์ด๋‹ค.

 



์•„๋‹ˆ ๋‹ค๋ฅธ ๊ธฐ์ˆ  ๋ธ”๋กœ๊ทธ ์“ฐ๋Š” ์‚ฌ๋žŒ๋“ค์€ ์ž˜๋งŒ ์“ฐ๋˜๋ฐ ์™œ ๋‚˜๋Š” ์ด๋ ‡๊ฒŒ ๋š๋”ฑ ๊ฑฐ๋ฆฌ์ง€..

๊ทผ๋ฐ ์‚ฌ์‹ค ๋ณด๋Š” ์‚ฌ๋žŒ๋„ ์—†์–ด์„œ ๋ง‰ ์จ๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ƒฅ ๋‚˜์˜ ๊ฒฝํ—˜์„ ํŽธํžˆ ํ’€์–ด ๋ณด์•„์•ผ๊ฒ ๋‹ค.

๊ธ€์„ ์“ฐ๋ฉด์„œ ํ•ด๋‹น ๋‚ด์šฉ์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ˆ™์ง€ํ•˜๊ณ  ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์— ์˜๋ฏธ๋ฅผ ๋‘์–ด์•ผ์ง€.

 

1. nestjs ์‹œ์ž‘ํ•˜๊ธฐ

nest new test

 

๋„ค์ŠคํŠธ๋กœ ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  localhost:3000์œผ๋กœ ์ ‘์†ํ•˜๊ฒŒ ๋˜๋ฉด hello world๋ฅผ ๋ฑ‰์–ด์ค€๋‹ค.

ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์„ ๋ณดํ†ต์˜ ์„œ๋ฒ„์— ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์„œ๋ฒ„๋ฆฌ์Šค ํ™˜๊ฒฝ์œผ๋กœ lambda์— ๋ฐฐํฌํ•˜๊ณ  api๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

2. serverless.yml ์„ค์ •ํ•˜๊ธฐ

๋‹ค๋ฅธ ๊ฑด ์ฐจ์ฐจ ์•Œ๋ฉด ๋˜๊ณ  ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ ํ•ด๋‹นํ•˜๋Š” ๋žŒ๋‹ค๊ฐ€ ์–ด๋–ค ํŒŒ์ผ์„ ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ์œผ๋ฉฐ ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ ์–ธ์ œ ๋ฐœ์ƒ์ด ๋˜๋Š”์ง€๋ฅผ ์„œ๋ฒ„๋ฆฌ์Šค ํ™˜๊ฒฝ ํŒŒ์ผ์—์„œ ์ •์˜ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

๊ทธ ๋ถ€๋ถ„์ด function๊ตฌ๋ฌธ์ธ๋ฐ index.handler๋ถ€์˜ ๋ชจ๋“  ํ•จ์ˆ˜๋ฅผ ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ์œผ๋ฉฐ ํ•ด๋‹นํ•˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์–ธ์ œ ๋ฐœ์ƒ์ด ๋˜๋Š”์ง€๋Š” event ๋ถ€๋ฅผ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค.

service: test

provider:
  name: aws
  runtime: nodejs12.x
  region: ap-northeast-2

plugins:
  - serverless-offline

package:
  exclude:
    - .git/**
    - src/**
    - test/**
    - e2e/**
    - nodemon.json
    - README.md

functions:
  index:
    handler: dist/index.handler
    events:
      - http:
          cors: true
          path: '/'
          method: any
      - http:
          cors: true
          path: '{proxy+}'
          method: any

nest๊ฐ€ ์ฒ˜์Œ ์„œ๋ฒ„๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” main์„ index.ts๋ผ๋Š” ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์„œ๋ฒ„๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ  handler๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด

์„œ๋ฒ„๋ฆฌ์Šค๊ฐ€ ๊ตฌ๋™๋  ๋•Œ์— nest๋กœ ๋งŒ๋“ค์–ด์ง„ ์„œ๋ฒ„๋ฅผ ์ฝ์–ด ๋„์–ด์ฃผ๊ฒŒ ๋œ๋‹ค.

 

index.ts

import { APIGatewayProxyHandler } from 'aws-lambda';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Server } from 'http';
import { ExpressAdapter } from '@nestjs/platform-express';
import * as awsServerlessExpress from 'aws-serverless-express';
import * as express from 'express';

let cachedServer: Server;

const bootstrapServer = async (): Promise<Server> => {
  const expressApp = express();
  const adapter = new ExpressAdapter(expressApp);
  const app = await NestFactory.create(AppModule, adapter);
  app.enableCors();
  await app.init();
  return awsServerlessExpress.createServer(expressApp);
};

export const handler: APIGatewayProxyHandler = async (event, context) => {
  if (!cachedServer) {
    cachedServer = await bootstrapServer();
  }
  return awsServerlessExpress.proxy(cachedServer, event, context, 'PROMISE')
    .promise;
};

 

 

ํ•ด๋‹นํ•˜๋Š” ์„œ๋ฒ„๋ฆฌ์Šค๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์ฃผ๋ฉด ์„œ๋ฒ„๋ฆฌ์Šค ํ™˜๊ฒฝ ํŒŒ์ผ์„ ์ฝ์–ด ๋กœ์ปฌ์—์„œ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

serverless offline

 

 

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜ ๋นŒ๋“œ์‹œํ‚จ ํ›„ , ์„œ๋ฒ„๋ฆฌ์Šค ๋ฐฐํฌ๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด ๋žŒ๋‹ค ํ™˜๊ฒฝ์— ์ž˜ ์˜ฌ๋ผ๊ฐ€์ง„ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

yarn build && sls:deploy

 

๊ฒŒ์ดํŠธ์›จ์ด ๋ถ™์ด๋Š” ๊ฒƒ์€ ๋‹ค์Œ์— ์ž‘์„ฑํ•ด์•ผ์ง€.