[Daily morning study] Serverless vs Container ๋น๊ต
#daily morning study
๊ฐ์
Serverless์ Container๋ ํ๋ ํด๋ผ์ฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฐํฌ์ ๋ ๊ฐ์ง ์ฃผ์ ํจ๋ฌ๋ค์์ด๋ค. ๊ฐ๊ฐ์ ํน์ฑ์ ์ดํดํ๊ณ ์ํฉ์ ๋ง๊ฒ ์ ํํ๋ ๊ฒ์ด ์ค์ํ๋ค.
Container
์ปจํ ์ด๋๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๊ทธ ์คํ ํ๊ฒฝ(๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์ค์ ํ์ผ ๋ฑ)์ ํ๋์ ์ด๋ฏธ์ง๋ก ํจํค์งํ ๋ ๋ฆฝ์ ์ธ ์คํ ๋จ์๋ค.
ํต์ฌ ํน์ง
- ์ด์์ฑ: ๋์ผํ ์ด๋ฏธ์ง๊ฐ ์ด๋ค ํ๊ฒฝ์์๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋์
- ์ผ๊ด์ฑ: ๊ฐ๋ฐยทํ ์คํธยทํ๋ก๋์ ํ๊ฒฝ์ ์์ ํ ๋์ผํ๊ฒ ์ ์ง
- ์ค์ผ์คํธ๋ ์ด์ : Kubernetes๋ก ๋๊ท๋ชจ ํด๋ฌ์คํฐ ๊ด๋ฆฌ ๊ฐ๋ฅ
- ์ฅ๊ธฐ ์คํ์ ์ ํฉ: ํญ์ ์ผ์ ธ ์๋ ์๋ฒ ํ๋ก์ธ์ค์ ์์ฐ์ค๋ฝ๊ฒ ๋ง์
์ฃผ์ ๊ธฐ์
- Docker: ์ปจํ ์ด๋ ๋น๋ ๋ฐ ์คํ
- Kubernetes (K8s): ์ปจํ ์ด๋ ์ค์ผ์คํธ๋ ์ด์
- AWS ECS / EKS, GKE, AKS: ๊ด๋ฆฌํ ์ฟ ๋ฒ๋คํฐ์ค ์๋น์ค
Dockerfile ์์ (Node.js)
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
docker build -t my-app .
docker run -p 3000:3000 my-app
Serverless
Serverless๋ ์๋ฒ ๊ด๋ฆฌ ์์ด ์ฝ๋(ํจ์)๋ฅผ ์คํํ๋ ํจ๋ฌ๋ค์์ด๋ค. ํด๋ผ์ฐ๋ ํ๋ก๋ฐ์ด๋๊ฐ ์ธํ๋ผ๋ฅผ ์์ ํ ๊ด๋ฆฌํ๊ณ , ๊ฐ๋ฐ์๋ ๋น์ฆ๋์ค ๋ก์ง์๋ง ์ง์คํ๋ค.
ํต์ฌ ํน์ง
- ์ด๋ฒคํธ ๊ธฐ๋ฐ: HTTP ์์ฒญ, ํ ๋ฉ์์ง, ํ์ด๋จธ ๋ฑ์ผ๋ก ํธ๋ฆฌ๊ฑฐ
- ์๋ ์ค์ผ์ผ๋ง: ์์ฒญ๋์ ๋ฐ๋ผ 0 โ ์์ฒ ๊ฐ๋ก ์๋ ํ์ฅยท์ถ์
- ์ฌ์ฉ๋ ๊ธฐ๋ฐ ๊ณผ๊ธ: ํจ์ ์คํ ์๊ฐยทํ์๋งํผ๋ง ๋น์ฉ ๋ฐ์
- ์ฝ๋ ์คํํธ: ๋นํ์ฑ ์ํ์์ ์ฒซ ์์ฒญ ์ ์ด๊ธฐํ ์ง์ฐ ๋ฐ์
์ฃผ์ ์๋น์ค
- AWS Lambda
- Google Cloud Functions
- Azure Functions
- Cloudflare Workers
Lambda ํจ์ ์์ (Node.js)
exports.handler = async (event) => {
const { name } = JSON.parse(event.body);
return {
statusCode: 200,
body: JSON.stringify({ message: `Hello, ${name}!` }),
};
};
๋น๊ต ์ ๋ฆฌ
| ํญ๋ชฉ | Container | Serverless |
|---|---|---|
| ์๋ฒ ๊ด๋ฆฌ | ์ง์ ๊ด๋ฆฌ (๋๋ ๊ด๋ฆฌํ) | ํด๋ผ์ฐ๋ ํ๋ก๋ฐ์ด๋๊ฐ ์ ๋ด |
| ์ค์ผ์ผ๋ง | ์๋ ์ค์ / HPA | ์๋ (0~๋ฌดํ๋) |
| ๊ณผ๊ธ ๋ฐฉ์ | ์คํ ์ค์ธ ์ธ์คํด์ค ๊ธฐ์ค | ํจ์ ์คํ ์๊ฐยทํ์ ๊ธฐ์ค |
| ์ฝ๋ ์คํํธ | ์์ (ํญ์ ์คํ ์ค) | ์์ (๋นํ์ฑ ํ ์ฒซ ์์ฒญ ์ ์ง์ฐ) |
| ์คํ ์๊ฐ ์ ํ | ์์ | ์์ (Lambda ์ต๋ 15๋ถ) |
| ์ํ ์ ์ง | ๊ฐ๋ฅ | ๊ธฐ๋ณธ์ ์ผ๋ก stateless |
| ํ๊ฒฝ ์ปค์คํฐ๋ง์ด์ง | ๋์ | ๋ฎ์ (๋ฐํ์ ์ ํ) |
| ์ด๊ธฐ ์ค์ ๋ณต์ก๋ | ๋์ | ๋ฎ์ |
์ธ์ ์ด๋ค ๊ฑธ ์ ํํ ๊น
Container๊ฐ ์ ํฉํ ๊ฒฝ์ฐ
- ์น ์๋ฒ, API ์๋ฒ์ฒ๋ผ ํญ์ ์ผ์ ธ ์์ด์ผ ํ๋ ์ฅ๊ธฐ ์คํ ํ๋ก์ธ์ค
- ๋ณต์กํ ์์กด์ฑ์ด๋ ์ปค์คํ ๋ฐํ์์ด ํ์ํ ๊ฒฝ์ฐ
- ์คํ ์๊ฐ์ด 15๋ถ์ ๋๋ ๋ฐฐ์น ์์
- ์ธ๋ฐํ ์ธํ๋ผ ์ ์ด๊ฐ ํ์ํ ๋
- ๋ ๊ฑฐ์ ์์คํ ์ ์ ์ง์ ์ผ๋ก ํด๋ผ์ฐ๋๋ก ์ด์ ํ ๋
Serverless๊ฐ ์ ํฉํ ๊ฒฝ์ฐ
- ํ์ผ ์ ๋ก๋ ํ ์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ง, ์ด๋ฉ์ผ ๋ฐ์ก์ฒ๋ผ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ฒ๋ฆฌ
- ํธ๋ํฝ์ด ๋ถ๊ท์นํ๊ฑฐ๋ ์์ธกํ๊ธฐ ์ด๋ ค์ด ๊ฒฝ์ฐ
- ๋น ๋ฅธ ํ๋กํ ํ์ดํ๊ณผ MVP ๊ฐ๋ฐ
- ์คํ ์๊ฐ์ด ์งง์ API ์๋ํฌ์ธํธ
- ํฌ๋ก ์ก(์ค์ผ์ค ๊ธฐ๋ฐ ์์ )
์ฝ๋ ์คํํธ ๋ฌธ์ ์ ํด๊ฒฐ ๋ฐฉ๋ฒ
Serverless์ ๊ฐ์ฅ ํฐ ๋จ์ ์ ์ฝ๋ ์คํํธ๋ค. ํจ์๊ฐ ์ผ์ ์๊ฐ ๋นํ์ฑ ์ํ์๋ค๊ฐ ์์ฒญ์ด ๋ค์ด์ค๋ฉด ์ปจํ ์ด๋ ์ด๊ธฐํ์ ์๋ฐฑ ms~์ ์ด์ ์ง์ฐ์ด ๋ฐ์ํ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
- Provisioned Concurrency (AWS Lambda): ์ธ์คํด์ค๋ฅผ ๋ฏธ๋ฆฌ ์๋ฐ์ ํด ๋๊ธฐ ์ํ๋ก ์ ์ง
- ์ฃผ๊ธฐ์ ์ธ Warm-up ์์ฒญ: CloudWatch ์ด๋ฒคํธ๋ก ๋๋ฏธ ์์ฒญ์ ๋ณด๋ด ํ์ฑ ์ ์ง
- ๊ฐ๋ฒผ์ด ๋ฐํ์ ์ ํ: Python, Node.js๋ Javaยท.NET๋ณด๋ค ์ด๊ธฐํ๊ฐ ํจ์ฌ ๋น ๋ฆ
- ์์กด์ฑ ์ต์ํ: ํจํค์ง ํฌ๊ธฐ๋ฅผ ์ค์ฌ ์ด๊ธฐํ ์๊ฐ ๋จ์ถ
// ํธ๋ค๋ฌ ๋ฐ์์ DB ํด๋ผ์ด์ธํธ๋ฅผ ์ด๊ธฐํํ๋ฉด ์ฌ์ฌ์ฉ ๊ฐ๋ฅ
// ์ฝ๋ ์คํํธ ์์๋ง ์์ฑ๋๊ณ , ์ดํ ์์ฒญ์์๋ ์ฌ์ฌ์ฉ๋จ
const dbClient = new DatabaseClient(process.env.DB_URL);
exports.handler = async (event) => {
const result = await dbClient.query('SELECT * FROM users');
return { statusCode: 200, body: JSON.stringify(result) };
};
ํ์ด๋ธ๋ฆฌ๋ ์ํคํ ์ฒ
์ค์ ํ๋ก๋์ ์์๋ Container์ Serverless๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
- Kubernetes ์์์ ๋ฉ์ธ ์น ์๋ฒ ์คํ โ Container
- Lambda๋ก ์ด๋ฏธ์ง ์ฒ๋ฆฌ, ์๋ฆผ ๋ฐ์ก โ Serverless
- AWS Fargate๋ก ๋ฐฐ์น ์์ ์คํ โ Container์ฒ๋ผ ์ฐ์ง๋ง ์๋ฒ ๊ด๋ฆฌ ๋ถํ์
Fargate๋ Container์ Serverless์ ์ค๊ฐ ํํ๋ค. ์ปจํ ์ด๋ ์ด๋ฏธ์ง ๊ทธ๋๋ก ์คํํ๋ฉด์๋ ์๋ฒ ํ๋ก๋น์ ๋์ด ํ์ ์๋ค. Google Cloud Run๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค.
์ ๋ฆฌ
Container์ Serverless๋ ๋๋ฆฝ ๊ด๊ณ๊ฐ ์๋๋ผ ์ํธ ๋ณด์์ ์ด๋ค. ์ฅ๊ธฐ ์คํยท๋ณต์กํ ํ๊ฒฝ์ด ํ์ํ๋ฉด Container๋ฅผ, ์ด๋ฒคํธ ๊ธฐ๋ฐ์ ์งง์ ์คํยท์์ธก ๋ถ๊ฐํ ํธ๋ํฝ์๋ Serverless๋ฅผ ์ ํํ๋ค. Fargate, Cloud Run ๊ฐ์ ์๋น์ค๊ฐ ๋ฑ์ฅํ๋ฉด์ ๋ ํจ๋ฌ๋ค์์ ๊ฒฝ๊ณ๋ ์ ์ ํ๋ ค์ง๊ณ ์๋ค. ์ค์ํ ๊ฑด ์๋น์ค์ ํน์ฑ์ ๋ง๊ฒ ๋๊ตฌ๋ฅผ ๊ณ ๋ฅด๋ ๊ฒ์ด๋ค.