์ƒˆ์†Œ์‹

Js/express

ํ•œ๊ธ€๋ช…์–ธ OPEN API ๊ธฐ์ˆ  ์„ค๋ช…์„œ

  • -

๐ŸŒŸ ํ•œ๊ธ€๋ช…์–ธ OPEN API ๊ธฐ์ˆ ์„ค๋ช…์„œ

๋ณธ ๋ฌธ์„œ๋Š” ํ•œ๊ธ€๋ช…์–ธ OPEN API ํ”„๋กœ์ ํŠธ์˜ ์ „๋ฐ˜์ ์ธ ์‹œ์Šคํ…œ ๊ตฌ์„ฑ, ์‚ฌ์šฉ ๊ธฐ์ˆ (๋ฒ„์ „ ํฌํ•จ), ๋ชจ๋“ˆ๋ณ„ ์—ญํ• , ์‹คํ–‰ ๋ฐฉ๋ฒ•, ๋ฐฐํฌ ํ™˜๊ฒฝ, ๊ด€๋ จ ๋งํฌ ์ •๋ณด ๋ฐ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์„ค์ •์— ๊ด€ํ•œ ์„ค๋ช…์„œ์ž…๋‹ˆ๋‹ค.


1. ๊ฐœ์š”

api key๋‚˜ ๋ณต์žกํ•œ ์ธ์ฆ ํ•„์š”์—†์ด ํ•œ๊ธ€๋กœ ๋ฒˆ์—ญํ•œ ๋ช…์–ธ์„ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ๋Š” OPEN API ์„œ๋น„์Šค ๊ตฌํ˜„


2. ๊ด€๋ จ ๋งํฌ ๐Ÿ“‘

์•„๋ž˜๋Š” ํ”„๋กœ์ ํŠธ์™€ ๊ด€๋ จ๋œ ๋‹ค์–‘ํ•œ ๋งํฌ ์ •๋ณด์ž…๋‹ˆ๋‹ค.


3. ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ ๐Ÿ—๏ธ

3.1. ์‹œ์Šคํ…œ ๊ตฌ์„ฑ

[ํด๋ผ์ด์–ธํŠธ (ํ”„๋ก ํŠธ์—”๋“œ)]
• EJS ํ…œํ”Œ๋ฆฟ ์—”์ง„: ๋™์  HTML ํŽ˜์ด์ง€ ๋ Œ๋”๋ง
• Tailwind CSS: ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ UI ์Šคํƒ€์ผ๋ง

[์„œ๋ฒ„ (๋ฐฑ์—”๋“œ)]
• Express.js: RESTful API ์—”๋“œํฌ์ธํŠธ ์ œ๊ณต
• ๋ฏธ๋“ค์›จ์–ด: ์š”์ฒญ ํŒŒ์‹ฑ, ์ฟ ํ‚ค ๋ฐ ์„ธ์…˜ ๊ด€๋ฆฌ, CORS ์„ค์ • ๋“ฑ

[๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค]
• PostgreSQL: ๋ช…์–ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ
• Sequelize ORM: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ๊ฐ์ฒด ์ง€ํ–ฅ์  ์ธํ„ฐ๋ž™์…˜

[๋ฐฐํฌ ๋ฐ ์ธํ”„๋ผ]
• Docker: ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ ๋ฐฐํฌ ๊ด€๋ฆฌ
• Nginx Proxy Manager: ํ”„๋ก์‹œ ๊ด€๋ฆฌ ๋ฐ SSL/TLS ์ธ์ฆ์„œ ๋ฐœ๊ธ‰
• GCP (Google Cloud Platform): ํด๋ผ์šฐ๋“œ ์ธํ”„๋ผ ๋ฐฐํฌ

3.2. ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๐Ÿ”„

  1. ์š”์ฒญ ์ฒ˜๋ฆฌ – ํด๋ผ์ด์–ธํŠธ๊ฐ€ /quote/random ๋“ฑ API ์—”๋“œํฌ์ธํŠธ๋กœ HTTP ์š”์ฒญ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  2. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ – Express ๋ผ์šฐํ„ฐ์—์„œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ํ•„์š”์‹œ Sequelize๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค.
  3. ์‘๋‹ต ์ƒ์„ฑ – ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ(๋žœ๋ค ๋ช…์–ธ ๋“ฑ)๋ฅผ JSON ํ˜•์‹ ๋˜๋Š” EJS ํ…œํ”Œ๋ฆฟ์„ ํ†ตํ•ด HTML๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.
  4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ – ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ ์ ˆํ•œ ์ƒํƒœ ์ฝ”๋“œ์™€ ๋ฉ”์‹œ์ง€๋กœ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

4. ์‚ฌ์šฉ ๊ธฐ์ˆ  ๋ฐ ๋ฒ„์ „ ๐Ÿ› ๏ธ

4.1. ๋ฐฑ์—”๋“œ

  • Express.js – Node.js ๊ธฐ๋ฐ˜ ์›น ํ”„๋ ˆ์ž„์›Œํฌ, ๋ฒ„์ „: ^4.19.2
  • EJS – ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ํ…œํ”Œ๋ฆฟ ์—”์ง„, ๋ฒ„์ „: ^3.1.10
  • body-parser – HTTP ์š”์ฒญ ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ, ๋ฒ„์ „: 1.20.2
  • cookie-parser – ์ฟ ํ‚ค ํŒŒ์‹ฑ ๋ฏธ๋“ค์›จ์–ด, ๋ฒ„์ „: ^1.4.7
  • express-session – ์„ธ์…˜ ๊ด€๋ฆฌ, ๋ฒ„์ „: ^1.18.1
  • express-validator – ์š”์ฒญ ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ, ๋ฒ„์ „: ^7.2.1
  • multer – ํŒŒ์ผ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ, ๋ฒ„์ „: ^1.4.5-lts.1
  • cors – CORS ์„ค์ •, ๋ฒ„์ „: ^2.8.5

4.2. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

  • PostgreSQL – ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œ์Šคํ…œ, ๋ฒ„์ „: ^16.4
  • Sequelize – ORM (Object Relational Mapping) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ๋ฒ„์ „: ^6.37.3

4.3. ๊ธฐํƒ€ ๋„๊ตฌ

  • dotenv – ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ด€๋ฆฌ, ๋ฒ„์ „: ^16.4.5
  • apidoc – API ๋ฌธ์„œ ์ž๋™ ์ƒ์„ฑ ๋„๊ตฌ, ๋ฒ„์ „: ^1.2.0
  • Tailwind CSS – ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ CSS ํ”„๋ ˆ์ž„์›Œํฌ, ๋ฒ„์ „: ^3.4.17
  • PostCSS – CSS ์ „์ฒ˜๋ฆฌ ๋„๊ตฌ, ๋ฒ„์ „: ^8.5.1
  • Autoprefixer – ์ž๋™ ๋ฒค๋” ํ”„๋ฆฌํ”ฝ์Šค ์ถ”๊ฐ€ ๋„๊ตฌ, ๋ฒ„์ „: ^10.4.20
  • nodemon – ํŒŒ์ผ ๋ณ€๊ฒฝ ์‹œ ์ž๋™ ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ๋„๊ตฌ, ๋ฒ„์ „: ^3.1.4

4.4. ๋ฐฐํฌ ๋ฐ ์ธํ”„๋ผ ๊ด€๋ จ ๋„๊ตฌ

  • Docker – ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ ๋ฐฐํฌ ๊ด€๋ฆฌ ๋„๊ตฌ, ๋ฒ„์ „: ^26.1.4
  • Nginx Proxy Manager – ํ”„๋ก์‹œ ๊ด€๋ฆฌ ๋ฐ SSL/TLS ์ธ์ฆ์„œ ๋ฐœ๊ธ‰ ๋„๊ตฌ, ๋ฒ„์ „: ^2.11.3
  • GCP (Google Cloud Platform) – ํด๋ผ์šฐ๋“œ ์ธํ”„๋ผ ์„œ๋น„์Šค

5. ๋ชจ๋“ˆ ๊ตฌ์„ฑ ๋ฐ ์ฃผ์š” ๊ธฐ๋Šฅ ๐Ÿ“ฆ

5.1. ์„œ๋ฒ„ ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ

  • ํŒŒ์ผ: src/app.js
  • ์—ญํ• : Express ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ, ๋ฏธ๋“ค์›จ์–ด ์„ค์ •( body-parser, cookie-parser, cors, session ๋“ฑ ), ๋ผ์šฐํ„ฐ ๋ฐ API ์—”๋“œํฌ์ธํŠธ ์—ฐ๊ฒฐ, ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋ฏธ๋“ค์›จ์–ด ์„ค์ •, ์„œ๋ฒ„ ํฌํŠธ ๋ฆฌ์Šค๋‹ ์‹œ์ž‘

5.2. ๋ผ์šฐํ„ฐ ๋ชจ๋“ˆ

  • ๊ฒฝ๋กœ: src/routes/
  • ์ฃผ์š” ๊ธฐ๋Šฅ:
    • ๋žœ๋ค ๋ช…์–ธ ์กฐํšŒ API: GET /quote/random
    • ์˜ค๋Š˜์˜ ๋ช…์–ธ ์กฐํšŒ API: GET /quote/today
    • ๊ด€๋ฆฌ์žํŽ˜์ด์ง€: GET /admin

5.3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋ธ

  • Sequelize ๋ชจ๋ธ:
    Quote ๋ชจ๋ธ – ์†์„ฑ: id, body (๋ช…์–ธ ๋‚ด์šฉ), author (๋‚จ๊ธด์ด), createdAt, updatedAt ๋“ฑ
    • ๋ชจ๋ธ ๊ฐ„ ๊ด€๊ณ„ ๋ฐ ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์„ค์ •

5.4. ๋ทฐ ํ…œํ”Œ๋ฆฟ

  • EJS ํ…œํ”Œ๋ฆฟ
    • ๊ฒฝ๋กœ: views/
    • ๋™์  HTML ๋ Œ๋”๋ง์„ ํ†ตํ•ด ๋ช…์–ธ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต

6. ๋นŒ๋“œ ๋ฐ ์‹คํ–‰ ํ™˜๊ฒฝ ๐Ÿš€

6.1. ์˜์กด์„ฑ ์„ค์น˜

ํ„ฐ๋ฏธ๋„์—์„œ npm install ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์˜์กด์„ฑ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

6.2. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— .env ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ , ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค:

PORT=3000
DATABASE_URL=postgres://username:password@localhost:5432/database_name
SESSION_SECRET=your_secret_key

6.3. ์‹คํ–‰ ๋ช…๋ น์–ด

  • ๊ฐœ๋ฐœ ๋ชจ๋“œ ์‹คํ–‰ (nodemon ์‚ฌ์šฉ): npm run dev
  • ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ ์‹คํ–‰: npm start
  • Tailwind CSS ๋นŒ๋“œ (์‹ค์‹œ๊ฐ„ ๊ฐ์‹œ): npm run css
  • Tailwind CSS ์ •์  ๋นŒ๋“œ: npm run build:css
  • API ๋ฌธ์„œ ์ƒ์„ฑ (apidoc ์‚ฌ์šฉ): npm run api

7. ๋ฐฐํฌ ๋ฐ ์ธํ”„๋ผ ์„ค์ • โ˜๏ธ

7.1. Docker ๊ธฐ๋ฐ˜ ๋ฐฐํฌ

Docker Compose ํŒŒ์ผ (docker-compose.yml)

version: '3.8'

services:
  prod:
    build:
      context: .
      dockerfile: Dockerfile.prod
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development

  dev:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development

์ฃผ์š” ๋‚ด์šฉ

  • ๋ฒ„์ „: Compose ํŒŒ์ผ ๋ฒ„์ „ 3.8 ์‚ฌ์šฉ
  • services: prod์™€ dev ๋‘ ๊ฐ€์ง€ ์„œ๋น„์Šค๋กœ ๊ตฌ์„ฑ
    • prod ์„œ๋น„์Šค:
      • ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋นŒ๋“œ ์ปจํ…์ŠคํŠธ๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, Dockerfile.prod๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œ
      • ํฌํŠธ 3000์„ ํ˜ธ์ŠคํŠธ์™€ ์ปจํ…Œ์ด๋„ˆ ๊ฐ„ ๋งคํ•‘
      • ์†Œ์Šค์ฝ”๋“œ์™€ node_modules ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ณผ๋ฅจ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ ๋™๊ธฐํ™”
      • NODE_ENV ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ development๋กœ ์„ค์ •
    • dev ์„œ๋น„์Šค: prod์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•˜์ง€๋งŒ, ๋ณ„๋„์˜ Dockerfile.dev๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์— ๋งž๋Š” ์„ค์ • ๊ฐ€๋Šฅ

Dockerfile.prod

# ๋ฒ ์ด์Šค ์ด๋ฏธ์ง€ ์„ค์ •
FROM node:20

# ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ •
WORKDIR /app

# ํŒจํ‚ค์ง€ ์„ค์น˜๋ฅผ ์œ„ํ•ด package.json ๋ฐ package-lock.json ๋ณต์‚ฌ
COPY package*.json ./

# ํŒจํ‚ค์ง€ ์„ค์น˜ (production ๋ชจ๋“œ)
RUN npm install --production

# ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ๋ณต์‚ฌ
COPY . .

# Tailwind CSS ๋นŒ๋“œ
RUN npm run build:css

# ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋  ํฌํŠธ ์„ค์ •
EXPOSE 3000

# ์„œ๋ฒ„ ์‹คํ–‰
CMD [ "npm", "run", "start" ]

์ฃผ์š” ๋‚ด์šฉ

  • ๋ฒ ์ด์Šค ์ด๋ฏธ์ง€: node:20 ์‚ฌ์šฉ
  • ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ: /app์œผ๋กœ ์„ค์ •
  • ํŒจํ‚ค์ง€ ์„ค์น˜: package.json ๋ฐ package-lock.json ํŒŒ์ผ์„ ๋ณต์‚ฌ ํ›„, production ๋ชจ๋“œ๋กœ ์˜์กด์„ฑ ์„ค์น˜
  • ์ฝ”๋“œ ๋ณต์‚ฌ: ์ „์ฒด ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๋‚ด /app ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋ณต์‚ฌ
  • Tailwind CSS ๋นŒ๋“œ: npm run build:css๋ฅผ ํ†ตํ•ด CSS ๋นŒ๋“œ ์ˆ˜ํ–‰
  • ํฌํŠธ ๋…ธ์ถœ: 3000๋ฒˆ ํฌํŠธ๋ฅผ ์™ธ๋ถ€์— ๋…ธ์ถœ
  • ์‹คํ–‰ ๋ช…๋ น์–ด: npm run start๋กœ ์„œ๋ฒ„ ์‹คํ–‰

7.2. Nginx Proxy Manager ์„ค์ •

  • ์—ญํ• : ๋„๋ฉ”์ธ ํ”„๋ก์‹œ ์„ค์ •, SSL ์ธ์ฆ์„œ ๊ด€๋ฆฌ, Docker ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ฐฐํฌ๋œ API ์„œ๋ฒ„ ์ ‘๊ทผ ์ œ์–ด
  • ์„ค์ • ์˜ˆ์‹œ: API ์„œ๋ฒ„ ๋‚ด๋ถ€ ์ฃผ์†Œ(์˜ˆ: http://localhost:3000)๋ฅผ ํ”„๋ก์‹œ ๋Œ€์ƒ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , HTTPS ๋ฐ ํ•„์š”ํ•œ ํฌํŠธ ํฌ์›Œ๋”ฉ ์„ค์ •

7.3. GCP ๋ฐฐํฌ

  • ํ™œ์šฉ ๋ฐฉ๋ฒ•: Compute Engine, Kubernetes Engine ๋˜๋Š” Cloud Run์„ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌ
  • Docker ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œ ํ›„ GCP Container Registry ๋˜๋Š” Artifact Registry์— ์—…๋กœ๋“œ, ๋ฐฐํฌ ์ง„ํ–‰
  • Nginx Proxy Manager์™€ ์—ฐ๋™ํ•˜์—ฌ ๋„๋ฉ”์ธ ๊ด€๋ฆฌ ๋ฐ SSL ์ธ์ฆ์„œ ์ ์šฉ

8. ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐ ๋กœ๊น… ๐Ÿ”

8.1. ์—๋Ÿฌ ์ฒ˜๋ฆฌ

  • 400 Bad Request – ์š”์ฒญ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์„ ๊ฒฝ์šฐ, ์ƒํƒœ ์ฝ”๋“œ 400๊ณผ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
  • 404 Not Found – ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์—”๋“œํฌ์ธํŠธ ์ ‘๊ทผ ์‹œ, ์ƒํƒœ ์ฝ”๋“œ 404์™€ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
  • 500 Internal Server Error – ์„œ๋ฒ„ ๋‚ด๋ถ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ, ์ƒํƒœ ์ฝ”๋“œ 500๊ณผ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜ ๋ฐ ๋กœ๊น…์„ ํ†ตํ•ด ์›์ธ ๋ถ„์„

8.2. ๋กœ๊น…

  • ์„œ๋ฒ„ ๋กœ๊ทธ๋Š” ์ฝ˜์†” ์ถœ๋ ฅ ๋ฐ ํ•„์š”์— ๋”ฐ๋ผ ํŒŒ์ผ๋กœ ์ €์žฅ
  • ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๋ฅผ ํ•จ๊ป˜ ๊ธฐ๋กํ•˜์—ฌ ๋””๋ฒ„๊น…์— ํ™œ์šฉ

9. ๋ณด์•ˆ ๊ณ ๋ ค ์‚ฌํ•ญ ๐Ÿ”’

  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ด€๋ฆฌ: ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” .env ํŒŒ์ผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ๋ฒ„์ „ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์—์„œ ์ œ์™ธ(.gitignore ์„ค์ •)
  • ์„ธ์…˜ ๊ด€๋ฆฌ: express-session์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ์…˜์„ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋ฉฐ, SESSION_SECRET์€ ๋ฐ˜๋“œ์‹œ ์•ˆ์ „ํ•œ ๊ฐ’์œผ๋กœ ์„ค์ •
  • CORS ์ •์ฑ…: ํ—ˆ์šฉ๋œ ๋„๋ฉ”์ธ๋งŒ ์ ‘๊ทผํ•˜๋„๋ก CORS ๋ฏธ๋“ค์›จ์–ด ์„ค์ •
  • ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ๊ฒ€์ฆ: express-validator๋ฅผ ํ†ตํ•ด ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ SQL Injection ๋ฐ XSS ๊ณต๊ฒฉ ๋Œ€๋น„

10. CI/CD Pipeline (GitHub Actions) ๐Ÿš€

ํ”„๋กœ์ ํŠธ๋Š” GitHub Actions๋ฅผ ํ™œ์šฉํ•˜์—ฌ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
ํŒŒ์ดํ”„๋ผ์ธ์€ master ๋ธŒ๋žœ์น˜์— ๋Œ€ํ•œ push ๋˜๋Š” pull request ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ์‹คํ–‰๋˜๋ฉฐ, Docker ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜์—ฌ Docker Hub์— ์—…๋กœ๋“œ ํ›„, SSH๋ฅผ ํ†ตํ•ด ์›๊ฒฉ ์„œ๋ฒ„์— ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.

name: CI/CD Pipeline

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build Docker image
        run: |
          docker build . -f Dockerfile.prod -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:${{ github.sha }}
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:${{ github.sha }} ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:latest

      - name: Push Docker image to Docker Hub
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:${{ github.sha }}
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:latest

  deploy:
    runs-on: ubuntu-latest
    needs: build

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Deploy to server
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          port: 22
          script: |
            sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:latest
            sudo docker stop ${{ secrets.PROJECT_NAME }} || true
            sudo docker rm ${{ secrets.PROJECT_NAME }} || true
            sudo docker run -d -p 3000:3000 --name ${{ secrets.PROJECT_NAME }} --env-file ${{ secrets.ENV_PATH }} ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROJECT_NAME }}:latest

์ฃผ์š” ๋‚ด์šฉ

  • ํŠธ๋ฆฌ๊ฑฐ: push ๋ฐ pull_request ์ด๋ฒคํŠธ๊ฐ€ master ๋ธŒ๋žœ์น˜์—์„œ ๋ฐœ์ƒํ•˜๋ฉด ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰
  • ๋นŒ๋“œ ๋‹จ๊ณ„: Repository ์ฒดํฌ์•„์›ƒ, Docker Buildx ์„ค์ •, Docker Hub ๋กœ๊ทธ์ธ, Dockerfile.prod๋ฅผ ์‚ฌ์šฉํ•œ ์ด๋ฏธ์ง€ ๋นŒ๋“œ ๋ฐ ํƒœ๊ทธ ์ƒ์„ฑ, Docker Hub๋กœ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
  • ๋ฐฐํฌ ๋‹จ๊ณ„: ๋นŒ๋“œ ์™„๋ฃŒ ํ›„ SSH๋กœ ์›๊ฒฉ ์„œ๋ฒ„ ์ ‘์†, ์ตœ์‹  ์ด๋ฏธ์ง€ pull, ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ ์ค‘์ง€ ๋ฐ ์‚ญ์ œ ํ›„ ์ƒˆ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ (ํฌํŠธ 3000 ๋งคํ•‘ ๋ฐ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํŒŒ์ผ ์ ์šฉ)

11. ๋งˆ๋ฌด๋ฆฌ ๐ŸŽ‰

์ถ”๊ฐ€ ๋ฌธ์˜๋‚˜ ๊ฐœ์„  ์š”์ฒญ์ด ์žˆ์œผ์‹œ๋ฉด ์–ธ์ œ๋“ ์ง€ ์—ฐ๋ฝ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž ์ด๋ฉ”์ผ : dktjdej@naver.com

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ˜Š

๋ฐ˜์‘ํ˜•
Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.