목차
- 서버 없이 전 세계에서 실행되는 API? Cloudflare Workers 이야기
- Cloudflare Workers가 뭔지 쉽게 풀어보기
- 엣지 컴퓨팅(Edge Computing)이란?
- Workers의 핵심 특징
- 환경 설정: Wrangler CLI 설치부터 시작
- 1단계: Node.js 및 Wrangler 설치
- 2단계: 새 Workers 프로젝트 생성
- 실전 구현: 서버리스 REST API 만들기
- 기본 라우팅이 포함된 API Worker
- Workers KV 설정하기
- 로컬에서 테스트하기
- ⚠️ 주의사항 및 실제 겪은 트러블슈팅
- 문제 1: Workers KV 쓰기 전파 지연
- 문제 2: CPU 시간 제한
- 문제 3: Node.js API 호환성 이슈
- 문제 4: 환경 변수 관리
- 결과 확인: 대시보드에서 모니터링하기
- 커스텀 도메인 연결
- 마무리: Workers가 잘 맞는 상황 vs 아닌 상황
- ✅ Workers가 잘 맞는 경우
- ⚠️ 다른 선택지를 고려해야 할 경우
- 자주 묻는 질문 (FAQ)
서버 없이 전 세계에서 실행되는 API? Cloudflare Workers 이야기
솔직히 말씀드리면, 처음 Cloudflare Workers를 접했을 때 "이게 뭔 소리지?" 싶었거든요. 서버리스(Serverless)라는 개념 자체는 알고 있었는데, "엣지에서 실행된다"는 말이 딱 와닿지 않았습니다. 그러다 실제로 간단한 API 하나를 올려봤는데... 서울에서 요청하면 서울 근처 데이터센터에서, 미국에서 요청하면 미국 데이터센터에서 응답이 오는 거예요. 레이턴시(Latency, 응답 지연)가 확 줄어드는 게 느껴졌습니다. 그때 "아, 이래서 엣지 컴퓨팅이구나" 하고 감이 왔죠.
홈랩에서 이것저것 돌리다 보면 늘 고민이 생기잖아요. 외부에서 접근 가능한 간단한 API가 필요한데, 서버 하나 띄우자니 유지보수가 귀찮고, 클라우드 VM 쓰자니 비용이 아깝고. 그 틈새를 Cloudflare Workers가 정말 잘 채워줬습니다. 오늘은 제가 실제로 Workers로 서버리스 API를 구축하면서 겪은 경험을 바탕으로, 처음 시작하시는 분들도 따라할 수 있게 정리해 드릴게요.
▲ Cloudflare Workers의 엣지 컴퓨팅 구조 — 전 세계 데이터센터에서 코드가 실행되는 개념도
Cloudflare Workers가 뭔지 쉽게 풀어보기
엣지 컴퓨팅(Edge Computing)이란?
일반적인 클라우드 서버는 특정 리전(Region, 지역)에 고정되어 있어요. 예를 들어 AWS ap-northeast-2(서울 리전)에 서버를 올리면, 미국 사용자가 접속할 때는 태평양을 건너서 요청이 오가야 하죠. 이게 레이턴시의 주범입니다.
엣지 컴퓨팅은 이 문제를 뒤집어서 생각한 거예요. "서버를 중앙에 두지 말고, 사용자 가까이에 두자!" 라는 발상이죠. Cloudflare는 전 세계 200개 이상의 도시에 데이터센터(PoP, Point of Presence)를 운영하고 있는데, Workers 코드가 이 모든 위치에서 실행됩니다. 쉽게 말해, 사용자가 어디에 있든 가장 가까운 서버에서 응답이 오는 거예요.
Workers의 핵심 특징
- V8 엔진 기반: Node.js가 아닌 V8 Isolate(아이솔레이트) 방식으로 실행됩니다. 컨테이너보다 훨씬 빠르게 시작해요 (콜드 스타트 거의 없음)
- JavaScript / TypeScript 지원: 프론트엔드 개발자분들도 친숙하게 쓸 수 있어요
- Workers KV: 엣지에서 사용 가능한 키-값(Key-Value) 스토리지
- 무료 티어 존재: 하루 10만 요청까지 무료 (최신 정보는 Cloudflare 공식 가격 페이지 확인 권장)
- 배포가 초간단: Wrangler CLI 명령어 하나로 전 세계 배포 완료
| 구분 | 전통적 서버 | 일반 서버리스 (Lambda 등) | Cloudflare Workers |
|---|---|---|---|
| 실행 위치 | 단일 리전 | 단일 리전 | 전 세계 엣지 |
| 콜드 스타트 | 없음 | 수백ms ~ 수초 | 거의 없음 (0ms 수준) |
| 관리 부담 | 높음 | 낮음 | 매우 낮음 |
| 런타임 | 자유 | Node.js, Python 등 | V8 (JS/TS/Wasm) |
| 무료 티어 | 없음 | 있음 | 있음 |
환경 설정: Wrangler CLI 설치부터 시작
본격적으로 시작해볼게요. Wrangler는 Cloudflare Workers 개발을 위한 공식 CLI(Command Line Interface) 도구입니다. 이게 없으면 아무것도 못 하니까 먼저 설치부터요.
1단계: Node.js 및 Wrangler 설치
Node.js 16 이상이 설치되어 있다는 전제 하에 진행합니다.
# Wrangler CLI 전역 설치
npm install -g wrangler
# 설치 확인
wrangler --version
# Cloudflare 계정 로그인 (브라우저가 열립니다)
wrangler login
로그인하면 브라우저에서 Cloudflare 대시보드로 이동해서 권한 허용을 요청해요. 그냥 허용 누르시면 됩니다. 처음에 이 과정이 좀 낯설었는데, 익숙해지면 진짜 편하더라고요.
2단계: 새 Workers 프로젝트 생성
# 새 프로젝트 생성 (대화형 설정)
npm create cloudflare@latest my-api-worker
# 프로젝트 디렉토리로 이동
cd my-api-worker
생성 과정에서 몇 가지 질문이 나오는데, "Hello World" 템플릿 선택하고, TypeScript 쓸지 JavaScript 쓸지 고르면 됩니다. 저는 보통 TypeScript를 선택하는 편이에요. 타입 안정성이 있으니까요.
프로젝트 구조는 이렇게 됩니다:
my-api-worker/
├── src/
│ └── index.ts # 메인 Worker 코드
├── wrangler.toml # Worker 설정 파일
├── package.json
└── tsconfig.json
실전 구현: 서버리스 REST API 만들기
이제 진짜 코드를 써볼게요. 단순한 "Hello World"는 재미없으니까, 실제로 쓸 만한 간단한 REST API를 만들어보겠습니다. 라우팅(Routing)과 메서드 분기를 포함한 구조예요.
▲ Wrangler를 이용한 로컬 개발 환경 — wrangler dev 명령으로 로컬에서 Workers를 테스트할 수 있어요
기본 라우팅이 포함된 API Worker
// src/index.ts
export interface Env {
// 나중에 KV 바인딩을 여기 추가할 거예요
MY_KV: KVNamespace;
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
const path = url.pathname;
const method = request.method;
// CORS 헤더 설정
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
// Preflight 요청 처리
if (method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
// 라우팅 처리
if (path === '/api/hello' && method === 'GET') {
return Response.json(
{ message: '안녕하세요! Cloudflare Workers에서 응답합니다.', timestamp: Date.now() },
{ headers: corsHeaders }
);
}
if (path === '/api/items' && method === 'GET') {
return handleGetItems(env, corsHeaders);
}
if (path === '/api/items' && method === 'POST') {
return handlePostItem(request, env, corsHeaders);
}
// 404 처리
return Response.json(
{ error: 'Not Found', path },
{ status: 404, headers: corsHeaders }
);
},
};
// GET /api/items — KV에서 아이템 목록 조회
async function handleGetItems(env: Env, headers: Record<string, string>): Promise<Response> {
const data = await env.MY_KV.get('items', 'json') as string[] | null;
return Response.json(
{ items: data ?? [] },
{ headers }
);
}
// POST /api/items — KV에 아이템 추가
async function handlePostItem(
request: Request,
env: Env,
headers: Record<string, string>
): Promise<Response> {
const body = await request.json() as { name: string };
if (!body.name) {
return Response.json(
{ error: 'name 필드가 필요합니다' },
{ status: 400, headers }
);
}
const existing = await env.MY_KV.get('items', 'json') as string[] | null;
const items = existing ?? [];
items.push(body.name);
await env.MY_KV.put('items', JSON.stringify(items));
return Response.json(
{ success: true, items },
{ status: 201, headers }
);
}
코드 보시면 구조가 꽤 직관적이죠? fetch 함수가 모든 HTTP 요청의 진입점이고, URL 경로와 HTTP 메서드로 분기처리를 합니다. Node.js의 Express 같은 느낌이에요.
Workers KV 설정하기
Workers KV는 엣지에서 사용 가능한 분산 키-값 스토리지예요. 데이터베이스를 별도로 운영하지 않아도 간단한 데이터를 저장하고 조회할 수 있거든요. 쓰기는 약간의 전파 지연이 있지만, 읽기는 엣지에서 바로 처리되니까 빠릅니다.
# KV 네임스페이스(Namespace) 생성
wrangler kv:namespace create MY_KV
# 로컬 개발용 프리뷰 네임스페이스도 생성
wrangler kv:namespace create MY_KV --preview
명령어 실행 후 출력되는 ID를 wrangler.toml에 붙여넣어야 합니다.
# wrangler.toml
name = "my-api-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[[kv_namespaces]]
binding = "MY_KV" # 코드에서 env.MY_KV로 접근
id = "여기에_실제_KV_ID_입력"
preview_id = "여기에_프리뷰_KV_ID_입력"
💡 팁: binding 이름이 TypeScript 인터페이스의 Env에 선언한 이름과 일치해야 해요. 처음에 이게 안 맞아서 에러가 났었는데, 삽질 좀 했습니다 ㅎㅎ
로컬에서 테스트하기
# 로컬 개발 서버 실행
wrangler dev
# 기본적으로 http://localhost:8787 에서 실행됩니다
# 다른 터미널에서 API 테스트
curl http://localhost:8787/api/hello
# POST 테스트
curl -X POST http://localhost:8787/api/items \
-H "Content-Type: application/json" \
-d '{"name": "테스트 아이템"}'
# GET으로 확인
curl http://localhost:8787/api/items
로컬에서 잘 돌아가면 이제 배포할 차례예요!
# 전 세계 배포 (진짜 이 명령어 하나예요)
wrangler deploy
# 배포 후 URL이 출력됩니다
# 예: https://my-api-worker.your-subdomain.workers.dev
🎉 배포 완료! 이 URL로 전 세계 어디서든 접근 가능합니다. 처음에 이게 진짜로 되는 건지 믿기지 않아서 VPN으로 미국, 일본, 유럽 각각에서 테스트해봤는데 전부 잘 됐더라고요.
⚠️ 주의사항 및 실제 겪은 트러블슈팅
좋은 것만 얘기하면 재미없죠. 실제로 쓰다 보면 꼭 한 번씩 걸리는 것들이 있어요.
문제 1: Workers KV 쓰기 전파 지연
KV에 데이터를 쓰고 바로 읽으면 이전 값이 나오는 경우가 있어요. KV는 최종 일관성(Eventual Consistency) 모델이라서, 쓰기 작업이 전 세계 엣지에 전파되는 데 시간이 걸립니다. 공식 문서에 따르면 최대 60초 정도 걸릴 수 있어요. 로컬 개발 환경에서는 이게 즉시 반영되는 것처럼 보이는데, 프로덕션에서는 다를 수 있습니다.
해결책: 쓰기 직후 즉시 읽기가 필요한 로직은 KV 대신 Durable Objects(내구성 있는 객체, 강한 일관성 보장)를 고려하세요. 단순 캐시나 설정값 저장에는 KV가 딱 좋습니다.
문제 2: CPU 시간 제한
Workers는 요청당 CPU 시간 제한이 있어요. 무료 티어는 요청당 10ms, 유료 플랜은 더 길어요. 무거운 연산(이미지 처리, 복잡한 암호화 등)은 Workers에 맞지 않습니다. 저도 처음에 이미지 리사이징 로직을 Workers에 넣으려다 바로 한계에 부딪혔어요.
해결책: Workers는 가볍고 빠른 로직에 최적화되어 있거든요. 무거운 작업은 백엔드 서버로 위임하고, Workers는 게이트웨이(Gateway, 진입 관문) 역할만 맡기는 패턴이 좋습니다.
문제 3: Node.js API 호환성 이슈
Workers는 Node.js 런타임이 아니에요. V8 Isolate 기반이라 Node.js 전용 API(예: fs, path, crypto 일부)가 기본적으로 없어요. npm 패키지 중에도 Node.js 내장 모듈에 의존하는 것들은 Workers에서 안 돌아갈 수 있습니다.
해결책: wrangler.toml에 node_compat = true를 추가하면 일부 Node.js API 폴리필(Polyfill, 하위 호환 구현체)이 활성화됩니다. 그래도 안 되는 경우엔 Workers 환경에 맞는 대안 라이브러리를 찾아야 해요.
# wrangler.toml에 추가
node_compat = true
문제 4: 환경 변수 관리
API 키 같은 민감한 정보를 코드에 하드코딩하면 절대 안 되죠. Workers에는 Secrets(시크릿) 기능이 있어요.
# 시크릿 등록 (값은 프롬프트로 입력)
wrangler secret put MY_API_KEY
# 등록된 시크릿 목록 확인
wrangler secret list
// 코드에서 env로 접근
export interface Env {
MY_KV: KVNamespace;
MY_API_KEY: string; // 시크릿도 Env에 선언
}
// 사용 예시
const apiKey = env.MY_API_KEY;
결과 확인: 대시보드에서 모니터링하기
배포 후 Cloudflare 대시보드에서 Workers 섹션을 보면 꽤 유용한 정보들을 확인할 수 있어요.
▲ Cloudflare Workers 대시보드 — 요청 수, 에러율, CPU 시간 등 실시간 모니터링이 가능해요
- ✅ 요청 수(Requests): 분/시간/일별 요청량 확인
- ✅ 에러율(Error Rate): 4xx, 5xx 에러 비율
- ✅ CPU 시간: 요청당 평균 CPU 사용 시간
- ✅ 실시간 로그:
wrangler tail명령으로 실시간 로그 스트리밍 가능
# 실시간 로그 스트리밍
wrangler tail
# 특정 Worker 지정
wrangler tail my-api-worker
로그에서 요청 경로, 응답 코드, 실행 시간 등이 다 나와요. 디버깅할 때 꽤 유용하더라고요. 처음에 이 기능 몰라서 console.log 찍어가며 고생했는데, 알고 나서 "진작 쓸걸" 했죠.
커스텀 도메인 연결
기본 제공되는 *.workers.dev 도메인 말고, 본인 도메인을 연결할 수도 있어요. Cloudflare에 도메인이 등록되어 있다면 Workers 설정에서 Route(라우트, 트래픽 경로)를 추가하면 됩니다.
# wrangler.toml에 라우트 추가
[[routes]]
pattern = "api.yourdomain.com/*"
zone_name = "yourdomain.com"
이렇게 하면 api.yourdomain.com으로 들어오는 모든 요청이 Workers로 처리돼요. 깔끔하죠?
마무리: Workers가 잘 맞는 상황 vs 아닌 상황
▲ Cloudflare Workers 적합/비적합 사용 사례 요약 — 어떤 상황에서 Workers를 선택해야 할지 한눈에 보기
몇 달 써보면서 느낀 건, Workers는 만능이 아니에요. 잘 맞는 상황이 있고, 억지로 쓰면 오히려 복잡해지는 상황도 있더라고요.
✅ Workers가 잘 맞는 경우
- CORS 프록시, API 게이트웨이
- A/B 테스트, 기능 플래그(Feature Flag) 처리
- 간단한 인증/인가(Authentication/Authorization) 미들웨어
- 정적 사이트의 동적 기능 추가 (Jamstack 패턴)
- 봇 차단, 요청 필터링
- 지리적으로 분산된 캐시 레이어
⚠️ 다른 선택지를 고려해야 할 경우
- 무거운 연산이나 긴 실행 시간이 필요한 작업
- 강한 데이터 일관성이 필요한 트랜잭션 처리
- 파일 시스템 접근이 필요한 경우
- 기존 Node.js/Python 등 런타임 의존성이 많은 경우
자주 묻는 질문 (FAQ)
- Q. Workers KV와 일반 데이터베이스의 차이는?
- A. Workers KV는 읽기에 최적화된 분산 스토리지예요. 복잡한 쿼리나 관계형 데이터가 필요하다면 Cloudflare D1(SQLite 기반) 이나 외부 DB를 연동하는 게 낫습니다.
- Q. 무료로 얼마나 쓸 수 있나요?
- A. 공식 문서 기준 무료 티어는 하루 10만 요청까지 제공합니다. 정확한 현행 조건은 Cloudflare 공식 가격 페이지에서 반드시 확인하세요. 자주 바뀌는 편이거든요.
- Q. TypeScript 말고 다른 언어도 되나요?
- A. WebAssembly(웹어셈블리)로 컴파일되는 언어라면 이론상 가능해요. Rust로 Workers를 작성하는 사례도 있습니다. 다만 생태계는 JS/TS가 가장 풍부해요.
오늘 다룬 내용이 Cloudflare Workers로 서버리스 API와 엣지 컴퓨팅을 시작하는 데 도움이 됐으면 좋겠어요. 다음 글에서는 Cloudflare D1(서버리스 SQLite 데이터베이스)과 Workers를 연동해서 더 완성도 있는 API를 만드는 방법을 다룰 예정입니다. Workers KV만으로는 아쉬울 때 딱 좋은 조합이거든요.
궁금한 점이나 직접 해보다가 막히는 부분 있으시면 댓글로 남겨주세요. 같이 삽질해봅시다! 😄
'IT > Cloud' 카테고리의 다른 글
| [Cloud] Ansible 클라우드 보안 자동화: 취약점 관리 및 규정 준수 가이드 (1) | 2026.05.05 |
|---|---|
| [Cloud] AWS 비용 최적화: EC2, S3, RDS 절감 전략 및 Cost Explorer 활용 가이드 (1) | 2026.05.01 |
| [Cloud] Terraform으로 AWS/GCP/Azure 멀티 클라우드 환경 구축 가이드 (0) | 2026.04.29 |
| [Cloud] Terraform 원격 상태 관리: S3, GCS, Azure Blob 백엔드 설정 가이드 (0) | 2026.04.28 |
| [Cloud] Terraform 멀티 클라우드 IaC 자동화 가이드 — AWS/GCP/Azure 통합 관리 (0) | 2026.04.21 |
| [Cloud] Terraform 멀티 클라우드 관리 가이드 - AWS/GCP/Azure 한 번에 관리하기 (0) | 2026.04.21 |