클라우드 인코딩 비용이 청구서에 쌓이고 있다면, 이 글이 그 공식을 다시 생각하게 만들 것이다. Mac Mini 4대를 Tailscale로 묶고 ffmpeg 분산 파이프라인을 직접 돌렸다. 결과는 단순했다 — 월 비용 0원, 처리 속도는 AWS Elastic Transcoder 대비 압도적이었다.
Tailscale로 Mac Mini 4대 묶기
"클러스터"라고 하면 거창하게 들리지만 실제로는 단순하다. Tailscale은 WireGuard 위에 올라간 메시 VPN이다. 설치하면 각 노드가 100.x.x.x 대역 IP를 받고, 방화벽 포트를 별도로 열 필요가 없다. 공유기 뒤에 있든, NAT 뒤에 있든 그냥 연결된다.
처음엔 직접 SSH 터널링으로 해봤다. 공유기 포트포워딩 설정, 동적 IP 대응, 방화벽 규칙 — 노드 하나 추가할 때마다 이 사이클을 반복해야 했다. Tailscale로 바꾸고 나서는 이 작업이 통째로 사라졌다.
# 각 노드에서 실행
brew install tailscale
sudo tailscaled &
tailscale up --authkey tskey-xxxxxxxxxxxxxxxx
# 연결 확인
tailscale status
4대 모두 같은 Tailnet에 등록되면 ssh mini2@100.64.0.2 한 줄로 붙는다. 관리 콘솔에서 각 노드의 IP, 상태, 마지막 접속 시각을 한눈에 확인할 수 있다.
ffmpeg 세그먼트 분산 인코딩
영상 하나를 통째로 인코딩하면 한 코어가 막힌다. 세그먼트로 쪼개서 각 노드에 뿌리면 이야기가 달라진다.
실측 결과 (2분짜리 4K ProRes 원본 기준)
| 구성 | 처리 시간 |
|---|---|
| 단일 노드 | 4분 12초 |
| 4노드 분산 | 58초 |
단순 4배 이상 차이가 나는 이유는 I/O 병목도 같이 분산되기 때문이다. 한 노드가 읽고 쓰는 동안 다른 노드는 연산에만 집중한다.
# 원본을 30초 단위로 분할
ffmpeg -i input.mov -c copy -f segment \
-segment_time 30 -reset_timestamps 1 segment_%03d.mov
# 각 노드에 전송 후 인코딩 (노드별 병렬 실행)
for i in 00 01 02 03; do
scp segment_0${i}.mov mini${i}@100.64.0.${i}:~/encode/
ssh mini${i}@100.64.0.${i} \
"ffmpeg -i ~/encode/segment_0${i}.mov \
-c:v libx264 -crf 23 -preset fast \
~/encode/out_0${i}.mp4" &
done
wait
# 결과 병합
ffmpeg -f concat -safe 0 -i filelist.txt -c copy final_output.mp4
wait 한 줄이 중요하다. 모든 백그라운드 ssh 세션이 끝날 때까지 병합 단계로 넘어가지 않는다. 이걸 빠뜨리면 인코딩이 덜 끝난 세그먼트가 병합 대상에 들어가면서 조용히 깨진 파일이 만들어진다.
Draw Things로 프레임 AI 업스케일
Draw Things는 이미지 생성만 하는 툴이 아니다. img2img 파이프라인으로 저해상도 프레임을 고해상도로 올릴 수 있다. M2 Pro 노드 2대를 Draw Things 전용 업스케일 워커로 할당했다.
720p 원본 프레임이 ESRGAN을 통과하면 1440p로 나온다. M2 Pro Neural Engine 기준 프레임 1장당 실측 처리 시간은 0.8초. 30fps 영상 전체를 업스케일하면 현실적이지 않으니, ffmpeg로 씬 변화가 있는 키프레임만 추출해서 처리한다.
# 씬 변화 감지 기준 키프레임만 추출
ffmpeg -i input.mp4 \
-vf "select=gt(scene\,0.3)" \
-vsync vfr frames/frame_%04d.png
# 업스케일 실행 (Draw Things CLI 래퍼 예시)
python upscale_runner.py \
--input frames/ \
--output upscaled/ \
--model realesrgan-x4
# 업스케일 프레임 + 원본 오디오 합성
ffmpeg -framerate 30 -i upscaled/frame_%04d.png \
-i input.mp4 \
-map 0:v -map 1:a \
-c:v libx264 -crf 18 -preset slow \
final_hq.mp4
scene=0.3 임계값은 환경마다 다르게 튜닝해야 한다. 액션이 많은 영상은 0.2, 정적인 인터뷰 영상은 0.4 정도가 적당했다. 너무 낮추면 중복 프레임이 쏟아져서 업스케일 시간이 폭발한다.
운영하면서 만난 함정들
세그먼트 경계 아티팩트: -c copy로 분할하면 키프레임 경계가 맞지 않을 때 첫 프레임이 깨지는 경우가 있다. -force_key_frames "expr:gte(t,n_forced*30)" 옵션으로 30초마다 강제 키프레임을 박으면 해결된다.
Tailscale 대역폭 제한: 로컬 LAN처럼 쓰지만 DERP 서버를 거치면 속도가 뚝 떨어진다. tailscale ping mini2 로 직접 연결(direct) 상태인지 확인하고, 같은 공유기 아래 있다면 subnet routing으로 LAN 경로를 강제한다.
Docker 환경 차이: Linux 노드 섞어서 쓰는 경우 ffmpeg 빌드 옵션이 달라서 인코딩 결과물 품질이 미묘하게 다를 수 있다. 가능하면 동일한 ffmpeg 바이너리를 배포하거나, Docker 이미지로 통일하는 게 낫다.
클라우드 인코딩 비용이 쌓이고 있다면 지금 보유한 장비부터 다시 보자. Tailscale 메시와 ffmpeg 세그먼트 분산만으로 4노드 기준 처리 시간이 4분 12초에서 58초로 줄었다. 셀프호스팅은 단순한 절약이 아니라 파이프라인 전체를 직접 제어하는 구조다. Draw Things 업스케일까지 붙이면 영상 후처리까지 로컬에서 완결된다.
다음 글에서는 이 파이프라인에 n8n 워크플로우를 연결해서 S3 업로드 → 인코딩 트리거 → 완료 알림까지 자동화하는 과정을 다룬다.
🐦 X에서 더 빠르게: @baegseungh7061
📚 이 시리즈 더 보기: AI 인사이트
💌 새 글 알림: X 팔로우 또는 블로그 RSS 구독
'AI 인사이트' 카테고리의 다른 글
| Superpowers — 코딩 에이전트가 스스로 설계·계획·TDD를 수행하는 완전 자동 개발 방법론 (0) | 2026.05.07 |
|---|---|
| everything-claude-code — 10개월 에이전트 노하우를 Claude Code에 이식하는 법 (0) | 2026.05.07 |
| Git Worktree로 브랜치 전환 없이 병렬 개발하는 법 (0) | 2026.05.01 |
| VS Code Remote Development로 서버 성능을 내 손끝에 — SSH 원격 개발 완전 정복 (0) | 2026.04.29 |
| DeepSeek-V3 로컬 추론 환경 구축 — Ollama로 API 비용 제로 만들기 (0) | 2026.04.29 |