Skip to content

prography/6th-nodejs-study

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

56 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

nodejs study

ํ”„๋กœ๊ทธ๋ผํ”ผ 6๊ธฐ nodejs ์Šคํ„ฐ๋”” ๋ ˆํฌ์ž…๋‹ˆ๋‹ค. ์ด ์Šคํ„ฐ๋””๋Š” Typescript์™€ express๋ฅผ ํ™œ์šฉํ•œ ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ œ์ž‘์„ ๋ชฉํ‘œ๋กœ ํ•˜๋Š” ์„œ๋ฒ„ ๊ธฐ์ดˆ ์Šคํ„ฐ๋””์ž…๋‹ˆ๋‹ค. node ๋ฒ„์ ผ์€ latest LTS์ธ v12(์ž‘์„ฑ์ผ ๊ธฐ์ค€ v12.16.1)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ปดํ“จํ„ฐ์— ์—†๋‹ค๋ฉด ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด์˜ค๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์„ค์น˜ ๋ฐฉ๋ฒ•์€ ๊ฐ OS๋ณ„๋กœ ๋‹ค๋ฅด๋‹ˆ nodejs ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€์—์„œ ํ™•์ธํ›„์— ์„ค์น˜ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์—๋””ํ„ฐ๋Š” ๊ตญ๋ฃฐ vscode๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Table of contents

  1. ๊ฐœ๋ฐœํ™˜๊ฒฝ ์…‹ํŒ…ํ•˜๊ธฐ

    1. Typescript
    2. js์™€ ts ๋น„๊ต
    3. lint
    4. ํ…Œ์ŠคํŠธ(jest)
  2. ์„œ๋ฒ„

    1. ์„œ๋ฒ„ ๋งŒ๋“ค๊ธฐ
    2. e2e ํ…Œ์ŠคํŠธ
  3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉํ•˜๊ธฐ

    1. prisma
    2. CRUD ๊ฐœ๋ฐœ
    3. e2e ํ…Œ์ŠคํŠธ
  4. ๋„์ปค๋กœ ์˜ฌ๋ ค๋ณด๊ธฐ

    1. ๊ฐ€์ƒํ™”์™€ ๋„์ปค์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ธฐ
    2. ๋„์ปค ๊ธฐ์ดˆ ์‹ค์Šต
      1. Dockerfile ์ž‘์„ฑ
      2. ์ด๋ฏธ์ง€ ๋นŒ๋“œํ•˜๊ธฐ
      3. ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑํ•˜๊ธฐ
    3. ๋„์ปค ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ํ•œ๋ฒˆ์— ์ผœ๊ณ  ๋„๊ธฐ
      1. docker-compose.yml ์ž‘์„ฑ
  5. ElasticBeanstalk๋กœ ์„œ๋น„์Šค ๋ฐฐํฌํ•˜๊ธฐ

    1. IAM์œผ๋กœ ๊ถŒํ•œ ์ƒ์„ฑํ•˜๊ธฐ
    2. eb cli ์„ค์น˜ํ•˜๊ธฐ
    3. ๋ฐฐํฌํ•˜๊ธฐ

1.๊ฐœ๋ฐœํ™˜๊ฒฝ ์…‹ํŒ…ํ•˜๊ธฐ

NodeJS ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์€ ์‚ฌ์‹ค nodejs๋งŒ ์„ค์น˜ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค.๊ผญ ๋ธ”๋กœ๊ทธ ๋”ฐ๋ผํ•˜๋ฉด ์‹คํ–‰ ์•ˆ๋จ ๋งˆ๋ƒฅ ๋”ฐ๋ผ ์„ค์น˜ํ•˜๋ฉด ๋˜๋”๋ผ. ๋ณด๋‹ค๋Š” ์™œ ์„ค์น˜ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์„ค์น˜๋ฅผ ํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด ์Šคํ„ฐ๋””์—์„œ๋Š” ๊ธฐ๋ณธ node์—์„œ ๋‚˜์•„๊ฐ€ ํƒ€์ž…์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์˜ ์Šคํฌ๋ฆฝํŠธ ์ˆœ์„œ๋Œ€๋กœ Typescript, eslint, jest ๊ฐ๊ฐ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

i.Typescript

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ(Typescript)๋Š” nodejs์—์„œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. javascript ์ฝ”๋”ฉ ์ค‘์—๋Š” ํƒ€์ž…์— ๋Œ€ํ•ด์„œ ์‹ ๊ฒฝ์“ธ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ž์œ ๋ฅผ ๋А๋ผ๋ฉฐ ๋งˆ๊ตฌ๋งˆ๊ตฌ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ž‘์„ฑํ•˜๋‹ค๋ณด๋ฉด ๋Ÿฐํƒ€์ž„์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์žก๋Š” ๋ฐ์— ์—„์ฒญ๋‚œ ์‹œ๊ฐ„์„ ์Ÿ๋Š” ๋Œ€์ฐธ์‚ฌ๋ฅผ ๊ฒฝํ—˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(ํŠนํžˆ ์˜คํƒ€๋กœ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜) ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๋ฉด, ์ฝ”๋“œ ์ž‘์„ฑ ๋‹จ๊ณ„์—์„œ ๋Ÿฐํƒ€์ž„์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž…์ด ์ด๊ฑธ ํ•ด๋ƒ…๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ณต์‹๋ฌธ์„œ์—์„œ ๋ณด๋ฉด static type checker๋ผ๊ณ  ํ‘œํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ ์—ญํ• ์„ ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. Typescript๋ฅผ ๋ฐ›์•„์ฃผ์„ธ์š”. ์„ค์น˜ ํ›„์—๋Š” ์ปดํŒŒ์ผ ์„ค์ • ํŒŒ์ผ์ธ tsconfig.json์„ ์ƒ์„ฑํ•˜๋ฉด ์ค€๋น„๊ฐ€ ๋๋‚ฉ๋‹ˆ๋‹ค.

# typescript ์„ค์น˜
npm i --save-dev typescript

# tsconfig.json ์ดˆ๊ธฐ ํŒŒ์ผ ์ƒ์„ฑ
npx tsc --init

# ์ปดํŒŒ์ผ
npx tsc

์ฝ”๋“œ ์ž‘์—…์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ™•์žฅ์ž์ธ .js ๋Œ€์‹ ์— .ts๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. .ts ํŒŒ์ผ์— ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ ํ›„์— npx tsc ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜๋ฉด .jsํŒŒ์ผ๋กœ ์ปดํŒŒ์ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฅ? ์—ด์‹ฌํžˆ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ์ผ๋Š”๋ฐ ์™œ ๋‹ค์‹œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋Œ์•„๊ฐ€์ฃ ? ํ•˜๊ณ  ์˜๋ฌธ์ ์„ ๋А๋‚„ ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ฝ”๋“œ ์ž‘์„ฑ์— ๋„์›€์„ ์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ณ  ๊ฒฐ๊ตญ ๋Ÿฐํƒ€์ž„์€ nodeJS ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋Œ์•„๊ฐ€์•ผํ•ฉ๋‹ˆ๋‹ค.์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์“ฐ๋‹ค๋ณด๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ชป์ฐพ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•„์ฃผ ์ž˜์•„๋Š” ์„œ๋ฒ„ ํ”„๋ ˆ์ž„์›Œํฌ์ธ express๋ฅผ ์“ธ ๋•Œ๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ชป์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ๋Š” @types/express ๋ฅผ ์„ค์น˜ํ•˜๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. @types/ ๋’ค์— ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ด๋ฆ„์„ ์จ์„œ ๋ฐ›์œผ๋ฉด ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํƒ€์ดํ•‘ ํŒŒ์ผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ดํ•‘ ํŒŒ์ผ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค๋‹ˆ๋‹ค. @types/ ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ณต์‹์ง€์›ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ณด์‹œ๋ฉด๋ฉ๋‹ˆ๋‹ค. ์ตœ๊ทผ์—๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ๋งˆ๋‹ค ํƒ€์ดํ•‘์„ ์ œ๊ณตํ•ด์„œ ๋ฐ›์ง€ ์•Š์•„๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„ํ˜น๊ฐ€๋‹ค ์•„์˜ˆ ํƒ€์ดํ•‘์ด ์ œ๊ณต๋˜์ง€ ์•Š๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์žˆ๋Š”๋ฐ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์‚ฌ์šฉ์‹œ์—๋Š” ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์•ˆ์“ฐ๊ธฐ๋ฅผ ์ ๊ทน ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด, ์ง์ ‘ ํƒ€์ดํ•‘ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. **.d.ts๋ผ๋Š” ๋„ค์ด๋ฐ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํƒ€์ดํ•‘์„ ์ง์ ‘ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€์—์„œ ์ฐพ์•„๋ณด์„ธ์š”.

iii.js์™€ ts ๋น„๊ต

js์™€ ts์˜ ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ๋น„๊ตํ•ด๋ด…๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๊ณ„์‚ฐ๊ธฐ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ธฐ๋ณธ์ ์ธ Calculator ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ™”๋ฉด์— ๊ฒฐ๊ณผ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

class Calculator {
   add(a, b) {
      return a + b;
   }
   privateSubtract(a, b) {
      return a - b;
   }
}

const calculator = new Calculator();
console.log(calculator.add(1, 2)); // 1. ์ •์ƒ ์‹คํ–‰
console.log(calculator.privateSubtract(2, 1)); // 2. ์ •์ƒ ์‹คํ–‰
console.log(calculator.multiply(3, 4)); // 3. ๋Ÿฐํƒ€์ž„์ƒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ - ์—†๋Š” ๋ฉ”์„œ๋“œ
console.log(calculator.add('a', 'b')); // 4. ๋Ÿฐํƒ€์ž„์ƒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ - 'ab' ๋ฆฌํ„ด

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

class Calculator {
   public add(a: number, b: number) {
      return a + b;
   }
   private subtract(a: number, b: number) {
      return a - b;
   }
}

const calculator = new Calculator();
console.log(calculator.add(1, 2)); // 1. ์ •์ƒ ์‹คํ–‰
console.log(calculator.subtract(2, 1)); // 2. ์ฝ”๋“œ์ƒ ์˜ค๋ฅ˜๋กœ ๊ฑธ๋ฆผ - private ๋ฉ”์„œ๋“œ ์ ‘๊ทผ ๋ถˆ๊ฐ€
console.log(calculator.multiply(3, 4)) // 3. ์ฝ”๋“œ์ƒ ์˜ค๋ฅ˜๋กœ ๊ฑธ๋ฆผ - ์—†๋Š” ๋ฉ”์„œ๋“œ
console.log(calculator.add('a', 'b')); // 4. ์ฝ”๋“œ์ƒ ์˜ค๋ฅ˜๋กœ ๊ฑธ๋ฆผ - ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ๋ถˆ์ผ์น˜

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ์ž‘์—…์„ ํ•˜๋ฉด ๊ฐ ๋ฉ”์„œ๋“œ์— ๋ฐ›์„ ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ ‘๊ทผ์ง€์ •์ž(public, private, protected)๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์บก์Аํ™”๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ์ƒ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฏธ๋ฆฌ ์•Œ๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์˜ ์—๋Ÿฌ์œจ์ด ํ˜„์ €ํžˆ ์ค„์–ด๋“œ๋Š” ๊ฒƒ์„ ๊ฒฝํ—˜ํ• ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ ์ฝ”๋”ฉ์„ ์ ‘ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒ ํƒ€์ž…์— ๋Œ€ํ•ด์„œ ์ดํ•ดํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ ํž˜๋“  ์ ๋“ค์ด ์žˆ๊ฒ ์ง€๋งŒ, ์–ด๋А์ •๋„ ์ต์ˆ™ํ•ด์ง€๊ณ ๋‚˜์„œ๋Š” ์ฝ”๋”ฉ์ด ๊ต‰์žฅํžˆ ํŽธํ•ด์ง‘๋‹ˆ๋‹ค.

ii.lint

๋ฏธ๋ฆฌ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ด์ฃผ๋Š” typescript๋„ ์žˆ์ง€๋งŒ, ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ์˜ˆ์˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํˆด๋„ ์žˆ์Šต๋‹ˆ๋‹ค. lint๋Š” ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ทœ์น™์„ ์ •ํ•ด์„œ, ๊ทœ์น™์— ๋งž์ง€ ์•Š์œผ๋ฉด ๋งž์ง€ ์•Š์€ ๊ฒƒ์„ ์•Œ๋ ค์ฃผ๊ฑฐ๋‚˜ npx eslint --fix ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํ•œ๋ฒˆ์— ์ฝ”๋“œ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ ์ž…๋‹ˆ๋‹ค. ์ ฏ๋ธŒ๋ ˆ์ธ ์—๋””ํ„ฐ(์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค, ์ธํ…”๋ฆฌ์ œ์ด ๋“ฑ)์„ ์‚ฌ์šฉํ•˜์‹œ๋Š” ๋ถ„๋“ค์ด๋ผ๋ฉด Ctrl + Alt + L์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.(์ ฏ๋ธŒ๋ ˆ์ธ ์ฝ”๋“œ์Šคํƒ€์ผ์ด ์žˆ์Œ) ์ด ์Šคํ„ฐ๋””์—์„œ๋Š” VSCODE๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, lint๋ฅผ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜๊ฐ€ ํ•„์š”ํ•ฉ๋‚˜๋‹ค. eslint์™€ prettier๋ฅผ ๋ฐ›์•„์ฃผ์„ธ์š”.

# eslint, prettier ์„ค์น˜
npm install --save-dev eslint prettier

# eslint ์ดˆ๊ธฐํ™”
npx eslint --init

# ์ž๋™ ํ”ฝ์Šค
npx eslint --fix

๋งค๋ฒˆ cli ๋ช…๋ น์–ด๋กœ ์ˆ˜์ •ํ•˜๊ธฐ ๊ท€์ฐฎ๋‹ค๋ฉด, vscode ์ต์Šคํ…์…˜์„ ์„ค์น˜ํ•˜์—ฌ ํŒŒ์ผ ์ €์žฅ์‹œ์— ์ž๋™์œผ๋กœ ๋งž์ถœ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

iv.ํ…Œ์ŠคํŠธ(jest)

์ด ์Šคํ„ฐ๋””์—์„œ๋Š” ์ด๋ฏธ ๊ฐœ๋ฐœ๋œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ์•Œ๊ณ  ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ์žฅ์ ์€ ์ฒซ๋ฒˆ์งธ ๋””๋ฒ„๊น…์ด ํ›จ์”ฌ ์šฉ์ดํ•ด์ง‘๋‹ˆ๋‹ค. ํฌ์ŠคํŠธ๋งจ์œผ๋กœ ๋‚ ๋ ค๋ณด๊ณ  ๋ฐ์ดํ„ฐ ํ™•์ธํ•˜๊ณ , ์„œ๋ฒ„ ๋กœ๊ทธ ์ฐ์–ด์„œ ์–ด๋””์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ด์ƒํ•ด์ง€๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ด๋Ÿฐ ๊ณผ์ •์„ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.(console.log ์•ˆ๋…•~) ๋‘˜์งธ๋กœ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ–ˆ์„ ๋•Œ, ์ˆ˜์ •์ด ๋‚ณ๋Š” ๋ฒ„๊ทธ๋ฅผ ๋ง‰์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๋‹ค๋ณด๋ฉด ์ž˜๋˜๋˜ ์ฝ”๋“œ์—์„œ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํ˜„์ƒ์„ ๊ฒฝํ—˜ํ•˜๊ธฐ๋„ ํ•˜๋Š”๋ฐ, ๋ฐฐํฌ ํ•˜๊ธฐ ์ „์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ๋ฒˆ์งธ๋กœ TDD(ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ)์— ๋” ๊ฐ€๊นŒ์›Œ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ข€ ๋” ์ฒ ์ €ํ•œ e2e(์—”๋“œ ํˆฌ ์—”๋“œ, ์„œ๋ฒ„์— ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ํ…Œ์ŠคํŠธ) ํ…Œ์ŠคํŠธ๋ฅผ ๋ฏธ๋ฆฌ ์ž‘์„ฑํ•ด๋‘๊ณ  ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด ํ”„๋ก ํŠธ์—”๋“œ(์•ฑ, ์›น)์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์ด ์–ด๋–ป๊ฒŒ ๋‚˜์˜ค๋Š”์ง€๋ฅผ ๋ฏธ๋ฆฌ ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋ก ํŠธ์—์„œ ์„œ๋ฒ„๊ฐ€ ์™„์„ฑ๋˜๊ธฐ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฐœ๋ฐœ ๊ณต๋ฐฑ์„ ์—†์•จ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šคํ„ฐ๋””์—์„œ๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ํŽ˜์ด์Šค๋ถ์—์„œ ๊ฐœ๋ฐœํ•œ jest๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

# jest, ts-jest ์„ค์น˜
npm install --save-dev jest ts-jest

# jest.config.js ํŒŒ์ผ ์ƒ์„ฑ
npx jest --init

jest.config.js ํŒŒ์ผ์— ts-jest ์„ค์ •์„ ํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ, ์ด ํŒŒ์ผ์„ ๋ณด๊ณ  ์ˆ˜์ •ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. tests ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ…Œ์ŠคํŠธ ํŒŒ์ผ์„ ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค. tests/Calculator.spec.ts์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

import { Calculator } from '../src/Calculator';

describe('test start', () => {
  const calculator = new Calculator();
  test('calculator.add', () => {
    expect(calculator.add(1, 2)).toBe(3);
  });
});

์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด ๋ณด์„ธ์š”

# test ์‹คํ–‰
npx jest

๋ช…๋ น์–ด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ…Œ์ŠคํŠธ๋ฅผ vscode์—์„œ ๋ฒ„ํŠผ์œผ๋กœ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. vscode์—์„œ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์ •์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. .vscode/launch.json ๋ฅผ ๋งŒ๋“ค๊ณ  ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ์„ธ์š”.

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest All test files",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": ["--runInBand"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
      "windows": {
        "program": "${workspaceFolder}/node_modules/jest/bin/jest",
      },
    }, {
      "type": "node",
      "request": "launch",
      "name": "Jest Current File",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": [
        "${fileDirname}/${fileBasenameNoExtension}",
        "--config",
        "jest.config.js"
      ],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
      "windows": {
        "program": "${workspaceFolder}/node_modules/jest/bin/jest",
      },
    }
  ]
}

ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋Š” ์ด๊ฒƒ ๋ง๊ณ ๋„ ๊ต‰์žฅํžˆ ๋‹ค์–‘ํ•˜๊ฒŒ ์žˆ๋Š”๋ฐ, ๋” ๊ถ๊ธˆํ•˜๋‹ค๋ฉด jest ํ™ˆํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”


2.์„œ๋ฒ„

์ด์ œ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํƒ€์ž…์„ ์ผ์„ ๋•Œ ๋„์›€์ด ๋งŽ์ด ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ๋ฐ›์•„์ฃผ์„ธ์š”

npm i --save express reflect-metadata routing-controllers class-validator class-transformer
npm i --save-dev @types/express

i.์„œ๋ฒ„ ๋งŒ๋“ค๊ธฐ

routing-controllers๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋”ฐ๋ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

src/app.ts

import express from 'express';
import { useExpressServer } from 'routing-controllers';

const app = express();

useExpressServer(app, {
  controllers: [`${__dirname}/controllers/**`]
})

export {
  app
}

src/index.ts

import { app } from './app';

app.listen(3000, () => {
  console.log(`server is running on ${3000}`);
})

src/controllers/TodoController.ts

import { BaseController } from './BaseController';
import { JsonController, Get, Param } from 'routing-controllers';

@JsonController('/todos')
export class TodoController extends BaseController {
  @Get()
  public index() {
    return [
      {
        id: 1,
        title: 'first task',
        description: 'create express app'
      }
    ]
  }

  @Get('/:todoId')
  public retrieve(@Param('todoId') todoId: number) {
    return {
      id: todoId,
      title: 'new todo title',
      description: 'todo description',
    }
  }
}

npx tsc && node dist๋ฅผ ํ†ตํ•ด์„œ ์„œ๋ฒ„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ii.e2e ํ…Œ์ŠคํŠธ

์ด์ œ ๋งŒ๋“ค์–ด์ง„ ์„œ๋ฒ„๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค. jest ํ™˜๊ฒฝ์— ๋”๋ถˆ์–ด์„œ supertest ๋ฅผ ์„ค์น˜ํ•˜์—ฌ ์„œ๋ฒ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

npm i --save supertest
npm i --save-dev @types/supertest

tests/features/Todo.spec.ts

import supertest from 'supertest';
import { app } from '../../src/app';

describe('test Todo', () => {
  const client = supertest(app);

  test('test index todos', async () => {
    const response = await client.get('/todos');
    // ๊ธฐ๋ณธ ์ƒํƒœ์ฝ”๋“œ๋กœ ํ…Œ์ŠคํŠธ
    expect(response.status).toBe(200);
    // ์‘๋‹ต ๋‚ด์šฉ์ด ๋ฐฐ์—ด์ธ์ง€ ๊ตฌ๋ถ„ํ•˜๋Š” ํ…Œ์ŠคํŠธ
    expect(Array.isArray(response.body)).toBe(true);
  })
})

์œ„์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ๋ณด๋ฉด ์„œ๋ฒ„๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜๋Š” ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ข€๋” deepํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ๋‹ค๋ฉด, ์‘๋‹ต์˜ ๋‚ด์šฉ์— ์›ํ•˜๋Š” ํ‚ค๊ฐ’์ด ์ž˜ ๋“ค์–ด ์žˆ๋Š”์ง€ ํŒ๋‹จํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

tests/features/Todo.spec.ts

import supertest from 'supertest';
import { app } from '../../src/app';

// ํ‚ค๊ฐ’์ด ๋ชจ๋‘ ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑ
const assertItem = (item) => {
  const expectedKeys = ['id', 'title', 'description'];
  Object.keys(item).forEach((key) => {
    const idx = expectedKeys.indexOf(key);
    if (idx > -1) {
      expectedKeys.splice(idx, 1);
    }
  })
  expect(expectedKeys).toBe([]);
}

describe('test Todo', () => {
  const client = supertest(app);

  test('test index todos', async () => {
    const response = await client.get('/todos');
    expect(response.status).toBe(200);
    expect(Array.isArray(response.body)).toBe(true);
    // ๋ฐฐ์—ด ๋‚ด์˜ ๋ชจ๋“  ์•„์ดํ…œ์— ๋Œ€ํ•˜์—ฌ ๊ฒ€์‚ฌ
    for (const item of response.body) {
      assertItem(item);
    }
  })
})

์—ฌ๊ธฐ๊นŒ์ง€ ์„œ๋ฒ„๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค.

3.๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉํ•˜๊ธฐ

์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค๋ฉด ํด๋ผ์ด์–ธํŠธ(ํ”„๋ก ํŠธ)์™€ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ ํ†ต์‹ ์ด ์˜ค๊ฐ€์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ์ €์žฅํ•ด์•ผ๋˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ๊ธฐ๋Š”๋ฐ ์ €์žฅ์„ ์œ„ํ•ด์„œ Mysql, MariaDB, Postgres, MongoDB ๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ์ €์žฅ๊ณผ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰์ด ์šฉ์ดํ•ด ์ง‘๋‹ˆ๋‹ค. ๋ชฉ์ ์— ๋”ฐ๋ผ์„œ RDB ๋˜๋Š” NoSQL์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ณ , ์ฟผ๋ฆฌ๋ฅผ ํŽธํ•˜๊ฒŒ ์“ฐ๊ธฐ ์œ„ํ•ด์„œ ORM์„ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šคํ„ฐ๋””์—์„œ๋Š” ORM์€ ์•„๋‹ˆ์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉ์ด ์šฉ์ดํ•œ prisma๋ฅผ ๋‹ค๋ค„๋ด…๋‹ˆ๋‹ค.

i.prisma

๋‹ค์Œ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด๋ด…๋‹ˆ๋‹ค.

prisma๋Š” ํŠน์ดํ•˜๊ฒŒ ์•„๋ž˜์ฒ˜๋Ÿผ ๋‘๊ฐœ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆด ๋”ฐ๋กœ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

npm install --save-dev @prisma/cli
npm install --save @prisma/client

์ด์ œ ๋ชจ๋ธํŒŒ์ผ์„ ๋งŒ๋“ค์–ด๋ด…๋‹ˆ๋‹ค. url์— ๋“ค์–ด๊ฐ€๋Š” ๋‚ด์šฉ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ uri schema๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. mysql://{ID}:{PASSORD}@{ENDPOINT}/{DATABASE} ์˜ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์œ„์˜ url์„ ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

datasource mysql {
  url      = env("DB_URL")
  provider = "mysql"
}

generator client {
  provider = "prisma-client-js"
}

model Todo {
  id          Int      @default(autoincrement()) @id
  createdAt   DateTime @default(now()) @map("created_at")
  updatedAt   DateTime @map("updated_at") @updatedAt
  title       String
  description String?

  @@map("todos")
}

prisma๋Š” .prisma ํ˜•์‹์˜ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ๋ชจ๋ธ์„ ๊ด€๋ฆฌํ•˜๊ณ  npx prisma migrate save๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ , npx prisma migrate up ๊ณผ npx prisma migrate down ์œผ๋กœ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋ธ ํŒŒ์ผ(.prisma)์ด ์ •์˜ ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์—์„œ npx prisma generate ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ๋ชจ๋ธ ํƒ€์ดํ•‘์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ ‘๊ทผํ•˜๋Š” ํƒ€์ดํ•‘์ด ์ƒ์„ฑ๋˜์–ด์„œ ์ฝ”๋”ฉ์ด ํŽธํ•ด์ง‘๋‹ˆ๋‹ค.

์•„๋ž˜ ์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const client = new PrismaClient();
await client.todo.create({
  data: {
    title: 'New Todo Item',
    description: 'do something!'
  },
});

ii.CRUD ๊ฐœ๋ฐœ

import { BaseController } from './BaseController';
import {
  JsonController,
  Get,
  Param,
  Post,
  BodyParam,
  Put,
  Delete,
} from 'routing-controllers';
import { PrismaClient } from '@prisma/client';

@JsonController('/todos')
export class TodoController extends BaseController {
  private client: PrismaClient;

  constructor() {
    super();
    this.client = new PrismaClient();
  }

  @Get()
  public index() {
    return this.client.todo.findMany();
  }

  @Get('/:todoId')
  public retrieve(@Param('todoId') todoId: number) {
    return this.client.todo.findOne({ where: { id: Number(todoId) } });
  }

  @Post()
  public async create(
    @BodyParam('title') title: string,
    @BodyParam('description') description: string
  ) {
    return this.client.todo.create({
      data: {
        title,
        description,
      },
    });
  }

  @Put('/:todoId')
  public async update(
    @Param('todoId') todoId: number,
    @BodyParam('title') title: string,
    @BodyParam('description') description: string
  ) {
    return this.client.todo.update({
      where: { id: Number(todoId) },
      data: {
        title,
        description,
      },
    });
  }

  @Delete('/:todoId')
  public async delete(@Param('todoId') todoId: number) {
    return this.client.todo.delete({ where: { id: Number(todoId) } });
  }
}

iii.e2e ํ…Œ์ŠคํŠธ

์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ์ด ์ž˜ ๋˜์—ˆ๋Š”์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋„ฃ์—ˆ์„ ๋•Œ, ์‹ค์ œ๋กœ ๋””๋น„์— ์ €์žฅ์ด ๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import supertest from 'supertest';
import { app } from '../../src/app';
import { PrismaClient } from '@prisma/client';

describe('test Todo', () => {
  const client = supertest(app);
  test('test index todos', async () => {
    const response = await client.get('/todos');
    expect(response.status).toBe(200);
    const actual = await new PrismaClient().todo.findOne({
      where: { id: Number(response.body.id) },
    });
    expect(actual.description).toBe(response.body.description);
    expect(actual.title).toBe(response.body.title);
  });
});

4.๋„์ปค๋กœ ์˜ฌ๋ ค๋ณด๊ธฐ

i.๊ฐ€์ƒํ™”์™€ ๋„์ปค์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ธฐ

์–•์€์ง€์‹์œผ๋กœ ์“ฐ๋Š” ๊ฒƒ๋ณด๋‹จ ์ž˜ ์„ค๋ช…๋˜์–ด ์žˆ๋Š” ๋ธ”๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ•™์Šต์„ ํ•˜๋ฉด ์ข€๋” ํŽธํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ฐ€์ƒํ™˜๊ฒฝ์ด๋ž‘ ์ดํ•ดํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ™์€๋ฐ, ์šฐ๋ฆฌ๋Š” ์•„๋ž˜ 3๊ฐ€์ง€๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  1. Dockerfile ์ž‘์„ฑ
  2. ๋„์ปค ์ด๋ฏธ์ง€ ์ƒ์„ฑ
  3. ๋„์ปค ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ

ii.๋„์ปค ๊ธฐ์ดˆ ์‹ค์Šต

a.Dockerfile ์ž‘์„ฑ

์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋„์ปคํŒŒ์ผ ๋ช…๋ น์–ด๋“ค์ด ์žˆ๋‹ค. ๋‚ด์šฉ์€ ๋„์ปค ๋„ํ๋จผํŠธ๋‚ด์—์„œ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. Dockerfile best practice์„ ์“ฐ์œฝ ์ฝ์–ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

์ด ์Šคํ„ฐ๋””์—์„œ ์ž‘์„ฑํ•œ ๋„์ปคํŒŒ์ผ์„ ๋ณด์ž

# ์€ ์ฃผ์„์„ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

# ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„ํ•œ๋‹ค. node ๋ฒ„์ ผ 12๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›๋Š”๋‹ค.
FROM node:12

# ๋„์ปคํŒŒ์ผ ๋‚ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ณ€์ˆ˜ ์„ ์–ธ
ARG PROJECT_PATH=/web/service/api

# ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ด๋ฏธ์ง€๋กœ ํŒŒ์ผ ๋ณต์‚ฌ
COPY package.json ${PROJECT_PATH}/package.json
COPY package-lock.json ${PROJECT_PATH}/package-lock.json

# ๋ช…๋ น์–ด๋ฅผ ๊ธฐ๋ณธ ์‹คํ–‰ํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€ ๊ฒฝ๋กœ ์„ค์ •(์•„๊นŒ ARG๋กœ ์„ค์ •ํ•œ ๋‚ด์šฉ์„ ์“ด๋‹ค)
WORKDIR ${PROJECT_PATH}

# ๋ช…๋ น์–ด ์‹คํ–‰
RUN npm install

# ํ”„๋กœ์ ํŠธ ํŒŒ์ผ ๋ณต์‚ฌ(ADD์™€ COPY ๋‘๊ฐ€์ง€ ๋ช…๋ น์–ด๊ฐ€ ๋ณต์‚ฌ๋ผ๋Š” ์—ญํ• ์„ ํ•˜๋Š”๋ฐ ๋‘˜์˜ ์ฐจ์ด๋Š” ๋ฌธ์„œ์—์„œ ํ™•์ธํ•ด๋ณด์ž)
COPY . ${PROJECT_PATH}

# ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ
RUN npm run build

# ๋„์ปค ์™ธ๋ถ€์— ๋ณด์—ฌ์ค„ ์ด ์ปดํ“จํ„ฐ๊ฐ€ ์ œ๊ณตํ•  ํฌํŠธ ์ •์˜
EXPOSE 3000

# ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹คํ–‰ ๋  ๋•Œ ์ฒ˜์Œ์— ์‹คํ–‰ํ•  ๋ช…๋ น์–ด ์ •์˜ ๊ฐ™์€ ์—ญํ• ์„ ํ•˜๋Š” ENTRYPOINT๊ฐ€ ์žˆ๋‹ค. ๋ฌธ์„œ์—์„œ ๋‘˜์˜ ์ฐจ์ด๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ฐพ์•„๋ณด์ž
CMD ["npm", "start"]

b.์ด๋ฏธ์ง€ ๋นŒ๋“œํ•˜๊ธฐ

์œ„์—์„œ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋“œ๋Š” docker build๋ผ๋Š” ๋ช…๋ น์–ด๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

docker build -t {ํƒœ๊ทธ} {Dockerfile ๊ฒฝ๋กœ}

ํƒœ๊ทธ๋Š” ์ด๋ฏธ์ง€์— ๋ถˆํž ์ด๋ฆ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€ ์ด๋ฆ„ + ๋ฒ„์ ผ์œผ๋กœ๋„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. simple-server:latest, simple-server:2 ๋“ฑ๋“ฑ ์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด๋ฏธ์ง€ ์ด๋ฆ„๊ณผ ๋ฒ„์ ผ์œผ๋กœ ๋ฒ„์ ผ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€ ์ด๋ฆ„์„ ์•ˆ์“ฐ๋Š” ๊ฒฝ์šฐ ๋ฌด์ž‘์œ„ ์ด๋ฆ„์„ ์ง€์–ด์ค๋‹ˆ๋‹ค.

ex)

docker build -t simple-server .

c.์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑํ•˜๊ธฐ

์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ์€ run์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡๊ฐ€์ง€ ์˜ต์…˜์„ ์•Œ์•„๋‘๋ฉด ๋„์›€์ด ๋˜๊ฒ ๋‹ค.

  • --rm: ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊บผ์ง€๋ฉด ๋ฐ”๋กœ ์‚ญ์ œํ•˜๋Š” ์˜ต์…˜
  • -v, --volume: ์ปจํ…Œ์ด๋„ˆ์˜ ๋””๋ ‰ํ† ๋ฆฌ์™€ ์ปดํ“จํ„ฐ์˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์˜ต์…˜, ํ™˜๊ฒฝ์€ ์ปจํ…Œ์ด๋„ˆ, ํŒŒ์ผ์€ ์ปดํ“จํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. -v {์ปดํ“จํ„ฐ ๊ฒฝ๋กœ}:{์ปจํ…Œ์ด๋„ˆ ๊ฒฝ๋กœ}
  • -p, --publish: ์ปจํ…Œ์ด๋„ˆ์˜ ํฌํŠธ์™€ ์ปดํ“จํ„ฐ์˜ ํฌํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์˜ต์…˜, -p {์ปดํ“จํ„ฐ ํฌํŠธ}:{์ปจํ…Œ์ด๋„ˆ ํฌํŠธ}
  • --entrypoint: ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰์‹œ ๊ธฐ์กด์— Dockerfile์— ์ •์˜๋œ CMD๋‚˜ ENTRYPOINT๋ฅผ Overriding ํ•˜๋Š” ์˜ต์…˜, ์‹ค์ œ ์„œ๋ฒ„ ์‹คํ–‰์„ ์•ˆํ•˜๊ณ  ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • --name: ์ปจํ…Œ์ด๋„ˆ์— ์ด๋ฆ„์„ ๋ถ™์ด๋Š” ์˜ต์…˜
  • -it: ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ํ„ฐ๋ฏธ๋„๋กœ ์ธํ„ฐ๋ž™์…˜(๋กœ๊ทธ ํ™•์ธ ๋“ฑ) ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • -d: -it์˜ ๋ฐ˜๋Œ€, detached ์˜ต์…˜, ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ๋งŒ ๋Œ์•„๊ฐ€๋„๋ก ์„ค์ •ํ•œ๋‹ค.
  • --link: ์ด๋ฏธ ์ž‘๋™์ค‘์ธ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์— ์—ฐ๊ฒฐํ•˜๋Š” ์˜ต์…˜, ์ด ์˜ต์…˜์ด ์—†์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ๋“ค ๋ผ๋ฆฌ ์—ฐ๊ฒฐ์ด ์•ˆ๋œ๋‹ค.
docker run {image-name}

ex)

docker run -it \
-p 3000:3000 \
-v (PWD):/web/service/api \
--name simple-container \
simple-server

์ดํ›„์— ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ผœ๊ณ  ๋„๋ ค๋ฉด

# ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ ๋ชฉ๋ก
docker ps

# ๋ชจ๋“  ์ปจํ…Œ์ด๋„ˆ ๋ชฉ๋ก
docker ps -a

# ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ(๊ฐ€์ƒ ์ปดํ“จํ„ฐ ์ข…๋ฃŒ)
docker stop {์ปจํ…Œ์ด๋„ˆ ID ๋˜๋Š” ์ด๋ฆ„}

# ์ปจํ…Œ์ด๋„ˆ ์‹œ์ž‘(๊ฐ€์ƒ ์ปดํ“จํ„ฐ ์‹คํ–‰)
docker start {์ปจํ…Œ์ด๋„ˆ ID ๋˜๋Š” ์ด๋ฆ„}

# ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹œ์ž‘
docker restart {์ปจํ…Œ์ด๋„ˆ ID ๋˜๋Š” ์ด๋ฆ„}

# ์ปจํ…Œ์ด๋„ˆ ์‚ญ์ œ
docker rm {์ปจํ…Œ์ด๋„ˆ ID ๋˜๋Š” ์ด๋ฆ„}

iii.๋„์ปค ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ํ•œ๋ฒˆ์— ์ผœ๊ณ  ๋„๊ธฐ

๋„์ปค ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ํ•œ๋ฒˆ์— ์ผœ๊ณ  ๋Œ ์ˆ˜ ์žˆ๋‹ค. docker-compose.yml์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋Šฅํ•œ๋‹ค. ์Šคํƒ์ด๋‚˜ ํŒŸ์„ ๋งŒ๋“ค์–ด๋„ ๊ฐ€๋Šฅํ•œ๋ฐ ์ดˆ๋ณด์ž์˜ ์ž…์žฅ์—์„  ์ด๊ฒƒ๋งŒ์œผ๋กœ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ --link ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ์ปจํ…Œ์ด๋„ˆ๋“ค ๋ผ๋ฆฌ ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•œ๋ฐ, ์ปจํ…Œ์ด๋„ˆ์˜ ์ข…์†์„ฑ์ด ๊ผฌ์ด๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ๋„์ปค ๋„คํŠธ์›Œํฌ๋ฅผ ๋งŒ๋“ค๊ณ  ํ•˜๋‚˜์˜ ๋„คํŠธ์›Œํฌ์— ์ปจํ…Œ์ด๋„ˆ๋“ค์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด ๋‹ค๋ฅธ ์„ค์ •์„ ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ์ปจํ…Œ์ด๋„ˆ๋ผ๋ฆฌ ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

a.docker-compose.yml ์ž‘์„ฑ

docker-comnpose.yml ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ์ˆ˜์ •ํ•ด์„œ ์จ๋ณด์„ธ์š”

# docker-compose ๋ฒ„์ ผ
version: "3.7"

# ์ปจํ…Œ์ด๋„ˆ ๋ชฉ๋ก
services:
  # ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์ง์ ‘ ๊ณ ๋ฅด๋ฉด ๋œ๋‹ค.
  db:
    # ์ปจํ…Œ์ด๋„ˆ์— ์‚ฌ์šฉํ•  ์ด๋ฏธ์ง€
    image: mysql:latest
    # ํฌํŠธ ์—ฐ๊ฒฐ ์„ค์ •
    ports:
      - 3306:3306
    # ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰์‹œ์— ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉ
    environment:
      MYSQL_ROOT_PASSWORD: 1016
      MYSQL_DATABASE: sample
    # ์žฌ์‹œ์ž‘ํ•˜๋Š” ์กฐ๊ฑด
    restart: on-failure
    # ์ปจํ…Œ์ด๋„ˆ์— ์—ฐ๊ฒฐํ•  ๋ณผ๋ฅจ ์—ฐ๊ฒฐ
    volumes:
      - ./db/conf.d:/etc/mysql/conf.d
      - ./db/data:/var/lib/mysql
    # ๋„คํŠธ์›Œํฌ ์„ค์ •
    networks:
      default:
        ipv4_address: 172.16.2.2

  server:
    # ์ปจํ…Œ์ด๋„ˆ์— ์‚ฌ์šฉํ•  Dockerfile์ด ์žˆ๋Š” ๊ฒฝ๋กœ, image ๋Œ€์‹ ์— ์“ฐ๋ฉด, ์—†๋Š” ๊ฒฝ์šฐ ์ด๋ฏธ์ง€๋ฅผ ์ž๋™์œผ๋กœ ๋นŒ๋“œํ•˜๊ณ  ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
    build: .
    ports:
      - 3000:3000
    environment:
      HOST: 0.0.0.0
      PORT: 3000
      DB_URL: mysql://root:[email protected]/sample
    # ๊ธฐ๋ณธ์ ์œผ๋กœ ์จ์žˆ๋Š” CMD๋‚˜ ENTRYPOINT์— ๋ฎ์–ด์“ธ ๋‚ด์šฉ
    entrypoint: "npm run dev"
    networks:
      default:
        ipv4_address: 172.16.2.3

networks:
  default:
    driver: bridge
    ipam:
      config:
        - subnet: 172.16.2.0/24

์œ„์˜ ํŒŒ์ผ์€ ๋”ฐ์ง€๊ณ  ๋ณด๋ฉด docker run ๋ช…๋ น์–ด๋ฅผ ํ…์ŠคํŠธ๋กœ ์ž‘์„ฑํ•ด๋’€๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. ์ด์ œ ์ด ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์†์‰ฌ์šด ๋ช…๋ น์–ด๋กœ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ผœ๊ณ  ๋Œ ์ˆ˜ ์žˆ๋‹ค.

# ์ด๋ฏธ์ง€๊ฐ€ ์—†๋‹ค๋ฉด ๋นŒ๋“œํ›„ ๋จผํ…Œ์ด๋„ˆ ์˜คํ”ˆ(docker-compose.yml ํŒŒ์ผ์— ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ปจํ…Œ์ด๋„ˆ ์žฌ ์ƒ์„ฑ)
docker-compose up -d(detached ์˜ต์…˜, ์ด๊ฒŒ ์—†์œผ๋ฉด ์„œ๋ฒ„์™€ ๋””๋น„ ๋ชจ๋‘ ์ฝ˜์†”์ด ์ผœ์ง„ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.)

# ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ ํ›„ ์ปจํ…Œ์ด๋„ˆ ์‚ญ์ œ, ์ด๋ฏธ์ง€ ์‚ญ์ œ๋Š” ์•„๋‹˜!(build ์˜ต์…˜์˜ ๊ฒฝ์šฐ์—๋งŒ)
docker-compose down

# ์ปนํ…Œ์ด๋„ˆ๋งŒ ์ผœ๊ณ  ๋„๊ณ  ์žฌ์‹œ์ž‘
docker-compose start
docker-compose stop
docker-compose restart

# ์ด๋ฏธ์ง€ ๋นŒ๋“œ๋งŒ ์‹คํ–‰
docker-compose build

์ด๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ex)

docker-compose up -d

5.ElasticBeanstalk๋กœ ์„œ๋น„์Šค ๋ฐฐํฌํ•˜๊ธฐ

์•„๋งˆ์กด์—์„œ ์ œ๊ณตํ•˜๋Š” ElasticBeanstalk๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐฐํฌ๋ฅผ ํ•œ๋‹ค. ์™œ ์ด๊ฑธ ์“ฐ๋ƒ๋ฉด, ec2 ์ธ์Šคํ„ด์Šค ๋ฐ›๊ณ  ๊ฐœ๋ฐœํ™˜๊ฒฝ ์„ค์ •ํ•˜๊ณ  ํ„ฐ๋ฏธ๋„๋กœ ์ ‘์†ํ•ด์„œ ์„œ๋ฒ„ ์‹คํ–‰ ํ•˜๊ณ ๋ฅผ ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋‚ด ์ปดํ“จํ„ฐ์˜ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ํ„ฐ๋ฏธ๋„ ์ปค๋งจ๋“œ ํ•˜๋‚˜๋งŒ๋กœ ๋ฐฐํฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„ˆ๋ฌด ํŽธํ•ด์„œ ์“ด๋‹ค.

i.IAM์œผ๋กœ ๊ถŒํ•œ ์ƒ์„ฑํ•˜๊ธฐ

eb๋Š” ์•„๋งˆ์กด์˜ ์ฝ˜์†”์—์„œ๋„ ์ƒ์„ฑํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ cli๋กœ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” IAM ๊ถŒํ•œ์ด ํ•„์š”ํ•˜๋‹ค. ๊ถŒํ•œ์„ ์œ„ํ•ด ์‚ฌ์šฉ์ž ์„ค์ •์„ ํ•ด๋ณด์ž

  1. IAM ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ ๋ฒ„ํŠผ ํด๋ฆญ IAM ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ ๋ฒ„ํŠผ ํด๋ฆญ

  2. IAM ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ์ ‘๊ทผ ๋ฐฉ์‹ ์ •์˜ IAM ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ์ ‘๊ทผ ๋ฐฉ์‹ ์ •์˜

  3. ElasticBeanstalkFullAccess ๊ถŒํ•œ ์ถ”๊ฐ€ ElsaticBeanstalkFullAccess ๊ถŒํ•œ ์ถ”๊ฐ€

  4. IAM ์‚ฌ์šฉ์ž ํƒœ๊ทธ(์˜ต์…˜) IAM ์‚ฌ์šฉ์ž ํƒœ๊ทธ

  5. IAM ์‚ฌ์šฉ์ž ๋“ฑ๋ก ์™„๋ฃŒ IAM ์‚ฌ์šฉ์ž ๋“ฑ๋ก ์™„๋ฃŒ

  6. ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ ์™„๋ฃŒ - aws-access-key ์™€ aws-secret-key๋ฅผ ๊ธฐ์–ตํ•ด๋‘์ž(๋ณต์‚ฌ๋ฅผ ํ•ด๋„ ๋˜๊ณ , csv ํŒŒ์ผ์„ ๋ฐ›์•„์„œ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค) AccessKey์™€ SecretKey๋ฅผ ํ™•์ธํ•˜๋Š” ํ™”๋ฉด

ii.eb cli ์„ค์น˜ํ•˜๊ธฐ

eb cli๋ฅผ ๋กœ์ปฌํ™˜๊ฒฝ์—์„œ ์„ค์น˜ํ•˜๋ ค๋ฉด eb cli ํ”„๋กœ๊ทธ๋žจ ์„ค์น˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์„ค์น˜ํ• ๋•Œ๋Š” pip๋ฅผ ์ด์šฉํ•˜๋Š”๊ฒŒ ์ •์‹ ๊ฑด๊ฐ•์— ์ด๋กญ๋‹ค. ๋‚˜๋Š” ์ฃฝ์–ด๋„ ํŒŒ์ด์ฌ์„ ์„ค์น˜ํ•˜๊ธฐ ์‹ซ๋‹ค๋ฉด, ํŒŒ์ด์ฌ์šฉ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์„ค์ •์„ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. (์ฐธ๊ณ )

  1. ebcli ์„ค์น˜ pip๋ฅผ ์ด์šฉํ•œ ebcli ์„ค์น˜

iii.๋ฐฐํฌํ•˜๊ธฐ

  1. eb init์œผ๋กœ ๊ถŒํ•œ ์„ค์ • eb init์œผ๋กœ ๊ถŒํ•œ ์„ค์ •

  2. IAM์—์„œ ํ™•์ธํ•œ aws-access-key ์™€ aws-secret-key๋ฅผ ์ ๋Š”๋‹ค. eb init์œผ๋กœ ๊ถŒํ•œ ์„ค์ •2

  3. ๋ฐฐํฌํ• ๋•Œ ํ•„์š”ํ•œ ํŒŒ์ผ ์„ค๋ช…

    • .ebextensions/**: ๋ฐฐํฌ์‹œ ํ•„์š”ํ•œ ํ™˜๊ฒฝ ์„ค์ •์„ ๊ด€๋ฆฌํ•˜๋Š” ํŒŒ์ผ. ํ™˜๊ฒฝ๋ณ€์ˆ˜(git์— ํฌํ•จ๋˜๋ฉด ์•ˆ๋œ๋‹ค)์™€ timezone, ๋ชจ๋‹ˆํ„ฐ๋ง, ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ ๋“ฑ๋“ฑ
    • Dockerrun.aws.json: ๋„์ปค ์‹คํ–‰์‹œ ํ•„์š”ํ•œ ๋‚ด์šฉ ์ •์˜(docker-compose.yml ์ฒ˜๋Ÿผ ์‹คํ–‰์‹œ ์‚ฌ์šฉํ•  port, volume, ๋กœ๊น…, ์‹œ์ž‘ ๋ช…๋ น์–ด ๋“ฑ์„ ์ •์˜) - ์ฐธ๊ณ : aws๋ฌธ์„œ - ๋‹จ์ผ ์ปจํ…Œ์ด๋„ˆ Docker ๊ตฌ์„ฑ
    • .ebignore: ๋ฐฐํฌ์‹œ ์ œ์™ธ ์‹œํ‚ฌ ํŒŒ์ผ์„ ์ •์˜, ์ˆจ๊น€ํŒŒ์ผ(.์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŒŒ์ผ ๋˜๋Š” ํด๋”) ๋‚ด์šฉ์€ ์—…๋กœ๋“œ๊ฐ€ ์•ˆ๋˜๋Š”๋ฐ, .ebextensions ๋‚ด์šฉ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด .ebignore์— ๋“ฑ๋ก๋œ ๋‚ด์šฉ์„ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ํฌํ•จ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
  4. eb create๋กœ ์ฒซ ๋ฐฐํฌ eb init์œผ๋กœ ๊ถŒํ•œ ์„ค์ •2

  5. ๋‹ค์‹œ ๋ฐฐํฌํ•  ๋•Œ๋Š” eb deploy๋ฅผ ์“ฐ๋ฉด ๋œ๋‹ค.

  6. ์‚ญ์ œ์‹œ์—๋Š” eb teminate๋ฅผ ์“ฐ๋ฉด ๋œ๋‹ค.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors