돈벌기

돈이 없다. 이것은 학생의 숙명이다. 프리티어를 떠도는 노마드의 삶이다. 그런데 코딩을 하면 배포할 일이 생긴다. 당연한 거 아닌가. 배포를 그럼 git clone하라고 할 수도 없지 않나.
FaaS/서버리스
서버리스의 장점은 그것이다. 24/7이 필요하긴 한데, 굳이 막 항상 사람이 들어오는 건 아닌 사이트 많지 않나? 그런 상황이 많다. 서버리스는 그 상황에 딱 맞는다. 트래픽 없다? 서버 내릴게. 서버 내려? 돈 안뺄게.
Azure Functions
Azure Functions는 마이크로소프트의 서버리스 플랫폼이다.
장점:
- 언어 독립적이다, 안 되면 커스텀 핸들러로 어떻게든 된다
- SLA가 있다(무료티어 포함)
- 무료 티어도 있고 학생 크레딧을 쓸 수 있다
단점:
- 하드캡이 없다. 카드 넣어야 한다
- 콜드 스타트가 좀 걸린다
- 저장공간은 또 다른 서비스 써야 한다
꽤 고립적이다Hono 지원
Cloudflare Workers
Cloudflare Workers는 JS를 지원하는 FaaS이다.
장점:
- 빠른 콜드 스타트(0ms!!!!)
- 무료티어 넘어가면 청구 없이 터진다(Paid 플랜 업그레이드하지 않으면)
- CI/CD를 CF에서 제공한다(=Github Action 요금 낼 필요 없다, 워크플로우 짤 필요 없다)
- 분당 1000회 무료 티어
- 다른 WinterTC 계열 서비스 대비 더 넉넉하다
단점:
- JS와 WASM 컴파일을 지원하는 일부 언어만 가능하다
- Github Action은 어짜피 퍼블릭레포 무제한 무료라 굳이…?
- 런타임은 Node.JS와 거리가 멀다, DOM 없다
- CPU 타임이 제한적이다(무료플랜 10ms/콜)
Deno Deploy
Deno Deploy는 Cloudflare Workers와 유사한 FaaS 호스팅 서비스다.
장점:
- Cloudflare Workers 대비 넉넉한 CPU 타임(15h/월)
- 빠른 콜드 스타트
- 셋업하기 쉽다(
import { Hono } from "jsr:hono", TypeScript OOTB 지원 등) - 제일 JS스럽고, 배워야 할 자체 개념이 적다
단점:
- JS/TS만 지원한다
- 카드 등록이 필요하다(업그레이드하기 전까진 billing X)
- Cloudflare Workers 대비 물리적 인프라가 떨어진다
- 다들 Cloudflare 계정은 있지만 Deno Deploy는 없는 경우도 있다
Hono
“신”
Hono는 각종 FaaS 프로바이더를 위한 프레임워크다. 지원하는 실행 환경은…
- Node.js
- Deno(Deno Deploy 포함)
- Bun
- WebAssembly
- Service Worker
이러하다. 또 호스팅은 이 플랫폼들을 지원한다.
- Cloudflare Workers, Cloudflare Pages
- Fastly Compute
- Vercel, Netlify
- Next.js
- AWS Lambda, Lambda@Edge
- Azure Functions
- Google Cloud Run
- Supabase Functions
- Ali Function Compute
이 무슨 개얼탱없는 라인업이란 말인가. 당장 써야지. 원래 FaaS 서비스들은 꽤 벤더 종속적이다. 벤더에서 제공한 API를 쓰게 되는데, 이러면 다른 곳으로 마이그레이션하기 상당히 어렵다.
// Cloudflare Workers, ES Modules 문법export default { async fetch(request, env, ctx) { const url = new URL(request.url); const name = url.searchParams.get('name');
if (name) { return new Response(`Hello, ${name}! Welcome to Cloudflare Workers.`, { status: 200, headers: { 'Content-Type': 'text/plain; charset=utf-8', }, }); } else { return new Response('Hello World! This is Cloudflare Workers.', { status: 200, headers: { 'Content-Type': 'text/plain; charset=utf-8', }, }); } },};// Azure Functionsexport async function serve(context, req) { context.log('HTTP trigger function processed a request.');
const name = req.query.name || (req.body && req.body.name);
if (name) { context.res = { status: 200, body: `Hello, ${name}! Welcome to Azure Functions.` }; } else { context.res = { status: 200, body: 'Hello World! This is Azure Functions.' }; }};export default serve;네이티브 API를 쓰면 벌써 코드가 다르다.
CF Workers는 함수를 객체에 담아 export default하고, 그 함수는 Response 객체를 리턴한다.
하지면 Azure Functions는 함수가 context.res를 수정한다.
그런데 그때, Hono가 등장한다…
import { Hono } from 'hono';
type Env = { Bindings: Record<string, unknown>;};
const app = new Hono<Env>();
// POST 요청 처리 예제app.post('/api/hello', async (c) => { const body = await c.req.json<{ name?: string }>(); const name = body.name || 'World';
return c.json({ message: `Hello, ${name}!`, method: 'POST', framework: 'Hono', });});
export default app;이거, 어디선가 본 패턴이지 않은가?
import express, { Request, Response } from 'express';
const app = express();
app.use(express.json());
app.post('/api/hello', (req: Request, res: Response) => { const body = req.body as { name?: string }; const name = body.name || 'World';
res.json({ message: `Hello, ${name}!`, method: 'POST', framework: 'Express', });});
const PORT = process.env.PORT || 3000;app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`);});
export default app;Express.js와 매우 유사하다. 선언적이고, 자유분방하다. 게다가 타입스크립트를 염두하고 만들어졌기 때문에,
//...const app=new Hono() .post("/post", ...) .get("/get", ...);export default app;이와 같은 방식으로 메서드 체인을 걸면, app의 타입 자체에 라우트 정보가 작성된다. 이는 RPC나 테스팅 시 매우 유용하다.
개인 사용을 위해 Hono용 템플릿을 작성해두었다.