๐ข Next.js ์ฌํ 10์ฅ: Deployment & Infrastructure โ Vercel vs Docker vs Node.js ์๋ฒ
๐ ๊ฐ์
Vercel, Docker, Node.js ์๋ฒ ๊ฐ ๋ฐฐํฌ ๋ฐฉ์์ ์ฐจ์ด์ ์ธํ๋ผ ์ค๊ณ ๊ธฐ์ค์ ์์๋ด ๋๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ์์์ผ ํ๋๊ฐ
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ์ธ ๊ฐ์ง ๋ฐฐํฌ ์ ๋ต ๋น๊ต ๐ข
- ๐ Vercel ๋ฐฐํฌ โ ์ ๋ก ์ค์ ์ ๋ง๋ฒ ๐ก
- ๐ณ Docker ์ปจํ ์ด๋ ๋ฐฐํฌ โ ์ํฐํ๋ผ์ด์ฆ ํ์ค ๐ก
- ๐ฅ๏ธ Node.js ์๋ฒ ์ง์ ๋ฐฐํฌ ๐ก
- โ๏ธ ํ๊ฒฝ ๋ณ์์ ๋น๋ฐํค ๊ด๋ฆฌ ๐ด
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
- ๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 18๋ถ (์ ์ฒด) / ํต์ฌ ํํธ๋ง: 9๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์(PM): "์ด์ ์๋น์ค๋ฅผ ์ค์ ๋ก ๋ฐฐํฌํด์ผ ํด์. Vercel๋ก ๋น ๋ฅด๊ฒ ๋๊ฐ์ผ ํ๋์, ์๋๋ฉด ํ์ฌ ์๋ฒ(AWS EC2)์ Docker๋ก ์ฌ๋ ค์ผ ํ๋์? ์ฐจ์ด๊ฐ ๋ญ์ง ์๊ณ ๊ฒฐ์ ํ๊ณ ์ถ์ด์."
- ์ํธ(๋ฆฌ๋): "ํ ๊ท๋ชจ, ๋น์ฉ, ๊ธฐ์ ์ฑ์๋์ ๋ฐ๋ผ ๋ฌ๋ผ์. ์คํํธ์ ์ด๊ธฐ๋ผ๋ฉด Vercel์ด ์ต์ ์ด์์. ISR, Edge Functions, ํ๋ฆฌ๋ทฐ ๋ฐฐํฌ๊ฐ ๊ธฐ๋ณธ์ด๊ณ ์ธํ๋ผ ๊ฑฑ์ ์ ์์ ์ ํด๋ ๋๊ฑฐ๋ ์. ๋ฐ๋ฉด ๊ธฐ์ ๋ด๋ถ ์๋ฒ๋ ํน์ ๊ท์ (์ปดํ๋ผ์ด์ธ์ค)์ด ์์ผ๋ฉด Docker๋ก ์์ฒด ์๋ฒ์ ์ฌ๋ ค์ผ ํด์."
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
์ธ ๊ฐ์ง ์ ๋ต ๋น๊ต โ Vercel ๋ฐฐํฌ ์ค์ โ Docker ์ต์ Dockerfile โ Node.js ์๋ฒ ์ง์ ๋ฐฐํฌ โ ํ๊ฒฝ ๋ณ์ ๊ด๋ฆฌ
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ํ๊ณผ ์๋น์ค ์ํฉ์ ๋ง๋ ๋ฐฐํฌ ์ ๋ต์ ์ ํํ ์ ์๋ค
- Next.js ์ฑ์ ์ํ ์ต์ ํ๋
Dockerfile์ ์์ฑํ ์ ์๋ค - ๋น๋ฐํค๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌํ๋ ํ๊ฒฝ ๋ณ์ ์์น์ ์งํฌ ์ ์๋ค
๐ค ์ ์์์ผ ํ๋๊ฐ
๋ก์ปฌ์์ ์ ๋์ํ๋ ์ฝ๋๊ฐ ๋ฐฐํฌ ํ ๊ฐ์๊ธฐ ์ ๋์ํ๊ฑฐ๋, ์๋ฒ ๋น์ฉ์ด ์์๋ณด๋ค 10๋ฐฐ ๋์ค๊ฑฐ๋, ํ๊ฒฝ ๋ณ์๊ฐ ํด๋ผ์ด์ธํธ์ ๋ ธ์ถ๋๋ ์ฌ๊ณ โ ๋ฐฐํฌ๋ฅผ ๋ชจ๋ฅด๋ฉด ์ด๋ฐ ์ผ์ด ์๊ฒจ.
๋ฐฐํฌ๋ "์ด๋ค ์ธํ๋ผ์์ ์ด๋ป๊ฒ ์คํํ ๊ฒ์ธ๊ฐ"์ ๋ํ ์ํคํ ์ฒ ๊ฒฐ์ ์ด์ผ. ์ฝ๋ฉ๋งํผ ์ค์ํ ์ ํ์ด์ผ.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
์์ ๋ฐฐ๋ฌ ๋ฐฉ์์ ๋น์ ํด๋ด:
- Vercel = ๋ฐฐ๋ฌ์๋ฏผ์กฑ ์ ์ . ์ฃผ๋ฐฉ๋ง ์์ผ๋ฉด ๋๊ณ , ๋ฐฐ๋ฌยท๊ฒฐ์ ยท๊ด๊ณ ๋ ํ๋ซํผ์ด ๋ค ํด์ค. ๋น ๋ฅธ ๋์ ์์๋ฃ(๋น์ฉ)๊ฐ ์๊ณ , ํ๋ซํผ ๊ท์น์ ๋ฐ๋ผ์ผ ํด.
- Docker = ์์์ ์ง์ ์ด์ + ๋ฐฐ๋ฌ ํธ๋ญ ๋ณด์ . ๋ชจ๋ ๊ฑธ ์ง์ ๊ด๋ฆฌํด์ผ ํ์ง๋ง ์์ ๋๊ฐ ์ต๊ณ ์ผ.
- Node.js ์ง์ ๋ฐฐํฌ = ์์์ ์ง์ ์ด์์ธ๋ฐ ๋ฐฐ๋ฌ ํธ๋ญ์ ์ธ๋๊ธฐ. Docker๋ณด๋ค ์กฐ๊ธ ๋ ๋จ์ํ์ง๋ง ๊ด๋ฆฌํ ๊ฒ ์ฌ์ ํ ๋ง์.
๐งฉ ์ธ ๊ฐ์ง ๋ฐฐํฌ ์ ๋ต ๋น๊ต ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ์ธ ๊ฐ์ง ๋ฐฐํฌ ์ ๋ต์ ์ฅ๋จ์ ์ ์ ํํ ์๊ณ ์ํฉ์ ๋ง๋ ์ ํ์ ํ ์ ์๋ค
| ๊ธฐ์ค | Vercel | Docker (K8s ํฌํจ) | Node.js ์๋ฒ ์ง์ |
|---|---|---|---|
| ์ค์ ๋ณต์ก๋ | โญ ๊ฑฐ์ ์์ | ๐ด ๋์ | ๐ก ์ค๊ฐ |
| ๋น์ฉ ์์ธก์ฑ | ๐ก ํธ๋ํฝ ๋ฐ๋ผ ๋ณ๋ | โ ์์ธก ๊ฐ๋ฅ | โ ์์ธก ๊ฐ๋ฅ |
| ISR / Edge ์ง์ | โ ์๋ฒฝ ์ง์ | ๐ก ์ค์ ํ์ | ๐ก ์ ํ์ |
| ์์ฒด ์๋ฒ ํตํฉ | โ ์ด๋ ค์ | โ ์๋ฒฝ ํตํฉ | โ ๊ฐ๋ฅ |
| ์ปดํ๋ผ์ด์ธ์ค | ๐ก ๋ฐ์ดํฐ ๋ฏธ๊ตญ ์๋ฒ | โ ์์ฒด ์๋ฒ ์์ ์ ์ด | โ ์์ฒด ์ ์ด |
| ๊ฐ์ฅ ์ ํฉํ ์ํฉ | ์คํํธ์ , ์ฌ์ด๋ ํ๋ก์ ํธ, ๋น ๋ฅธ ์ถ์ | ๊ธฐ์ , ๋ง์ดํฌ๋ก์๋น์ค, ๊ณ ๊ฐ์ฉ์ฑ | ๊ธฐ์กด VM ๋ณด์ , ์ค์ ๊ท๋ชจ |
2026๋ ๊ธฐ์ค ์ ํ ๊ฐ์ด๋:
ํ ๊ท๋ชจ ์ + ๋น ๋ฅธ ์ถ์ + ๋น์ฉ ์ต์ํ โ Vercel
๋ฐ์ดํฐ ๊ตญ๋ด ์๋ฒ ํ์ + ๊ธฐ์
๋ณด์ ๊ท์ โ Docker (์ฌ๋ด K8s)
๊ธฐ์กด VM ๋ณด์ + ๋จ์ ๋ฐฐํฌ + ์์ธก ๋น์ฉ โ Node.js ์ง์ ๋ฐฐํฌ
๐ Vercel ๋ฐฐํฌ โ ์ ๋ก ์ค์ ์ ๋ง๋ฒ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- Vercel์์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํ๊ณ ์ปค์คํ ๋๋ฉ์ธ์ ์ฐ๊ฒฐํ ์ ์๋ค
vercel.json์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ์ ํค๋๋ฅผ ์ค์ ํ ์ ์๋ค
Vercel ๋ฐฐํฌ ๊ณผ์ :
# 1. Vercel CLI ์ค์น
npm i -g vercel
# 2. ํ๋ก์ ํธ ์ฐ๊ฒฐ ๋ฐ ๋ฐฐํฌ
vercel
# 3. ํ๋ก๋์
๋ฐฐํฌ
vercel --prod๋๋ GitHub ์ฐ๋์ผ๋ก pushํ ๋๋ง๋ค ์๋ ๋ฐฐํฌ (๊ถ์ฅ).
vercel.json ์ค์ :
{
"framework": "nextjs",
"buildCommand": "npm run build",
"devCommand": "npm run dev",
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" }
]
}
],
"redirects": [
{ "source": "/old-blog/(.*)", "destination": "/posts/$1", "permanent": true }
]
}Vercel ํ๊ฒฝ ๋ณ์ ์ค์ :
Vercel Dashboard โ ํ๋ก์ ํธ โ Settings โ Environment Variables
๊ฐ๋ฐ: DATABASE_URL=postgresql://localhost:5432/dev
ํ๋ฆฌ๋ทฐ: DATABASE_URL=postgresql://preview-server/preview
ํ๋ก๋์
: DATABASE_URL=postgresql://prod-server/prod
โ ๏ธ NEXT_PUBLIC_ ์ ๋์ฌ๊ฐ ๋ถ์ ๋ณ์๋ง ํด๋ผ์ด์ธํธ์ ๋
ธ์ถ๋จ!
Vercel์ ํน๋ณ ๊ธฐ๋ฅ:
โ
Preview URL: PR๋ง๋ค ๊ณ ์ ํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ URL ์๋ ์์ฑ
- https://my-app-pr-123-team.vercel.app
โ
ISR ์ง์: revalidate ์ค์ ์ฆ์ ๋์
โ
Edge Functions: middleware๊ฐ Vercel Edge์์ ์๋ ์คํ
โ
Analytics: Core Web Vitals ์ค์ ์ฌ์ฉ์ ๋ฐ์ดํฐ ์๋ ์์ง
๐ณ Docker ์ปจํ ์ด๋ ๋ฐฐํฌ โ ์ํฐํ๋ผ์ด์ฆ ํ์ค ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- Next.js ์ฑ์ ์ํ ์ต์ ํ๋ ๋ฉํฐ ์คํ ์ด์ง Dockerfile์ ์์ฑํ ์ ์๋ค
- ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ต์ํํ๋ ๋น๋ ํจํด์ ์ ์ฉํ ์ ์๋ค
Next.js ๊ณต์ ๊ถ์ฅ ๋ฉํฐ ์คํ ์ด์ง Dockerfile:
# Dockerfile
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Stage 1: ์์กด์ฑ ์ค์น
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
FROM node:20-alpine AS deps
WORKDIR /app
# package.json๊ณผ lock ํ์ผ๋ง ๋จผ์ ๋ณต์ฌ (๋ ์ด์ด ์บ์ฑ ์ต์ ํ)
COPY package.json package-lock.json ./
RUN npm ci --only=production
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Stage 2: ๋น๋
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
FROM node:20-alpine AS builder
WORKDIR /app
# ๋น๋์ ํ์ํ ์ ์ฒด ์์กด์ฑ ์ค์น (devDependencies ํฌํจ)
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# ๋น๋ ํ์ ํ๊ฒฝ ๋ณ์
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
# standalone ๋ชจ๋๋ก ๋น๋ (์๋ฒ์ ํ์ํ ํ์ผ๋ง ์ถ๋ ฅ)
RUN npm run build
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Stage 3: ์คํ ์ด๋ฏธ์ง (์ต์ ํฌ๊ธฐ)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# ๋ณด์: ๋ฃจํธ ๊ถํ์ผ๋ก ์คํํ์ง ์๊ธฐ
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# standalone ๋น๋ ๊ฒฐ๊ณผ๋ฌผ๋ง ๋ณต์ฌ (์ต์ ํ์ผ)
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]// next.config.ts โ standalone ๋ชจ๋ ํ์ฑํ (Docker ํ์ ์ค์ )
const nextConfig = {
output: 'standalone', // ์๋ฒ์ ํ์ํ ์ต์ ํ์ผ๋ง .next/standalone์ ์ถ๋ ฅ
}# docker-compose.yml โ ๋ก์ปฌ ๊ฐ๋ฐ/์คํ
์ด์ง์ฉ
services:
app:
build:
context: .
args:
NEXT_PUBLIC_API_URL: https://api.youngsu.community
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/youngsu
- SESSION_SECRET=your-secret-key-here
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_DB: youngsu
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:# ์ด๋ฏธ์ง ๋น๋ ๋ฐ ์คํ
docker build -t youngsu-community .
docker run -p 3000:3000 --env-file .env.production youngsu-community
# ๋๋ compose๋ก
docker-compose up -d๐ฅ๏ธ Node.js ์๋ฒ ์ง์ ๋ฐฐํฌ ๐ก
๊ธฐ์กด EC2, NCP ๊ฐ์ VM์ ์ง์ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ด์ผ.
# server.sh โ ์๋ฒ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ
#!/bin/bash
set -e
echo "๐ฆ ์์กด์ฑ ์ค์น..."
npm ci
echo "๐จ ๋น๋..."
npm run build
echo "๐ ์๋ฒ ์ฌ์์ (PM2 ์ฌ์ฉ)..."
pm2 restart youngsu-community || pm2 start npm --name youngsu-community -- start
echo "โ
๋ฐฐํฌ ์๋ฃ!"// ecosystem.config.js โ PM2 ์ค์
module.exports = {
apps: [
{
name: 'youngsu-community',
script: 'npm',
args: 'start',
instances: 'max', // CPU ์ฝ์ด ์๋งํผ ํ๋ก์ธ์ค ์คํ
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
},
],
}โ๏ธ ํ๊ฒฝ ๋ณ์์ ๋น๋ฐํค ๊ด๋ฆฌ ๐ด
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
NEXT_PUBLIC_์ ๋์ฌ์ ์๋ฏธ์ ์ํ์ฑ์ ์ดํดํ๋ค- ๋น๋ฐํค๊ฐ ํด๋ผ์ด์ธํธ ๋ฒ๋ค์ ํฌํจ๋๋ ์ฌ๊ณ ๋ฅผ ๋ฐฉ์งํ๋ ๊ท์น์ ์๋ค
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
NEXT_PUBLIC_DATABASE_URL=postgresql://...์ด๋ผ๊ณ ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํ๋ฉด ์ด๋ค ์ผ์ด ์๊ธธ๊น?
ํ๊ฒฝ ๋ณ์์ ๋ ์ข ๋ฅ:
NEXT_PUBLIC_ ์ ๋์ฌ ์์ โ ํด๋ผ์ด์ธํธ(๋ธ๋ผ์ฐ์ ) ๋ฒ๋ค์ ํฌํจ
โ ๋๊ตฌ๋ DevTools์์ ๋ณผ ์ ์์ โ ๏ธ
NEXT_PUBLIC_ ์ ๋์ฌ ์์ โ ์๋ฒ์์๋ง ์ ๊ทผ ๊ฐ๋ฅ
โ ๋ธ๋ผ์ฐ์ ์ ์ ๋ ๋
ธ์ถ ์ ๋จ โ
# .env.local (๋ก์ปฌ ์ ์ฉ โ .gitignore์ ๋ฐ๋์ ํฌํจ!)
DATABASE_URL=postgresql://localhost:5432/dev # ์๋ฒ ์ ์ฉ โ
SESSION_SECRET=dev-secret-key # ์๋ฒ ์ ์ฉ โ
NEXT_PUBLIC_API_URL=http://localhost:3000 # ํด๋ผ์ด์ธํธ ์ ๊ทผ ๊ฐ๋ฅ (๊ณต๊ฐ OK)
# โ ์ ๋ ๊ธ์ง!
NEXT_PUBLIC_DATABASE_URL=postgresql://... # DB ์ ์ ์ ๋ณด๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋
ธ์ถ!
NEXT_PUBLIC_SESSION_SECRET=secret-key # ์ํธํ ํค๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋
ธ์ถ!server-only ํจํค์ง๋ก ์ค์ ๋ฐฉ์ง:
// lib/db.ts โ ์๋ฒ์์๋ง ์คํ๋๋ ํ์ผ
import 'server-only'
import { PrismaClient } from '@prisma/client'
// ์ด ํ์ผ์ด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ import๋๋ฉด ๋น๋ ์๋ฌ ๋ฐ์
// โ ์ค์๋ก DB ์ฐ๊ฒฐ ์ ๋ณด๊ฐ ํด๋ผ์ด์ธํธ์ ๋
ธ์ถ๋๋ ์ฌ๊ณ ๋ฐฉ์ง
export const db = new PrismaClient().env ํ์ผ ๊ณ์ธต:
.env โ ๊ธฐ๋ณธ๊ฐ (git ์ถ์ ๊ฐ๋ฅ, ๋ฏผ๊ฐ ์ ๋ณด ์์ด์ผ ํจ)
.env.local โ ๋ก์ปฌ ๊ฐ๋ฐ (git ์ ์ธ, ๊ฐ์ธ ์ค์ )
.env.development โ ๊ฐ๋ฐ ํ๊ฒฝ (git ์ถ์ ๊ฐ๋ฅ)
.env.production โ ํ๋ก๋์
(git ์ ์ธ! ๋๋ ๋น๋ฐ ๊ด๋ฆฌ ์๋น์ค๋ก)
๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
โ Docker ๋น๋ ํ output: 'standalone' ๊ฒฐ๊ณผ๋ฌผ์ public ํ์ผ ์์
์์ธ: standalone ๋ชจ๋๋ public ํด๋๋ฅผ ์๋์ผ๋ก ํฌํจํ์ง ์์.
ํด๊ฒฐ์ฑ :
# Dockerfile์์ public ํด๋๋ฅผ ๋ช
์์ ์ผ๋ก ๋ณต์ฌ
COPY --from=builder /app/public ./publicโ ๋ฐฐํฌ ํ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ชป ์ฝ์ (undefined)
์์ธ ์ฒดํฌ๋ฆฌ์คํธ:
.env.local์ ๋ก์ปฌ ์ ์ฉ. ์๋ฒ์์๋ ์์คํ ํ๊ฒฝ ๋ณ์ ๋๋.env.production์ฌ์ฉNEXT_PUBLIC_์๋ ๋ณ์๋ฅผ ํด๋ผ์ด์ธํธ ์ฝ๋์์ ์ฝ์ผ๋ ค ํ ๊ฒฝ์ฐ- Docker ์คํ ์
--env-file์ต์ ๋๋ฝ
โ Vercel ๋ฐฐํฌ ํ API Route๊ฐ 504 Timeout
์์ธ: Vercel์ ๋ฌด๋ฃ ํ๋์์ ํจ์ ์คํ ์๊ฐ ํ๋(10์ด) ์ด๊ณผ.
ํด๊ฒฐ์ฑ :
// vercel.json์์ ํน์ ๊ฒฝ๋ก ํ์์์ ์ฐ์ฅ (Pro ํ๋ ํ์)
{
"functions": {
"app/api/heavy-task/route.ts": {
"maxDuration": 60
}
}
}๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
๐ ๋ฐฐํฌ ์ ๋ต ์ ํ ๊ธฐ์ค
| ์ํฉ | ๊ถ์ฅ ๋ฐฐํฌ ์ ๋ต |
|---|---|
| ์คํํธ์ , ์ด๊ธฐ ์ถ์, ์๊ท๋ชจ ํ | Vercel |
| ๊ธฐ์ ๋ด๋ถ ์๋ฒ, ๋ฐ์ดํฐ ๊ตญ๋ด ๋ณด๊ด ํ์ | Docker + ์ฌ๋ด ์๋ฒ |
| ๊ธฐ์กด VM ๋ณด์ , ๋จ์ ๋ฐฐํฌ | Node.js ์ง์ (PM2) |
โ ๏ธ ์ ๋ ํ์ง ๋ง ๊ฒ
| ์ํฉ | โ ๋์ ์ | โ ์ข์ ์ |
|---|---|---|
| DB ์ฐ๊ฒฐ ๋ฌธ์์ด | NEXT_PUBLIC_DATABASE_URL | DATABASE_URL (์๋ฒ ์ ์ฉ) |
| ๋น๋ฐํค git ์ถ์ | .env.production git commit | Vercel ํ๊ฒฝ ๋ณ์ ๋๋ AWS Secrets Manager |
| Docker์์ root ์คํ | ๊ธฐ๋ณธ root user | USER nextjs ์ค์ |
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. NEXT_PUBLIC_SESSION_SECRET์ฒ๋ผ ๋น๋ฐํค์ NEXT_PUBLIC_ ์ ๋์ฌ๋ฅผ ๋ถ์ด๋ฉด ์ด๋ค ๋ฌธ์ ๊ฐ ์๊ธฐ๋๊ฐ?
โ ์ ๋ต: ๊ฐ์ด ํด๋ผ์ด์ธํธ ๋ฒ๋ค์ ํฌํจ๋์ด ๋ธ๋ผ์ฐ์ ์์ ๋ ธ์ถ๋๋ค.
๐ก ์์ธ ํด์ค: NEXT_PUBLIC_์ "๋ธ๋ผ์ฐ์ ์์ ์ฝ์ด๋ ๋๋ ๊ฐ"์ด๋ผ๋ ์ ์ธ์ด๋ค. ์ธ์ ์๋ช ํค, DB URL, API secret์๋ ์ ๋ ๋ถ์ด๋ฉด ์ ๋๋ค. ํ๊ฒฝ ๋ณ์ ์ด๋ฆ์ ๋ฐฐํฌ ์ ๋ต๋ณด๋ค ๋จผ์ ํ์ธํด์ผ ํ๋ ๋ณด์ ๊ฒฝ๊ณ๋ค.
Q2. Docker ๋ฐฐํฌ์์ output: 'standalone'์ ์ฌ์ฉํ ๋ public ํด๋์ .next/static์ ๋ณ๋๋ก ๋ณต์ฌํด์ผ ํ๋ ์ด์ ๋?
โ ์ ๋ต: standalone ์ถ๋ ฅ์ ์คํ ์๋ฒ์ ํ์ํ ์ต์ ํ์ผ ์ค์ฌ์ด๋ผ ์ ์ ์์ฐ์ ์๋์ผ๋ก ๋ชจ๋ ํฌํจํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
๐ก ์์ธ ํด์ค: standalone์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ด๋ ๋ฐ ์ ์ฉํ์ง๋ง, Dockerfile์์ public๊ณผ .next/static์ ๋ช ์์ ์ผ๋ก ๋ณต์ฌํ์ง ์์ผ๋ฉด ์ด๋ฏธ์ง, ํฐํธ, JS ์ ์ ํ์ผ์ด 404๊ฐ ๋ ์ ์๋ค. ๋น๋ ์ฑ๊ณต๊ณผ ๋ฐํ์ ์ ์ ์์ฐ ์ ๊ณต์ ๋ณ๊ฐ์ ๊ฒ์ฆ์ด๋ค.
Q3. ์์ฒ ์ด์ ํ ์คํธ ํ์: ์์ฒด Node ์๋ฒ๋ฅผ ์ฌ๋ฌ ์ธ์คํด์ค๋ก ๋๋ ธ๋๋ ISR/ํ๊ทธ ์บ์ ๋ฐ์ ์์ ์ด ์ธ์คํด์ค๋ง๋ค ๋ค๋ฅด๋ค. ๋ฌด์์ ๊ฒํ ํด์ผ ํ ๊น?
โ ์ ๋ต: ๊ณต์ ์บ์, ํ๊ทธ ๋ฌดํจํ ์ ํ, CDN ์บ์ ์ ์ฑ ์ฒ๋ผ ๋ค์ค ์ธ์คํด์ค์์ ์บ์ ์ผ๊ด์ฑ์ ๋ง์ถ๋ ์ธํ๋ผ๋ฅผ ๊ฒํ ํด์ผ ํ๋ค.
๐ก ์์ธ ํด์ค: ๊ณต์ ๋ฐฐํฌ ๋ฌธ์๋ ๊ธฐ๋ณธ Node ์๋ฒ๋ ๊ธฐ๋ฅ์ ์ํํ์ง๋ง, ๋ค์ค ์ธ์คํด์ค์์๋ ๊ณต์ ์บ์์ ๋ฌดํจํ ์กฐ์จ์ด ์ด์ ํ์ง์ ์ข์ฐํ๋ค๊ณ ์ค๋ช ํ๋ค. Vercel์ ๋ง์ ๋ถ๋ถ์ ํ๋ซํผ์ด ๋งก์ง๋ง, ์์ฒด ๋ฐฐํฌ๋ ํ์ด ์ง์ ๊ด์ธก๊ณผ ์ ํ ๊ฒฝ๋ก๋ฅผ ์ค๊ณํด์ผ ํ๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋์ ๋ฐฐํฌ๋ฅผ "์๋ฒ์ ์ฌ๋ฆฌ๊ธฐ"๊ฐ ์๋๋ผ Next.js ๋ฐํ์ ๊ธฐ๋ฅ์ด ์ค์ ํ๊ฒฝ์์ ๋๊น์ง ์๋ํ๊ฒ ๋ง๋๋ ์ผ๋ก ๋ณด๊ฒ ๋๋ค. Server Components, streaming, ISR, Server Actions, ์ ์ ์์ฐ์ด ๋ชจ๋ ๋ฐฐํฌ ํ๋ซํผ์ ์ง์๊ณผ ์ฐ๊ฒฐ๋์ด ์์๋ค.
๐ก "๋ฐฐํฌ ์ ๋ต์ ๋น์ฉํ๊ฐ ์๋๋ผ ๋ฐํ์ ๊ธฐ๋ฅ ์๊ตฌ์ฌํญ์ ๊ฒฐ๊ณผ๋ค."
๋ค์ ๋ฐฐํฌ ์ค๊ณ์์๋ Vercel, Docker, ์์ฒด Node ์๋ฒ๋ฅผ ์ทจํฅ์ผ๋ก ๊ณ ๋ฅด์ง ์๊ฒ ๋ค. ์คํธ๋ฆฌ๋ฐ์ด ํ์ํ์ง, ์๋ฒ ์ก์ ๋ณธ๋ฌธ ์ ํ์ ์ถฉ๋ถํ์ง, ์ด๋ฏธ์ง ์ต์ ํ์ ๊ณต์ ์บ์๋ ๋๊ฐ ์ฑ ์์ง๋์ง๋ถํฐ ํ์ธํ๊ณ ์ ํ์ง๋ฅผ ์ ์ํ๊ฒ ๋ค.