“컨테이너는 가벼운 VM”이라고들 하지만, 사실 둘은 원리가 완전히 다릅니다. 컨테이너는 가상 머신이 아니라 “격리된 프로세스”일 뿐입니다. 그 격리를 만드는 두 가지 리눅스 커널 기능 — namespaces와 cgroups — 를 이해하면 LXC·Docker가 왜 그렇게 가벼운지, 그리고 왜 Docker-in-LXC에 특별한 설정이 필요한지가 보입니다.
1. 컨테이너 vs VM — 근본 차이
VM
컨테이너
격리 방식
하드웨어 가상화
커널 기능(격리된 프로세스)
커널
게스트마다 별도
호스트와 공유
부팅
OS 부팅(수십 초)
프로세스 시작(즉시)
오버헤드
큼
거의 없음
컨테이너는 호스트 커널을 그대로 공유하면서, “이 프로세스는 자기만의 세상에 있는 것처럼” 보이게 속입니다. 그 속임수의 두 축이 namespaces와 cgroups입니다.
2. namespaces — “무엇을 볼 수 있는가”
namespace는 프로세스가 보는 시야를 격리합니다. 종류별로 각각 다른 자원을 가립니다.
namespace
격리 대상
PID
프로세스 목록(자기 PID 1)
NET
네트워크(자기 IP·인터페이스)
MNT
파일시스템 마운트
UTS
호스트명
IPC
프로세스 간 통신
USER
사용자·권한(UID 매핑)
그래서 컨테이너 안에서 ps를 치면 자기 프로세스만 보이고, 자기만의 IP를 갖습니다. 실제로는 호스트의 한 프로세스일 뿐인데도요. USER namespace가 바로 “unprivileged 컨테이너”의 핵심 — 컨테이너의 root를 호스트의 비특권 사용자로 매핑해 보안을 높입니다.
Proxmox에서 LXC에 cores·memory를 지정하면, 내부적으로 cgroups가 그 한도를 강제합니다. vCPU 오버커밋이 가능한 것도 cgroups가 실제 사용량을 조율하기 때문입니다.
4. 그래서 Docker-in-LXC가 까다롭다
컨테이너가 이 커널 기능들에 의존하다 보니, 컨테이너 안에서 또 컨테이너(LXC 안 Docker)를 돌리려면 커널 기능 접근을 열어줘야 합니다.
nesting=1: 중첩된 namespace 생성 허용
keyctl=1: Docker가 쓰는 커널 키링 접근 허용
원리를 알고 나면 이 플래그들이 왜 필요한지 자연스럽게 이해됩니다 — 컨테이너의 격리 메커니즘을 한 겹 더 쌓는 것이니까요.
5. 정리
컨테이너 = namespaces(시야 격리) + cgroups(자원 제한)로 만든 “격리된 프로세스”입니다. VM처럼 커널을 통째로 복제하지 않으니 가볍고 빠른 거죠. 이 원리 하나를 잡으면 LXC·Docker의 동작, unprivileged의 의미, nesting 플래그의 이유가 전부 하나로 꿰어집니다.
Proxmox에서 어떤 서비스를 올릴 때, 무거운 VM을 통째로 띄우는 대신 가벼운 LXC 컨테이너 안에서 Docker를 돌리는 방법이 있습니다. 저는 사진 서버(Immich)도, 이 블로그 자동화 봇도 이 방식으로 운영합니다. 실제 설정과 반드시 알아야 할 함정을 정리합니다.
1. 왜 VM이 아니라 LXC + Docker인가
가볍다: LXC는 호스트 커널을 공유해서 VM보다 메모리·오버헤드가 훨씬 적습니다.
빠르다: 부팅이 거의 즉시고, 자원 낭비가 적습니다.
Docker 생태계 그대로: compose 파일과 이미지를 그대로 씁니다.
단, “다른 커널이 필요하다”거나 “강한 격리가 필수”라면 그땐 VM이 맞습니다. 일반적인 웹서비스·봇·셀프호스팅 앱이라면 LXC + Docker가 가성비 최고입니다.
2. 핵심 — 두 개의 기능 플래그
기본 LXC에 Docker를 깔면 안 돌아갑니다. 두 가지 features를 켜야 합니다.
# 컨테이너(예: 113)에 nesting + keyctl 활성화
pct set 113 --features nesting=1,keyctl=1
플래그
역할
nesting=1
컨테이너 안에서 또 컨테이너(Docker) 실행 허용
keyctl=1
Docker가 쓰는 커널 키링 접근 허용
실제로 제 컨테이너들은 이렇게 잡혀 있습니다 — 봇 컨테이너는 nesting=1,keyctl=1, Immich 컨테이너는 nesting=1. 그리고 둘 다 unprivileged(비특권) 컨테이너입니다. 보안상 가능하면 unprivileged로 두는 걸 권합니다.
3. Docker 설치
플래그를 켜고 컨테이너를 재시작한 뒤, 안에서 평범하게 Docker를 설치하면 됩니다.
# LXC 내부에서 (공식 스크립트)
curl -fsSL https://get.docker.com | sh
docker --version # 예: Docker version 29.4.0
docker compose version
4. 반드시 밟는 함정 — 좀비 프로세스
여기서 많은 분이 당합니다. 컨테이너 안에서 자식 프로세스를 반복 생성하는 앱(브라우저 자동화, 이미지 변환 등)을 Docker로 돌리면, 죽은 자식이 좀비로 쌓입니다. 컨테이너의 PID 1이 이를 거두지 않기 때문입니다(저는 이걸로 좀비 307개를 만든 적이 있습니다 — 관련 글).
# docker-compose.yml — tini를 PID 1로 넣어 좀비 자동 수거
services:
app:
image: my-app:latest
init: true
데이터는 볼륨으로: 컨테이너를 갈아엎어도 데이터가 남게, 영구 데이터는 호스트 경로/NAS 볼륨에 마운트.
백업: LXC 자체를 Proxmox 스냅샷/백업하면 Docker 스택까지 통째로 보존됩니다.
6. 정리
LXC + Docker는 홈랩에서 VM의 무게 없이 Docker 생태계를 쓰는 최적의 절충안입니다. 핵심은 딱 두 가지 — nesting=1과 keyctl=1을 켜는 것, 그리고 서브프로세스 앱엔 init: true를 잊지 않는 것. 이 두 개만 챙기면 미니 PC 한 대에 서비스를 훨씬 많이 얹을 수 있습니다.
구글 포토의 무료 무제한이 사라진 뒤로 “사진을 어디에 둘까”는 모두의 고민입니다. 저는 홈랩에 Immich를 올려서 스마트폰 사진을 자동 백업하고 있습니다. 구글 포토와 거의 똑같은 경험을 내 서버, 내 디스크에서요. 실제 운영 구성과 GPU 없이 돌리는 요령을 공개합니다.
1. Immich가 뭐고 왜 좋은가
Immich는 셀프호스팅 사진·영상 관리 서버입니다. 구글 포토를 대체하도록 만들어져서 —
스마트폰 앱으로 자동 백업(찍으면 알아서 올라감)
얼굴 인식·사물 검색(“바다”, “강아지”로 검색)
타임라인·앨범·공유 등 익숙한 UI
무엇보다 내 데이터가 외부로 안 나감
2. 실제 구성 — 4개 컨테이너
제 홈랩에서는 LXC 컨테이너 안에 Docker로 Immich 스택을 돌립니다. 구성은 이렇게 4개로 나뉩니다.
컨테이너
역할
immich-server
API·웹 UI·업로드 처리
immich-machine-learning
얼굴 인식·스마트 검색(ML)
postgres(pgvector)
메타데이터 + 벡터 검색 DB
redis(valkey)
작업 큐·캐시
여기서 눈여겨볼 건 postgres가 pgvector 계열이라는 점입니다. 얼굴·사물 검색을 위해 사진의 특징을 벡터로 저장하고, 그 벡터를 DB에서 유사도로 검색합니다. 그래서 “비슷한 사진”이나 자연어 검색이 됩니다.
3. 사진은 ZFS NAS에, 대용량을 감당
핵심은 사진 원본을 어디에 두느냐입니다. 저는 컨테이너 디스크가 아니라 ZFS 기반 NAS 데이터셋에 저장합니다. 현재 사진 라이브러리만 1.3TB가 넘는데, 컨테이너 rootfs(수십 GB)로는 어림도 없죠.
# docker-compose.yml (요지) — 업로드 경로를 NAS 볼륨에 매핑
services:
immich-server:
volumes:
- /mnt/nas/immich:/usr/src/app/upload # 원본은 대용량 NAS로
이렇게 하면 애플리케이션(컨테이너)과 데이터(NAS)를 분리할 수 있습니다. 컨테이너를 갈아엎어도 사진은 NAS에 그대로 있고, ZFS라 스냅샷·확장도 자유롭습니다.
4. GPU 없이 ML 돌리기
Immich의 얼굴 인식·스마트 검색은 머신러닝이라 “GPU 있어야 하지 않나?” 싶지만, 제 홈랩엔 외장 GPU가 없습니다. ML 컨테이너는 CPU로도 잘 돌아갑니다. 다만 —
처음 대량의 사진을 일괄 인덱싱할 때만 CPU를 오래 씁니다(밤새 돌려두면 됨).
인덱싱이 끝나면 이후 검색·인식은 가볍습니다.
즉 초기 1회만 참으면 GPU 없이도 실사용에 지장이 없습니다.
수만 장을 한 번에 넣으면 며칠 걸릴 수 있으니, 처음엔 ML 작업을 밤 시간대에 몰아서 돌리는 걸 권합니다.
5. 운영하며 느낀 점
백업은 별개다: Immich는 사진 “관리”이지 백업이 아닙니다. NAS가 죽으면 끝이니, 사진 원본은 반드시 별도 백업(오프사이트)을 두세요.
DB도 소중하다: 앨범·얼굴 정보는 postgres에 있습니다. 사진 파일과 함께 DB 백업도 챙겨야 완전 복구가 됩니다.
업그레이드 전 스냅샷: 마이너 업데이트에서도 DB 마이그레이션이 있으니, 올리기 전에 컨테이너·DB 스냅샷을 찍어두면 안전합니다.
구글 포토를 벗어나고 싶은 분께 Immich는 현재 가장 완성도 높은 선택지입니다. 홈랩에 NAS가 있다면, 사진 주권을 되찾는 첫걸음으로 강력 추천합니다.
홈랩은 잘 돌아갈 땐 조용하지만, 한 번 터지면 새벽까지 붙잡게 됩니다. 이번 글은 제가 실제로 겪고 해결한 두 가지 사건 — “빌드하다 디스크가 꽉 참”과 “좀비 프로세스 307개” — 을 그대로 복기합니다. 둘 다 홈랩에서 흔히 만나는 함정이라, 같은 벽에 부딪힌 분께 도움이 될 겁니다.
사건 1. 컨테이너 빌드 중 “disk quota exceeded”
Docker 이미지를 새로 빌드하는데 갑자기 실패했습니다.
failed to solve: ... write ...: disk quota exceeded
원인을 찾아보니 해당 LXC의 rootfs가 8GB였는데, 그 안에서 Playwright(헤드리스 크롬) 이미지를 재빌드하려니 공간이 부족했습니다. 크로미움을 포함한 이미지는 통째로 1GB를 훌쩍 넘고, 여기에 빌드 캐시가 눈덩이처럼 쌓여 순식간에 rootfs를 채운 겁니다.
해결은 두 단계였습니다. 먼저 쌓인 빌드 캐시를 비우고,
# 안 쓰는 빌드 캐시 전량 정리 (공간 즉시 회수)
docker builder prune -af
그래도 빠듯해서 Proxmox 호스트에서 LXC rootfs를 온라인으로 확장했습니다(무중단).
# LXC 113의 rootfs를 8G → 16G 로 확장
pct resize 113 rootfs +8G
배운 것: 크로미움·플레이라이트처럼 무거운 이미지를 빌드하는 컨테이너는 rootfs를 처음부터 넉넉히(최소 16GB) 잡아야 합니다. 그리고 docker builder prune을 주기적으로 돌리지 않으면 빌드 캐시가 조용히 디스크를 잠식합니다. 빌드 전 df -h / 확인은 습관으로.
사건 2. 좀비 프로세스가 307개까지 쌓였다
어느 날 컨테이너 상태를 보니 좀비(zombie) 프로세스가 307개나 쌓여 있었습니다.
# 좀비 프로세스 개수 확인
ps aux | awk '$8 ~ /Z/ {c++} END {print c}'
범인은 헤드리스 크롬이었습니다. Playwright가 크로미움을 반복 실행/종료하는데, 자식 프로세스가 끝나면 부모가 그 종료 상태를 거둬(reap)줘야 합니다. 그런데 컨테이너의 PID 1(내 파이썬 앱)은 그 일을 하지 않습니다. 일반 리눅스라면 init이 고아 프로세스를 거두지만, 컨테이너 안엔 그 init이 없어서 죽은 크롬 프로세스가 계속 좀비로 남은 겁니다.
해결은 가벼운 init(tini)을 PID 1로 넣는 것이었습니다. Docker Compose라면 한 줄이면 됩니다.
services:
app:
image: my-bot:latest
init: true # tini가 PID 1이 되어 좀비를 자동 수거
init: true를 켜자 좀비가 더 이상 쌓이지 않았습니다. tini가 PID 1로 앉아 자식들의 종료를 대신 거둬 주기 때문입니다.
배운 것: 컨테이너 안에서 자식 프로세스를 반복 생성하는 앱(브라우저 자동화, 이미지 변환, 서브프로세스 호출 등)을 돌린다면 init: true는 선택이 아니라 필수입니다. 컨테이너의 PID 1은 “프로세스 청소부” 역할을 하지 않는다는 걸 꼭 기억하세요.
정리 — 홈랩 삽질에서 얻은 두 습관
사건
근본 원인
예방 습관
디스크 풀
빌드 캐시 누적 + 작은 rootfs
rootfs 넉넉히, builder prune 주기화, 빌드 전 df -h
좀비 307개
컨테이너 PID 1이 자식 미수거
서브프로세스 앱엔 init: true
둘 다 “알고 나면 별것 아니지만, 모르면 새벽을 태우는” 문제였습니다. 홈랩의 실력은 이런 삽질을 하나씩 기록하며 쌓이는 것 같습니다.
안녕하세요, 13년차의 서버실 주인장입니다. 제 홈랩 이야기를 풀어놓는 곳이죠. 오늘은 많은 분들이 궁금해하실 만한 주제, 바로 Podman(팟맨)과 Docker(도커)에 대해 이야기해보려고 합니다. 저도 처음 인프라 엔지니어 일을 시작할 때부터 Docker를 줄곧 써왔고, 사실 컨테이너 하면 Docker가 거의 대명사처럼 쓰였잖아요? 근데 요즘 들어 Podman이 심상치 않다는 이야기를 많이 듣게 되더라고요. 특히나 개인적인 홈랩 환경에서는 어떤 선택이 더 좋을지 직접 비교해보고 싶어서, 제 홈랩 서버에 둘 다 설치해서 며칠간 굴려봤습니다. 삽질도 좀 했고요. ㅎㅎ
컨테이너 기술은 이제 선택이 아닌 필수가 되었죠. 마이크로서비스 아키텍처(MSA)부터 CI/CD 파이프라인, 심지어 IoT 디바이스까지, 어디든 컨테이너가 쓰이지 않는 곳이 없습니다. 홈랩에서도 마찬가지예요. 웹서버, 데이터베이스, 각종 모니터링 툴까지 컨테이너로 띄워두면 관리도 편하고 자원도 효율적으로 쓸 수 있거든요. 하지만 두 가지 주요 컨테이너 런타임(Container Runtime), Podman과 Docker 중에서 어떤 것을 선택해야 할지 고민하는 분들이 많으실 겁니다. 저도 그랬거든요.
Podman과 Docker의 핵심 아키텍처 차이를 시각적으로 비교한 다이어그램입니다. 데몬 유무, rootless 모드 지원 여부 등에 초점을 맞춥니다.
Podman과 Docker, 뭐가 다른가요?
쉽게 말해, 둘 다 컨테이너를 만들고 실행하는 도구죠. 하지만 내부적으로 작동하는 방식에는 꽤 큰 차이가 있어요. 제가 직접 써보면서 느낀 핵심적인 차이점들을 짚어볼게요.
Docker (도커): 컨테이너 기술의 사실상 표준이 되었죠. 데몬(Daemon) 기반으로 작동합니다. 즉, dockerd라는 백그라운드 프로세스가 항상 떠 있어서 클라이언트의 명령을 받고 컨테이너를 관리하는 형태예요. 이 데몬이 모든 컨테이너 작업을 총괄하고, API를 통해 명령을 주고받는 클라이언트-서버 아키텍처(Client-Server Architecture)죠.
Podman (팟맨): Red Hat에서 주도적으로 개발한 컨테이너 런타임입니다. 가장 큰 특징은 데몬리스(Daemonless)라는 점이에요. 백그라운드 데몬 없이 필요한 시점에만 프로세스가 실행되고, 컨테이너를 직접 생성하고 관리합니다. 그리고 루트리스(Rootless) 모드를 기본적으로 지원해서, 일반 사용자 계정으로도 컨테이너를 실행할 수 있다는 게 강력한 장점이거든요.
제 홈랩 서버는 Ubuntu 22.04 LTS를 사용하고 있습니다. 일반적으로 많이 쓰시는 환경이라 이 기준으로 설명드릴게요.
1. Docker 설치 및 기본 사용
Docker는 워낙 유명하니 설치는 비교적 간단합니다. 공식 문서에 따라 진행하면 되죠.
# 기존 Docker 버전 제거 (선택 사항)
sudo apt-get remove docker docker-engine docker.io containerd runc
# 필수 패키지 설치
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
# Docker 공식 GPG 키 추가
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Docker APT 저장소 설정
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker Engine 설치
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 사용자 계정을 docker 그룹에 추가 (sudo 없이 docker 명령어 사용)
sudo usermod -aG docker $USER
newgrp docker # 변경사항 즉시 적용
# Docker 서비스 확인
systemctl status docker
# Nginx 컨테이너 실행 예시
docker run -d --name my-nginx -p 8080:80 nginx:latest
docker ps
설치 후에는 docker run, docker ps 같은 명령어로 컨테이너를 쉽게 관리할 수 있어요. 익숙한 명령어들이죠? docker-compose도 플러그인 형태로 같이 설치되니 멀티 컨테이너 환경 구성에도 편리합니다.
2. Podman 설치 및 기본 사용 (그리고 Rootless!)
Podman도 Ubuntu에서는 APT 저장소를 통해 쉽게 설치할 수 있어요.
# Podman 설치
sudo apt-get update
sudo apt-get install podman
# Podman 버전 확인
podman --version
# Nginx 컨테이너 실행 예시 (루트리스 모드)
podman run -d --name my-nginx-podman -p 8081:80 nginx:latest
podman ps
# Podman 서비스 활성화 (원격 API나 systemd 통합을 위해)
# 이 명령은 rootless 모드에서 사용자별 systemd 서비스를 활성화합니다.
systemctl --user enable --now podman.socket
# Docker CLI처럼 원격으로 Podman 데몬에 연결하는 방법 (선택 사항)
# DOCKER_HOST 환경 변수를 설정하면 docker CLI 명령어를 podman에 연결할 수 있습니다.
# export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock
# docker ps # 이제 podman 컨테이너를 보여줍니다 (docker CLI 사용)
루트리스 모드(Rootless Mode)가 Podman의 가장 큰 매력 중 하나라고 했잖아요? 위 예시처럼 그냥 podman run을 실행하면 기본적으로 현재 사용자 계정의 권한으로 컨테이너가 실행돼요. 이게 진짜 편하더라고요. 보안 측면에서도 훨씬 안전하고요. 만약 컨테이너에서 어떤 취약점이 발견되더라도, 호스트 시스템의 루트 권한을 직접적으로 탈취하기가 훨씬 어려워지거든요.
Podman으로 rootless 컨테이너를 실행하고 터미널에서 확인하는 화면입니다. user namespace가 잘 설정되었음을 보여줍니다.
3. 멀티 컨테이너 오케스트레이션: Docker Compose vs Podman Play Kube
여러 컨테이너를 함께 띄워야 할 때 Docker Compose(도커 컴포즈)는 정말 유용해요. 하나의 docker-compose.yaml 파일로 서비스들을 정의하고 한 번에 관리할 수 있죠. Podman에서는 비슷한 역할을 하는 podman-compose라는 툴도 있지만, 저는 podman play kube를 주로 사용해봤습니다. YAML 파일을 Kubernetes(쿠버네티스) 형식으로 작성해서 Podman으로 실행하는 방식인데, 미래를 생각하면 이쪽이 더 좋겠다 싶더라고요.
# Docker Compose 실행
docker-compose up -d
# Podman Play Kube를 위한 YAML 파일 (Kubernetes Pod 정의)
# web-pod.yaml 예시
apiVersion: v1
kind: Pod
metadata:
name: my-web-pod
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
hostPort: 8082 # Podman에서는 hostPort를 명시해야 외부 노출
- name: postgres-container
image: postgres:13
env:
- name: POSTGRES_DB
value: mydb
- name: POSTGRES_USER
value: user
- name: POSTGRES_PASSWORD
value: password
# Podman Play Kube 실행
podman play kube web-pod.yaml
podman ps -a
podman play kube는 Kubernetes의 Pod(파드) 개념을 Podman 환경에서 그대로 사용할 수 있게 해줍니다. 나중에 Kubernetes로 전환할 계획이 있다면, 미리 익숙해질 수 있는 좋은 기회가 되죠.
⚠️ 삽질 경험: Podman rootless 모드와 포트 바인딩
제가 Podman을 처음 쓰면서 가장 삽질했던 부분이 바로 루트리스 모드에서의 포트 바인딩(Port Binding)이었어요. podman run -p 80:80 nginx 처럼 80번 같은 특권 포트(Privileged Port, 1024번 이하)를 바인딩하려고 하면 에러가 나더라고요. 처음엔 이게 뭔가 싶었는데, 일반 사용자 계정은 1024번 이하 포트에 바인딩할 권한이 없기 때문이었습니다.
해결책:
비특권 포트 사용: 가장 간단한 방법은 8080, 8000처럼 1024번 이상의 비특권 포트(Non-privileged Port)를 사용하는 거예요. podman run -p 8080:80 nginx 이렇게요. 홈랩에서는 보통 이 방법으로 충분합니다.
rootful Podman 사용: 정말 특권 포트를 써야 한다면 sudo podman run -p 80:80 nginx 처럼 루트 권한으로 실행할 수도 있어요. 하지만 이는 루트리스 모드의 장점을 포기하는 것이 되니, 특별한 경우가 아니면 권장하지 않습니다.
sysctl 설정 (주의 필요!): 극히 드물지만, 일반 사용자도 특권 포트를 사용할 수 있도록 시스템 설정을 변경하는 방법도 있어요. sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80 와 같은 명령어를 사용하는데, 보안상 매우 위험하니 절대 따라 하지 마세요. 제 삽질 경험을 공유하는 차원에서만 언급합니다.
이 외에도 Podman이 systemd와 통합되는 방식이나, SELinux(에스이리눅스)가 활성화된 환경에서는 추가적인 설정이 필요할 수 있어요. 로그를 확인할 때는 journalctl --user -xeu podman.socket 처럼 사용자별 systemd 저널을 보는 것이 도움이 됩니다.
성능 비교 및 관리 용이성
자, 그럼 가장 중요한 부분이죠. 성능과 관리 용이성은 어땠을까요? 제가 직접 여러 컨테이너를 띄워놓고 htop, sar, iostat 같은 도구들로 모니터링해봤습니다.
성능
솔직히 말하면, 제 홈랩 환경(저사양 미니 PC)에서는 Podman과 Docker 간의 드라마틱한 성능 차이를 벤치마크 수치로 딱 잘라 말하기는 어려웠어요. 하지만 체감적으로 Podman이 약간 더 가볍게 느껴지는 부분은 있었습니다. 특히 시스템 리소스가 제한적인 홈랩 환경에서는 이 작은 차이가 중요할 수 있더라고요.
메모리 사용량 (Memory Usage): Docker는 dockerd라는 데몬이 항상 일정량의 메모리를 점유하고 있어요. Podman은 데몬이 없으니 이 오버헤드(Overhead)가 없습니다. 여러 개의 컨테이너를 띄우지 않는다면 큰 차이가 아닐 수 있지만, 저처럼 컨테이너를 수십 개씩 띄우는 홈랩에서는 무시할 수 없는 부분입니다.
CPU 사용량 (CPU Usage): 마찬가지로 데몬의 존재 유무가 CPU 사용량에도 영향을 미칠 수 있어요. 특히 유휴 상태(Idle State)일 때 Podman이 미세하게 더 낮은 CPU 사용률을 보였습니다.
I/O 성능 (Disk I/O): 이 부분에서는 큰 차이를 느끼기 어려웠어요. 컨테이너 런타임보다는 기본 스토리지 드라이버나 실제 디스크 성능에 더 큰 영향을 받더라고요.
결과 해석 기준: 만약 htop에서 `dockerd` 프로세스가 지속적으로 1% 이상의 CPU를 점유하거나, `top` 명령어로 확인했을 때 `VIRT` (Virtual Memory Size) 값이 수백 MB 이상으로 높게 나온다면, 데몬으로 인한 오버헤드를 고려해볼 만해요. 홈랩처럼 리소스가 제한된 환경에서는 이런 작은 수치들이 전체 시스템 안정성에 영향을 줄 수 있거든요.
홈랩 환경에서 Podman과 Docker 컨테이너의 CPU, 메모리, 디스크 I/O 사용량을 비교하는 대시보드 스크린샷입니다. Prometheus, Grafana 같은 툴을 활용한 시각화를 보여줍니다.
관리 용이성
명령어 호환성: Podman은 Docker CLI 명령어와 거의 100% 호환돼요. docker run 대신 podman run이라고만 바꾸면 되니, 기존 Docker 사용자들이 쉽게 적응할 수 있습니다. 이게 진짜 편하더라고요.
systemd 통합: Podman은 systemd와 아주 잘 통합돼요. 컨테이너를 systemd 서비스로 등록해서 자동으로 시작하고 관리할 수 있죠. podman generate systemd --name my-nginx-podman > ~/.config/systemd/user/my-nginx-podman.service 이런 식으로 쉽게 서비스 파일을 만들 수 있어서, 서버 재부팅 시 컨테이너를 수동으로 다시 띄울 필요가 없어집니다.
Kubernetes 친화적: podman play kube 기능을 통해 Kubernetes YAML 파일을 직접 실행할 수 있다는 점은 향후 클라우드 환경이나 복잡한 오케스트레이션으로 넘어갈 때 큰 강점이 돼요.
그래서, 홈랩에는 어떤 컨테이너 런타임이 좋을까요?
저의 13년차 인프라 엔지니어이자 홈랩 운영자로서의 경험을 바탕으로 명확한 결론과 추천을 드려볼게요.
Docker를 추천하는 경우:
이미 Docker에 익숙하고, 복잡한 설정 변경을 원치 않는다면: 기존 Docker Compose 파일들이 많고, 커뮤니티 자료나 플러그인 생태계를 그대로 활용하고 싶다면 Docker가 여전히 좋은 선택이에요.
Docker Swarm(도커 스웜)을 활용한 간단한 클러스터가 필요하다면: Podman은 Swarm을 직접 지원하지 않아요.
상대적으로 고사양의 서버를 사용하고 데몬 오버헤드가 크게 문제 되지 않는다면: 데몬의 안정성과 광범위한 사용 사례를 그대로 가져갈 수 있습니다.
Podman을 추천하는 경우:
보안을 최우선으로 생각하고, 루트리스 컨테이너를 선호한다면: 홈랩 환경에서 보안은 아무리 강조해도 지나치지 않아요. 루트리스 모드는 잠재적인 보안 위협을 크게 줄여줍니다.
시스템 리소스가 제한적인 저사양 홈랩 서버를 운영한다면: 데몬 오버헤드가 없기 때문에 미세하게라도 자원을 더 효율적으로 사용할 수 있어요.
향후 Kubernetes 환경으로 확장할 계획이 있다면: podman play kube를 통해 Kubernetes YAML 파일에 익숙해질 수 있고, Pod 개념을 미리 체험해볼 수 있습니다.
systemd와의 긴밀한 통합을 통해 컨테이너 자동화를 하고 싶다면: Podman의 systemd 통합은 컨테이너 관리를 한층 더 편리하게 만들어줍니다.
Podman과 Docker의 주요 장단점을 비교하고, 홈랩 환경에 적합한 선택 기준을 시각적으로 요약한 인포그래픽입니다.
개인적으로는 요즘 Podman에 손이 더 많이 갑니다. 특히 루트리스 모드와 systemd 통합이 저에게는 굉장히 매력적이더라고요. 제 홈랩 서버가 그렇게 고사양은 아니라서 리소스 효율성도 무시할 수 없고요. 물론 Docker가 가진 강력한 생태계와 안정성은 여전히 큰 장점이지만, 새로운 기술을 시도하고 실험해보는 홈랩의 재미를 생각하면 Podman은 충분히 도전해볼 가치가 있는 툴입니다.
여러분도 이 글을 통해 자신의 홈랩 환경에 맞는 컨테이너 런타임을 선택하는 데 도움이 되셨으면 좋겠어요. 다음 글에서는 Podman으로 Nginx와 Let’s Encrypt를 연동해서 HTTPS 웹서버를 구축하는 방법에 대해 더 자세히 다뤄볼 예정이니 기대해주세요! 그때 또 다른 삽질 경험담과 해결책을 공유해드리겠습니다. 🎉
안녕하세요, 13년차 인프라 엔지니어 ‘서버실’입니다. 홈랩을 운영하면서 다양한 장비들을 써보고 또 바꿔보고 있는데요. 오늘은 제가 1년 전에 겪었던 큰 변화, 바로 TrueNAS CORE에서 Unraid로 NAS 운영체제(OS)를 마이그레이션한 경험에 대해 이야기해보려 합니다. 지금 TrueNAS와 Unraid 사이에서 고민하거나, NAS 환경에 변화를 주고 싶은 분들이라면 제 경험담이 참고가 될 거예요.
솔직히 말씀드리면, TrueNAS CORE는 정말 훌륭한 NAS OS입니다. ZFS(Zettabyte File System)라는 강력한 파일 시스템을 기반으로 데이터 무결성과 안정성 면에서는 타의 추종을 불허하죠. 저도 오랫동안 TrueNAS CORE를 사용하면서 데이터 손실 걱정 없이 잘 지냈습니다. 하지만 홈랩 환경이라는 게 항상 똑같지 않잖아요? 이런저런 실험을 하다 보니, 좀 더 유연하고 다양한 컨테이너(Container) 환경을 쉽게 구축하고 싶다는 욕구가 생기더라고요. 특히 Docker나 가상 머신(Virtual Machine, VM)을 좀 더 자유롭게 쓰고 싶어졌습니다.
처음엔 TrueNAS SCALE을 고려하기도 했지만, 당시에는 아직 안정화가 덜 됐다는 판단이 들어서 다른 대안을 찾아봤어요. 그러다 눈에 들어온 게 바로 Unraid였습니다. 근데 이게 FreeBSD 기반의 TrueNAS CORE와는 완전히 다른 Linux 기반이라, 마이그레이션 결정까지 꽤나 고민이 많았죠. 과연 이 결정이 옳았을까요? 지금부터 그 1년 간의 여정을 솔직하게 풀어보겠습니다.
TrueNAS CORE와 Unraid의 핵심 아키텍처 및 기능 차이를 한눈에 볼 수 있는 다이어그램입니다. 각 시스템의 장단점이 명확히 드러나죠.
TrueNAS CORE vs. Unraid: 핵심 개념 이해하기
먼저, 두 NAS 운영체제의 핵심 개념부터 간단히 짚고 넘어갈게요. 마이그레이션을 고려한다면 반드시 알아야 할 차이점들입니다.
TrueNAS CORE (FreeBSD 기반, ZFS): TrueNAS CORE는 FreeBSD 운영체제 위에 ZFS(Zettabyte File System)를 핵심으로 사용합니다. ZFS는 RAID-Z1, RAID-Z2, RAID-Z3 등 다양한 방식의 RAID를 소프트웨어적으로 구현하며, 데이터 무결성(Data Integrity)과 스냅샷(Snapshot), 복제(Replication) 기능이 강력해요. 드라이브(Drive)를 추가할 때는 기존 VDEV(Virtual Device)에 새 드라이브를 추가하거나, 새로운 VDEV를 만들어 풀(Pool)에 통합하는 방식입니다. 한 번 구성된 풀은 드라이브를 유연하게 추가/교체하기가 쉽지 않다는 특징이 있어요.
Unraid (Linux 기반, Array/Cache Pool): Unraid는 경량 Linux 배포판을 기반으로 하며, 독자적인 패리티(Parity) 시스템을 사용합니다. TrueNAS처럼 전통적인 RAID 방식이 아니라, 개별 드라이브들을 묶어 하나의 큰 스토리지 배열(Array)을 만들고, 그 중 하나 또는 두 개를 패리티 드라이브(Parity Drive)로 지정해 데이터를 보호하는 방식이에요. 가장 큰 장점은 드라이브 용량에 관계없이 자유롭게 드라이브를 추가/제거할 수 있다는 점입니다. 또한, SSD를 이용한 캐시 풀(Cache Pool)을 별도로 구성하여 성능을 높이는 게 일반적입니다.
쉽게 말해, TrueNAS는 ‘데이터 안정성’에 방점을 두고 탄탄하게 설계된 엔터프라이즈(Enterprise)급 스토리지 솔루션이고, Unraid는 ‘유연성과 확장성’에 초점을 맞춘 홈랩 친화적인 솔루션이라고 볼 수 있어요. 제가 Unraid로 눈을 돌린 것도 바로 이 유연성 때문이었습니다.
Unraid로의 마이그레이션: 선택 기준 비교표
어떤 NAS OS를 선택할지는 개인의 사용 목적과 환경에 따라 크게 달라집니다. 제가 TrueNAS CORE에서 Unraid로 넘어가기로 결정했던 주요 기준들을 정리해봤어요. 비슷한 고민을 하고 계신 분이라면 이 표가 참고가 될 거라고 생각합니다.
고려 사항
TrueNAS CORE가 더 적합한 경우
Unraid가 더 적합한 경우
제가 Unraid를 선택한 이유
데이터 무결성 & 안정성
최고 수준의 데이터 보호(ZFS), 기업용 환경, 미션 크리티컬(Mission-critical) 데이터
개별 드라이브 오류 보호(패리티), 일반적인 홈 미디어/파일 서버
홈랩 환경에서 극단적인 무결성보다 유연성이 더 필요하다고 판단
드라이브 확장성
새 VDEV 구성 또는 풀 확장 시 복잡성, 유연성 부족, 동일 용량 드라이브 권장
용량 무관하게 자유로운 드라이브 추가/제거, 유휴 드라이브 활용 용이
다양한 용량의 드라이브를 보유하고 있어 유연한 확장이 절실
Docker & 가상화
Jail/Plugin(컨테이너), bhyve(가상화) 지원하나 리소스 관리 및 생태계 제한적
Docker 및 KVM 기반 VM 지원이 강력, 플러그인 생태계 활발, GUI 친화적
Docker 컨테이너를 더 쉽게, 더 많이 활용하고 싶었음
하드웨어 요구사항
ZFS 특성상 ECC RAM 필수 권장, CPU 성능 중요
ECC RAM 필수 아님(권장), 저전력 CPU로도 충분, USB 부팅
기존 하드웨어 재활용 시 ECC RAM 제약이 덜함
운영 편의성
초기 설정 후 안정적, 학습 곡선(Learning Curve) 존재
직관적인 웹 UI, 플러그인으로 기능 확장 용이, 활발한 커뮤니티
더 빠르고 쉽게 새로운 서비스를 배포하고 싶었음
실전 마이그레이션 준비 및 과정
마이그레이션은 항상 신중해야 합니다. 특히 데이터가 걸려있는 작업이니까요. 제가 진행했던 과정을 간략하게 설명해 드릴게요. ⚠️ 가장 중요한 것은 데이터 백업입니다. 어떤 상황이 발생할지 모르니, 반드시 핵심 데이터는 별도의 공간에 백업해두세요. 저는 외부 USB 드라이브와 클라우드를 활용했습니다.
1. 데이터 백업 및 TrueNAS 풀 내보내기
기존 TrueNAS CORE 시스템에서 중요한 데이터를 백업했습니다. 그리고 기존 ZFS 풀을 안전하게 내보내는(Export) 작업을 진행했어요. 이건 필수 단계는 아니지만, 혹시 모를 상황에 대비하는 차원이었습니다.
sudo zpool export my_data_pool
my_data_pool은 본인의 ZFS 풀 이름으로 바꿔주시면 됩니다. 이 명령은 풀을 비활성화하고 시스템에서 분리해요.
2. Unraid USB 부트 드라이브 생성
Unraid는 USB 드라이브로 부팅하는 방식입니다. 공식 웹사이트에서 다운로드한 툴을 사용해 USB를 만들었어요. 💡 팁: 안정적인 부팅을 위해 가급적 검증된 USB 3.0 드라이브를 사용하는 게 좋습니다.
3. 하드웨어 세팅 및 Unraid 초기 설정
기존 TrueNAS 서버의 드라이브들을 물리적으로 Unraid 서버에 연결하고, Unraid USB로 부팅했습니다. Unraid 웹 UI에 접속해서 초기 설정을 진행했죠. 여기서 패리티 드라이브를 지정하고, 데이터 드라이브들을 배열(Array)에 추가합니다. 저는 기존의 모든 드라이브를 Unraid에 연결하고, 가장 큰 용량의 드라이브를 패리티 드라이브로 지정했어요.
Unraid의 깔끔한 웹 인터페이스입니다. 드라이브의 상태, 패리티 동기화 여부, 캐시 풀 등을 한눈에 확인할 수 있어요.
4. 데이터 복사
가장 시간이 오래 걸리는 작업입니다. 기존 TrueNAS에 있던 데이터 드라이브들을 Unraid 시스템에 임시로 연결하고, rsync 명령어를 이용해 데이터를 Unraid 배열로 복사했어요. 이 과정에서 여러 번의 삽질이 있었습니다.
-a (archive mode), -v (verbose), -h (human-readable), --progress (진행 상황 표시) 옵션은 대용량 파일 복사 시 정말 유용해요. 특히 TrueNAS의 ZFS 스냅샷 때문에 생긴 .zfs 폴더나 권한 문제 때문에 애를 먹기도 했습니다. Unraid의 사용자(User) 및 공유(Share) 권한 설정을 제대로 이해하는 게 중요하더라고요.
삽질 경험 및 트러블슈팅
마이그레이션이 늘 순탄하지만은 않죠. 저도 몇 가지 삽질을 경험했습니다.
⚠️ ZFS 풀 마운트 문제: TrueNAS의 ZFS 풀을 Unraid(Linux)에서 직접 읽어오려고 시도했는데, 생각보다 쉽지 않더라고요. zfs-fuse 같은 도구를 써보려 했으나, 안정성과 성능 문제로 포기하고 결국 드라이브를 하나씩 연결해서 rsync로 복사하는 방식을 택했습니다. 이 과정에서 드라이브를 여러 번 뺐다 끼웠는데, 이게 물리적인 삽질이더라고요. 그냥 안전하게 네트워크로 데이터를 옮기거나, SATA 포트가 충분하다면 동시에 연결해서 옮기는 게 정신 건강에 이롭습니다.
💡 Unraid 공유 권한 설정: Unraid는 공유 폴더(Share) 단위로 사용자 권한을 설정해요. 처음에는 TrueNAS의 복잡한 권한 체계에 익숙해져 있다 보니 Unraid의 비교적 단순한 권한 설정에서 헷갈렸습니다. 특히 Docker 컨테이너에서 접근할 볼륨(Volume) 권한을 제대로 설정하지 않아 컨테이너가 파일을 생성하지 못하는 문제가 발생했더라고요. Unraid의 Users 탭에서 사용자 생성 및 권한을, Shares 탭에서 각 공유 폴더의 접근 권한을 꼼꼼히 설정해야 합니다.
✅ Docker 컨테이너 전환: TrueNAS의 Jail이나 플러그인으로 운영하던 서비스들을 Unraid의 Docker로 옮기는 과정은 생각보다 훨씬 수월했어요. Unraid의 Community Applications(CA) 플러그인 덕분인데, 이게 마치 앱스토어처럼 다양한 Docker 템플릿을 제공해서 클릭 몇 번으로 Plex, Nextcloud, Home Assistant 같은 서비스들을 쉽게 설치할 수 있더라고요. 처음엔 TrueNAS의 iocage 명령어나 플러그인 설정에 익숙했었는데, Unraid의 Docker 환경은 신세계였습니다.
1년 사용 후기: 장점과 단점
Unraid로 마이그레이션하고 1년이 지난 지금, 저는 매우 만족하고 있어요. 주요 장점과 단점을 정리해볼게요.
장점
경이로운 드라이브 확장성: 가장 큰 만족 부분이에요. 집에 굴러다니던 1TB, 2TB, 4TB 드라이브들을 모두 활용해서 큰 스토리지 풀을 만들 수 있었거든요. 용량 증설이 필요할 때마다 새 드라이브를 사서 꽂기만 하면 되니, 정말 편하더군요.
압도적인 Docker 생태계: Community Applications 플러그인 덕분에 다양한 서비스를 매우 쉽게 설치하고 관리할 수 있어요. 웹 UI에서 Docker 컨테이너를 시작, 중지, 업데이트하는 게 직관적이고, 트러블슈팅도 로그 확인이 쉽습니다.
KVM 기반 가상화: 가상 머신 관리가 정말 편리해요. Windows Server나 Ubuntu Server 같은 VM을 몇 번의 클릭으로 설치하고, 웹 UI에서 자원 할당이나 콘솔 접속까지 가능합니다.
저전력 운영: 모든 드라이브가 항상 스핀업(Spin up)되어 있지 않고, 필요할 때만 깨어나기 때문에 전기 요금 절감에도 도움이 돼요.
단점 및 아쉬운 점
ZFS의 부재: 역시 ZFS 특유의 데이터 무결성 검증이나 스냅샷 기능이 아쉬울 때가 있어요. Unraid의 패리티 시스템도 훌륭하지만, ZFS만큼 강력하진 않다는 느낌을 받습니다. 중요한 데이터는 별도의 백업 전략을 더 철저히 세워야겠다고 느꼈어요.
성능: 개별 드라이브에 직접 접근하는 방식이라, 단일 파일에 대한 순차 읽기/쓰기 성능은 RAID 시스템보다 떨어질 수 있어요. 하지만 캐시 풀을 적극적으로 활용하면 대부분의 홈랩 환경에서는 충분한 성능을 제공합니다.
Unraid에서 다양한 Docker 컨테이너들이 안정적으로 동작하는 모습입니다. 각 컨테이너의 리소스 사용량도 한눈에 파악할 수 있어요.
결론: 어떤 NAS OS를 선택해야 할까?
1년 간의 Unraid 사용 경험을 바탕으로, 어떤 분들이 어떤 NAS OS를 선택해야 할지 명확하게 추천해 드릴게요.
최고의 데이터 안정성과 무결성, 그리고 엔터프라이즈급 기능을 원한다면 TrueNAS CORE (또는 SCALE)를 선택하세요. 특히 중요한 업무용 데이터를 다루거나, ZFS의 강력한 기능을 적극 활용하고 싶다면 TrueNAS가 정답이에요. ECC RAM과 안정적인 하드웨어 투자가 필수적입니다.
유연한 드라이브 확장성, 강력한 Docker 및 가상화 기능, 그리고 쉬운 홈랩 환경 구축을 원한다면 Unraid를 선택하세요. 다양한 용량의 드라이브를 활용하고 싶거나, 미디어 서버, 스마트 홈 허브 등 여러 서비스를 Docker로 쉽게 운영하고 싶다면 Unraid가 탁월한 선택이 될 거예요. 초보자도 비교적 쉽게 접근할 수 있어요.
제 경우, 홈랩 환경에서는 유연성과 확장성, 그리고 Docker의 편리함이 데이터 무결성의 최우선 순위보다 더 중요했어요. 그래서 Unraid로의 마이그레이션은 저에게 아주 만족스러운 결정이었습니다. 물론 ZFS의 강력함은 여전히 인정하고 존경합니다만, 제 사용 패턴에는 Unraid가 더 잘 맞았던 거죠.
어떤 선택이든 정답은 없습니다. 중요한 건 자신이 무엇을 가장 중요하게 생각하는지 명확히 파악하고 그에 맞는 도구를 선택하는 것이에요. 이 글이 여러분의 현명한 NAS OS 선택에 조금이나마 도움이 되었기를 바랍니다. 다음번에는 Unraid에서 Docker 컨테이너를 더 효율적으로 관리하는 실전 팁에 대해 다뤄보겠습니다. 그때까지 즐거운 홈랩 생활하세요! 🎉
TrueNAS와 Unraid, 두 NAS 운영체제의 핵심 장단점과 각 OS에 적합한 사용 시나리오를 한눈에 비교할 수 있는 요약 인포그래픽입니다.
홈랩 CCTV를 오래 굴리다 보면 제일 먼저 지치는 게 저장공간이 아니라 오탐(false positive, 잘못된 감지)입니다. 바람에 흔들리는 나뭇잎, 새벽 벌레, 비 오는 날 헤드라이트 반사까지 전부 이벤트로 찍히면, 정작 봐야 할 장면은 묻혀버리거든요. 저도 처음엔 알림이 많이 오면 좋은 줄 알았습니다. 근데 실제로 써보니까 너무 많이 울리는 시스템은 결국 안 보게 되더라고요. 그래서 이번 글에서는 Frigate AI NVR를 기준으로, 홈랩 CCTV 환경에서 객체 감지 정확도를 높이고 오탐 감소에 집중했던 과정을 사례 연구 형태로 정리해보겠습니다.
특히 이 글은 “무조건 최신 장비를 사면 해결된다”가 아니라, 이미 가지고 있는 보안 카메라 최적화와 설정 조정만으로 어디까지 개선되는지에 초점을 맞췄습니다. 혹시 지금 홈랩 CCTV 알림 때문에 피곤하신 분이라면, 꽤 공감되실 겁니다.
Frigate AI NVR가 카메라 스트림을 받아 객체를 감지하고 이벤트를 기록하는 전체 흐름을 보여주는 개요 이미지입니다.
1. Frigate AI NVR가 왜 홈랩 CCTV에 잘 맞는가
쉽게 말해 Frigate AI NVR는 카메라 영상을 받아서 사람이 직접 보기 전에, 먼저 객체를 구분해 주는 NVR(Network Video Recorder, 네트워크 비디오 레코더)입니다. 단순히 녹화만 하는 장비가 아니라, 사람이 지나갔는지 차량이 들어왔는지 같은 이벤트를 기준으로 영상을 정리해 주는 쪽에 가깝습니다.
여기서 핵심은 모션 감지(motion detection)와 객체 감지(object detection)를 분리해서 생각하는 겁니다. 모션 감지는 픽셀 변화만 보고 움직임을 잡아내기 때문에 비, 그림자, 벌레에도 민감합니다. 반면 객체 감지는 “이게 사람인지, 차량인지”를 구분하려고 시도합니다. 물론 완벽하진 않지만, 방향이 다르죠.
구분
모션 감지
객체 감지
기준
화면 변화
사람, 차량 등 대상 식별
장점
가볍고 빠름
의미 있는 이벤트 분류 가능
단점
오탐이 많음
설정이 잘못되면 놓침 발생
홈랩 활용
보조 지표
주 이벤트 기준
제가 직접 해보니, 오탐 감소의 출발점은 모델이나 하드웨어보다도 카메라 구도, 감지 영역, 프레임 수, 객체 필터였습니다. 이 네 가지를 안 잡고 나머지만 만지면, 정말 삽질이 길어집니다.
2. 오탐이 생기는 진짜 이유
처음엔 저도 “감지 엔진이 별로인가?” 싶었는데, 실제 원인은 꽤 현실적이었습니다.
야간 적외선(IR, 적외선 조명)에서 벌레가 렌즈 가까이 지나감
차량 헤드라이트가 벽면에 반사되면서 큰 움직임처럼 보임
현관 앞 화분이나 나뭇가지가 바람에 흔들림
너무 넓은 화각으로 도로와 인도까지 같이 잡음
RTSP 스트림 해상도와 감지 해상도가 맞지 않아 형태가 흐려짐
여기서 중요한 포인트가 있습니다. 오탐 감소는 AI 모델만의 문제가 아니라 입력 품질의 문제이기도 하다는 점입니다. 카메라가 쓸데없는 영역을 너무 많이 보고 있으면, Frigate AI NVR가 아무리 열심히 판단해도 헷갈릴 수밖에 없거든요.
3. 제가 적용한 홈랩 CCTV 객체 감지 최적화 순서
실제로는 이것저것 한 번에 건드리면 뭐가 효과 있었는지 모르게 됩니다. 그래서 저는 아래 순서로 정리했습니다.
카메라별 감시 목적 정의: 현관, 주차, 창고처럼 역할을 나눴습니다.
프레임 구도 조정: 필요 없는 도로, 하늘, 나무 영역을 최대한 빼냈습니다.
감지 해상도와 FPS(Frame Per Second, 초당 프레임 수) 조정
객체 종류 제한: 사람과 차량만 먼저 추적했습니다.
영역(Zone, 존) 기반 필터 적용
며칠 로그를 보고 다시 미세 조정
이 순서가 중요한 이유는, 나중 단계로 갈수록 앞선 입력 품질에 의존하기 때문입니다. 예를 들어 존 설정을 정교하게 해도 카메라가 가로등 반사광을 계속 크게 잡으면 의미가 반감됩니다.
4. 실전 구현: Docker와 Frigate 기본 구성
제 홈랩에서는 Docker Compose로 올려서 운영하는 편이 관리가 편했습니다. 아래 예시는 구조를 이해하기 위한 기본 예시입니다. RTSP URL이나 저장 경로는 환경에 맞게 바꾸셔야 합니다.
이렇게 하면 화면 전체가 아니라, 실제로 사람이 서거나 지나가는 구역에 더 집중하게 됩니다. 물론 좌표는 직접 화면 보고 잡아야 해서 약간 귀찮습니다. 저도 처음엔 점 몇 개 찍는 게 뭐가 어렵나 했는데, 은근히 감각이 필요합니다. 너무 빡빡하게 잡으면 사람이 프레임 가장자리로 들어올 때 이벤트를 놓칠 수 있거든요.
또 하나는 FPS입니다. 많은 분이 높을수록 좋다고 생각하시는데, 홈랩 CCTV 객체 감지 목적이라면 무조건 그렇진 않습니다. 오히려 감지용 스트림은 적절한 수준으로 낮춰서 안정적으로 분석하게 하는 편이 나았습니다. 특히 CPU가 빠듯한 미니 PC나 홈서버에서는 더 체감됐습니다.
실무 느낌으로 정리한 튜닝 우선순위
1순위: 카메라 각도와 불필요한 배경 제거
2순위: 사람/차량처럼 필요한 객체만 추적
3순위: 현관, 주차 구역 등 존 설정
4순위: detect 해상도와 FPS 조정
5순위: 이벤트 로그 보고 재조정
6. ⚠️ 실제로 겪은 트러블슈팅
이 부분은 정말 중요합니다. 설정 예시만 복붙하면 끝날 것 같지만, 현실은 늘 다르거든요. 제가 삽질했던 지점들을 정리해보겠습니다.
1) 밤에 벌레가 사람처럼 잡히는 문제
적외선 조명이 강한 카메라는 렌즈 앞 벌레가 크게 부각됩니다. 이 경우 소프트웨어만으로 100% 해결은 어렵습니다. 저는 카메라 위치를 조금 옮기고, 조명이 벽을 과하게 비추지 않게 조정하니 확실히 줄었습니다. 보안 카메라 최적화는 설정 파일 안에서만 일어나지 않더라고요.
2) 비 오는 날 반사광 이벤트 폭증
주차장 바닥이 젖으면 차량 불빛이 넓게 퍼집니다. 이때 화면 하단 반사 구역을 존 밖으로 빼거나, 실제 진입 경로만 존으로 남겨두는 식으로 정리했습니다. 이건 예상보다 효과가 컸습니다.
3) RTSP 스트림 품질이 들쭉날쭉한 문제
와이파이 구간이 불안정하면 감지 자체가 흔들립니다. 처음엔 객체 감지 모델을 의심했는데, 결국 네트워크 품질 이슈였습니다. 가능하면 고정 배선이나 안정적인 AP 구성이 먼저입니다.
4) 화면은 넓은데 정작 대상은 너무 작게 나오는 문제
한 화면에 마당 전체, 담장, 도로까지 다 넣으면 보기엔 시원합니다. 그런데 감지 정확도는 떨어질 수 있습니다. 사람 객체가 너무 작게 잡히면 분류가 불리해지거든요. 저는 차라리 카메라 역할을 나눠서 넓게 보는 카메라와 좁게 보는 카메라를 분리했습니다.
문제
증상
해결 방향
벌레 오탐
야간에 작은 물체가 크게 감지됨
카메라 위치, IR 반사, 구도 조정
반사광
비 오는 날 이벤트 급증
존 축소, 반사 영역 제외
불안정한 스트림
감지 누락, 프레임 깨짐
네트워크 안정화
너무 넓은 화각
대상이 작아져 분류 어려움
카메라 역할 분리
7. 검증: 어떤 기준으로 결과를 확인했는가
최적화는 느낌으로 하면 끝이 없습니다. 저는 최소 3일 이상 로그를 보고, 같은 시간대 기준으로 비교했습니다. 예를 들어 새벽 1시부터 5시까지 이벤트 수가 얼마나 줄었는지, 실제 사람 방문 이벤트는 놓치지 않았는지를 같이 봤습니다.
최적화 전 이벤트 수를 대략 기록합니다.
존과 객체 필터를 바꾼 뒤 2~3일 관찰합니다.
오탐과 실제 이벤트를 분리해서 확인합니다.
놓친 감지가 있으면 구도 또는 존을 다시 완화합니다.
제가 직접 해보니 가장 좋은 결과는 “이벤트 수가 적은 상태”가 아니라 의미 없는 이벤트는 줄고, 확인해야 할 이벤트는 남는 상태였습니다. 이 균형이 정말 중요합니다. 오탐 감소만 너무 밀어붙이면 진짜 사람이 지나갔는데도 안 잡히는 상황이 생길 수 있습니다.
최적화 전후의 이벤트 분포, 시간대별 감지 빈도, 실제 유효 이벤트 비율을 비교하는 결과 시각화 이미지입니다.
로그를 볼 때는 에러만 찾지 말고, 감지가 몰리는 시간대와 카메라를 함께 보는 게 좋습니다. 특정 카메라만 유독 시끄럽다면 소프트웨어보다 설치 위치 문제일 가능성이 큽니다.
8. 정리와 다음 단계
Frigate AI NVR를 홈랩 CCTV에 붙여서 오탐 감소를 시도해 보면, 결국 답은 거창한 데 있지 않았습니다. 카메라가 무엇을 보고 있는지, 어떤 객체만 추적할지, 어느 구역만 의미 있게 볼지. 이 세 가지를 정리하니 체감이 확 오더라고요. 드디어 됐다! 싶은 순간이 있었습니다.
정리하면 이렇습니다.
Frigate AI NVR는 모션 감지보다 의미 있는 이벤트 정리에 강점이 있습니다.
홈랩 CCTV에서는 카메라 각도와 존 설정이 오탐 감소에 가장 큰 영향을 줍니다.
객체 감지는 많이 잡는 것보다, 필요한 것만 정확히 잡게 만드는 쪽이 중요합니다.
보안 카메라 최적화는 소프트웨어와 설치 환경을 같이 봐야 효과가 납니다.
혹시 지금 알림 피로가 심한 상태라면, 제일 먼저 카메라 한 대만 골라서 테스트해 보세요. 전체를 한 번에 손대면 금방 복잡해집니다. 다음 글에서는 Frigate AI NVR와 Home Assistant 연동, 그리고 이벤트 자동화 흐름도 다뤄볼 예정입니다. 이전 글에서 홈랩 네트워크 분리와 저장소 구성 얘기를 보셨다면, 이번 최적화와 연결해서 보시면 더 이해가 쉬우실 겁니다.
카메라 각도, 존 설정, 객체 필터, 네트워크 안정화 등 핵심 체크포인트를 한 장으로 정리한 요약 이미지입니다.
자주 묻는 질문
Frigate AI NVR를 쓰면 오탐이 완전히 없어지나요?
아닙니다. 다만 의미 없는 이벤트를 줄이고, 확인할 가치가 있는 이벤트 비율을 높이는 데 큰 도움이 됩니다.
객체 감지는 무조건 많은 클래스를 켜는 게 좋나요?
아닙니다. 목적이 현관 감시라면 사람 중심으로, 주차 감시라면 차량 중심으로 좁히는 편이 관리가 쉽습니다.
설정만 만지면 해결되나요?
경험상 절반만 맞습니다. 카메라 위치, 조명, 반사, 네트워크 상태까지 같이 봐야 제대로 정리됩니다.
홈랩에서 카메라 몇 대만 붙여도 처음엔 잘 돌아가다가, 어느 순간 녹화가 뚝뚝 끊기고 CPU가 치솟는 경험 한 번쯤 있으실 겁니다. 저도 Frigate NVR 녹화 끊김 문제 때문에 꽤 오래 삽질했었는데요. 처음엔 카메라 문제인가 싶었고, 그다음엔 디스크가 느린가 싶었고, 나중엔 네트워크까지 의심하게 되더라고요. 근데 실제로 써보니까 이런 증상은 한 군데만 보는 식으로는 잘 안 잡힙니다. 입력 스트림, 디코딩, 감지 파이프라인, 저장소, 컨테이너 자원을 같이 봐야 하거든요.
이번 글에서는 제가 홈랩에서 자주 만났던 Frigate NVR 성능 문제를 기준으로, 어디부터 확인해야 하는지 순서대로 정리해보겠습니다. 막연하게 “서버가 느린가?” 수준에서 끝내지 않고, 실제 로그와 명령어로 좁혀가는 방식입니다. 지금도 녹화 파일이 띄엄띄엄 생기거나, 타임라인이 비거나, 감지가 몰릴 때 프레임이 급격히 떨어지는 상황이라면 꽤 바로 도움이 되실 겁니다.
Frigate NVR, IP 카메라, 스토리지, GPU 또는 iGPU 가속 경로를 한눈에 보여주는 홈랩 구성 예시입니다.
Frigate NVR 녹화 끊김이 생기는 구조부터 이해해봅시다
쉽게 말해 Frigate는 카메라에서 들어오는 영상 스트림을 받아서, 필요한 경우 decode(디코드, 압축 해제)하고, detect(객체 감지)에 쓰고, record(녹화)용으로 저장합니다. 여기서 중요한 포인트가 있습니다. 우리가 보기엔 그냥 “영상 하나”지만, 내부적으로는 역할이 나뉘어 있는 경우가 많습니다.
record(녹화): 원본에 가깝게 저장하는 흐름입니다.
detect(감지): 객체 인식용으로 해상도나 프레임을 낮춰 쓰는 경우가 많습니다.
ffmpeg: 스트림을 받아서 변환하고 전달하는 핵심 도구입니다.
hwaccel(하드웨어 가속): CPU 대신 GPU나 iGPU를 활용해 디코딩 부담을 줄입니다.
이 구조를 모르고 접근하면 보통 녹화 끊김이 생겼을 때 CPU만 봅니다. 저도 처음엔 그랬거든요. 근데 실제 원인은 CPU가 아니라 RTSP 스트림 불안정, 디스크 I/O 병목, 컨테이너 볼륨 권한 문제, detect와 record를 같은 고해상도 스트림으로 태운 설정 같은 쪽에서 더 자주 나왔습니다.
Frigate 디버깅 순서: 제가 먼저 확인하는 체크리스트
Frigate 디버깅은 순서가 중요합니다. 여기서 한 번에 다 건드리면 더 헷갈립니다. 저는 아래 순서로 봅니다.
컨테이너와 Frigate 로그에 에러가 있는지 확인합니다.
CPU, 메모리, 디스크 I/O 사용량을 동시에 봅니다.
카메라 RTSP 스트림이 독립적으로 안정적인지 테스트합니다.
detect용 스트림과 record용 스트림을 분리했는지 확인합니다.
하드웨어 가속이 실제로 적용됐는지 확인합니다.
저장소가 로컬 디스크인지, 느린 네트워크 스토리지인지 확인합니다.
여기서 중요한 건 증상과 원인을 분리하는 겁니다. 예를 들어 CPU 90%는 원인이 아니라 결과일 수 있습니다. RTSP 재연결이 반복되면 ffmpeg 프로세스가 늘어나고, 그게 다시 전체 성능 저하로 보일 수 있거든요.
제가 직접 해보니 여기서 이미 방향이 잡히는 경우가 많았습니다. 예를 들어 docker stats에서 CPU가 높게 치솟는데 디스크는 한가하다면 디코딩이나 감지 쪽을 먼저 의심하게 되고요. 반대로 CPU는 괜찮은데 iostat에서 await가 길게 나오면 저장소 병목일 가능성이 큽니다.
로그에서 특히 자주 보는 단서는 이런 것들입니다.
Connection timed out: 카메라 또는 네트워크 구간 문제일 수 있습니다.
No frames received: 스트림이 끊기거나 인증이 꼬였을 수 있습니다.
error while decoding: 코덱, 하드웨어 가속, 손상된 스트림을 의심합니다.
Unable to write: 저장소 권한 또는 디스크 공간 문제일 수 있습니다.
자원 병목을 빠르게 비교하는 기준
증상
먼저 볼 곳
의심 원인
우선 조치
녹화가 띄엄띄엄 저장됨
디스크 I/O, 볼륨 경로
저장소 병목, 권한 문제
로컬 SSD 확인, 마운트 경로 재검토
CPU가 계속 높음
ffmpeg 프로세스, hwaccel
소프트웨어 디코딩, 고해상도 detect
하드웨어 가속 적용, detect 스트림 분리
특정 카메라만 자주 끊김
카메라 RTSP 테스트
카메라 펌웨어, 네트워크 불안정
개별 스트림 재생 테스트
감지 몰릴 때 전체가 느려짐
객체 감지 설정, 해상도
detect 과부하
해상도/프레임 조정
실전 구현 2: 카메라 스트림과 설정을 분리해서 봅니다
Frigate NVR 성능 문제를 줄이는 데서 가장 체감이 큰 건, 보통 녹화용 스트림과 감지용 스트림을 분리하는 겁니다. 처음엔 “어차피 같은 카메라 영상인데 왜 나누지?” 싶었는데, 이게 효과가 꽤 큽니다. 감지는 낮은 해상도와 적당한 프레임으로도 충분한 경우가 많거든요.
Frigate 밖에서 재생이 불안정하면, Frigate 안에서 아무리 튜닝해도 해결이 안 됩니다. 여기서 끊기면 카메라 자체 설정, 스위치 포트, PoE 상태, 무선 구간 사용 여부까지 봐야 합니다.
실전 구현 3: 하드웨어 가속과 저장소를 점검합니다
저도 처음엔 “서버 CPU가 꽤 괜찮은데 왜 이러지?” 했었는데, 실제로 써보니까 하드웨어 가속이 빠졌거나 제대로 붙지 않은 상태가 정말 흔합니다. 특히 여러 대 카메라를 붙이면 소프트웨어 디코딩만으로는 금방 버거워집니다.
리눅스에서 장치가 보이는지부터 확인합니다.
ls /dev/dri
vainfo
docker exec -it frigate ls /dev/dri
여기서 장치가 보이지 않으면 컨테이너에 디바이스 전달이 안 된 경우가 많습니다. 반대로 장치는 보이는데 여전히 CPU가 높다면, ffmpeg 쪽 옵션이나 실제 사용 코덱과 가속 경로가 맞지 않는 경우가 있습니다. 이런 부분은 하드웨어마다 조금씩 다르기 때문에, 무리해서 확정적으로 단정하기보다 로그와 실제 CPU 변화를 같이 보시는 게 안전합니다.
저장소도 중요합니다. 특히 NVR 오류 해결을 하다 보면 네트워크 스토리지에 바로 녹화하는 구성이 종종 보이는데요. 편하긴 한데, 지연(latency, 지연 시간)이 조금만 늘어나도 타임라인이 비거나 녹화가 밀리는 증상이 생길 수 있습니다. 저는 가능하면 로컬 SSD에 먼저 기록하고, 이후 보관 정책으로 넘기는 방식을 선호합니다.
⚠️ 실제로 자주 만난 Frigate 녹화 끊김 문제와 해결법
여기부터는 제가 직접 해보니 재현 빈도가 높았던 케이스들입니다. Frigate 디버깅할 때 꽤 자주 만납니다.
1. 특정 시간대에만 녹화 끊김이 생기는 경우
이건 네트워크 트래픽 몰림이나 디스크 백그라운드 작업이 원인인 경우가 많았습니다. 백업, 썸네일 작업, 다른 컨테이너 업데이트가 겹치면 체감상 “Frigate만 문제”처럼 보이거든요.
detect 해상도나 fps가 과한 경우가 많았습니다. 특히 카메라 수가 늘어날수록 누적 부담이 커집니다.
해결 팁: detect 해상도와 fps를 낮춰봅니다.
확인 포인트: 객체 감지 정확도와 CPU 사용량을 같이 봅니다.
3. 컨테이너 재시작 후부터 녹화 경로 오류가 나는 경우
볼륨 마운트 경로가 달라졌거나 권한이 꼬인 경우가 있었습니다. 로그에는 단순한 write error처럼 보이는데, 알고 보면 호스트 경로 소유권 문제더라고요.
ls -al /path/to/frigate/media
id
docker inspect frigate
해결 팁: 컨테이너 사용자와 호스트 디렉터리 권한을 같이 확인합니다.
4. 카메라 한 대만 유독 불안정한 경우
이건 Frigate가 아니라 카메라 쪽 문제였던 적이 많았습니다. 펌웨어, RTSP 세션 제한, 비트레이트 과다, 스위치 포트 상태 같은 게 숨어 있더라고요.
해결 팁: 카메라를 직접 재생해보고, 동일 모델 다른 장비와 비교합니다.
추가 확인: 고정 비트레이트(CBR)와 키프레임 간격도 확인해보면 좋습니다.
CPU 사용량, 디스크 지연, 로그 메시지를 함께 보면서 병목 지점을 찾아가는 실제 디버깅 흐름 예시입니다.
검증: Frigate 성능 개선 후 무엇을 보면 될까요?
설정을 바꿨으면 바로 체감으로만 판단하지 마시고, 최소 몇 시간은 지표를 보시는 걸 권장드립니다. 저도 처음엔 “드디어 됐다!” 싶었는데, 밤에 다시 끊겨서 허탈했던 적이 있거든요.
Frigate 타임라인에 빈 구간이 줄었는지 확인합니다.
컨테이너 CPU 사용률이 이전보다 안정적인지 봅니다.
디스크 await와 utilization이 과하게 치솟지 않는지 봅니다.
특정 카메라의 재연결 로그가 줄었는지 확인합니다.
감지 정확도가 너무 희생되지 않았는지 같이 봅니다.
여기서 중요한 포인트! 성능 최적화와 감지 품질은 항상 트레이드오프가 있습니다. detect 해상도와 fps를 너무 낮추면 CPU는 편해지지만, 작은 객체를 놓칠 수 있거든요. 그래서 저는 한 번에 크게 바꾸지 않고, 한 항목씩 줄여가면서 로그와 결과를 비교합니다.
조치 항목
기대 효과
주의점
detect fps 낮춤
CPU 감소
빠른 움직임 감지 저하 가능
detect 해상도 낮춤
디코딩/감지 부담 감소
작은 객체 인식률 저하 가능
하드웨어 가속 적용
CPU 대폭 완화 가능
장치 전달, 코덱 호환 확인 필요
로컬 SSD 저장
녹화 안정성 향상
보관 공간 관리 필요
타임라인 빈 구간이 줄고 CPU와 디스크 지표가 안정화된 결과를 보여주는 대시보드 예시입니다.
정리: Frigate NVR 녹화 끊김은 한 군데만 보면 잘 안 잡힙니다
이번 글을 한 줄로 요약하면 이겁니다. Frigate NVR 녹화 끊김 문제는 카메라, ffmpeg, 감지 설정, 저장소, 하드웨어 가속을 같이 봐야 풀립니다. 저도 처음엔 이게 뭔가 싶었는데, 결국 가장 효과적이었던 건 복잡한 튜닝보다도 원인 후보를 하나씩 지워가는 디버깅 순서였습니다.
특히 아래 네 가지는 거의 항상 점검하시는 걸 추천드립니다.
detect와 record 스트림을 분리했는지
하드웨어 가속이 실제로 적용됐는지
RTSP 스트림 자체가 안정적인지
녹화 저장소가 병목이 아닌지
이 방식으로 보면 Frigate NVR 성능 문제가 생각보다 빨리 좁혀집니다. 다음 글에서는 홈랩 기준으로 저장소 분리 전략이나, 카메라 수가 늘어났을 때 운영 포인트도 따로 정리해보겠습니다. 이전에 다뤘던 컨테이너 자원 분리 방식과 같이 보시면 더 이해가 잘 되실 거예요.
최적화 전후의 CPU 사용량, 녹화 안정성, 디버깅 포인트를 한 장으로 정리한 요약 인포그래픽입니다.
자주 묻는 질문
Q1. CPU만 낮추면 Frigate 디버깅이 끝난 걸까요?
아닙니다. CPU가 낮아도 디스크 쓰기 지연이나 RTSP 재연결이 있으면 녹화는 계속 끊길 수 있습니다. 그래서 로그와 저장소 지표를 같이 봐야 합니다.
Q2. Frigate NVR 녹화 끊김이 있을 때 가장 먼저 볼 항목은 뭔가요?
저는 컨테이너 로그, 카메라 스트림 단독 재생, 디스크 I/O 이 세 가지부터 봅니다. 이 세 군데에서 방향이 잡히는 경우가 많았습니다.
Q3. 무조건 detect 해상도를 낮추면 되나요?
그건 아닙니다. 작은 객체를 중요하게 보시는 환경이면 감지 품질이 너무 떨어질 수 있습니다. 한 번에 크게 바꾸지 말고 단계적으로 조정해보시는 게 좋습니다.
Frigate NVR 하드웨어를 어떻게 골라야 하는지 막막하셨다면, 딱 그 지점에서 이 글을 보시면 됩니다. 저도 처음 Frigate를 붙일 때는 “카메라 몇 대 안 되는데 아무 미니 PC나 쓰면 되겠지” 하고 시작했었거든요. 근데 실제로 써보니까 NVR(Network Video Recorder, 네트워크 영상 녹화 장치)은 단순 저장 장비가 아니라 영상 디코딩, 객체 감지, 저장, 네트워크 처리가 한 번에 몰리는 워크로드였습니다. 여기서 하드웨어 선택을 대충 하면 CPU는 100%로 치솟고, 녹화는 끊기고, 홈랩 보안은 오히려 불안해지더라고요.
이번 글은 광고성 추천이 아니라, 제가 홈랩에서 Frigate, 보안 카메라, Coral AI(코랄 AI 가속기) 조합을 만지면서 정리한 실전 체크리스트입니다. 제품명만 나열하기보다 어떤 부품이 왜 중요한지, 어디서 병목이 생기는지, 그리고 최소한 무엇부터 챙겨야 하는지 멘토처럼 짚어보겠습니다.
Frigate, 보안 카메라, 스토리지, Coral AI, 스위치가 어떻게 연결되는지 한눈에 보여주는 전체 구성도입니다.
1. 왜 Frigate NVR 하드웨어가 먼저 정리되어야 할까요?
쉽게 말해 Frigate는 “녹화기”이면서 동시에 “영상 분석기”입니다. 카메라에서 RTSP(Real Time Streaming Protocol, 실시간 스트리밍 프로토콜)로 영상을 받아오고, ffmpeg로 스트림을 처리하고, 객체 감지를 돌리고, 이벤트 클립과 스냅샷을 저장하죠. 이 중에서 특히 무거운 건 영상 디코딩과 객체 감지입니다.
제가 직접 해보니 같은 카메라 4대라도 설정에 따라 부하 차이가 꽤 컸어요. 해상도가 높아질수록, 프레임 수가 늘어날수록, 감지 구역이 많아질수록 하드웨어 부담이 훅 올라갑니다. 그래서 Frigate NVR 하드웨어를 고를 때는 “서버가 켜지느냐”보다 지속적으로 안정 동작하느냐를 봐야 합니다. 여기서 중요한 포인트! 처음부터 과하게 비싼 장비를 살 필요는 없지만, 병목이 생기는 영역은 정확히 알아야 삽질을 줄일 수 있습니다.
2. Frigate와 NVR의 핵심 개념, 쉽게 말해 이겁니다
Frigate는 오픈소스 NVR로 많이 알려져 있고, 홈 어시스턴트(Home Assistant)와 함께 쓰는 분도 꽤 많아요. 구조를 아주 단순하게 풀면 아래 흐름입니다.
보안 카메라가 영상을 계속 보냅니다.
Frigate가 그 영상을 받아 녹화합니다.
필요하면 객체 감지(Object Detection, 사람/차량/동물 등 인식)를 수행합니다.
이벤트만 따로 저장하거나 알림을 보냅니다.
이때 CPU는 전체 제어와 일부 디코딩을 맡고, GPU(Graphics Processing Unit, 그래픽 처리 장치)나 iGPU(내장 GPU)는 영상 가속을 도와주고, Coral AI 같은 TPU(Tensor Processing Unit, 추론 가속기)는 객체 감지를 덜어줍니다. 스토리지는 녹화 영상을 버티는 저장소 역할을 하고요. 즉, 한 부품만 좋아서는 안 되고 전체 밸런스가 맞아야 해요.
3. Frigate NVR 하드웨어 체크리스트: 꼭 보는 항목 6가지
3-1. CPU: 무조건 고클럭보다 “지속 부하”가 중요합니다
처음엔 코어 수만 보면 되는 줄 알았는데, 실제로 써보니까 Frigate는 장시간 켜두는 서비스라서 발열과 스로틀링(throttling, 발열로 인한 성능 제한)도 같이 봐야 하더라고요. 소형 장비는 순간 성능은 괜찮아도 여름철에 성능이 출렁이는 경우가 있습니다.
카메라 수: 2대와 8대는 완전히 다른 이야기입니다.
해상도/프레임: 1080p와 4MP 이상급은 부하 차이가 큽니다.
하드웨어 가속 유무: 지원되는 환경에서는 CPU 부담을 크게 줄어들어요.
3-2. Coral AI: 객체 감지용 가속기는 체감 차이가 큽니다
Frigate 이야기에서 Coral AI를 빼기 어렵습니다. 저도 처음엔 “CPU로도 되지 않나?” 싶었는데, 객체 감지를 CPU로 오래 돌리면 다른 작업까지 같이 무거워지더라고요. Coral USB Accelerator나 M.2 기반 Edge TPU 같은 실존하는 Coral 장치는 Frigate 구성에서 많이 쓰이는 편입니다.
특히 사람, 차량 같은 이벤트 감지를 꾸준히 돌릴 계획이라면 Coral AI 같은 추론 가속기를 고려할 만한 가치가 충분해요. 다만 여기서 중요한 건, Coral이 모든 문제를 해결해주진 않는다는 점입니다. 영상 디코딩 병목은 여전히 별개라서 CPU/iGPU/스토리지도 같이 맞춰야 합니다.
3-3. 저장장치: SSD와 HDD를 역할 분리하면 편합니다
이거 진짜 편하더라고요. 운영체제, 컨테이너, 데이터베이스 성격의 파일은 SSD에 두고, 연속 녹화는 HDD에 두는 방식입니다. 제가 한동안 전부 한 디스크에 몰아넣고 썼었는데, 로그와 녹화가 같이 쌓이니 관리가 번거로웠어요.
보안 카메라는 한 대씩 보면 대역폭이 커 보이지 않는데, 여러 대가 동시에 붙으면 스위치와 업링크가 생각보다 바빠집니다. PoE(Power over Ethernet, 랜선 전원 공급) 스위치를 쓰면 배선은 깔끔해지지만, 전력 예산도 함께 봐야 해요. 홈랩 보안에서 의외로 자주 놓치는 부분입니다.
3-5. 카메라 스트림 호환성: RTSP와 코덱 확인은 필수입니다
Frigate 자체보다 카메라 설정에서 더 오래 헤매는 경우도 많더라고요. 메인 스트림은 녹화용, 서브 스트림은 감지용으로 나누는 구성이 흔한데요, 실제로 써보니까 카메라가 RTSP를 안정적으로 제공하는지, H.264/H.265 코덱을 어떻게 내보내는지부터 확인해야 했습니다.
3-6. 전원과 냉각: 조용한 서버가 꼭 좋은 서버는 아니더라고요
24시간 켜둘 장비라면 어댑터 품질, 케이스 통풍, 팬 소음보다 먼저 안정성을 보셔야 합니다. 미니 PC나 소형 보드 장비는 공간은 적게 먹지만, 먼지와 여름철 온도에 꽤 민감하더라고요. 저도 처음엔 무소음이 좋아 보였는데, 결국 약한 강제 냉각을 넣고 훨씬 안정화됐습니다.
항목
중요 이유
체크 포인트
CPU
전체 처리와 디코딩 부담
카메라 수, 발열, 지속 성능
Coral AI
객체 감지 오프로딩
USB 또는 M.2 연결 가능 여부
스토리지
녹화 데이터 누적
SSD/HDD 분리, 보관 기간
네트워크
다중 카메라 스트림 수집
PoE, 스위치 용량, 케이블 상태
카메라
스트림 품질과 호환성
RTSP, 서브 스트림, 코덱
냉각/전원
24시간 안정성
온도, 어댑터, 팬 구성
4. 실전 구현: 제가 주로 확인하는 구축 순서
여기서는 제품 추천보다, 어떤 순서로 확인하면 덜 꼬이는지 말씀드리겠습니다. 저도 처음엔 Docker부터 올렸다가 카메라 스트림 문제를 뒤늦게 발견해서 삽질 좀 했습니다 ㅎㅎ 순서는 아래처럼 가는 게 훨씬 낫습니다.
카메라 RTSP 접속 확인
서버에서 저장소 마운트 구성
Docker와 Frigate 컨테이너 실행
감지용 서브 스트림 연결
Coral AI 인식 여부 확인
녹화/이벤트 저장 경로 검증
온도와 CPU 사용률 모니터링
docker run --rm hello-world
ls /dev/bus/usb
lsblk
df -h
위 명령은 아주 기본이지만 꼭 해보시는 걸 권합니다. 특히 Coral USB를 쓴다면 장치가 보이는지부터 확인해야 하고, 저장소는 남은 공간보다 어디에 마운트됐는지가 더 중요합니다.
실제로 써보니까 하루 정도는 멀쩡해도, 3일째부터 문제가 드러나는 경우가 있었습니다. 그래서 저는 최소 며칠은 돌려보면서 로그를 확인합니다. 🎉 이 과정을 통과하면 그때부터는 꽤 마음이 편해집니다.
카메라 상태, 이벤트 감지, CPU 사용률을 함께 확인하는 검증 단계의 대시보드 이미지입니다.
7. 옵션별 판단 기준: 어떤 환경에 무엇이 맞을까요?
정답은 한 가지가 아닙니다. 다만 사용 목적에 따라 우선순위는 분명히 갈립니다.
환경
우선순위
추천 판단 기준
카메라 1~2대 소형 홈랩
저전력, 저소음
서브 스트림 활용, SSD 중심 구성
카메라 여러 대 상시 녹화
스토리지, 냉각
HDD 분리, 안정 전원, 네트워크 점검
객체 감지 비중이 큰 환경
Coral AI
Edge TPU 연결성과 컨테이너 인식 확인
확장 예정이 있는 홈랩
여유 포트와 슬롯
저장장치 추가 가능성, USB/M.2 여유
여기서 중요한 포인트! 지금 당장 카메라가 2대라고 해서 2대 기준으로만 짜면 나중에 꼭 후회하더라고요. 보안 카메라는 한 번 맛보면 주차장, 현관, 복도까지 늘어나기 쉽습니다. 저도 그랬습니다.
8. 자주 묻는 질문과 마무리 체크
Q. Frigate는 무조건 Coral AI가 있어야 하나요? A. 꼭 그렇진 않습니다. 다만 객체 감지를 오래 안정적으로 돌릴 계획이면 Coral AI 같은 가속기가 체감상 도움이 큽니다.
Q. SSD만으로도 가능한가요? A. 가능합니다. 다만 장시간 녹화 보관이 목적이라면 저장 전략을 따로 설계하는 게 낫습니다.
Q. 보안 카메라는 어떤 점을 먼저 봐야 하나요? A. RTSP 지원, 스트림 분리 가능 여부, 코덱 호환성을 먼저 보시는 게 좋습니다.
CPU, Coral AI, 스토리지, 네트워크, 냉각 요소를 한 장으로 정리한 요약 이미지입니다.
정리해보면 Frigate NVR 하드웨어 선택의 핵심은 비싼 장비를 사는 게 아니라 병목이 생기는 지점을 먼저 이해하는 것입니다. CPU만 보지 마시고, Coral AI 같은 감지 가속기, 저장장치 역할 분리, 카메라 스트림 설계, 그리고 전원과 냉각까지 같이 보셔야 합니다. 제가 직접 해보니 이 순서로 접근하면 시행착오가 훨씬 줄었습니다.
다음 글에서는 Frigate 설정 파일을 더 깊게 들어가서, 감지 구역(zone), 마스크(mask), 녹화 보관 정책을 어떻게 잡으면 좋은지 다뤄볼 예정입니다. 이전 글에서 홈랩 네트워크와 역방향 프록시(Reverse Proxy, 리버스 프록시) 구성 이야기를 보셨다면, 그 위에 얹는 방식으로 생각하시면 이해가 훨씬 쉬우실 겁니다. 홈랩 보안, 천천히 하나씩 쌓아가면 됩니다. 급하게 가면 꼭 다시 뜯게 되더라고요.
Linux Namespace는 요즘 컨테이너 기술 이야기할 때 거의 빠지지 않는 핵심 요소입니다. Docker를 쓰든, containerd를 쓰든, Kubernetes 위에서 파드를 띄우든 결국 밑바닥에는 이런 격리 기술이 깔려 있거든요. 근데 운영하다 보면 막연히 “컨테이너는 분리돼 있다” 정도로만 이해해서는 한계가 옵니다. 장애가 났을 때 왜 프로세스는 안 보이는지, 왜 네트워크가 따로 노는지, 왜 마운트가 호스트랑 다르게 보이는지 알아야 하더라고요.
저도 처음엔 이게 뭔가 싶었습니다. 컨테이너는 많이 올려봤는데, 정작 Linux Namespace를 직접 까보지 않으면 문제 원인을 제대로 못 잡겠더라고요. 특히 홈랩에서 테스트할 때 네트워크 네임스페이스를 잘못 건드려서 통신이 안 붙고, 마운트 네임스페이스 때문에 파일이 보였다 안 보였다 해서 삽질 좀 했습니다 ㅎㅎ 이번 글에서는 이론만 나열하지 않고, Linux Namespace를 실제로 어떻게 적용하고 검증하는지, 그리고 현업이나 홈랩에서 어디에 유용한지 경험 기준으로 풀어보겠습니다.
프로세스, 네트워크, 마운트가 각각 분리되는 구조를 한눈에 보여주는 개요 이미지입니다.
1. 왜 Linux Namespace를 이해해야 하나요
쉽게 말해 Linux Namespace는 커널(Kernel)이 프로세스에게 보여주는 세상을 따로 나누는 기능이거든요. 같은 서버 위에서 돌아가더라도 A 프로세스는 자기 PID 목록만 보고, B 프로세스는 자기 네트워크 인터페이스만 보게 만들 수 있습니다. 이게 컨테이너 기술의 출발점입니다.
여기서 중요한 포인트! 가상머신(Virtual Machine)은 커널까지 통째로 분리하는 방식이고, Namespace는 같은 커널을 공유하면서 보이는 범위만 나누는 방식입니다. 그래서 더 가볍고 빠릅니다. 대신 보안 경계(Security Boundary)로 과신하면 안 됩니다. 저도 처음엔 “분리됐으니 완전히 안전하겠지”라고 생각했는데, 실제로 써보니 Namespace는 격리의 한 축일 뿐이고 cgroups, capabilities, seccomp 같은 요소랑 같이 봐야 하더라고요.
2. Linux Namespace 핵심 개념 정리
대표적인 Namespace는 아래처럼 이해하시면 됩니다.
종류
영문
무엇을 격리하나
현실적인 사용 예
PID
Process ID Namespace
프로세스 번호와 프로세스 트리
컨테이너 내부에서 1번 프로세스만 보이게 구성
NET
Network Namespace
네트워크 인터페이스, 라우팅, 포트
컨테이너별 가상 NIC와 독립 라우팅
MNT
Mount Namespace
마운트 지점과 파일시스템 뷰
호스트와 다른 루트 파일시스템 제공
UTS
UNIX Timesharing System Namespace
호스트명, 도메인명
컨테이너별 hostname 분리
IPC
Inter-Process Communication Namespace
공유 메모리, 세마포어, 메시지 큐
프로세스 간 IPC 격리
USER
User Namespace
UID/GID 매핑
컨테이너 root를 호스트 비특권 사용자로 매핑
한 줄로 줄이면 이렇습니다. Linux Namespace는 프로세스가 보는 시스템 자원을 논리적으로 쪼개는 장치거든요. 컨테이너 런타임은 이걸 조합해서 “내 것처럼 보이지만 사실은 제한된 환경”을 만들어냅니다.
3. 실제 적용 사례: 컨테이너 기술에서 어떻게 쓰이나요
가장 흔한 사례는 역시 Docker나 containerd 같은 런타임입니다. 예를 들어 웹 애플리케이션 컨테이너 하나를 띄운다고 해보죠. 그 안의 애플리케이션은 자기 PID 공간만 보고, 자기 네트워크 인터페이스만 보고, 자기 루트 파일시스템만 봅니다. 사용자는 그냥 컨테이너가 하나 올라간 걸로 보지만, 내부적으로는 여러 Namespace가 같이 엮여 있죠.
제가 홈랩에서 많이 해보는 패턴은 이렇습니다.
리버스 프록시(Reverse Proxy) 컨테이너는 외부와 붙게 둡니다.
백엔드 애플리케이션 컨테이너는 별도 네트워크 네임스페이스에 둡니다.
로그 수집기나 모니터링 에이전트는 필요한 마운트만 노출합니다.
가능하면 User Namespace까지 고려해서 호스트 권한을 줄입니다.
이 방식이 왜 좋냐면, 장애 범위가 줄어듭니다. 어떤 애플리케이션이 오작동해서 내부 프로세스를 마구 생성하더라도, 적어도 다른 워크로드의 프로세스 공간까지 바로 오염시키지는 않거든요. 물론 이것만으로 충분하진 않지만, 운영 안정성에서 체감 차이가 꽤 큽니다.
4. 실전 구현: unshare로 Namespace 직접 만들기
이제 이론 말고 직접 보겠습니다. 저는 Namespace를 설명할 때 항상 <code>unshare부터 보여드립니다. 이걸 한 번 손으로 쳐보면 감이 확 옵니다. 아래 예시는 PID, UTS, Mount Namespace를 분리해서 새 쉘을 띄우는 방식입니다.
sudo unshare --fork --pid --mount --uts /bin/bash
이 상태에서 호스트명도 바꿔보겠습니다.
hostname ns-lab
hostname
ps -ef
여기서 ps -ef를 보면 호스트 전체 프로세스가 아니라 새 Namespace 기준의 프로세스만 보여집니다. 처음 보면 “어? 왜 이렇게 적지?” 싶거든요. 그게 정상입니다.
마운트도 분리해보죠.
mount -t proc proc /proc
mount | grep proc
Mount Namespace를 분리한 뒤 /proc를 다시 마운트하지 않으면 프로세스 정보가 기대와 다르게 보일 수 있습니다. 이 부분에서 많이 헷갈립니다. 저도 예전에 “PID Namespace가 안 먹었나?” 하고 한참 봤었는데, 알고 보니 /proc를 새로 안 붙였던 거였습니다.
실습 중간에 확인해야 하는 핵심 명령과 분리된 PID 공간이 보이는 터미널 예시입니다.
4-1. 네트워크 Namespace 실습
네트워크는 조금 더 재미있습니다. 별도 네임스페이스를 만들고 veth pair(가상 이더넷 쌍)로 연결하면 거의 미니 컨테이너 네트워크처럼 테스트할 수 있죠.
sudo ip netns add ns1
sudo ip link add veth-host type veth peer name veth-ns
sudo ip link set veth-ns netns ns1
sudo ip addr add 10.10.10.1/24 dev veth-host
sudo ip link set veth-host up
sudo ip netns exec ns1 ip addr add 10.10.10.2/24 dev veth-ns
sudo ip netns exec ns1 ip link set lo up
sudo ip netns exec ns1 ip link set veth-ns up
sudo ip netns exec ns1 ping -c 3 10.10.10.1
이 실습이 좋은 이유는 컨테이너 기술의 네트워크 격리 원리를 거의 그대로 보여주기 때문입니다. 브리지(Bridge), NAT, 포트 포워딩까지 붙이면 Docker 네트워크 구조를 훨씬 잘 이해하게 됩니다.
4-2. 간단한 프로세스 격리 확인용 C 코드
시스템 프로그래밍 관점에서 보면 clone() 계열 시스템 콜로 Namespace를 만드는 흐름을 이해하는 것도 중요합니다. 아래 코드는 개념 확인용으로 아주 단순화한 예시입니다.
⚠️ loopback 미활성화: Network Namespace 안에서 lo를 올리지 않으면 localhost 통신이 어색하게 깨집니다.
⚠️ 권한 문제: User Namespace를 섞으면 UID/GID 매핑 때문에 파일 접근이 예상과 다를 수 있습니다.
⚠️ 네트워크 라우팅 누락: veth만 연결해놓고 라우팅이나 NAT를 안 잡으면 외부 통신이 안 됩니다.
특히 네트워크 부분은 진짜 많이 삽질합니다. 저는 예전에 “분명 인터페이스는 올라왔는데 왜 패킷이 안 나가지?” 하고 tcpdump만 한참 봤거든요. 알고 보니 호스트 쪽 IP 포워딩(IP Forwarding)이 빠져 있었습니다. 그래서 아래처럼 확인하는 습관을 들였습니다.
sysctl net.ipv4.ip_forward
ip netns exec ns1 ip route
ip addr show veth-host
보안 측면에서도 한 가지 강조하고 싶습니다. Namespace는 강력하지만 만능은 아니거든요. 격리 기술이라고 해서 무조건 안전한 게 아니고, 커널 취약점이나 잘못된 capability 설정이 있으면 경계가 흐려질 수 있습니다. 그래서 현업에서는 보통 cgroups, seccomp, AppArmor 또는 SELinux 같은 보안 메커니즘과 함께 갑니다.
호스트와 네임스페이스가 veth로 연결되고 패킷이 흐르는 경로를 이해하기 위한 구성도입니다.
6. 검증과 결과 확인: 분리됐는지 어떻게 보나
설정만 해놓고 끝내면 안 됩니다. 반드시 검증해야 합니다. 저는 보통 아래 순서로 봅니다.
프로세스가 분리됐는지 ps, /proc로 확인합니다.
호스트명이 분리됐는지 hostname으로 확인합니다.
네트워크 인터페이스가 분리됐는지 ip addr로 확인합니다.
마운트 뷰가 다른지 mount 출력으로 비교합니다.
필요하면 네임스페이스 핸들을 lsns로 확인합니다.
lsns
sudo ip netns exec ns1 ip addr
sudo ip netns exec ns1 hostname
sudo ip netns exec ns1 ps -ef
이렇게 보면 각 격리가 실제로 먹었는지 금방 드러납니다. lsns는 운영 중 문제 파악할 때 꽤 유용하더라고요. 어떤 프로세스가 어떤 Namespace에 속했는지 감을 잡는 데 도움이 되거든요.
실무 관점의 결과를 정리하면 이렇습니다.
검증 항목
성공 시 기대 결과
실패 시 의심 포인트
PID 분리
내부 프로세스만 보임
/proc 재마운트 누락
hostname 분리
Namespace 내부 이름만 변경됨
UTS 미분리
네트워크 분리
별도 인터페이스/라우팅 표시
veth 연결, lo 활성화 누락
마운트 분리
호스트와 다른 마운트 목록
Mount Namespace 미적용
분리된 Namespace가 실제로 적용됐는지 확인하는 검증 결과 예시 이미지입니다.
7. 실제 운영에서 어디에 써먹나
혹시 이런 경험 있으신가요? 개발팀은 “컨테이너니까 독립적이다”라고 생각하는데, 운영팀은 “그래도 결국 같은 커널인데?”라는 불안이 남습니다. 둘 다 맞는 말이거든요. 그래서 Namespace를 이해하면 커뮤니케이션이 훨씬 쉬워집니다.
제가 현장에서 보거나 직접 적용해본 패턴은 대체로 이렇습니다.
멀티테넌트(Multi-tenant) 환경에서 워크로드 간 기본 격리
CI 러너나 빌드 작업의 프로세스/파일시스템 분리
네트워크 실험 환경 구성과 장애 재현
보안 테스트용 최소 권한 실행 환경 만들기
특히 홈랩에서는 이게 정말 좋습니다. VM 여러 대 띄우기 부담스러울 때 Namespace 기반으로 작은 실험 환경을 빠르게 만들 수 있거든요. 물론 커널 공유라는 특성 때문에 VM을 완전히 대체하진 못하지만, 문제 재현과 구조 학습에는 진짜 편하더라고요.
8. 정리와 다음 단계
Linux Namespace를 이해하면 컨테이너가 갑자기 훨씬 덜 추상적으로 보입니다. 그냥 “신기한 배포 단위”가 아니라, PID Namespace, Network Namespace, Mount Namespace 같은 커널 기능의 조합으로 보이기 시작하거든요. 저도 처음엔 Docker 명령만 외웠는데, 바닥 기술을 알고 나니 장애 대응 속도가 확실히 빨라졌습니다. 드디어 됐다! 싶은 순간이 오더라고요.
오늘 정리한 핵심만 다시 적어보면 이렇습니다.
Linux Namespace는 프로세스가 보는 시스템 자원을 분리합니다.
컨테이너 기술은 여러 Namespace를 조합해 가벼운 실행 환경을 만듭니다.
실전에서는 네트워크, 마운트, 권한 매핑에서 가장 많이 막힙니다.
검증 명령을 반드시 함께 익혀야 운영에서 써먹을 수 있습니다.
다음 단계로는 cgroups와 함께 보면 좋습니다. Namespace가 “보이는 범위”를 나눈다면, cgroups는 CPU와 메모리 같은 자원 사용량을 통제하거든요. 다음 글에서 다룰 예정입니다. 그리고 이전 글에서 컨테이너 런타임 구조를 정리했다면 같이 보시면 연결이 더 잘 됩니다.
PID, NET, MNT 등 주요 Namespace와 운영 포인트를 빠르게 복습할 수 있는 요약 이미지입니다.
9. 자주 묻는 질문
Q1. Namespace만 쓰면 컨테이너를 직접 만든 셈인가요?
완전히 그렇진 않습니다. Namespace는 핵심 구성요소지만, 실제 컨테이너 환경에는 cgroups, 루트 파일시스템, capability 제어, 보안 정책 등이 함께 필요하죠.
Q2. Docker를 쓰는데도 Namespace를 따로 알아야 하나요?
네, 운영이나 장애 대응을 생각하면 알아두는 게 좋습니다. 특히 네트워크 안 붙음, 파일 안 보임, 프로세스 이상 동작 같은 문제는 바닥 기술을 이해해야 빨리 풀린다고 봅니다.
Q3. User Namespace는 꼭 써야 하나요?
상황에 따라 다릅니다. 보안상 이점은 분명하지만, 권한 매핑과 파일 접근에서 복잡도가 올라갑니다. 운영 환경에서는 호환성과 보안 요구사항을 함께 봐야 합니다.