Cloudflare Workers에서 ffmpeg를 번들링하지 말고, 호출해서 실행하세요.
Workers는 V8 isolate 안에서 실행돼요 — 파일시스템도, 네이티브 바이너리도 없고 CPU 시간에는 엄격한 제한이 걸려 있어요. Worker가 HTTPS로 URL 하나를 Fotovid에 넘기면 인코딩은 isolate 밖에서 처리되고, 결과는 호스팅된 링크로 돌아오기 때문에 CPU 예산을 전혀 소모하지 않아요.
export default {
async fetch(req: Request, env: { FOTOVID_API_KEY: string }): Promise<Response> {
const { videoUrl, logoUrl } = await req.json();
const res = await fetch("https://api.fotovid.co/v1/video/watermark", {
method: "POST",
headers: {
Authorization: `Bearer ${env.FOTOVID_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
source_url: videoUrl,
params: { type: "image", watermark_image_url: logoUrl, position: "bottom-right" },
}),
});
const { url } = await res.json();
return Response.json({ url });
},
};Worker가 ffmpeg 앞에서 막히는 이유
Cloudflare Workers는 컨테이너가 아니라 V8 isolate 안에서 실행돼요. 임시 파일을 쓸 파일시스템이 없고, 네이티브 바이너리를 셸아웃으로 실행할 방법도 없으며, 요청당 CPU 시간에는 엄격한 제한이 걸려 있어요. ffmpeg 바이너리는 애초에 그 안에 존재할 수 없어요. WASM 빌드는 기술적으로 로드는 되지만 isolate의 메모리와 CPU 예산에 발목이 잡혀서, 아주 짧은 클립을 넘어서는 순간 멈춰버려요. 현실적인 방법은 호스팅된 API뿐이에요.
- 파일시스템 없음: ffmpeg는 입력을 읽고 출력을 쓸 임시 파일이 필요한데, Workers에는 그게 없어요.
- 네이티브 바이너리 불가: V8 isolate 안에서는 ffmpeg 바이너리를 설치하거나 실행할 수 없어요.
- WASM ffmpeg는 로드는 되지만 isolate의 메모리와 CPU 제한에 걸려요 — 실제 영상에서는 멈추거나 타임아웃이 나요.
- 요청당 엄격한 CPU 예산 때문에 트랜스코딩 수준의 작업은 애초에 시작조차 할 수 없어요.
팀들이 Cloudflare Workers에서 ffmpeg를 돌리려 시도하는 방법들
Fotovid가 없던 시절엔 이런 선택지뿐이었어요 — 하나같이 직접 떠안고 싶지 않은 일이죠.
| Option | What it costs you | Verdict |
|---|---|---|
| Cloudflare Workers 함수에 ffmpeg 번들링하기 | Workers는 네이티브 바이너리를 아예 실행할 수 없음 | |
| 컨테이너나 VM을 직접 호스팅 | 상시 가동 비용에 패치, 스케일링, 모니터링까지 부담 | |
| 작업 큐 + 워커 운영 | 새 인프라 필요: 큐, 워커, 재시도, 데드레터 처리 | |
| 브라우저에서 트랜스코딩 (WASM) | 느리고 메모리를 많이 먹으며 모바일에서는 크래시 발생 | |
| Fotovid API 호출 | HTTPS 요청 한 번이면 끝 — 실행할 것도, 패키징할 것도, 스케일링할 것도 없음 |
3단계로 끝내는 첫 호출
- 1무료 API 키 발급받기
가입하고 키를 하나 만드세요. Authorization: Bearer p6_<key_id>:<secret> 형태의 토큰을 받는데, 이 토큰으로 https://api.fotovid.co에 대한 모든 호출을 인증해요. 인프라도, ffmpeg 빌드도 필요 없어요 — 헤더 하나면 충분해요.
- 2Worker에서 영상 POST하기
표준 envelope로 POST /v1/video/watermark를 호출하세요: 입력 영상의 HTTPS URL을 가리키는 source_url과 params 객체가 필요해요 — type을 image, text, combo 중 하나로 설정하고, position(예: bottom-right), opacity, scale도 함께 지정하세요. Worker 안에서는 그냥 fetch 한 번이면 되니 isolate의 요청 모델에 완벽히 들어맞아요.
- 3호스팅된 결과 URL 사용하기
Fotovid는 { id, type, url, expires_at, duration } 형태의 flat JSON을 반환해요. url은 Fotovid에 호스팅된 완성된 워터마크 영상을 가리켜요. 그대로 클라이언트에 넘기거나, 영구 보관하려면 직접 버킷에 복사하세요 — 호스팅된 결과물은 임시 파일이에요.
