13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[작성자:] admin

  • [HomeLabs] 라즈베리파이 4로 홈 어시스턴트 구축 — 스마트홈 초보자 완벽 가이드

    라즈베리파이 4로 홈 어시스턴트 구축하기 — 스마트홈 구축 실전 가이드

    솔직히 처음엔 스마트홈이 그냥 비싼 장난감이라고 생각했어요. 삼성 스마트싱스, 애플 홈킷 같은 것들도 월정액이 나가고, 집 데이터가 외부 서버로 나가는 게 찜찜했거든요. 그러다 홈랩 커뮤니티에서 Home Assistant(홈 어시스턴트)를 알게 됐어요. 오픈소스, 로컬 실행, 수천 가지 기기 연동… 정말 원하던 그것이더라고요.

    그래서 서랍 속 라즈베리파이 4를 꺼냈습니다. 처음 설치하는 데 두 시간쯤 삽질했는데, 지금은 집에 들어오면 자동으로 불이 켜지고, 외출하면 에어컨이 꺼져요. 한번 써보면 정말 못 돌아가요. 이 글에서는 그 과정을 처음부터 끝까지 함께 해보겠습니다.

    라즈베리파이 4를 중심으로 한 홈 어시스턴트 스마트홈 구성도 — 허브 하나로 조명, 센서, 가전을 모두 연결합니다.

    홈 어시스턴트란 무엇일까요

    Home Assistant는 집 안의 스마트 기기들을 한 곳에서 통합 관리하는 오픈소스 홈 오토메이션 플랫폼입니다. 구글 홈이나 아마존 알렉사처럼 외부 클라우드에 의존하지 않고, 내 서버(라즈베리파이)에서 직접 돌아가는 게 핵심이에요.

    제가 가장 좋아하는 점은 프라이버시입니다. 집 데이터가 어느 미국 회사 서버에 올라가지 않고, 내 라즈베리파이에서만 처리된다는 거죠. 인터넷이 끊겨도 자동화가 작동하고요.

    설치 방식 비교

    설치 방식 특징 초보자 추천
    HAOS (Home Assistant OS) 전용 OS 이미지, 가장 간단한 설치, 공식 권장 ✅ 강력 추천
    Home Assistant Supervised 기존 Debian 위에 설치, 유연하지만 복잡 중급자 이상
    Home Assistant Container Docker 위에서 실행, 애드온 없음 고급 사용자
    Home Assistant Core Python 환경에 직접 설치, 가장 복잡 개발자용

    초보자라면 고민할 것도 없이 HAOS(Home Assistant Operating System)로 가세요. 저도 처음엔 Docker로 시작했다가 결국 HAOS로 갈아탔거든요. 애드온 생태계가 워낙 편리해서요.

    라즈베리파이 4 홈 어시스턴트 설치 — 준비물 체크리스트

    시작 전에 뭐가 필요한지 먼저 확인해 봅시다. 없으면 설치 중간에 멈추게 되니까요. 저는 SD카드가 없어서 한 번 멈췄거든요.

    • ✅ 라즈베리파이 4 (RAM 4GB 이상 권장, 2GB도 동작은 함)
    • ✅ MicroSD 카드 (32GB 이상, Class 10 이상 권장 — 저는 64GB 씁니다)
    • ✅ MicroSD 카드 리더기 (노트북에 내장된 것 있으면 OK)
    • ✅ USB-C 전원 어댑터 (라즈베리파이 4 공식 권장 5V/3A)
    • ✅ 유선 랜 케이블 (초기 설정 시 와이파이보다 안정적)
    • ✅ Raspberry Pi Imager 또는 Balena Etcher (이미지 굽는 소프트웨어, 무료)

    💡 팁: SSD로 부팅하는 방법도 있는데, 처음엔 SD카드로 시작하세요. 안정화되면 그때 SSD로 옮기는 게 훨씬 수월합니다.

    라즈베리파이 4 홈 어시스턴트 설치 — 단계별 실전 가이드

    1단계 — Home Assistant OS 이미지 다운로드 및 굽기

    먼저 Raspberry Pi Imager를 PC나 맥에 설치합니다. 공식 홈페이지(raspberrypi.com)에서 무료로 받을 수 있어요.

    1. Raspberry Pi Imager 실행
    2. “Choose OS” 클릭 → “Other specific-purpose OS” 선택
    3. “Home assistants and home automation” → “Home Assistant” 선택
    4. 라즈베리파이 4용 이미지 선택
    5. “Choose Storage”에서 SD카드 선택
    6. “Write” 클릭 — 다 쓰는 데 5~10분 정도 걸려요

    ⚠️ 주의: SD카드에 있던 데이터는 전부 지워집니다. 중요한 파일 있으면 미리 백업하세요!

    2단계 — 라즈베리파이 첫 부팅

    이미지를 다 구웠으면, SD카드를 라즈베리파이에 꽂고 랜 케이블을 연결한 후 전원을 넣어주세요. 처음 부팅은 조금 오래 걸려요. 저는 약 5분 정도 기다렸어요.

    부팅이 완료되면 같은 네트워크에 연결된 PC 브라우저에서 아래 주소로 접속합니다:

    http://homeassistant.local:8123

    혹시 위 주소로 안 된다면, 공유기 관리 페이지에서 라즈베리파이에 할당된 IP를 확인하고 직접 입력해 보세요:

    http://192.168.x.x:8123

    3단계 — 초기 설정 마법사

    접속하면 초기 설정 화면이 뜹니다. 여기서는 별로 어려운 게 없어요.

    1. 계정 생성: 이름, 아이디, 비밀번호 입력 (이게 홈 어시스턴트 관리자 계정이 됩니다)
    2. 위치 설정: 집 위치를 설정하면 일출/일몰 기반 자동화가 가능해져요
    3. 기기 자동 탐색: 같은 네트워크에 있는 스마트 기기를 자동으로 찾아줍니다 — 저는 여기서 필립스 휴 전구가 바로 잡히더라고요 🎉

    홈 어시스턴트 초기 설정 마법사 화면 — 몇 가지 기본 정보만 입력하면 바로 대시보드가 활성화됩니다.

    4단계 — 첫 통합(Integration) 추가하기

    Integration(통합)이란 홈 어시스턴트가 특정 기기나 서비스와 통신하는 방법을 정의한 모듈이에요. 쉽게 말해 드라이버 같은 거죠.

    설정 → 기기 및 서비스 → 통합 추가 버튼을 누르면 수백 가지 통합 목록이 나옵니다. 자주 쓰는 것들을 몇 가지 소개하면:

    • Philips Hue: 휴 조명 연동
    • MQTT: 다양한 IoT 센서 연동 프로토콜
    • ESPHome: ESP8266/ESP32 기반 DIY 센서 연동
    • Google Cast: 구글 홈, 크롬캐스트 연동
    • Samsung SmartThings: 삼성 스마트싱스 기기 연동

    5단계 — 첫 자동화(Automation) 만들기

    자동화야말로 홈 어시스턴트의 핵심이에요. 저는 처음에 UI로 만들었다가, 나중에 YAML로 직접 작성하는 방식으로 넘어갔어요. 일단 UI부터 익히는 게 좋습니다.

    설정 → 자동화 및 장면 → 자동화 만들기 순서로 들어가세요. 아래는 “해질 무렵 거실 조명 켜기” 자동화 예시입니다:

    alias: "해질 무렵 거실 조명 켜기"
    description: "일몰 30분 전에 거실 조명을 자동으로 켭니다"
    trigger:
      - platform: sun
        event: sunset
        offset: "-00:30:00"
    condition: []
    action:
      - service: light.turn_on
        target:
          entity_id: light.living_room
        data:
          brightness_pct: 80
    mode: single

    YAML이 낯설어도 괜찮아요. UI에서 클릭 몇 번으로 똑같이 만들 수 있거든요. 위 코드는 나중에 “아, 이런 구조구나” 참고용으로 봐두시면 됩니다.

    홈 어시스턴트 설치 후 트러블슈팅 — 제가 겪은 문제들

    설치하면서 막혔던 부분들, 솔직하게 공유합니다. 저만 겪은 게 아닐 거예요.

    문제 1 — homeassistant.local 주소로 접속이 안 돼요

    mDNS(멀티캐스트 DNS)가 막혀 있는 네트워크 환경에서 종종 발생합니다. 해결법은 간단해요.

    1. 공유기 관리 페이지(보통 192.168.0.1 또는 192.168.1.1)에 접속
    2. 연결된 기기 목록에서 “homeassistant” 또는 “raspberrypi” 항목 찾기
    3. 해당 IP 주소로 직접 접속: http://192.168.x.x:8123

    💡 팁: 라즈베리파이에 고정 IP(Static IP)를 할당해 두면 IP가 바뀌는 불상사를 막을 수 있어요. 공유기 DHCP 설정에서 MAC 주소 기반으로 IP를 고정해 주세요.

    문제 2 — SD카드 속도가 너무 느려요

    이거 진짜 많이들 겪는 문제예요. 홈 어시스턴트는 데이터베이스를 SD카드에 계속 쓰는데, 저가형 SD카드면 엄청 느려집니다. 해결 방법은 두 가지예요:

    • 단기: 좋은 SD카드로 교체 (A2 등급 이상 권장)
    • 장기: USB 3.0 SSD로 부팅 전환 — 이 방법은 나중에 별도 글로 다룰게요

    문제 3 — 특정 기기가 자동 탐색이 안 돼요

    같은 네트워크에 있는데 기기가 안 잡히는 경우, 공유기에서 AP 격리(AP Isolation) 기능이 켜져 있는 게 원인인 경우가 많아요. 공유기 설정에서 AP 격리를 꺼주세요. 그래도 안 되면 해당 기기 전용 Integration을 수동으로 추가해야 합니다.

    자동화와 기기 연동이 완료된 홈 어시스턴트 대시보드 — 조명, 온도, 에너지 사용량을 한눈에 확인할 수 있습니다.

    설치 완료 — 결과 확인해 봅시다

    설치가 다 됐다면 대시보드에서 이런 것들이 보여야 정상입니다:

    • ✅ 연결된 기기들이 엔티티(Entity)로 표시됨
    • ✅ 기기 상태(켜짐/꺼짐, 온도 등)가 실시간으로 업데이트됨
    • ✅ 만들어 둔 자동화가 활성화 상태로 표시됨
    • ✅ 설정 → 시스템 → 정보에서 버전 정보 확인 가능

    스마트폰 앱도 설치하고 싶으시면, iOS/안드로이드 모두 “Home Assistant” 공식 앱이 있어요. 같은 네트워크에서는 물론이고, 외부에서도 접속하려면 Nabu Casa(나부 카사) 클라우드 서비스나 Tailscale(테일스케일, VPN 서비스)을 활용하면 됩니다. 이 부분은 다음 글에서 자세히 다룰 예정이에요.

    홈 어시스턴트 확장하기 — 추천 애드온

    HAOS의 장점이 바로 Add-on(애드온) 생태계입니다. 설정 → 애드온 메뉴에서 클릭 몇 번으로 추가 기능을 설치할 수 있어요. 제가 쓰는 것들 몇 가지 소개합니다:

    • Mosquitto Broker: MQTT 브로커, IoT 센서 연동의 핵심
    • ESPHome: ESP 기반 DIY 센서를 홈 어시스턴트에 연결
    • Node-RED: 시각적 자동화 편집기, 복잡한 자동화 만들 때 편함
    • File Editor: 브라우저에서 바로 설정 파일 편집 가능
    • Samba Share: 윈도우 파일 공유로 설정 파일 접근

    처음엔 File Editor 하나만 설치해도 충분해요. 나머지는 필요할 때 하나씩 추가하면 됩니다.

    홈 어시스턴트 vs 상용 스마트홈 플랫폼 비교 요약 — 프라이버시, 비용, 확장성 모든 면에서 홈 어시스턴트가 홈랩 환경에 적합합니다.

    홈 어시스턴트 설치 — 자주 묻는 질문 (FAQ)

    Q. 라즈베리파이 4 말고 다른 기기로도 되나요?

    네, 됩니다. 인텔 NUC, 구형 미니PC, 심지어 가상머신 위에서도 돌아가요. 다만 라즈베리파이 4는 전력 소모가 적고 가격 대비 성능이 좋아서 홈 어시스턴트 전용으로 쓰기 딱 좋습니다.

    Q. 한국 스마트 기기들도 연동이 되나요?

    삼성 스마트싱스 기기들은 공식 통합이 있고, LG ThinQ도 커뮤니티 통합이 있어요. 다만 국내 제조사 기기들은 공식 지원이 없는 경우도 있어서 사전에 호환성 확인이 필요합니다.

    Q. 인터넷이 끊기면 자동화도 안 되나요?

    홈 어시스턴트 자체는 로컬에서 돌아가기 때문에 인터넷이 끊겨도 로컬 자동화는 정상 작동해요. 다만 클라우드 기반 기기(일부 스마트 플러그 등)는 영향을 받을 수 있습니다.

    마무리 — 이제 진짜 스마트홈 시작입니다

    라즈베리파이 4로 홈 어시스턴트를 구축하는 것, 생각보다 어렵지 않죠? 처음 설치하고 거실 조명이 자동으로 켜지던 그 순간이 아직도 기억나요. 진짜 뿌듯하더라고요 🎉

    정리하자면 이렇습니다:

    1. 라즈베리파이 4 + 64GB SD카드 준비
    2. Raspberry Pi Imager로 HAOS 이미지 굽기
    3. 부팅 후 homeassistant.local:8123 접속
    4. 계정 생성 및 기기 연동
    5. 첫 자동화 만들기

    다음 글에서는 외부에서 홈 어시스턴트에 안전하게 접속하는 방법 — Tailscale VPN 연동을 다룰 예정입니다. 이 부분이 설정되면 집 밖에서도 스마트홈을 완전히 제어할 수 있어요.

    질문 있으시면 댓글로 남겨주세요. 제가 직접 겪은 문제라면 같이 해결해 드릴 수 있을 것 같습니다 😊

  • [HomeLabs] 라즈베리파이 5 홈랩 구축: 저전력 미니PC 활용 완전 가이드

    전기세 걱정 없는 홈서버, 라즈베리파이 5로 시작해보세요

    홈랩(Home Lab)을 처음 꾸릴 때 저도 똑같은 고민을 했거든요. “중고 서버 살까? 미니PC 살까?” 근데 막상 중고 타워 서버를 들여놨더니 소음이 장난이 아니더라고요. 한밤중에 서버실(사실 제 방 한 켠이지만) 앞을 지나갈 때마다 데이터센터 온 느낌이랄까요. 그리고 전기 요금 고지서 받아보고 진짜 식겁했습니다.

    그래서 찾게 된 게 라즈베리파이 5(Raspberry Pi 5) 홈랩이에요. 저전력 홈서버로 이만한 게 없더라고요. 처음엔 “이 작은 게 뭘 할 수 있겠어?” 싶었는데, 막상 세팅하고 나니까 놀라웠습니다. 이 글에서는 제가 직접 구축하면서 겪은 삽질과 함께, 라즈베리파이 5 홈랩을 제대로 활용하는 방법을 공유해 드릴게요.

    라즈베리파이 5 기반 홈랩의 전체 구성도 — 단일 보드 컴퓨터 하나로 이렇게 많은 서비스를 돌릴 수 있습니다.

    라즈베리파이 5가 홈랩에 적합한 이유

    라즈베리파이 시리즈는 워낙 유명하지만, 5세대로 넘어오면서 진짜 “쓸만한” 홈서버로 거듭났어요. 이전 세대와 비교하면 체감 성능 차이가 꽤 납니다.

    라즈베리파이 5의 주요 스펙을 간단히 정리하면:

    • CPU: Broadcom BCM2712, Arm Cortex-A76 쿼드코어
    • RAM: 4GB 또는 8GB LPDDR4X (홈랩용이라면 8GB 추천)
    • 스토리지 인터페이스: PCIe 2.0 슬롯 추가 (NVMe SSD 연결 가능)
    • 네트워크: 기가비트 이더넷
    • USB: USB 3.0 포트 2개, USB 2.0 포트 2개

    여기서 제가 특히 주목한 건 PCIe 슬롯이에요. 이전 세대까지는 microSD 카드에 전적으로 의존하거나 USB 방식 외장 SSD를 써야 했거든요. 5세대부터는 공식 HAT(Hardware Attached on Top, 확장 보드)나 서드파티 어댑터를 통해 NVMe SSD를 직접 연결할 수 있어요. 속도 차이가 체감상 확연합니다.

    저전력 홈서버로서의 장점

    • ✅ 소음 없음: 액티브 쿨러를 달아도 일반 PC 대비 훨씬 조용
    • ✅ 저전력: 일반 데스크탑 PC 대비 전력 소모가 현저히 낮음
    • ✅ 공간 효율: 손바닥 크기라 어디든 놓을 수 있음
    • ✅ 활발한 커뮤니티: 문제 생기면 검색하면 다 나옴 (이게 진짜 중요해요)
    • ✅ 합리적인 가격: 진입 장벽이 낮음

    물론 단점도 있어요. x86 아키텍처가 아닌 ARM이라 일부 소프트웨어는 ARM 빌드를 따로 찾아야 하고, 고성능 컴퓨팅 작업에는 한계가 있습니다. 하지만 홈랩 용도, 특히 네트워크 서비스, 모니터링, 미디어 서버, 자동화 같은 작업에는 충분하더라고요.

    준비물 체크리스트

    본격적으로 시작하기 전에 뭐가 필요한지 정리해 드릴게요. 제가 처음에 이것저것 빠뜨려서 두 번 주문했던 기억이 나서 말이에요. ㅎㅎ

    항목 필수 여부 비고
    라즈베리파이 5 (8GB 모델 권장) ✅ 필수 홈랩이라면 8GB로
    공식 전원 어댑터 (27W USB-C PD) ✅ 필수 5세대는 전원 요구사항 달라짐
    microSD 카드 (32GB 이상) 또는 NVMe SSD ✅ 필수 NVMe 강력 추천
    케이스 + 쿨러 권장 발열 관리 필요
    NVMe HAT (M.2 어댑터) 선택 NVMe SSD 쓸 경우 필요
    이더넷 케이블 권장 Wi-Fi보다 유선 안정적

    💡 팁: 라즈베리파이 5는 공식 27W USB-C PD 어댑터를 권장합니다. 전력이 부족하면 부팅 중 경고 메시지가 뜨거나 불안정해질 수 있어요. 저도 처음에 아무 충전기나 꽂았다가 낭패 봤습니다.

    OS 설치 및 초기 설정

    자, 이제 본격적으로 세팅 시작해볼게요. 생각보다 어렵지 않습니다.

    1단계: Raspberry Pi OS 설치

    가장 쉬운 방법은 Raspberry Pi Imager를 사용하는 거예요. 공식 도구라 믿을 수 있고, 설치 전에 SSH 활성화, Wi-Fi 설정, 사용자 계정 설정까지 다 할 수 있거든요.

    1. Raspberry Pi 공식 사이트에서 Raspberry Pi Imager 다운로드
    2. OS 선택: Raspberry Pi OS Lite (64-bit) — 홈서버용이라면 GUI 없는 Lite 버전이 리소스 효율적
    3. 고급 설정(⚙️ 아이콘)에서 SSH 활성화, 사용자명/비밀번호 설정
    4. microSD 또는 NVMe에 Write

    설치 완료 후 첫 부팅, SSH로 접속해서 기본 설정부터 해줍니다.

    # 시스템 업데이트 (항상 첫 번째로 해야 할 일)
    sudo apt update && sudo apt upgrade -y
    
    # 한국 타임존 설정
    sudo timedatectl set-timezone Asia/Seoul
    
    # 호스트명 변경 (나중에 여러 대 운영할 때 헷갈리지 않으려면)
    sudo hostnamectl set-hostname homelab-pi5
    
    # 자동 보안 업데이트 설치
    sudo apt install unattended-upgrades -y
    sudo dpkg-reconfigure --priority=low unattended-upgrades

    2단계: 고정 IP 설정

    홈서버는 IP가 바뀌면 진짜 골치 아파요. 라우터에서 DHCP 예약을 하거나, 직접 고정 IP를 설정해 줍니다. 저는 라우터 DHCP 예약 방식을 선호하는데, 그게 관리하기 편하더라고요.

    직접 설정하고 싶다면 NetworkManager를 씁니다.

    # 현재 연결 이름 확인
    nmcli connection show
    
    # 고정 IP 설정 (예: 192.168.1.100)
    nmcli connection modify "Wired connection 1" \
      ipv4.method manual \
      ipv4.addresses 192.168.1.100/24 \
      ipv4.gateway 192.168.1.1 \
      ipv4.dns "1.1.1.1,8.8.8.8"
    
    # 적용
    nmcli connection up "Wired connection 1"

    3단계: Docker 설치

    홈랩의 핵심은 Docker(도커, 컨테이너 기반 가상화 플랫폼)예요. 여러 서비스를 격리된 환경에서 깔끔하게 관리할 수 있거든요. ARM64 지원이 많이 좋아져서 이제는 대부분의 인기 이미지가 ARM64 빌드를 제공합니다.

    # Docker 공식 설치 스크립트
    curl -fsSL https://get.docker.com -o get-docker.sh
    sudo sh get-docker.sh
    
    # 현재 사용자를 docker 그룹에 추가 (sudo 없이 docker 명령 사용)
    sudo usermod -aG docker $USER
    
    # 변경사항 적용을 위해 재로그인 필요
    newgrp docker
    
    # 설치 확인
    docker --version
    docker run hello-world

    Docker Compose도 함께 설치해 줍니다. 여러 컨테이너를 한 번에 관리할 때 필수예요.

    # Docker Compose V2는 Docker 설치 시 플러그인으로 포함됨
    # 확인
    docker compose version

    Docker 컨테이너로 구성한 홈랩 서비스 스택 — 각 서비스가 독립된 컨테이너로 동작하는 구조입니다.

    핵심 서비스 구축: 실전 Docker Compose 설정

    이제 진짜 재미있는 부분이에요. 어떤 서비스를 돌릴지가 홈랩의 핵심이거든요. 제가 실제로 운영 중인 서비스 스택을 공유해 드릴게요.

    홈랩 필수 서비스 구성

    # ~/homelab/docker-compose.yml
    version: '3.8'
    
    services:
    
      # Portainer: 도커 컨테이너 웹 UI 관리 도구
      portainer:
        image: portainer/portainer-ce:latest
        container_name: portainer
        restart: unless-stopped
        ports:
          - "9000:9000"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - portainer_data:/data
    
      # Pi-hole: 네트워크 전체 광고 차단 DNS 서버
      pihole:
        image: pihole/pihole:latest
        container_name: pihole
        restart: unless-stopped
        ports:
          - "53:53/tcp"
          - "53:53/udp"
          - "8080:80/tcp"
        environment:
          TZ: 'Asia/Seoul'
          WEBPASSWORD: 'your_secure_password'  # 반드시 변경하세요!
        volumes:
          - pihole_data:/etc/pihole
          - dnsmasq_data:/etc/dnsmasq.d
        cap_add:
          - NET_ADMIN
    
      # Uptime Kuma: 서비스 모니터링 대시보드
      uptime-kuma:
        image: louislam/uptime-kuma:latest
        container_name: uptime-kuma
        restart: unless-stopped
        ports:
          - "3001:3001"
        volumes:
          - uptime_kuma_data:/app/data
    
    volumes:
      portainer_data:
      pihole_data:
      dnsmasq_data:
      uptime_kuma_data:
    # 서비스 시작
    cd ~/homelab
    docker compose up -d
    
    # 실행 상태 확인
    docker compose ps
    
    # 로그 확인
    docker compose logs -f

    🎉 이렇게 하면 세 가지 핵심 서비스가 한 번에 뜹니다. Portainer(포테이너)로 컨테이너를 웹에서 관리하고, Pi-hole(파이홀)로 집 안 모든 기기의 광고를 차단하고, Uptime Kuma(업타임 쿠마)로 서비스 가용성을 모니터링할 수 있어요.

    홈 미디어 서버 추가 (선택)

    미디어 서버도 많이들 구성하시는데, Jellyfin(젤리핀, 오픈소스 미디어 서버)이 ARM64 지원도 잘 되고 무료라서 추천드려요.

    # docker-compose.yml에 추가
      jellyfin:
        image: jellyfin/jellyfin:latest
        container_name: jellyfin
        restart: unless-stopped
        network_mode: host  # DLNA 사용 시 host 모드 권장
        volumes:
          - jellyfin_config:/config
          - jellyfin_cache:/cache
          - /mnt/media:/media:ro  # 미디어 파일 경로
        environment:
          - TZ=Asia/Seoul

    ⚠️ 삽질 경험담: 이것만 주의하세요

    13년 경력이라도 새 장비 세팅할 때는 항상 뭔가 하나씩 걸리더라고요. 제가 겪은 주요 문제들을 공유해 드릴게요.

    문제 1: 발열 관리

    라즈베리파이 5는 이전 세대보다 성능이 오른 만큼 발열도 있어요. 케이스 없이 쓰다가 CPU 쓰로틀링(Throttling, 과열 시 성능 제한)이 걸리는 걸 모니터링으로 발견했습니다.

    # CPU 온도 확인
    vcgencmd measure_temp
    
    # 실시간 모니터링
    watch -n 2 vcgencmd measure_temp
    
    # 쓰로틀링 여부 확인 (0x0이면 정상)
    vcgencmd get_throttled

    액티브 쿨러(팬)를 달거나, 방열판이 포함된 케이스를 사용하는 게 좋아요. 라즈베리파이 공식 액티브 쿨러 제품도 있고, 서드파티 케이스들도 많습니다.

    문제 2: ARM64 이미지 없는 경우

    가끔 원하는 Docker 이미지가 ARM64(aarch64)를 지원 안 하는 경우가 있어요. 이럴 때 확인하는 방법:

    # 이미지 아키텍처 확인
    docker manifest inspect [이미지명] | grep architecture
    
    # 만약 arm64 없으면 대안 이미지 검색 필요
    # 또는 QEMU 에뮬레이션 (성능 저하 있음)
    docker run --platform linux/amd64 [이미지명]

    ⚠️ QEMU 에뮬레이션으로 x86 이미지를 돌리면 성능이 많이 떨어집니다. 가능하면 ARM64 네이티브 이미지를 쓰세요.

    문제 3: microSD 카드 수명 문제

    Docker를 microSD에 올리고 로그를 막 쌓다 보면 카드 수명이 급격히 줄어요. 실제로 저 첫 번째 카드 6개월 만에 날렸습니다. 해결책은 두 가지예요.

    • NVMe SSD로 부팅 드라이브 변경 (가장 좋은 방법)
    • 로그 설정 최적화로 쓰기 횟수 줄이기
    # Docker 로그 크기 제한 설정
    # /etc/docker/daemon.json 생성 또는 수정
    sudo nano /etc/docker/daemon.json
    {
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "10m",
        "max-file": "3"
      }
    }
    # Docker 재시작으로 적용
    sudo systemctl restart docker

    운영 결과 확인: 이렇게 쓰고 있습니다

    세팅 완료 후 실제로 어떻게 돌아가는지 확인해 보는 시간이에요. 드디어 됐다! 싶은 순간이기도 하고요.

    시스템 리소스 모니터링

    # 전체 시스템 상태 한눈에 보기
    htop
    
    # Docker 컨테이너별 리소스 사용량
    docker stats
    
    # 디스크 사용량
    df -h
    
    # 메모리 상세
    free -h

    제 경우 위에 소개한 서비스들을 다 올려도 RAM 사용량이 여유 있더라고요. 8GB 모델이라면 훨씬 더 여유롭게 쓸 수 있어요.

    Uptime Kuma 모니터링 대시보드 — 홈랩의 모든 서비스 상태를 한눈에 확인할 수 있습니다.

    자동 시작 설정

    정전이나 재부팅 후에도 서비스가 자동으로 올라오도록 설정해 줍니다.

    # Docker 서비스 자동 시작
    sudo systemctl enable docker
    
    # docker-compose를 systemd 서비스로 등록
    sudo nano /etc/systemd/system/homelab.service
    [Unit]
    Description=Homelab Docker Compose
    Requires=docker.service
    After=docker.service
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    WorkingDirectory=/home/pi/homelab
    ExecStart=/usr/bin/docker compose up -d
    ExecStop=/usr/bin/docker compose down
    TimeoutStartSec=0
    
    [Install]
    WantedBy=multi-user.target
    # 서비스 등록 및 활성화
    sudo systemctl daemon-reload
    sudo systemctl enable homelab.service
    sudo systemctl start homelab.service

    다음 단계로 확장하기

    기본 세팅이 끝났다면 이제 더 재미있는 것들을 추가할 수 있어요. 제가 다음 글에서 다룰 예정인 주제들이기도 합니다.

    추천 확장 서비스 목록

    서비스 용도 ARM64 지원
    Nginx Proxy Manager 리버스 프록시, SSL 인증서 관리 ✅
    Grafana + Prometheus 메트릭 수집 및 시각화 대시보드 ✅
    Home Assistant 스마트홈 자동화 허브 ✅
    Vaultwarden 자체 호스팅 비밀번호 관리자 ✅
    Nextcloud 개인 클라우드 스토리지 ✅
    WireGuard VPN 서버 ✅

    💡 WireGuard(와이어가드, 경량 VPN 프로토콜)를 설정해 두면 외출 중에도 집 홈랩에 안전하게 접속할 수 있어요. 이건 다음 글에서 자세히 다루겠습니다.

    라즈베리파이 5 홈랩에서 활용 가능한 서비스 비교 — 용도에 맞게 골라서 구성해 보세요.

    자주 묻는 질문 (FAQ)

    Q. 라즈베리파이 5 홈랩, 24시간 켜놔도 되나요?

    네, 됩니다. 저도 항상 켜놓고 있어요. 다만 발열 관리(케이스 + 쿨러)와 안정적인 전원 공급이 중요합니다. UPS(무정전 전원 장치)까지 달면 더욱 안정적이에요.

    Q. microSD vs NVMe SSD, 어떤 게 낫나요?

    홈랩 용도라면 NVMe SSD를 강력히 추천드려요. 속도도 빠르고 수명도 훨씬 길거든요. 처음 세팅 비용이 조금 더 들지만, microSD 갈아 엎는 수고를 생각하면 훨씬 이득입니다.

    Q. 라즈베리파이 5 8GB vs 4GB, 뭐가 더 나을까요?

    홈랩 목적이라면 8GB를 권장합니다. Docker 컨테이너 여러 개 올리다 보면 4GB는 빠듯해질 수 있어요. 처음부터 8GB로 가는 게 나중에 후회가 없더라고요.

    마무리: 작게 시작해서 크게 배웁니다

    라즈베리파이 5 홈랩, 생각보다 어렵지 않죠? 처음엔 “이게 진짜 되겠어?” 싶었는데, 막상 세팅하고 나면 진짜 신세계가 열려요.

    제가 13년 동안 인프라 엔지니어로 일하면서 느낀 건, 홈랩이야말로 가장 빠르게 실력이 느는 방법이라는 거예요. 회사 서버는 함부로 건드릴 수 없으니까요. 집에서 마음껏 실험하고, 망가뜨려 보고, 복구해 보는 과정에서 진짜 실력이 쌓입니다.

    오늘 다룬 내용을 정리하면:

    • ✅ 라즈베리파이 5의 하드웨어 특성과 홈랩 적합성 이해
    • ✅ OS 설치 및 기본 시스템 설정
    • ✅ Docker 기반 서비스 스택 구성 (Portainer, Pi-hole, Uptime Kuma)
    • ✅ 발열, ARM64 호환성, 스토리지 수명 등 주요 이슈 해결
    • ✅ 시스템 안정성을 위한 자동 시작 설정

    다음 글에서는 Nginx Proxy Manager와 Let’s Encrypt를 활용한 HTTPS 설정을 다룰 예정이에요. 외부에서 홈랩 서비스에 안전하게 접속하는 방법인데, 이게 또 재미있거든요. 기대해 주세요! 😄

    궁금한 점이나 다른 삽질 경험이 있으시면 댓글로 공유해 주세요. 같이 고민해 봐요!

  • [Cloud] Cloudflare Workers로 서버리스 API 및 엣지 컴퓨팅 구축 가이드

    서버 없이 전 세계에서 실행되는 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만으로는 아쉬울 때 딱 좋은 조합이거든요.

    궁금한 점이나 직접 해보다가 막히는 부분 있으시면 댓글로 남겨주세요. 같이 삽질해봅시다! 😄

  • [Cloud] Terraform 원격 상태 관리: S3, GCS, Azure Blob 백엔드 설정 가이드

    로컬 tfstate 파일, 언제까지 쓸 건가요?

    Terraform을 처음 배울 때 저도 그냥 로컬에 terraform.tfstate 파일 두고 썼거든요. 혼자 쓸 때는 문제없었는데, 팀원이 생기고 나서 진짜 지옥이 시작됐습니다. 누군가 apply 해놓고 상태 파일 커밋을 깜빡한 거예요. 그 다음 날 제가 apply 했더니… 리소스 중복 생성 오류가 펑펑 터졌습니다. 😅

    그때부터 Terraform 원격 상태 관리를 제대로 공부하기 시작했어요. S3, GCS, Azure Blob — 클라우드별로 백엔드 설정 방법이 다 다르거든요. 오늘은 실제 현업에서 직접 써본 경험을 바탕으로, 세 가지 백엔드를 한 번에 정리해드리겠습니다.

    ▲ Terraform 원격 백엔드 구성 개요 — 여러 팀원이 동일한 원격 상태 파일을 공유하며 협업하는 구조입니다.


    Terraform 상태(State)란 뭔가요? — 개념부터 잡고 가기

    쉽게 말해서, Terraform은 자기가 만든 인프라를 상태 파일(state file)에 기록해둡니다. 다음에 plan이나 apply를 실행할 때 “지금 실제로 뭐가 있는지”를 이 파일 보고 판단하는 거예요. 일종의 인프라 장부 같은 거죠.

    기본값은 로컬 파일(terraform.tfstate)인데, 여기서 문제가 생깁니다.

    • 팀원끼리 상태 파일이 달라지는 상태 불일치(State Drift) 발생
    • 동시에 apply하면 상태 파일이 깨지는 동시성 문제
    • 상태 파일에 민감한 정보(비밀번호, 키 등)가 포함될 수 있는 보안 문제
    • 로컬 파일 분실 시 인프라 관리 불가능해지는 복구 불가 리스크

    이 모든 걸 해결해주는 게 바로 원격 백엔드(Remote Backend)입니다. 상태 파일을 클라우드 스토리지에 저장하고, 잠금(Lock) 메커니즘으로 동시 접근을 막는 방식이에요.

    백엔드별 잠금 메커니즘 비교

    백엔드 상태 저장소 상태 잠금 암호화 주요 클라우드
    S3 백엔드 AWS S3 DynamoDB 테이블 SSE-S3 / SSE-KMS AWS
    GCS 백엔드 Google Cloud Storage GCS 내장 Google 관리 키 / CMEK GCP
    Azure Blob 백엔드 Azure Blob Storage Blob 리스(Lease) Azure Storage 암호화 Azure

    GCS는 별도 잠금 인프라 없이 내장 기능으로 처리해줘서 가장 설정이 간단하더라고요. S3는 DynamoDB를 따로 만들어야 해서 초반에는 좀 번거롭긴 한데, 한 번 설정하면 정말 탄탄합니다.


    AWS S3 백엔드 설정 — Terraform 원격 상태 관리 실전 가이드

    AWS를 메인으로 쓰신다면 S3 백엔드가 가장 표준적인 선택입니다. 저도 현업에서 가장 많이 써본 조합이고, 안정성도 검증된 방식이거든요.

    1단계: S3 버킷과 DynamoDB 테이블 생성

    먼저 상태 파일을 저장할 S3 버킷과 잠금용 DynamoDB 테이블을 만들어야 합니다. 이걸 직접 Terraform으로 만들어도 되는데, 닭이 먼저냐 달걀이 먼저냐 문제가 생기거든요. 저는 보통 AWS CLI로 먼저 만듭니다.

    # S3 버킷 생성 (버전 관리 활성화 필수!)
    aws s3api create-bucket \
      --bucket my-terraform-state-prod \
      --region ap-northeast-2 \
      --create-bucket-configuration LocationConstraint=ap-northeast-2
    
    # 버전 관리 활성화 — 상태 파일 롤백을 위해 반드시 켜세요
    aws s3api put-bucket-versioning \
      --bucket my-terraform-state-prod \
      --versioning-configuration Status=Enabled
    
    # 퍼블릭 액세스 차단 — 보안상 필수
    aws s3api put-public-access-block \
      --bucket my-terraform-state-prod \
      --public-access-block-configuration \
        BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
    
    # DynamoDB 테이블 생성 (LockID가 파티션 키여야 합니다)
    aws dynamodb create-table \
      --table-name terraform-state-lock \
      --attribute-definitions AttributeName=LockID,AttributeType=S \
      --key-schema AttributeName=LockID,KeyType=HASH \
      --billing-mode PAY_PER_REQUEST \
      --region ap-northeast-2

    2단계: backend.tf 설정 파일 작성

    # backend.tf
    terraform {
      backend "s3" {
        bucket         = "my-terraform-state-prod"
        key            = "prod/ap-northeast-2/vpc/terraform.tfstate"
        region         = "ap-northeast-2"
        encrypt        = true  # 서버 사이드 암호화 활성화
        dynamodb_table = "terraform-state-lock"  # 잠금용 DynamoDB 테이블
    
        # KMS 키로 암호화하려면 아래 추가
        # kms_key_id = "arn:aws:kms:ap-northeast-2:123456789:key/your-key-id"
      }
    }

    💡 key 경로 설계 팁: 환경/리전/서비스명/terraform.tfstate 형태로 계층 구조를 잡으면 나중에 상태 파일이 수십 개 생겨도 관리하기 훨씬 편합니다. 저는 이 규칙 안 지켰다가 나중에 상태 파일 찾느라 정말 고생했거든요. 🤦

    3단계: 백엔드 초기화

    terraform init
    
    # 기존 로컬 상태를 원격으로 마이그레이션할 때
    terraform init -migrate-state

    S3 백엔드용 IAM 최소 권한 정책

    팀원들이 Terraform을 실행할 때 필요한 최소 권한만 부여하세요. 과도한 권한은 보안 위험이거든요.

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:ListBucket",
            "s3:GetBucketVersioning"
          ],
          "Resource": "arn:aws:s3:::my-terraform-state-prod"
        },
        {
          "Effect": "Allow",
          "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject"
          ],
          "Resource": "arn:aws:s3:::my-terraform-state-prod/prod/*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "dynamodb:DescribeTable",
            "dynamodb:GetItem",
            "dynamodb:PutItem",
            "dynamodb:DeleteItem"
          ],
          "Resource": "arn:aws:dynamodb:ap-northeast-2:123456789012:table/terraform-state-lock"
        }
      ]
    }

    ⚠️ 중요: 123456789012는 여러분의 AWS 계정 ID로 바꿔야 합니다. 또한 /prod/* 경로만 허용해서 다른 환경의 상태 파일은 건드리지 못하게 제한하는 게 좋습니다.

  • [k8s] 쿠버네티스 영구 스토리지: Longhorn vs Rook Ceph 비교 및 선택 가이드

    쿠버네티스 영구 스토리지, 왜 이렇게 어렵냐고요

    쿠버네티스(Kubernetes)로 처음 스테이트풀(Stateful) 애플리케이션을 올려본 분들이라면 공감하실 텐데요. 컨테이너는 죽었다 살아나는 게 당연한 세계인데, 데이터는 절대 사라지면 안 되잖아요. 데이터베이스, 메시지 큐, 로그 수집기… 이런 것들을 올리려면 결국 쿠버네티스 영구 스토리지(Persistent Storage) 문제를 해결해야 합니다.

    저도 처음 홈랩에서 쿠버네티스 클러스터를 구성할 때 이 부분에서 꽤 오래 고민했거든요. NFS 마운트로 버티다가 결국 제대로 된 분산 스토리지를 써야겠다 싶어서 Longhorn이랑 Rook Ceph를 둘 다 실제로 구성해봤습니다. 오늘은 그 경험을 바탕으로 두 솔루션을 비교하고, 어떤 상황에서 뭘 선택해야 하는지 정리해 드릴게요.

    ▲ 쿠버네티스 영구 스토리지의 전체 구조 — PVC(Persistent Volume Claim)가 어떻게 실제 스토리지 백엔드와 연결되는지 보여주는 아키텍처 다이어그램

    먼저 개념부터: PV, PVC, CSI가 뭔가요?

    비교 얘기 전에 기본 개념을 짚고 넘어가겠습니다. 저도 처음엔 이 용어들이 다 비슷비슷해 보여서 헷갈렸거든요 ㅎㅎ

    • PV (Persistent Volume, 영구 볼륨): 클러스터 관리자가 프로비저닝한 실제 스토리지 리소스입니다. 쉽게 말해 “실제 저장 공간”이에요.
    • PVC (Persistent Volume Claim, 영구 볼륨 클레임): 개발자(또는 파드)가 스토리지를 요청하는 오브젝트입니다. “나 10GB짜리 저장 공간 필요해요”라고 요청하는 거죠.
    • StorageClass (스토리지 클래스): 스토리지의 종류와 프로비저닝 방식을 정의합니다. PVC가 요청하면 자동으로 PV를 만들어주는 동적 프로비저닝(Dynamic Provisioning)을 가능하게 해줘요.
    • CSI (Container Storage Interface, 컨테이너 스토리지 인터페이스): 쿠버네티스가 다양한 스토리지 벤더와 통신하기 위한 표준 인터페이스입니다. Longhorn도, Rook Ceph도 이 CSI 드라이버를 통해 쿠버네티스와 연동돼요.

    💡 핵심 포인트: 개발자는 PVC만 선언하면 되고, 실제 스토리지가 어디에 있는지는 신경 안 써도 됩니다. 그 복잡한 연결을 StorageClass와 CSI 드라이버가 처리해주거든요.

    Longhorn 소개: CNCF가 인정한 경량 분산 스토리지

    Longhorn은 Rancher(현재 SUSE 산하)에서 개발한 쿠버네티스 전용 분산 블록 스토리지입니다. CNCF(Cloud Native Computing Foundation) 졸업 프로젝트로 등록되어 있고, 오픈소스이면서 완전히 쿠버네티스 네이티브하게 설계됐어요.

    Longhorn의 주요 특징

    • 쿠버네티스 위에서 동작하는 컨트롤러 기반 아키텍처
    • 볼륨 복제본(Replica)을 여러 노드에 자동 분산
    • 내장 UI 대시보드 — 볼륨 상태를 시각적으로 확인 가능
    • 스냅샷(Snapshot) 및 백업 기능 내장 (S3, NFS 등으로 백업 가능)
    • 볼륨 확장(Volume Expansion) 지원
    • RWO(ReadWriteOnce) 지원, RWX(ReadWriteMany)는 NFS 게이트웨이를 통해 제한적으로 지원

    Longhorn 설치 — Helm으로 빠르게

    실제로 설치해보겠습니다. 저는 k3s 기반 3노드 클러스터에서 테스트했어요.

    # 사전 요구사항 확인 (iscsi 패키지 필요)
    sudo apt-get install -y open-iscsi
    sudo systemctl enable --now iscsid
    
    # Helm 저장소 추가
    helm repo add longhorn https://charts.longhorn.io
    helm repo update
    
    # longhorn 네임스페이스 생성 및 설치
    helm install longhorn longhorn/longhorn \
      --namespace longhorn-system \
      --create-namespace \
      --set defaultSettings.defaultReplicaCount=3

    설치가 완료되면 longhorn-system 네임스페이스에 여러 파드가 뜨는 걸 확인할 수 있어요.

    kubectl get pods -n longhorn-system
    # NAME                                        READY   STATUS    RESTARTS
    # longhorn-manager-xxxxx                      1/1     Running   0
    # longhorn-driver-deployer-xxxxx              1/1     Running   0
    # longhorn-ui-xxxxx                           1/1     Running   0
    # engine-image-ei-xxxxx-xxxxx                 1/1     Running   0

    Longhorn UI에 접근하려면 포트 포워딩이나 인그레스(Ingress, 외부 트래픽 진입점)를 설정해야 합니다.

    kubectl port-forward -n longhorn-system svc/longhorn-frontend 8080:80

    브라우저에서 http://localhost:8080으로 접속하면 볼륨 상태, 노드 디스크 현황을 한눈에 볼 수 있는 대시보드가 나옵니다. 이거 처음 봤을 때 진짜 편하다 싶었어요.

    Longhorn StorageClass 및 PVC 생성 예시

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: longhorn
    provisioner: driver.longhorn.io
    allowVolumeExpansion: true
    parameters:
      numberOfReplicas: "3"
      staleReplicaTimeout: "2880"
      fromBackup: ""
      fsType: "ext4"
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-longhorn-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: longhorn
      resources:
        requests:
          storage: 10Gi

    Rook Ceph 소개: 엔터프라이즈급 분산 스토리지

    Rook은 Ceph를 쿠버네티스에서 오퍼레이터(Operator) 패턴으로 운영할 수 있게 해주는 프레임워크입니다. Ceph 자체는 수십 년의 역사를 가진 검증된 분산 스토리지 시스템이고, Rook은 그 복잡한 Ceph를 쿠버네티스 위에서 쉽게(?) 운영하게 해주죠.

    솔직히 말하면 “쉽게”라는 말에 따옴표를 붙인 이유가 있어요. 처음 Rook Ceph 설치할 때 삽질을 꽤 했거든요 ㅎㅎ

    Rook Ceph의 주요 특징

    • 블록 스토리지(RBD), 파일시스템(CephFS), 오브젝트 스토리지(S3 호환 RGW) 모두 지원
    • CephFS를 통한 RWX(ReadWriteMany) 네이티브 지원 — 여러 파드가 동시에 같은 볼륨 마운트 가능
    • PG(Placement Group), CRUSH Map 등 고급 튜닝 옵션
    • 대규모 클러스터에서 검증된 안정성
    • Ceph Dashboard 내장
    • 최소 3개 OSD(Object Storage Daemon) 노드 권장

    Rook Ceph 설치 — 조금 더 복잡합니다

    # Rook 오퍼레이터 설치
    git clone --single-branch --branch v1.13.0 https://github.com/rook/rook.git
    cd rook/deploy/examples
    
    # CRD 및 공통 리소스 먼저 설치
    kubectl create -f crds.yaml
    kubectl create -f common.yaml
    
    # 오퍼레이터 배포
    kubectl create -f operator.yaml
    
    # 오퍼레이터 파드 확인
    kubectl get pods -n rook-ceph
    # NAME                                  READY   STATUS    RESTARTS
    # rook-ceph-operator-xxxxx              1/1     Running   0

    오퍼레이터가 Running 상태가 되면 Ceph 클러스터를 생성합니다. 아래는 기본 클러스터 설정이에요.

    apiVersion: ceph.rook.io/v1
    kind: CephCluster
    metadata:
      name: rook-ceph
      namespace: rook-ceph
    spec:
      cephVersion:
        image: quay.io/ceph/ceph:v18.2.0
      dataDirHostPath: /var/lib/rook
      mon:
        count: 3
        allowMultiplePerNode: false
      mgr:
        count: 2
      dashboard:
        enabled: true
        ssl: true
      storage:
        useAllNodes: true
        useAllDevices: false
        deviceFilter: "^sd[b-z]"
      resources:
        mgr:
          requests:
            cpu: "500m"
            memory: "512Mi"

    ⚠️ 주의사항: deviceFilter 설정이 중요합니다. 잘못 설정하면 OS 디스크까지 Ceph OSD로 사용하려고 할 수 있어요. 저도 이 부분에서 한 번 아찔한 경험을 했습니다. 반드시 데이터 디스크만 지정하세요.

    # Ceph 블록 스토리지 풀 및 StorageClass 생성
    kubectl create -f csi/rbd/storageclass.yaml
    
    # CephFS (RWX 지원) StorageClass 생성
    kubectl create -f filesystem.yaml
    kubectl create -f csi/cephfs/storageclass.yaml

    ▲ Rook Ceph 아키텍처 — MON(모니터), MGR(매니저), OSD(오브젝트 스토리지 데몬)의 구성과 CSI 드라이버를 통한 쿠버네티스 연동 구조

    Longhorn vs Rook Ceph: 직접 써본 비교

    두 솔루션을 실제로 운영해보면서 느낀 점들을 솔직하게 비교해 드릴게요.

    항목 Longhorn Rook Ceph
    설치 난이도 ⭐⭐ (쉬움) ⭐⭐⭐⭐ (복잡함)
    최소 노드 수 1개 (복제본 설정에 따라) 3개 (OSD 최소 3개 권장)
    리소스 사용량 가벼움 무거움 (MON, MGR, OSD 등 다수)
    RWX 지원 제한적 (NFS 게이트웨이 필요) 네이티브 지원 (CephFS)
    오브젝트 스토리지 미지원 지원 (S3 호환 RGW)
    UI/관리 편의성 직관적인 내장 UI Ceph Dashboard (기능 풍부)
    백업 기능 내장 (S3, NFS 백업) 별도 구성 필요
    성숙도/안정성 CNCF 졸업 프로젝트 CNCF 졸업 프로젝트 (Ceph는 업계 표준)
    운영 복잡도 낮음 높음 (PG 튜닝, CRUSH Map 등)
    적합한 규모 소~중형 클러스터 중~대형 클러스터

    실제로 겪은 트러블슈팅 사례들

    Longhorn에서 겪은 문제: 노드 한 대를 재부팅했더니 해당 노드의 복제본이 degraded 상태가 됐어요. 근데 이건 Longhorn이 자동으로 다른 노드에 복제본을 재빌드해주더라고요. 시간이 좀 걸리긴 했지만 데이터 손실은 없었습니다. ✅

    Rook Ceph에서 겪은 문제: OSD 디스크 하나에 파티션이 남아있었는데, Rook이 해당 디스크를 인식 못 하는 문제가 있었어요. 이게 처음엔 왜 안 되는지 몰라서 꽤 삽질했습니다.

    # OSD 디스크 초기화 — 기존 파티션 제거
    sgdisk --zap-all /dev/sdb
    dd if=/dev/zero of=/dev/sdb bs=1M count=100 oflag=direct
    blkdiscard /dev/sdb
    
    # 파티션 확인
    lsblk /dev/sdb

    ⚠️ 경고: 위 명령어는 해당 디스크의 모든 데이터를 완전히 삭제합니다. 반드시 올바른 디스크를 지정했는지 확인하고 실행하세요.

    또 Ceph 클러스터 상태가 HEALTH_WARN으로 뜰 때 원인 파악하는 방법도 알아두면 좋아요.

    # Ceph 상태 확인
    kubectl exec -n rook-ceph -it deploy/rook-ceph-tools -- ceph status
    kubectl exec -n rook-ceph -it deploy/rook-ceph-tools -- ceph health detail
    
    # OSD 상태 확인
    kubectl exec -n rook-ceph -it deploy/rook-ceph-tools -- ceph osd status

    ▲ Longhorn 대시보드 — 볼륨 상태, 노드별 복제본 분산 현황, 백업 상태를 한눈에 모니터링하는 화면

    어떤 상황에서 뭘 선택해야 할까요?

    이게 결국 핵심 질문이잖아요. 저는 이렇게 기준을 잡아드리고 싶어요.

    Longhorn을 선택하세요, 만약…

    • ✅ 홈랩이나 소규모 클러스터(노드 3~5개 이하)를 운영한다면
    • ✅ 쿠버네티스 스토리지를 처음 도입하는 팀이라면
    • ✅ 운영 인력이 부족하고 관리 부담을 최소화하고 싶다면
    • ✅ 블록 스토리지(RWO) 위주로만 사용한다면
    • ✅ 백업/복구 기능을 간편하게 쓰고 싶다면
    • ✅ 빠르게 구성해서 바로 써야 하는 상황이라면

    Rook Ceph를 선택하세요, 만약…

    • ✅ 중대형 클러스터(노드 5개 이상)를 운영한다면
    • ✅ RWX(ReadWriteMany) 볼륨이 반드시 필요하다면
    • ✅ S3 호환 오브젝트 스토리지도 함께 필요하다면
    • ✅ 전담 인프라 운영 인력이 있다면
    • ✅ 엔터프라이즈 환경에서 검증된 기술 스택이 필요하다면
    • ✅ 고가용성과 세밀한 스토리지 정책 제어가 필요하다면

    둘 다 쓰는 경우도 있어요

    실제로 일부 팀에서는 일반적인 파드 스토리지는 Longhorn으로, RWX가 필요한 공유 파일시스템이나 오브젝트 스토리지는 Rook Ceph로 나눠서 운영하기도 합니다. 복잡해지긴 하지만 각각의 장점을 활용할 수 있는 방법이기도 해요.

    결과 검증: 실제로 제대로 동작하는지 확인하기

    설치만 하면 끝이 아니죠. 실제로 데이터가 잘 보존되는지 확인해봐야 합니다. 아래는 간단한 테스트 시나리오예요.

    # 테스트용 파드 생성
    apiVersion: v1
    kind: Pod
    metadata:
      name: storage-test
    spec:
      containers:
      - name: test
        image: busybox
        command: ["/bin/sh", "-c", "while true; do date >> /data/test.log; sleep 5; done"]
        volumeMounts:
        - mountPath: /data
          name: test-volume
      volumes:
      - name: test-volume
        persistentVolumeClaim:
          claimName: my-longhorn-pvc
    # 파드 실행 후 데이터 확인
    kubectl exec storage-test -- cat /data/test.log
    
    # 파드를 강제 삭제
    kubectl delete pod storage-test
    
    # 새 파드로 다시 마운트해서 데이터가 남아있는지 확인
    kubectl apply -f storage-test.yaml
    kubectl exec storage-test -- cat /data/test.log
    # 이전 로그가 그대로 남아있으면 성공! 🎉

    🎉 데이터가 살아있는 걸 확인했을 때의 그 안도감… 처음엔 진짜 설레더라고요. 쿠버네티스에서 영구 스토리지가 제대로 동작한다는 걸 눈으로 확인한 순간이었습니다.

    추가로 볼륨 상태도 확인해두면 좋아요.

    # PVC 상태 확인
    kubectl get pvc
    # NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    # my-longhorn-pvc    Bound    pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   10Gi       RWO            longhorn       5m
    
    # PV 상세 정보
    kubectl describe pv pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    ▲ Longhorn vs Rook Ceph 선택 가이드 요약 — 클러스터 규모, 기능 요구사항, 운영 복잡도를 기준으로 한 비교 인포그래픽

    자주 묻는 질문 (FAQ)

    Q. Longhorn은 프로덕션 환경에서 써도 되나요?

    네, CNCF 졸업 프로젝트이고 실제로 많은 기업에서 프로덕션에 사용하고 있습니다. 다만 대규모 클러스터나 높은 I/O가 필요한 환경에서는 Ceph 대비 한계가 있을 수 있어요.

    Q. Rook Ceph 최소 사양이 어떻게 되나요?

    OSD 노드 최소 3개를 권장합니다. 각 OSD 노드에는 전용 디스크가 필요하고, MON(모니터) 데몬 운영을 위한 CPU와 메모리도 여유 있게 확보해야 해요. 리소스가 빠듯한 환경에서는 Longhorn이 훨씬 현실적입니다.

    Q. 기존 NFS 스토리지에서 마이그레이션이 가능한가요?

    직접적인 마이그레이션 도구는 없고, 보통 데이터를 백업 후 새 PVC에 복원하는 방식을 사용합니다. Velero(벨레로) 같은 쿠버네티스 백업 도구를 활용하면 좀 더 체계적으로 진행할 수 있어요. 이 내용은 다음 글에서 다룰 예정입니다.

    Q. 홈랩에서는 뭘 추천하세요?

    저는 홈랩에서 Longhorn을 쓰고 있어요. 설치가 간단하고 UI가 직관적이어서 관리하기 편합니다. 노드 3대 이하 환경이라면 Longhorn이 압도적으로 편해요.

    마무리: 결국 “상황에 맞는” 선택이 정답입니다

    13년 동안 인프라 일을 하면서 느낀 건데요. 기술 선택에 “절대적인 정답”은 없더라고요. Longhorn이 좋냐, Rook Ceph가 좋냐가 아니라 내 환경에 뭐가 맞냐가 핵심이에요.

    소규모 클러스터에서 빠르게 쿠버네티스 영구 스토리지를 도입하고 싶다면 Longhorn으로 시작하세요. 운영하다가 규모가 커지고 RWX나 오브젝트 스토리지가 필요해지면 그때 Rook Ceph로 전환하거나 병행하는 것도 방법이에요.

    중요한 건 일단 시작하는 거라고 생각해요. NFS로 버티다가 나중에 대규모 마이그레이션 하는 것보다, 처음부터 제대로 된 CSI 드라이버 기반 스토리지를 도입하는 게 훨씬 낫거든요.

    다음 글에서는 Velero를 활용한 쿠버네티스 백업 전략에 대해 다룰 예정입니다. Longhorn 내장 백업과 Velero를 조합하면 꽤 탄탄한 백업 체계를 만들 수 있거든요. 기대해 주세요! 🎉

    혹시 설치하다가 막히는 부분이 있으시면 댓글로 남겨주세요. 제가 겪었던 삽질 경험이 도움이 될 수도 있으니까요 ㅎㅎ

  • [k8s] Helm Chart 베스트 프랙티스: 프로덕션 배포 및 관리 전략

    Helm Chart를 제대로 쓰고 있는 게 맞나요?

    솔직히 말씀드리면, 저도 처음 Helm을 쓰기 시작했을 때는 그냥 helm install 하나로 모든 게 해결된다고 생각했거든요. 차트 가져다 쓰고, values 파일 조금 수정하고, 배포하면 끝. 근데 이게 개발 환경에서는 통했는데, 프로덕션에 올리는 순간 문제가 터지기 시작하더라고요.

    롤백이 안 된다, 시크릿이 차트에 하드코딩돼 있다, 팀원이 values 파일을 잘못 수정해서 서비스가 내려갔다… 이런 일들을 겪으면서 “아, Helm Chart 베스트 프랙티스라는 게 괜히 있는 게 아니구나” 싶었습니다. 그래서 오늘은 13년 동안 쿠버네티스 인프라를 운영하면서 직접 삽질하며 정리한 Helm 배포 전략과 관리 노하우를 공유해드리려고 해요.

    쿠버네티스 Helm을 처음 시작하신 분들도, 이미 쓰고 계신데 뭔가 찜찜한 분들도 도움이 될 거예요.

    ▲ Helm Chart가 쿠버네티스 클러스터에 배포되는 전체 흐름 — Chart Repository부터 Release 관리까지 한눈에 볼 수 있습니다.

    Helm이 뭔지 다시 한번 짚고 가기

    아마 대부분 아시겠지만, 한 번 정리하고 넘어갈게요. Helm(헬름)은 쿠버네티스의 패키지 매니저입니다. 쉽게 말해, apt나 yum처럼 쿠버네티스 애플리케이션을 패키징하고 배포하는 도구예요.

    핵심 개념 세 가지만 기억하시면 됩니다.

    • Chart(차트): 쿠버네티스 리소스를 정의하는 파일 묶음. npm의 package.json 같은 개념이에요.
    • Release(릴리스): 클러스터에 설치된 Chart의 인스턴스. 같은 Chart를 여러 번 설치하면 각각 다른 Release가 됩니다.
    • Repository(레포지토리): Chart를 저장하고 공유하는 저장소. Docker Hub의 Chart 버전이라고 보시면 돼요.

    Helm 3 기준으로 설명드릴 거예요. Helm 2는 Tiller(틸러)라는 서버 컴포넌트가 있었는데, 보안 문제로 Helm 3에서 완전히 제거됐거든요. 혹시 아직 Helm 2를 쓰시는 분 계시면, 진짜 빨리 마이그레이션하세요.

    Chart 구조를 제대로 잡는 것부터 시작

    프로덕션 Helm 관리의 첫 번째 원칙은 Chart 디렉토리 구조를 일관성 있게 가져가는 것입니다. 처음부터 잘 잡아두지 않으면 나중에 수습하기가 정말 힘들어요.

    my-app/
    ├── Chart.yaml          # 차트 메타데이터 (이름, 버전, 의존성)
    ├── values.yaml         # 기본 설정값
    ├── values-dev.yaml     # 개발 환경 오버라이드
    ├── values-staging.yaml # 스테이징 환경 오버라이드
    ├── values-prod.yaml    # 프로덕션 환경 오버라이드
    ├── templates/
    │   ├── _helpers.tpl    # 재사용 가능한 템플릿 함수
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── ingress.yaml
    │   ├── configmap.yaml
    │   ├── hpa.yaml        # HorizontalPodAutoscaler
    │   ├── pdb.yaml        # PodDisruptionBudget
    │   └── NOTES.txt       # 설치 후 출력되는 안내 메시지
    └── charts/             # 의존 차트들 (서브차트)

    여기서 핵심은 환경별 values 파일을 분리하는 거예요. 하나의 values.yaml에 모든 환경 설정을 때려넣는 분들이 많은데, 그러면 관리가 안 됩니다. 제가 실제로 운영하는 방식은 기본값은 values.yaml에 두고, 환경별 차이점만 오버라이드 파일에 담아두는 거죠.

    # values.yaml (기본값)
    replicaCount: 1
    
    image:
      repository: my-registry/my-app
      tag: "latest"  # CI/CD에서 덮어씁니다
      pullPolicy: IfNotPresent
    
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 500m
        memory: 512Mi
    
    autoscaling:
      enabled: false
      minReplicas: 1
      maxReplicas: 10
      targetCPUUtilizationPercentage: 70
    
    podDisruptionBudget:
      enabled: false
      minAvailable: 1
    # values-prod.yaml (프로덕션 오버라이드)
    replicaCount: 3
    
    image:
      pullPolicy: Always
    
    resources:
      requests:
        cpu: 500m
        memory: 512Mi
      limits:
        cpu: 2000m
        memory: 2Gi
    
    autoscaling:
      enabled: true
      minReplicas: 3
      maxReplicas: 20
    
    podDisruptionBudget:
      enabled: true
      minAvailable: 2

    배포할 때는 이렇게 쓰면 됩니다.

    # 프로덕션 배포
    helm upgrade --install my-app ./my-app \
      -f values.yaml \
      -f values-prod.yaml \
      --namespace production \
      --create-namespace \
      --set image.tag=${IMAGE_TAG}

    💡 팁: --install 플래그를 함께 쓰면 없으면 설치하고, 있으면 업그레이드합니다. CI/CD 파이프라인에서 정말 유용하게 쓰이는 옵션이더라고요.

    실전 배포 전략: 이것만 지켜도 반은 성공

    ▲ GitOps 기반 Helm 배포 파이프라인 — Git push부터 프로덕션 릴리스까지의 자동화 흐름을 보여줍니다.

    1. Chart.yaml 버전 관리를 철저하게

    Chart.yaml에서 version과 appVersion을 구분하는 게 중요합니다. 처음엔 저도 이걸 같은 거라고 생각했는데, 아니더라고요.

    apiVersion: v2
    name: my-app
    description: My Application Helm Chart
    type: application
    version: 1.3.0      # Chart 자체의 버전 (Chart 구조가 바뀌면 올림)
    appVersion: "2.1.4" # 실제 애플리케이션 버전
    
    dependencies:
      - name: postgresql
        version: "12.x.x"
        repository: "https://charts.bitnami.com/bitnami"
        condition: postgresql.enabled

    SemVer(시맨틱 버저닝)를 반드시 지켜주세요. Chart 구조가 바뀌면 version을, 앱 소스만 바뀌면 appVersion만 올리는 습관을 들이면 나중에 롤백할 때 정말 편합니다.

    2. _helpers.tpl로 중복 제거하기

    템플릿 파일에서 같은 라벨, 같은 셀렉터를 매번 복붙하고 계신 분 계신가요? 저 예전에 그랬거든요. 나중에 앱 이름 하나 바꾸려고 파일을 10개 수정한 적이 있었는데, 그때 _helpers.tpl의 소중함을 알았습니다.

    # templates/_helpers.tpl
    {{/*
    공통 라벨 정의
    */}}
    {{- define "my-app.labels" -}}
    helm.sh/chart: {{ include "my-app.chart" . }}
    {{ include "my-app.selectorLabels" . }}
    {{- if .Chart.AppVersion }}
    app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
    {{- end }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
    {{- end }}
    
    {{/*
    셀렉터 라벨
    */}}
    {{- define "my-app.selectorLabels" -}}
    app.kubernetes.io/name: {{ include "my-app.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    {{- end }}
    
    {{/*
    ServiceAccount 이름
    */}}
    {{- define "my-app.serviceAccountName" -}}
    {{- if .Values.serviceAccount.create }}
    {{- default (include "my-app.fullname" .) .Values.serviceAccount.name }}
    {{- else }}
    {{- default "default" .Values.serviceAccount.name }}
    {{- end }}
    {{- end }}

    3. 시크릿 관리 — 절대 Chart에 넣지 마세요

    ⚠️ 경고: 이게 진짜 중요합니다. DB 패스워드, API 키, 인증서 같은 민감한 정보를 values.yaml이나 Chart에 직접 넣으면 안 돼요. Git에 올라가는 순간 끝입니다.

    제가 추천하는 방법은 두 가지예요.

    방법 1: 외부 시크릿 참조

    # templates/deployment.yaml
    env:
      - name: DB_PASSWORD
        valueFrom:
          secretKeyRef:
            name: my-app-secrets  # 별도로 생성된 Secret
            key: db-password

    방법 2: Helm Secrets 플러그인 활용

    # helm-secrets 플러그인 설치
    helm plugin install https://github.com/jkroepke/helm-secrets
    
    # secrets.yaml을 암호화 (SOPS + AWS KMS 또는 GPG 활용)
    helm secrets encrypt secrets.yaml
    
    # 배포 시 복호화하여 사용
    helm secrets upgrade --install my-app ./my-app \
      -f values.yaml \
      -f secrets.yaml

    저는 현재 AWS Secrets Manager와 External Secrets Operator를 조합해서 쓰고 있는데, 이 조합이 가장 깔끔하더라고요. 나중에 이 주제로 별도 글 하나 써볼게요.

    4. PodDisruptionBudget과 HPA는 프로덕션 필수

    롤링 업데이트 중에 서비스가 잠깐 내려간 경험 있으신가요? 저 처음에 그거 때문에 새벽에 전화 받았거든요. PDB(PodDisruptionBudget)를 설정하면 노드 드레인이나 업그레이드 중에도 최소 파드 수를 보장해줍니다.

    # templates/pdb.yaml
    {{- if .Values.podDisruptionBudget.enabled }}
    apiVersion: policy/v1
    kind: PodDisruptionBudget
    metadata:
      name: {{ include "my-app.fullname" . }}
      labels:
        {{- include "my-app.labels" . | nindent 4 }}
    spec:
      minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
      selector:
        matchLabels:
          {{- include "my-app.selectorLabels" . | nindent 6 }}
    {{- end }}
    # templates/hpa.yaml
    {{- if .Values.autoscaling.enabled }}
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: {{ include "my-app.fullname" . }}
      labels:
        {{- include "my-app.labels" . | nindent 4 }}
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: {{ include "my-app.fullname" . }}
      minReplicas: {{ .Values.autoscaling.minReplicas }}
      maxReplicas: {{ .Values.autoscaling.maxReplicas }}
      metrics:
        - type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
    {{- end }}

    ⚠️ 실제로 겪었던 트러블슈팅 사례

    문제 1: helm upgrade 후 롤백이 안 되는 상황

    배포했는데 문제가 생겨서 롤백하려고 했더니 이전 릴리스 히스토리가 없는 거예요. 알고 보니 --history-max 옵션을 설정 안 해서 히스토리가 날아가 있었고, 심지어 ConfigMap이 Helm 외부에서 직접 수정돼 있어서 상태가 꼬여 있었습니다.

    # 릴리스 히스토리 최대 10개 유지 (기본값 10)
    helm upgrade --install my-app ./my-app \
      --history-max 10 \
      --atomic \
      --timeout 5m0s
    
    # 롤백 방법
    helm history my-app -n production  # 히스토리 확인
    helm rollback my-app 3 -n production  # 3번 리비전으로 롤백

    💡 팁: --atomic 플래그를 쓰면 배포 실패 시 자동으로 이전 상태로 롤백해줍니다. CI/CD에서 정말 유용하더라고요.

    문제 2: helm diff 없이 배포했다가 낭패

    values 파일을 수정하고 바로 배포했다가 예상치 못한 리소스가 변경된 적이 있었어요. 이후로는 반드시 helm-diff 플러그인을 써서 변경 사항을 먼저 확인합니다.

    # helm-diff 플러그인 설치
    helm plugin install https://github.com/databus23/helm-diff
    
    # 배포 전 변경 사항 미리 확인
    helm diff upgrade my-app ./my-app \
      -f values.yaml \
      -f values-prod.yaml \
      -n production

    문제 3: 네임스페이스 간 의존성 충돌

    서브차트를 쓰다 보면 의존성 버전이 충돌하는 경우가 있어요. helm dependency update를 주기적으로 실행하고, Chart.lock 파일을 Git에 함께 커밋하는 걸 습관화하세요.

    # 의존성 업데이트
    helm dependency update ./my-app
    
    # 의존성 목록 확인
    helm dependency list ./my-app

    배포 결과 검증하기

    ▲ Helm 릴리스 상태와 쿠버네티스 리소스 헬스를 한눈에 확인할 수 있는 모니터링 대시보드 예시입니다.

    배포가 끝났다고 끝이 아닙니다. 제대로 됐는지 확인하는 과정이 중요해요.

    # 릴리스 상태 확인
    helm status my-app -n production
    
    # 실제 렌더링된 매니페스트 확인
    helm get manifest my-app -n production
    
    # 적용된 values 확인
    helm get values my-app -n production
    
    # 전체 릴리스 목록
    helm list -A
    
    # 배포된 리소스 상태 확인
    kubectl get all -l app.kubernetes.io/instance=my-app -n production
    
    # 파드 로그 확인
    kubectl logs -l app.kubernetes.io/name=my-app -n production --tail=100

    저는 배포 후 항상 이 체크리스트를 확인합니다.

    1. 모든 파드가 Running 상태인지 확인
    2. Readiness Probe가 통과했는지 확인
    3. HPA가 올바르게 연결됐는지 확인
    4. Ingress가 정상 응답하는지 확인
    5. 에러 로그가 없는지 확인

    Helm Chart 관리 전략 정리

    ▲ 프로덕션 Helm Chart 관리를 위한 핵심 베스트 프랙티스를 한눈에 정리한 요약 가이드입니다.

    항목 나쁜 예 좋은 예
    시크릿 관리 values.yaml에 패스워드 직접 기입 External Secrets 또는 helm-secrets 활용
    환경 분리 단일 values.yaml에 모든 환경 설정 환경별 values 파일 분리 + 오버라이드
    배포 전 검증 바로 helm upgrade 실행 helm diff로 변경 사항 먼저 확인
    롤백 준비 히스토리 관리 없이 배포 –history-max 설정 + –atomic 플래그
    가용성 보장 PDB 없이 운영 PodDisruptionBudget + HPA 설정
    차트 버전 version과 appVersion 혼용 SemVer 기반으로 명확히 분리
    중복 코드 각 템플릿에 라벨 직접 기입 _helpers.tpl로 공통 템플릿 관리

    마무리: Helm은 도구, 전략은 여러분 몫

    Helm Chart 베스트 프랙티스를 정리하다 보니 꽤 길어졌네요. 핵심만 다시 짚어드리면 이렇습니다.

    • ✅ 환경별 values 파일 분리는 선택이 아닌 필수
    • ✅ 시크릿은 절대 Chart에 직접 넣지 말 것
    • ✅ --atomic + --history-max로 안전망 확보
    • ✅ helm-diff로 배포 전 반드시 변경 사항 확인
    • ✅ PDB와 HPA는 프로덕션 환경에서 필수 설정
    • ✅ _helpers.tpl로 중복 템플릿 코드 제거

    사실 이 모든 게 처음부터 완벽하게 되지는 않아요. 저도 수많은 삽질을 거쳐서 지금의 방식에 안착했거든요. 중요한 건 조금씩 개선해나가는 거예요.

    다음 글에서는 Helm과 ArgoCD를 연동한 GitOps 배포 전략을 다뤄볼 예정입니다. Helm만으로는 아쉬운 부분들을 GitOps가 어떻게 채워주는지 실제 경험 기반으로 써볼게요. 기대해 주세요!

    궁금한 점이나 다른 경험 있으시면 댓글로 편하게 남겨주세요. 같이 고민해봐요. 🎉

  • [Proxmox] Proxmox 백업 자동화 완벽 가이드: PBS 및 스케줄 백업 활용

    백업 없이 운영하다가 날린 VM, 그 뼈아픈 경험 이야기

    솔직하게 고백하자면, 저도 한 번 날린 적 있습니다. 홈랩에서 열심히 세팅해 둔 VM(가상 머신) 하나가 스토리지 장애로 그냥 사라져버렸거든요. 백업? 당연히 없었죠. ‘홈랩인데 뭐 어때’ 라고 생각했던 게 화근이었습니다. 그 이후로 저는 Proxmox 백업 자동화를 진지하게 구축하기 시작했고, 지금은 매일 밤 자동으로 백업이 돌아가는 걸 보면서 마음이 편안해지는 사람이 됐습니다 ㅎㅎ.

    이 글은 Proxmox VE(Virtual Environment)를 운영하면서 Proxmox 백업 자동화를 아직 제대로 구성하지 못하신 분들을 위한 실전 가이드입니다. PBS(Proxmox Backup Server)를 활용한 자동화 방법부터, 스케줄 백업 설정, 그리고 실제 운영에서 겪은 삽질까지 전부 공유해 드릴게요.

    ▲ Proxmox VE와 PBS(Proxmox Backup Server)가 연동된 전체 백업 아키텍처 구성도. VM과 CT(컨테이너)가 PBS로 자동 백업되는 흐름을 보여줍니다.

    Proxmox 백업의 두 가지 방식: 어떤 걸 써야 할까?

    Proxmox VE에서 백업을 설정할 때 처음에 헷갈리는 게 바로 이 부분이에요. 백업 저장소를 어디로 잡느냐에 따라 Proxmox 백업 자동화 방식이 완전히 달라지거든요.

    구분 로컬/NFS/CIFS 백업 PBS(Proxmox Backup Server) 백업
    저장 방식 전체 이미지 파일 (.vma) 증분 백업 (변경분만 저장)
    중복 제거 ❌ 없음 ✅ 청크 기반 중복 제거
    암호화 제한적 ✅ 클라이언트 사이드 암호화 지원
    복원 속도 보통 빠름 (증분 복원 가능)
    스토리지 효율 낮음 매우 높음
    구축 난이도 쉬움 중간 (별도 서버 필요)

    쉽게 말해서, 로컬 백업은 간단하지만 디스크를 많이 잡아먹고, PBS는 증분 백업과 중복 제거 덕분에 같은 공간에 훨씬 많은 백업 포인트를 유지할 수 있어요. 홈랩이라 스토리지가 넉넉하지 않다면 PBS가 훨씬 유리합니다.

    저는 처음에 NFS 공유 폴더에 그냥 백업했다가, 한 달도 안 돼서 디스크가 꽉 차는 걸 경험했거든요. 그 이후로 Proxmox Backup Server로 갈아탔고, 같은 공간에 훨씬 오래된 백업 포인트를 유지할 수 있게 됐습니다.

    PBS(Proxmox Backup Server) 설치 및 초기 설정

    PBS는 Proxmox VE와는 별도의 소프트웨어입니다. 전용 ISO를 받아서 별도 머신(물리 서버든, VM이든)에 설치하는 게 기본이에요. 저는 홈랩에서 오래된 미니 PC 한 대를 PBS 전용으로 쓰고 있습니다.

    1단계: PBS 설치

    Proxmox 공식 사이트(proxmox.com)에서 PBS ISO를 다운받아서 설치하면 됩니다. 설치 과정은 Proxmox VE와 거의 동일해서 어렵지 않아요. 설치 후 웹 UI는 기본적으로 https://[PBS-IP]:8007로 접속합니다.

    2단계: 데이터스토어(Datastore) 생성

    PBS에서 백업이 실제로 저장되는 공간을 데이터스토어라고 부릅니다. 웹 UI에서 만들 수도 있고, CLI로도 만들 수 있어요.

    # PBS 서버에서 실행
    # /mnt/backup-pool 디렉토리를 데이터스토어로 생성
    proxmox-backup-manager datastore create main /mnt/backup-pool
    
    # 생성된 데이터스토어 목록 확인
    proxmox-backup-manager datastore list

    3단계: 사용자 및 토큰 생성 (API Token)

    Proxmox VE가 PBS에 접속할 때 사용할 API 토큰을 만들어야 합니다. 보안상 root 계정 대신 전용 사용자를 만드는 걸 권장해요.

    # PBS 서버에서 실행
    # 백업 전용 사용자 생성
    proxmox-backup-manager user create backup-user@pbs --password 'YourSecurePassword'
    
    # 데이터스토어에 대한 권한 부여 (DatastoreBackup 역할)
    proxmox-backup-manager acl update /datastore/main --auth-id 'backup-user@pbs' --role DatastoreBackup
    
    # API 토큰 생성
    proxmox-backup-manager user generate-token backup-user@pbs mytoken

    ⚠️ 중요! 토큰 값은 생성 시 한 번만 표시되니까 반드시 메모해 두세요. 저도 처음에 그냥 닫았다가 다시 만들었거든요 ㅎㅎ.

    Proxmox VE에 PBS 스토리지 연결하기

    이제 Proxmox VE 쪽에서 PBS를 백업 저장소로 등록해야 합니다.

    웹 UI로 연결하는 방법

    1. Proxmox VE 웹 UI 접속 → Datacenter 선택
    2. 왼쪽 메뉴에서 Storage 클릭
    3. Add 버튼 → Proxmox Backup Server 선택
    4. PBS 서버 IP, 포트(8007), 앞서 만든 사용자명과 토큰 값 입력
    5. 데이터스토어 이름 입력 후 저장

    CLI로 연결하는 방법

    # Proxmox VE 노드에서 실행
    # PBS 스토리지를 /etc/pve/storage.cfg에 추가
    pvesm add pbs pbs-backup \
      --server 192.168.1.100 \
      --datastore main \
      --username backup-user@pbs \
      --token mytoken \
      --tokenid 'backup-user@pbs!mytoken'
    
    # 연결 확인
    pvesm status

    연결이 성공하면 Proxmox VE 스토리지 목록에 PBS가 표시됩니다. 여기서 핑거프린트(Fingerprint) 불일치 오류가 나는 경우가 있는데, 이건 아래 트러블슈팅 섹션에서 다룰게요.

    ▲ Proxmox VE 웹 UI에서 PBS 스토리지를 연결하고 백업 작업을 설정하는 화면. Storage 메뉴에서 Proxmox Backup Server 타입을 선택해 연동합니다.

    Proxmox 스케줄 백업 설정: 자동화의 핵심

    이제 진짜 핵심입니다. 수동으로 백업 버튼 누르는 건 언젠가 반드시 까먹게 되어 있어요. Proxmox 스케줄 백업을 설정해두면 정해진 시간에 알아서 백업이 돌아갑니다.

    백업 작업(Backup Job) 생성

    Proxmox VE 웹 UI에서 Datacenter → Backup 메뉴로 이동하면 백업 작업을 만들 수 있어요.

    1. Add 버튼 클릭
    2. 노드(Node), 스토리지(Storage, 아까 연결한 PBS 선택), VM 선택
    3. 스케줄(Schedule) 설정
    4. 백업 모드(Mode) 선택
    5. 보존 정책(Retention) 설정

    스케줄 문법 이해하기

    Proxmox의 스케줄은 systemd 타이머 문법을 사용합니다. 처음엔 낯설 수 있는데, 익숙해지면 굉장히 직관적이에요.

    # 자주 쓰는 스케줄 예시
    daily          # 매일 00:00
    daily 02:00    # 매일 새벽 2시
    weekly         # 매주 월요일 00:00
    monthly        # 매월 1일 00:00
    sat 03:00      # 매주 토요일 새벽 3시
    */2:00         # 2시간마다
    
    # CLI로 백업 작업 생성 예시
    pvesh create /cluster/backup \
      --storage pbs-backup \
      --schedule 'daily 02:00' \
      --mode snapshot \
      --vmid 100,101,102 \
      --mailnotification always \
      --mailto '[email protected]'

    백업 모드(Mode) 선택 기준

    • Snapshot 모드: VM이 실행 중인 상태에서 백업. 서비스 중단 없음. 가장 많이 씀.
    • Suspend 모드: 백업 중 VM을 일시 정지. 데이터 일관성이 높지만 잠깐 서비스 중단.
    • Stop 모드: VM을 완전히 끄고 백업. 가장 안전하지만 다운타임 발생.

    💡 팁: 데이터베이스가 돌아가는 VM이라면 Snapshot 모드만으로는 데이터 일관성이 보장되지 않을 수 있어요. 이 경우 QEMU Guest Agent를 설치하면 스냅샷 전에 파일시스템을 freeze(동결)해줘서 훨씬 안전합니다.

    보존 정책(Retention Policy) 설정

    백업을 얼마나 오래 보관할지 정하는 게 보존 정책입니다. PBS에서는 굉장히 세밀하게 설정할 수 있어요.

    # PBS 데이터스토어에 보존 정책 설정
    proxmox-backup-manager datastore update main \
      --keep-last 3 \
      --keep-daily 7 \
      --keep-weekly 4 \
      --keep-monthly 3
    
    # 위 설정의 의미:
    # keep-last 3   : 최신 백업 3개는 무조건 보관
    # keep-daily 7  : 일별 백업을 7일치 보관
    # keep-weekly 4 : 주별 백업을 4주치 보관
    # keep-monthly 3: 월별 백업을 3개월치 보관

    이 설정 덕분에 같은 스토리지 공간으로 훨씬 오랜 기간의 백업 히스토리를 유지할 수 있습니다. 증분 백업 + 중복 제거 + 보존 정책, 이 세 가지가 Proxmox Backup Server의 핵심 강점이에요.

    ⚠️ 실제로 겪은 트러블슈팅 모음

    이론은 이론이고, 실제로 설정하다 보면 별의별 문제가 다 생기더라고요. 제가 겪은 것들을 공유합니다.

    문제 1: 핑거프린트(Fingerprint) 불일치 오류

    PBS 스토리지를 추가할 때 이런 오류가 나는 경우가 있어요.

    TASK ERROR: fingerprint 'XX:XX:...' does not match

    PBS 서버에서 핑거프린트를 직접 확인해서 Proxmox VE 설정에 넣어주면 해결됩니다.

    # PBS 서버에서 실행
    proxmox-backup-manager cert info | grep Fingerprint
    
    # 출력된 핑거프린트를 복사해서
    # Proxmox VE의 스토리지 설정에 fingerprint 항목에 붙여넣기

    문제 2: 백업 중 ‘lock timeout’ 오류

    VM 여러 개를 동시에 백업할 때 간혹 발생합니다. 기본적으로 Proxmox는 VM당 하나의 백업만 허용하는데, 이전 백업이 비정상 종료되면 락(Lock) 파일이 남아있을 수 있어요.

    # 특정 VM의 락 파일 확인 (VM ID 100 예시)
    ls /run/lock/qemu-server/lock-100.conf
    
    # 락 파일 제거 (백업이 실제로 안 돌아가고 있을 때만!)
    rm /run/lock/qemu-server/lock-100.conf

    문제 3: 스냅샷 백업 시 디스크 공간 부족

    Snapshot 모드로 백업할 때 임시 스냅샷을 위한 여유 공간이 필요합니다. 스토리지가 꽉 차있으면 백업이 실패해요. 저장소에 최소 20% 정도 여유 공간을 확보해 두는 게 좋습니다.

    문제 4: PBS 가비지 컬렉션 미실행으로 인한 공간 낭비

    PBS에서 오래된 백업을 삭제해도 실제 디스크 공간이 바로 회수되지 않아요. 가비지 컬렉션(Garbage Collection)을 주기적으로 실행해야 합니다.

    # PBS 서버에서 가비지 컬렉션 수동 실행
    proxmox-backup-manager garbage-collection start main
    
    # 스케줄 설정 (매주 일요일 새벽 4시)
    proxmox-backup-manager datastore update main \
      --gc-schedule 'sun 04:00'

    저도 이걸 몰라서 한동안 PBS 디스크가 예상보다 빨리 차는 걸 보고 의아했었는데, 가비지 컬렉션 설정하고 나서 해결됐습니다.

    ▲ PBS 웹 대시보드에서 백업 작업 현황, 스토리지 사용량, 보존 정책 적용 결과를 한눈에 확인할 수 있습니다.

    백업 검증: 백업했다고 끝이 아닙니다

    이게 진짜 중요한데 많이들 놓치는 부분이에요. 백업은 복원이 되어야 의미가 있습니다. 백업 파일이 존재한다는 것과, 그 백업으로 실제로 복원이 된다는 건 다른 얘기거든요.

    백업 무결성 검증 (Verify)

    PBS는 백업 데이터의 무결성을 검증하는 기능을 내장하고 있습니다.

    # PBS 서버에서 특정 데이터스토어 검증
    proxmox-backup-manager verify-job create \
      --store main \
      --schedule 'weekly' \
      --ignore-verified true \
      --outdated-after 30
    
    # 수동 검증 실행
    proxmox-backup-manager verify-job run verify-job-id

    복원 테스트

    저는 분기에 한 번씩은 실제로 VM을 복원해보는 테스트를 합니다. Proxmox VE 웹 UI에서는 간단하게 할 수 있어요.

    1. Proxmox VE 웹 UI → 해당 노드 → PBS 스토리지 선택
    2. 복원하고 싶은 백업 포인트 선택
    3. Restore 버튼 클릭
    4. 복원할 VM ID와 스토리지 지정 후 실행

    CLI로도 복원할 수 있습니다.

    # VM 백업 복원 (VM ID 100, 새 VM ID 200으로 복원)
    qmrestore pbs-backup:vm/100/2024-01-15T02:00:00Z 200 \
      --storage local-lvm \
      --force
    
    # CT(LXC 컨테이너) 백업 복원
    pct restore 201 pbs-backup:ct/101/2024-01-15T02:00:00Z \
      --storage local-lvm \
      --force

    VM 백업 전략: 어떻게 구성하면 좋을까?

    마지막으로 제가 실제로 운영 중인 VM 백업 전략을 공유할게요. 홈랩 기준이지만 소규모 운영 환경에도 참고하실 수 있을 거예요.

    ▲ VM 중요도에 따라 차등화된 백업 전략 인포그래픽. 중요 서비스는 매일, 개발/테스트 VM은 주 단위로 백업 주기를 다르게 설정합니다.

    제가 쓰는 3-2-1 백업 전략

    • 3: 데이터 복사본 3개 유지
    • 2: 2가지 다른 미디어/스토리지에 저장
    • 1: 1개는 오프사이트(다른 물리적 위치)에 보관

    홈랩에서 완전한 3-2-1을 구현하기 어렵다면, 최소한 PBS 백업 + 외장 하드 또는 클라우드 스토리지(B2, S3 등)에 추가 백업을 유지하는 것을 권장합니다.

    VM 중요도별 백업 주기

    • 중요 서비스 VM (홈서버, NAS 등): 매일 새벽 2시, 7일치 보관
    • 일반 서비스 VM: 매일 새벽 3시, 3일치 보관
    • 개발/테스트 VM: 주 1회, 2주치 보관

    마무리: 백업은 습관입니다

    여기까지 따라오셨다면, 이제 Proxmox 백업 자동화의 기본 틀은 완성됐습니다. 🎉

    정리하자면:

    • ✅ PBS를 설치하고 Proxmox VE와 연동했습니다
    • ✅ 증분 백업과 중복 제거로 스토리지를 효율적으로 사용합니다
    • ✅ 스케줄 백업으로 매일 자동으로 백업이 돌아갑니다
    • ✅ 보존 정책으로 오래된 백업을 자동 정리합니다
    • ✅ 검증과 복원 테스트로 백업의 신뢰성을 확인합니다

    백업은 한 번 설정했다고 끝이 아니에요. 주기적으로 백업이 제대로 돌아가고 있는지, 복원은 실제로 되는지 확인하는 습관이 중요합니다. 저도 매월 PBS 대시보드를 한 번씩 들여다보고, 분기에 한 번은 복원 테스트를 하고 있어요.

    다음 글에서는 Proxmox VE 클러스터 구성과 고가용성(HA) 설정에 대해 다룰 예정입니다. PBS 백업이 잘 되어 있으면 클러스터 구성도 훨씬 마음 편하게 할 수 있거든요. 기대해주세요!

    혹시 설정하다가 막히는 부분이 있으시면 댓글로 남겨주세요. 같이 해결해봐요 😊

    자주 묻는 질문 (FAQ)

    Q. PBS 서버는 반드시 별도 물리 서버여야 하나요?

    꼭 그렇지는 않습니다. Proxmox VE 위에 VM으로 PBS를 올릴 수도 있어요. 다만 해당 노드가 장애가 나면 백업 서버도 같이 다운된다는 단점이 있어서, 가능하면 별도 머신을 추천합니다.

    Q. 백업 중 VM 성능이 저하되나요?

    Snapshot 모드는 백업 중 성능 영향이 거의 없습니다. 다만 스토리지 I/O는 백업 중 증가할 수 있어요. 그래서 새벽 시간대에 스케줄을 잡는 게 좋습니다.

    Q. PBS 없이 로컬 백업만으로 충분하지 않나요?

    단순한 환경이라면 로컬 백업도 괜찮습니다. 하지만 VM이 5개 이상이거나, 스토리지 공간이 넉넉하지 않다면 Proxmox Backup Server의 증분 백업과 중복 제거 기능이 확실히 유리합니다.

  • [Proxmox] Proxmox VE Ceph 클러스터 구축 및 관리 완벽 가이드

    홈랩에 엔터프라이즈급 스토리지를? Proxmox Ceph 클러스터 도전기

    솔직히 말씀드리면, 처음 Proxmox VE에서 Ceph 클러스터를 구축하려고 했을 때 겁부터 먹었습니다. “분산 스토리지”라는 단어 자체가 주는 무게감이 있잖아요. 대기업 IDC에서나 쓰는 그런 거 아닌가 싶었거든요. 근데 막상 해보니까… 생각보다 훨씬 접근하기 좋더라고요. 물론 삽질은 좀 했습니다 ㅎㅎ.

    Proxmox Ceph 클러스터는 단순히 스토리지 용량을 늘리는 게 아니에요. VM(가상 머신)이나 컨테이너가 어느 노드에서 죽더라도 데이터가 살아있는, 진짜 고가용성(High Availability) 인프라를 만드는 핵심 기술이거든요. 이걸 홈랩에 구현할 수 있다는 게 Proxmox VE의 진짜 매력이라고 생각해요. 오늘은 제가 직접 구축하면서 배운 것들을 처음부터 끝까지 다 풀어드릴게요.

    ▲ Proxmox VE 3노드 Ceph 클러스터 전체 아키텍처 — Public Network, Cluster Network, OSD 구성을 한눈에 볼 수 있습니다.


    Ceph가 뭔지부터 제대로 이해하고 시작하자

    쉽게 말해, Ceph는 어떤 녀석인가요?

    Ceph를 한 줄로 설명하면 “여러 서버의 디스크를 하나의 거대한 스토리지 풀로 묶어주는 오픈소스 분산 스토리지 시스템”입니다. 쉽게 비유하자면, 서버 3대가 있으면 각 서버의 디스크를 전부 합쳐서 하나의 큰 창고처럼 쓰는 거예요. 게다가 데이터를 여러 곳에 복사해두기 때문에 서버 한 대가 꺼져도 데이터는 안전합니다.

    Proxmox VE는 Ceph를 웹 UI에서 직접 설치하고 관리할 수 있도록 통합해놨어요. 예전에 Ceph를 별도로 구성하던 시절을 생각하면 정말 편해진 거죠.

    핵심 구성 요소 이해하기

    구축 전에 이 개념들은 꼭 알고 시작하세요. 처음엔 저도 이게 뭔가 싶었는데, 알고 나면 구성이 훨씬 명확하게 보입니다.

    • MON (Monitor): 클러스터 상태를 감시하는 감시자. 클러스터 맵(어디에 데이터가 있는지 지도)을 관리합니다. 홀수 개로 운영해야 해요 (3개 권장).
    • OSD (Object Storage Daemon): 실제 데이터를 저장하는 데몬. 디스크 하나당 OSD 하나가 대응됩니다. 클러스터의 일꾼이라고 생각하시면 돼요.
    • MGR (Manager): 클러스터 모니터링과 플러그인 관리를 담당. 대시보드, Prometheus 연동 등이 여기서 나옵니다.
    • MDS (Metadata Server): CephFS(파일 시스템)를 쓸 때만 필요한 메타데이터 서버. 오늘 구성에서는 선택사항입니다.
    • Pool (풀): 데이터를 저장하는 논리적 구획. 복제 수(Replication Factor)를 풀 단위로 설정합니다.
    • PG (Placement Group): 데이터를 OSD에 분산 배치하는 단위. 너무 많거나 적으면 성능에 영향을 줍니다.

    네트워크 구성, 이게 제일 중요합니다

    여기서 중요한 포인트! Ceph는 네트워크를 두 개로 분리하는 걸 강력히 권장합니다.

    네트워크 종류 역할 권장 대역폭 비고
    Public Network (퍼블릭 네트워크) 클라이언트 ↔ Ceph 통신, MON 통신 1Gbps 이상 VM이 스토리지에 접근하는 경로
    Cluster Network (클러스터 네트워크) OSD 간 복제 및 리밸런싱 트래픽 10Gbps 권장 분리하면 성능 대폭 향상

    홈랩에서 10Gbps 스위치가 없다면 최소한 두 개의 물리 인터페이스로 분리만 해도 효과가 있어요. 저는 처음에 네트워크를 하나로 합쳐서 썼다가 OSD 리밸런싱 때 VM 네트워크가 뚝뚝 끊기는 걸 경험했거든요 ㅠㅠ.


    구축 환경 및 사전 준비

    최소 구성 요구사항

    Ceph 클러스터는 최소 3개 노드가 필요합니다. 이건 협상이 안 되는 부분이에요. MON이 과반수 투표로 클러스터 상태를 결정하기 때문에 짝수 노드는 스플릿 브레인(Split-Brain) 위험이 있거든요.

    • ✅ 노드 수: 최소 3개 (홀수 권장)
    • ✅ OS: Proxmox VE 7.x 또는 8.x
    • ✅ OSD용 디스크: 노드당 최소 1개 (OS 디스크와 별도)
    • ✅ 네트워크: 노드 간 통신 가능한 네트워크 (가급적 2개 분리)
    • ✅ RAM: OSD 하나당 약 1~2GB 여유 RAM 필요

    제 홈랩 구성은 이렇습니다:

    • 노드 3개: pve01, pve02, pve03
    • 각 노드 OSD 디스크: 500GB SSD × 2개
    • Public Network: 192.168.10.0/24
    • Cluster Network: 192.168.20.0/24

    Proxmox 클러스터 먼저 구성하기

    Ceph를 시작하기 전에 Proxmox VE 클러스터가 먼저 구성되어 있어야 합니다. 아직 안 하셨다면 pve01에서 시작하세요.

    # pve01에서 클러스터 생성
    pvecm create my-homelab-cluster
    
    # pve02, pve03에서 클러스터 참여
    pvecm add 192.168.10.101  # pve01의 IP
    
    # 클러스터 상태 확인
    pvecm status

    클러스터가 정상이면 이제 Ceph 설치로 넘어갑니다.


    Proxmox Ceph 클러스터 단계별 구축

    ▲ Proxmox VE 웹 UI에서 Ceph 설치 마법사를 통해 직관적으로 구성할 수 있습니다. GUI와 CLI 모두 지원합니다.

    1단계: Ceph 패키지 설치

    모든 노드에서 아래 작업을 수행해야 합니다. Proxmox 웹 UI에서 각 노드 → Ceph → Install을 클릭해도 되고, CLI로 해도 됩니다. 저는 CLI가 더 빠르더라고요.

    # 모든 노드(pve01, pve02, pve03)에서 실행
    # Proxmox VE 8.x 기준 (Ceph Reef/Quincy 지원)
    pveceph install --version reef
    
    # 설치 완료 후 확인
    ceph --version

    💡 팁: Proxmox VE 8.x에서는 Ceph Reef(18.x)를 권장합니다. 버전은 Proxmox 버전에 맞게 선택하세요.

    2단계: Ceph 초기화 (pve01에서만)

    클러스터 초기화는 한 노드에서만 합니다. 여기서 네트워크 설정이 핵심이에요.

    # pve01에서만 실행
    # Public Network와 Cluster Network를 분리해서 설정
    pveceph init \
      --network 192.168.10.0/24 \
      --cluster-network 192.168.20.0/24
    
    # 초기화 확인
    ceph status

    3단계: MON (Monitor) 추가

    각 노드에 MON을 추가합니다. 3개 이상의 홀수로 유지하는 게 핵심이에요.

    # pve01에서 순서대로 실행
    # pve01 MON 추가
    pveceph mon create pve01
    
    # pve02 MON 추가 (pve02에서 실행하거나 pve01에서 원격 실행)
    pveceph mon create pve02
    
    # pve03 MON 추가
    pveceph mon create pve03
    
    # MON 상태 확인
    ceph mon stat

    4단계: MGR (Manager) 추가

    # 각 노드에 MGR 추가 (Active/Standby 구성)
    pveceph mgr create pve01
    pveceph mgr create pve02
    pveceph mgr create pve03
    
    # MGR 상태 확인
    ceph mgr stat

    5단계: OSD 추가 — 진짜 데이터 저장소 만들기

    이 단계가 제일 중요합니다. OSD를 추가하기 전에 대상 디스크가 완전히 초기화되어 있어야 해요. 파티션이 남아있으면 추가가 안 됩니다.

    # 디스크 초기화 (주의: 데이터 전부 날아갑니다!)
    # 각 노드에서 OSD용 디스크 확인
    lsblk
    
    # 디스크에 남은 파티션/서명 제거
    wipefs -a /dev/sdb
    wipefs -a /dev/sdc
    
    # OSD 추가 (pve01의 /dev/sdb, /dev/sdc)
    pveceph osd create /dev/sdb
    pveceph osd create /dev/sdc
    
    # pve02에서도 동일하게
    pveceph osd create /dev/sdb
    pveceph osd create /dev/sdc
    
    # pve03에서도 동일하게
    pveceph osd create /dev/sdb
    pveceph osd create /dev/sdc
    
    # OSD 상태 확인
    ceph osd stat
    ceph osd tree

    ⚠️ 주의: wipefs 명령어는 되돌릴 수 없습니다. 반드시 올바른 디스크를 대상으로 하는지 lsblk로 두 번, 세 번 확인하세요. 저는 처음에 하마터면 OS 디스크를 날릴 뻔 했습니다 식은땀 났었어요.

    6단계: Pool (풀) 생성

    이제 실제 VM 디스크를 저장할 풀을 만들 차례입니다.

    # VM 디스크용 RBD(RADOS Block Device) 풀 생성
    # size=3: 데이터를 3개 복사 (3노드에 각 1개씩)
    # min_size=2: 최소 2개 복사본이 있어야 쓰기 허용
    pveceph pool create vm-pool --add-storages
    
    # 풀 상세 설정 (복제 수 조정)
    ceph osd pool set vm-pool size 3
    ceph osd pool set vm-pool min_size 2
    
    # PG 수 설정 (OSD 수에 따라 조정 — OSD 6개 기준)
    # 공식: (OSD 수 × 100) / 복제 수 → 가장 가까운 2의 제곱수
    ceph osd pool set vm-pool pg_num 128
    ceph osd pool set vm-pool pgp_num 128
    
    # 풀 상태 확인
    ceph osd pool ls detail

    💡 PG 수 계산 팁: OSD가 6개면 (6 × 100) / 3 = 200 → 2의 제곱수로 올림하면 256이 되지만, 홈랩 규모에서는 128도 충분합니다. 너무 많으면 오히려 오버헤드가 생겨요.

    7단계: Proxmox Storage에 Ceph 등록

    # Proxmox 스토리지로 등록 (이미 --add-storages 옵션으로 자동 등록됐을 수 있음)
    # 웹 UI: Datacenter → Storage → Add → RBD
    
    # CLI로 확인
    pvesm status

    ⚠️ 실제로 겪은 트러블슈팅 모음

    문제 1: OSD가 계속 down/out 상태

    OSD를 추가했는데 계속 down 상태로 떠있더라고요. 원인을 찾아보니 디스크에 예전 Ceph 서명이 남아있었어요.

    # 해결 방법: 더 강력한 디스크 초기화
    dd if=/dev/zero of=/dev/sdb bs=1M count=100
    wipefs -a /dev/sdb
    
    # 그래도 안 되면 sgdisk로 파티션 테이블 초기화
    sgdisk --zap-all /dev/sdb
    
    # 이후 OSD 재추가
    pveceph osd create /dev/sdb

    문제 2: ceph status가 HEALTH_WARN — “too few PGs per OSD”

    PG 수가 OSD 대비 너무 적거나 많을 때 나오는 경고입니다. 이건 풀의 PG 수를 조정하면 됩니다.

    # 현재 PG 상태 확인
    ceph osd pool ls detail
    
    # PG 수 조정 (늘릴 때는 두 배씩)
    ceph osd pool set vm-pool pg_num 256
    ceph osd pool set vm-pool pgp_num 256
    
    # PG 자동 조정 활성화 (Nautilus 이상)
    ceph osd pool set vm-pool pg_autoscale_mode on

    문제 3: 클러스터 네트워크 쪽 OSD 통신 불량

    Cluster Network를 분리했는데 OSD 간 복제가 안 되는 경우가 있었어요. 방화벽 문제였습니다.

    # Ceph OSD 포트 허용 (6800-7300)
    # pve 방화벽 설정 확인
    cat /etc/pve/firewall/cluster.fw
    
    # 임시로 방화벽 꺼서 테스트
    pve-firewall stop
    
    # 정상 확인 후 방화벽 규칙 추가
    # /etc/pve/firewall/cluster.fw 에 추가:
    # [RULES]
    # IN ACCEPT -p tcp --dport 6800:7300 -s 192.168.20.0/24

    문제 4: VM 마이그레이션 시 느림

    Ceph 스토리지로 라이브 마이그레이션(Live Migration)을 했는데 엄청 느렸어요. 알고 보니 마이그레이션 네트워크가 Public Network를 타고 있어서였습니다. Proxmox에서 마이그레이션 전용 네트워크를 지정해주면 해결됩니다.

    # /etc/pve/datacenter.cfg 에서 마이그레이션 네트워크 설정
    migration: secure
    migration_unsecure: 192.168.20.0/24

    ✅ 클러스터 상태 검증 및 모니터링

    ▲ Ceph 클러스터가 정상 구성되면 HEALTH_OK 상태와 함께 OSD 트리, 풀 사용량을 실시간으로 확인할 수 있습니다.

    필수 확인 명령어

    # 전체 클러스터 상태 (이게 제일 중요)
    ceph status
    ceph health detail
    
    # OSD 상태 및 트리 구조
    ceph osd tree
    ceph osd stat
    
    # 풀 사용량
    ceph df
    ceph osd pool stats
    
    # I/O 실시간 모니터링
    ceph -w
    
    # 성능 확인
    rados bench -p vm-pool 10 write --no-cleanup
    rados bench -p vm-pool 10 seq

    정상 상태 체크리스트

    • ✅ ceph status → HEALTH_OK 표시
    • ✅ MON 쿼럼(Quorum): 3/3 참여
    • ✅ OSD: all up, all in (예: 6/6 OSDs up)
    • ✅ PG: active+clean 상태
    • ✅ MGR: active 1개 + standby 2개

    Proxmox 대시보드에서도 확인

    웹 UI에서 Datacenter → Ceph 메뉴로 가면 OSD 상태, 풀 사용량, I/O 그래프를 한눈에 볼 수 있어요. 이게 진짜 편합니다. CLI로 하나씩 확인하던 시절이 생각나서 감동받았던 기억이 나네요.


    CephFS로 공유 파일시스템도 만들어보자 (보너스)

    VM 디스크(RBD) 외에도 CephFS(Ceph File System)를 구성하면 여러 VM이 동시에 마운트할 수 있는 공유 스토리지를 만들 수 있어요. Kubernetes의 PVC(Persistent Volume Claim)에도 활용할 수 있고요.

    # MDS(Metadata Server) 추가
    pveceph mds create pve01
    pveceph mds create pve02  # 스탠바이용
    
    # CephFS 생성
    pveceph fs create --name cephfs --add-storages
    
    # 상태 확인
    ceph fs status
    ceph mds stat

    CephFS 마운트 설정은 다음 글에서 Kubernetes 연동과 함께 자세히 다룰 예정입니다!


    구성 옵션 비교 — 내 환경에 맞는 선택은?

    ▲ 환경별 Ceph 구성 전략 비교 — 홈랩, 소규모 사업장, 엔터프라이즈 환경에 따라 최적 구성이 다릅니다.

    구성 옵션 홈랩 (3노드) 소규모 프로덕션 엔터프라이즈
    복제 수 (size) 2~3 3 3+
    OSD 디스크 SATA SSD NVMe SSD NVMe + WAL 분리
    클러스터 네트워크 1Gbps 분리 10Gbps 25Gbps+
    MON 수 3 3~5 5
    BlueStore WAL/DB OSD와 동일 디스크 별도 NVMe 권장 별도 NVMe 필수

    홈랩에서는 복제 수를 2로 설정해서 실제 사용 가능 용량을 늘리는 분들도 있는데, 저는 개인적으로 3을 유지하는 걸 권장합니다. 노드 하나가 죽었을 때도 데이터 안전성이 보장되니까요.


    자주 묻는 질문 (FAQ)

    Q. Ceph는 2노드로 구성할 수 없나요?

    기술적으로 가능은 하지만 권장하지 않습니다. MON이 2개면 한 노드가 죽었을 때 쿼럼을 유지할 수 없어서 클러스터 전체가 멈춥니다. 최소 3노드를 유지하세요.

    Q. 기존 Proxmox에 Ceph를 나중에 추가해도 되나요?

    네, 됩니다! Proxmox 클러스터가 이미 구성된 상태에서 Ceph를 나중에 추가해도 전혀 문제없어요. 저도 그렇게 했거든요. 기존 VM들은 로컬 스토리지를 계속 쓰고, 새 VM부터 Ceph 풀을 지정하면 됩니다.

    Q. OSD 디스크는 HDD도 되나요?

    됩니다. 다만 HDD는 레이턴시(응답 지연)가 높아서 VM 성능에 영향을 줍니다. 가능하면 SSD를 권장하고, HDD를 써야 한다면 BlueStore의 WAL(Write-Ahead Log)과 DB를 별도 SSD에 올리는 구성을 고려해보세요.

    Q. 클러스터에 노드를 나중에 추가할 수 있나요?

    네, Ceph의 가장 큰 장점 중 하나가 바로 수평 확장(Horizontal Scaling)입니다. 노드를 추가하면 Ceph가 자동으로 데이터를 재분배(Rebalancing)합니다. 다만 리밸런싱 중에는 I/O가 좀 느려질 수 있어요.


    마무리 — Proxmox Ceph의 진짜 가치

    처음 Ceph를 공부할 때 “이게 홈랩에서 쓸 수 있는 건가?” 싶었는데, 이제는 제 인프라에서 없어서는 안 될 핵심이 됐습니다. Proxmox VE + Ceph 클러스터 조합이 주는 진짜 가치는 이거예요.

    • 🎉 진짜 고가용성: 노드 하나가 죽어도 VM이 살아있는 인프라
    • 🎉 스토리지 통합 관리: 웹 UI 하나로 모든 걸 관리
    • 🎉 무중단 확장: 서비스 중단 없이 디스크/노드 추가 가능
    • 🎉 오픈소스 무료: 엔터프라이즈급 기능을 라이선스 비용 없이

    물론 단점도 있어요. 초기 구성이 복잡하고, 리소스(특히 RAM)를 꽤 먹습니다. 그리고 문제가 생겼을 때 디버깅이 쉽지 않을 수 있고요. 하지만 한 번 제대로 구성해두면 그 안정성은 정말 믿음직스럽습니다.

    다음 글에서는 Ceph 클러스터 위에 Kubernetes를 올리고 CSI(Container Storage Interface) 드라이버로 연동하는 방법을 다룰 예정이에요. 이전에 Proxmox 기본 클러스터 구성 글도 참고하시면 이번 내용이 더 잘 이해되실 겁니다.

    궁금한 점이나 삽질 경험이 있으시면 댓글로 남겨주세요. 저도 아직 배우는 중이니까요 😄

  • [Game] 스팀덱 도킹 스테이션 선택 가이드: 공식 독 vs 서드파티 비교 및 실전 설정

    스팀덱, 이렇게 쓰면 아깝지 않나요?

    솔직히 처음에 스팀덱 샀을 때, 그냥 침대에서 누워서 게임하는 용도로만 썼거든요. 그러다 어느 날 문득 ‘이거 TV에 연결하면 어떻게 되지?’ 싶어서 USB-C 케이블 하나 꽂아봤는데… 그게 시작이었습니다. 지금은 홈랩 한켠에 스팀덱 도킹 스테이션을 떡하니 놓고, 거실 TV 게임, 모니터 연결 작업, 심지어 리눅스 환경 테스트용으로도 쓰고 있어요. 13년 동안 인프라 엔지니어로 일하면서 온갖 장비를 다뤄봤는데, 이 작은 기기가 도킹 스테이션 하나로 이렇게 확장될 줄은 몰랐습니다.

    이번 글에서는 스팀덱 도킹 스테이션을 어떻게 골라야 하는지, 실제로 써보면서 겪은 삽질은 뭐가 있는지, 그리고 스팀덱 악세사리로 활용도를 극대화하는 방법까지 전부 풀어드릴게요. 휴대용 게임기를 거실 콘솔처럼 쓰고 싶은 분들, 이 글 끝까지 읽어보시면 분명 도움 되실 거예요.

    ▲ 스팀덱 도킹 스테이션을 중심으로 TV, 모니터, 키보드, 마우스, 이더넷 등 다양한 기기가 연결된 전체 구성 개요

    도킹 스테이션(Docking Station)이 뭔지, 일단 짚고 넘어갑시다

    혹시 노트북 도킹 스테이션은 들어보셨죠? 원리는 똑같아요. 도킹 스테이션(Docking Station)이란, USB-C 포트 하나로 여러 주변기기를 한 번에 연결해주는 허브 역할을 하는 장치입니다. 쉽게 말해서, 스팀덱 하나를 꽂으면 TV 출력, USB 기기 연결, 유선 인터넷, 충전까지 한 방에 해결해주는 거예요.

    스팀덱은 기본적으로 USB-C 포트가 하나뿐이에요. 이게 충전도 하고 영상 출력도 하고 데이터 전송도 다 담당하는데, 여기에 USB 3.2 Gen 2 규격의 도킹 스테이션을 연결하면 완전히 다른 기기처럼 변합니다. 저도 처음엔 그냥 HDMI 어댑터 하나면 되겠지 했는데, 막상 써보니 포트 하나 차이가 얼마나 큰지 뼈저리게 느꼈거든요.

    스팀덱 독(Steam Deck Dock)의 핵심 기능

    • 디스플레이 출력: HDMI 또는 DisplayPort를 통해 TV/모니터에 연결
    • USB-A 포트: 키보드, 마우스, 컨트롤러 등 USB 기기 연결
    • 유선 LAN(이더넷): 와이파이보다 안정적인 인터넷 환경 구성
    • PD 충전(Power Delivery): 도킹 중에도 배터리 충전 유지
    • microSD 슬롯: 일부 제품에서 추가 저장공간 확장 지원

    공식 독 vs 서드파티 독: 뭘 골라야 할까?

    여기서 제일 많이 받는 질문이 바로 이거예요. “밸브(Valve) 공식 독이랑 그냥 시중에 파는 독이랑 뭐가 달라요?” 제가 둘 다 써본 입장에서 정리해드릴게요.

    구분 밸브(Valve) 공식 스팀덱 독 서드파티 USB-C 독
    호환성 스팀덱 전용 설계, 최적화 제품마다 호환성 차이 있음
    포트 구성 HDMI, USB-A ×3, 이더넷, USB-C 충전 제품마다 다름 (HDMI, DP, USB-A, 이더넷 등)
    디자인 스팀덱 거치 전용 크래들 형태 일반 허브 형태가 많음
    펌웨어 업데이트 SteamOS 업데이트와 함께 지원 별도 업데이트 없는 경우 많음
    가격대 상대적으로 높음 저가~고가 폭넓은 선택지
    휴대성 크래들 형태라 이동 불편 소형 허브는 휴대 가능

    제 경험상, 거실 TV 고정 세팅이라면 공식 독이 편하고, 여행이나 출장 때도 들고 다닐 생각이라면 소형 서드파티 허브가 훨씬 실용적이에요. 저는 홈랩에 공식 독 하나, 여행용 소형 허브 하나 이렇게 두 개 운용하고 있습니다 ㅎㅎ

    ▲ 밸브 공식 스팀덱 독(왼쪽)과 소형 서드파티 USB-C 허브(오른쪽) 비교 — 용도에 따라 선택이 달라집니다

    스팀덱 도킹 스테이션 설정: 단계별 가이드

    처음 연결해보는 분들을 위해 단계별로 정리해봤어요. 생각보다 복잡하지 않으니까 겁먹지 마세요.

    1단계: 도킹 스테이션 연결 준비

    1. 스팀덱을 완전히 종료하거나 절전 모드로 전환합니다.
    2. 도킹 스테이션의 전원 어댑터를 콘센트에 연결합니다. (PD 충전 지원 제품의 경우)
    3. HDMI 또는 DisplayPort 케이블을 독과 TV/모니터에 연결합니다.
    4. 필요하다면 USB-A 포트에 키보드, 마우스, 컨트롤러를 미리 연결해두세요.
    5. 마지막으로 스팀덱의 USB-C 포트에 독을 연결합니다.

    2단계: SteamOS에서 디스플레이 설정

    1. 스팀덱 전원을 켭니다. TV/모니터에 화면이 자동으로 출력되는지 확인하세요.
    2. Steam 버튼 → 설정(Settings) → 디스플레이(Display) 메뉴로 진입합니다.
    3. 외부 디스플레이 해상도와 주사율(Refresh Rate)을 TV/모니터 스펙에 맞게 조정합니다.
    4. “화면 확장” 또는 “미러링” 옵션을 상황에 맞게 선택합니다. (TV 전용 게임이라면 “외부 디스플레이만” 선택 추천)

    3단계: 유선 이더넷(Ethernet) 설정

    이게 생각보다 게임 체인저예요. 와이파이로 스팀 다운로드 받다가 유선으로 바꾸는 순간 속도 차이를 체감하실 거예요. SteamOS는 유선 LAN 어댑터를 자동으로 인식하는 경우가 많은데, 혹시 안 잡히면 아래를 확인해보세요.

    # 스팀덱 데스크탑 모드(Desktop Mode)에서 터미널 열기
    # 네트워크 인터페이스 확인
    ip link show
    
    # 이더넷 어댑터가 잡혔는지 확인 (eth0 또는 enp 계열로 표시됨)
    # 만약 인식됐다면 아래로 IP 할당 여부 확인
    ip addr show

    대부분의 경우 자동으로 DHCP(동적 호스트 구성 프로토콜, 자동 IP 할당)가 잡히는데, 안 잡히면 네트워크 매니저(NetworkManager)로 수동 설정도 가능합니다.

    4단계: 컨트롤러 및 주변기기 확인

    1. USB-A 포트에 연결한 키보드/마우스는 별도 드라이버 없이 대부분 바로 사용 가능합니다.
    2. Xbox 컨트롤러, PS5 DualSense 등도 SteamOS에서 자동 인식됩니다.
    3. 블루투스 컨트롤러는 설정 → 블루투스 메뉴에서 페어링하면 됩니다.

    ⚠️ 실제로 겪은 삽질과 트러블슈팅

    이 부분이 진짜 중요한데요. 저도 처음에 연결하고 나서 “왜 이게 안 되지?” 하면서 꽤 시간을 날렸거든요. 비슷한 상황 겪으시는 분들 있을까봐 정리해봤습니다.

    문제 1: 4K 출력이 안 되거나 화면이 깜빡인다

    이건 케이블 문제인 경우가 80%예요. HDMI 케이블이 HDMI 2.0 이상을 지원해야 4K/60Hz가 제대로 나옵니다. 오래된 HDMI 1.4 케이블 쓰면 4K는 30Hz 제한이 걸리거나 아예 신호가 불안정해요. 저도 이거 때문에 독 불량인 줄 알고 반품 신청까지 했다가… 케이블 바꾸니까 바로 해결됐습니다. 진짜 허탈하더라고요 ㅎㅎ

    문제 2: 충전이 안 되거나 배터리가 오히려 줄어든다

    도킹 스테이션이 스팀덱에 전력을 공급하려면 PD(Power Delivery) 45W 이상을 지원해야 해요. 저가형 독 중에 PD 출력이 낮은 제품들이 있는데, 이런 경우 고사양 게임 구동 중에는 소비 전력이 공급 전력을 초과해서 배터리가 줄어드는 현상이 생깁니다. 독 구매 전에 반드시 PD 출력 스펙 확인하세요.

    문제 3: USB-C 독인데 스팀덱이 인식을 못 한다

    스팀덱은 USB-C 포트가 USB 3.2 Gen 2 규격인데, 일부 저가 독은 USB 2.0 수준의 USB-C 커넥터만 달린 경우가 있어요. 이럴 때는 영상 출력이 아예 안 되거나 인식 자체가 불안정합니다. 구매 전에 DisplayPort Alt Mode(DP 얼터네이트 모드) 지원 여부를 꼭 체크하세요. 이게 있어야 USB-C 단자로 영상 출력이 가능합니다.

    문제 4: 데스크탑 모드에서 마우스 커서가 이상하게 움직인다

    이건 SteamOS 특성상 게임패드 입력과 마우스 입력이 동시에 들어올 때 생기는 충돌이에요. 설정 → 컨트롤러 → 게임패드 입력 비활성화를 해두면 데스크탑 모드에서 훨씬 쾌적해집니다.

    ▲ 스팀덱 도킹 스테이션을 TV에 연결한 후 SteamOS 디스플레이 설정 화면 — 해상도와 주사율을 TV 스펙에 맞게 조정하는 것이 핵심입니다

    스팀덱 악세사리 조합으로 활용도 극대화하기

    도킹 스테이션 하나만 있어도 충분하지만, 여기에 몇 가지 스팀덱 악세사리를 더하면 진짜 미니 콘솔 수준이 됩니다. 제가 실제로 쓰고 있는 조합을 공유해드릴게요.

    💡 추천 악세사리 조합

    • 무선 컨트롤러: Xbox 무선 컨트롤러나 PS5 DualSense — SteamOS와 호환성 좋고 거실에서 쓰기 편합니다
    • 외장 SSD: USB-A 포트에 연결해서 게임 라이브러리 확장 가능. SteamOS에서 외장 드라이브도 게임 설치 경로로 지정 가능해요
    • 미니 키보드: 데스크탑 모드나 채팅할 때 유용. 터치패드 달린 미니 블루투스 키보드면 더 좋습니다
    • 보호 케이스: 독에 거치할 때 스팀덱 본체 보호를 위해 얇은 케이스 추천
    • 이더넷 케이블 Cat6: 유선 LAN 연결용. 짧고 슬림한 케이블이 책상 정리에 좋아요

    홈랩에서 스팀덱 + 독 활용하는 방법

    이건 좀 특수한 케이스인데, 저처럼 홈랩 운영하시는 분들한테 꽤 유용한 팁이에요. 스팀덱은 SteamOS 기반이고 Arch Linux 베이스라서, 데스크탑 모드에서 일반 리눅스처럼 쓸 수 있거든요. 도킹 스테이션에 모니터, 키보드, 마우스 연결하면 미니 리눅스 워크스테이션이 됩니다.

    # 스팀덱 데스크탑 모드에서 패키지 설치 (pacman 사용)
    # 먼저 읽기 전용 파일시스템 해제
    sudo steamos-readonly disable
    
    # pacman 키링 초기화
    sudo pacman-key --init
    sudo pacman-key --populate archlinux
    
    # 예: SSH 클라이언트 설치
    sudo pacman -S openssh
    
    # 홈랩 서버에 SSH 접속
    ssh [email protected]

    ⚠️ 주의: SteamOS 업데이트 후에는 읽기 전용이 다시 활성화되고, pacman으로 설치한 패키지가 초기화될 수 있어요. 지속적인 패키지 관리는 Flatpak이나 Distrobox를 활용하는 게 더 안전합니다.

    ✅ 실제 사용 결과: 달라진 점들

    스팀덱 도킹 스테이션을 제대로 세팅하고 나서 실제로 어떻게 달라졌는지 정리해볼게요.

    • 🎉 거실 TV 게임: 65인치 TV에 연결해서 가족들이랑 같이 게임하는 시간이 생겼어요. 침대에서만 혼자 하던 게임이 거실 이벤트가 됐습니다
    • 🎉 게임 다운로드 속도 향상: 유선 이더넷 연결 후 스팀 라이브러리 동기화 속도가 체감상 눈에 띄게 빨라졌습니다
    • 🎉 충전 걱정 없음: 도킹 중 PD 충전이 되니까 배터리 신경 안 쓰고 장시간 플레이 가능
    • 🎉 리눅스 실험 환경: 홈랩에서 간단한 스크립트 테스트나 SSH 접속 용도로도 활용 중
    • 💡 휴대성 유지: 외출할 때는 독에서 뽑아서 그냥 들고 나가면 되니까 휴대용 게임기의 장점은 그대로

    ▲ 스팀덱 도킹 스테이션 선택 기준과 활용 시나리오 요약 — 거실 TV 게임부터 홈랩 활용까지 다양한 사용 방법을 한눈에 정리

    도킹 스테이션 구매 전 체크리스트

    마지막으로 구매 전에 반드시 확인해야 할 스팀덱 도킹 스테이션 스펙들을 정리해드릴게요. 이거 모르고 샀다가 낭패 보는 분들이 꽤 많더라고요.

    1. DisplayPort Alt Mode 지원 여부: USB-C로 영상 출력하려면 필수
    2. PD 충전 출력 45W 이상: 게임 중 배터리 유지를 위해 필요
    3. HDMI 버전 확인: 4K/60Hz를 원한다면 HDMI 2.0 이상
    4. 이더넷 포트 유무: 유선 인터넷 사용 계획이 있다면 필수
    5. USB-A 포트 수: 키보드, 마우스, 컨트롤러 수신기 등 연결 기기 수 고려
    6. 발열 관리: 저가형 독 중에 발열이 심한 제품이 있으니 리뷰 확인 필수
    7. 크기와 휴대성: 거치형인지 휴대형인지 용도에 맞게 선택

    자주 묻는 질문 (FAQ)

    Q. 스팀덱에 아무 USB-C 허브나 연결해도 되나요?

    A. 단순 USB 허브는 연결되지만, 영상 출력이 안 될 수 있어요. DisplayPort Alt Mode를 지원하는 제품이어야 HDMI/DP 출력이 가능합니다. 구매 전 스펙 확인 필수예요.

    Q. 공식 독이 아니면 SteamOS 업데이트에 문제가 생기나요?

    A. SteamOS 업데이트는 독과 관계없이 진행됩니다. 다만 공식 독은 펌웨어 업데이트를 SteamOS와 함께 받을 수 있다는 장점이 있어요.

    Q. 도킹 중에도 스팀덱 화면이 켜져 있나요?

    A. 설정에서 선택 가능합니다. 외부 디스플레이만 사용하도록 설정하면 스팀덱 자체 화면은 꺼집니다. 배터리 절약에도 도움이 돼요.

    Q. 스팀덱 도킹 스테이션에 외장 HDD 연결하면 게임 설치 가능한가요?

    A. 네, 가능합니다. SteamOS에서 외장 드라이브를 게임 라이브러리 경로로 추가할 수 있어요. 다만 외장 HDD보다는 외장 SSD를 추천합니다. 로딩 속도 차이가 꽤 납니다.

    마무리: 스팀덱의 진짜 가능성은 도킹 스테이션에서 시작된다

    처음에 스팀덱 도킹 스테이션 없이 그냥 쓰는 것과, 제대로 된 독 하나 들여놓고 쓰는 건 정말 하늘과 땅 차이더라고요. 단순히 화면이 커지는 것만의 문제가 아니라, 이 작은 기기가 가진 가능성이 완전히 달라지는 느낌이었습니다.

    인프라 엔지니어 입장에서 보면, 스팀덱은 정말 잘 만든 리눅스 기기예요. 게임 콘솔이기도 하고, 리눅스 워크스테이션이기도 하고, 홈랩 클라이언트로도 쓸 수 있고. 여기에 도킹 스테이션 하나가 더해지면 활용 시나리오가 기하급수적으로 늘어납니다.

    다음 글에서는 스팀덱 데스크탑 모드를 제대로 활용하는 방법, 특히 Distrobox를 이용해서 일반 리눅스 앱을 스팀덱에서 안정적으로 쓰는 방법을 다뤄볼 예정이에요. 홈랩 연동 관점에서도 꽤 흥미로운 내용이 될 것 같으니 기대해주세요.

    궁금한 점이나 본인만의 스팀덱 도킹 스테이션 활용법이 있으시다면 댓글로 공유해주세요. 저도 새로운 삽질 경험 언제나 환영합니다 😄

  • [Game] 스팀덱 SSD 업그레이드 가이드: 성능 향상 및 저장 공간 확장

    스팀덱 SSD 업그레이드, 왜 고민하게 됐냐면요

    스팀덱(Steam Deck)을 처음 받았을 때 64GB 모델이었거든요. 처음엔 ‘뭐, 게임 몇 개만 넣으면 되지’라고 생각했는데… 현실은 달랐습니다. 엘든 링 하나만 깔아도 60GB 가까이 먹더라고요. 결국 저도 스팀덱 SSD 업그레이드를 결심하게 됐습니다.

    사실 인프라 엔지니어로 13년을 일하면서 서버 스토리지 교체는 수도 없이 해봤지만, 이렇게 작은 폼팩터의 기기를 분해하는 건 또 다른 긴장감이 있더라고요. 근데 막상 해보니까 생각보다 훨씬 할 만했습니다. 이 글에서는 제가 직접 해본 경험을 바탕으로 스팀덱 저장 공간 확장 방법과 주의사항을 솔직하게 공유해 드릴게요.

    스팀덱 내부 구조 개요 — M.2 2230 SSD 슬롯 위치와 주요 부품 배치를 한눈에 확인할 수 있습니다.

    스팀덱 SSD 업그레이드 전에 알아야 할 기본 개념

    스팀덱에 들어가는 SSD 규격

    스팀덱은 M.2 2230 규격의 NVMe SSD를 사용합니다. 여기서 ‘2230’은 폭 22mm, 길이 30mm를 의미해요. 일반 PC에서 많이 쓰는 2280(길이 80mm)보다 훨씬 짧은 사이즈거든요. 이게 중요한 이유는, 아무 NVMe SSD나 사다 꽂으면 안 된다는 뜻이라서요.

    쉽게 말해서, 스팀덱 SSD 교체를 위해 구매할 때는 반드시 M.2 2230 NVMe 제품인지 확인해야 합니다. 2280짜리를 사면 물리적으로 안 들어가요. 저도 처음에 이걸 몰라서 한 번 잘못 주문할 뻔했습니다 ㅎㅎ.

    스팀덱 모델별 기본 저장 용량

    모델 기본 저장 용량 SSD 타입 비고
    Steam Deck 64GB 64GB eMMC NVMe가 아님, 교체 가능하나 성능 차이 큼
    Steam Deck 256GB 256GB NVMe SSD M.2 2230 NVMe
    Steam Deck 512GB 512GB NVMe SSD M.2 2230 NVMe, 강화 유리

    ⚠️ 중요 포인트: 64GB 모델은 eMMC 방식으로 NVMe와 인터페이스 자체가 다릅니다. 물리적으로 M.2 슬롯에 NVMe SSD를 꽂는 건 가능하지만, 기술적으로 다소 복잡한 부분이 있으니 이 글에서는 256GB/512GB 모델 기준으로 설명드릴게요.

    스팀덱 SSD 업그레이드 준비물 체크리스트

    업그레이드 전에 미리 준비해두면 작업이 훨씬 수월합니다. 제가 처음 할 때 드라이버 하나 없어서 작업 중간에 멈춘 적 있거든요. 미리 다 챙겨두세요.

    • ✅ M.2 2230 NVMe SSD (교체할 새 SSD)
    • ✅ Phillips #0 드라이버 (십자 드라이버, 작은 사이즈)
    • ✅ 플라스틱 픽(Pick) 또는 스패저(Spudger) (기기 열 때 사용, 금속 도구는 기판 손상 위험)
    • ✅ USB 드라이브 (8GB 이상, 복구 이미지 담을 용도)
    • ✅ MicroSD 카드 또는 외장 스토리지 (데이터 백업용)
    • ✅ 정전기 방지 손목 밴드 (선택 사항이지만 강력 권장)
    • ✅ 밝은 조명과 넓은 작업 공간

    💡 팁: iFixit 같은 수리 도구 키트를 하나 사두면 두고두고 씁니다. 스팀덱뿐 아니라 다른 기기 수리할 때도 유용하거든요.

    스팀덱 SSD 업그레이드 단계별 가이드

    1단계: 데이터 백업

    이거 절대 건너뛰면 안 됩니다. 저도 인프라 엔지니어지만 백업 없이 작업하다가 한 번 날린 적 있어요. 그때의 허무함이란… 스팀덱은 게임 저장 데이터를 Steam Cloud에 자동 동기화해주는 경우가 많지만, 모든 게임이 그런 건 아니거든요.

    1. 스팀 설정 → 클라우드 → Steam Cloud 동기화 확인
    2. 클라우드 미지원 게임은 저장 파일을 MicroSD나 외부 저장소로 수동 복사
    3. 저장 파일 위치: /home/deck/.local/share/Steam/userdata/
    # 스팀덱 데스크탑 모드에서 터미널 열고 저장 파일 백업
    cp -r /home/deck/.local/share/Steam/userdata/ /run/media/mmcblk0p1/backup_userdata/
    
    # 백업 완료 확인
    ls /run/media/mmcblk0p1/backup_userdata/

    2단계: SteamOS 복구 이미지 준비

    SSD를 교체하면 운영체제(SteamOS)도 새로 설치해야 합니다. Valve에서 공식 복구 이미지를 제공하고 있으니까 미리 USB에 담아두세요.

    1. Valve 공식 웹사이트에서 Steam Deck Recovery Image 다운로드
    2. Rufus(Windows) 또는 balenaEtcher를 사용해 USB에 이미지 굽기
    3. USB는 스팀덱에 연결할 수 있도록 USB-C 허브 또는 USB-C 변환 어댑터 준비

    3단계: 스팀덱 분해

    드디어 본격적인 분해입니다. 여기서 침착하게 하는 게 중요해요. 서두르다가 나사 망가뜨리면 그날 작업은 그냥 끝이거든요.

    1. 배터리 완전 방전 또는 전원 완전 차단 — 작업 전 전원을 끄고 잠시 기다립니다
    2. 뒷면 나사 8개 제거 — Phillips #0 드라이버 사용. 모서리 4개와 중앙부 4개
    3. 플라스틱 픽으로 뒷면 커버 분리 — 아랫부분부터 천천히 틈을 벌리며 진행. 금속 도구 절대 사용 금지
    4. 배터리 커넥터 분리 — 안전을 위해 메인보드의 배터리 커넥터를 먼저 뽑습니다
    5. SSD 실드 나사 제거 — SSD를 덮고 있는 금속 실드의 나사를 제거
    6. 기존 SSD 제거 — SSD 고정 나사 1개를 풀고 비스듬히 들어올려 제거
    7. 새 SSD 장착 — 새 M.2 2230 SSD를 슬롯에 비스듬히 삽입 후 눌러서 고정 나사 조임
    8. 역순으로 조립

    ⚠️ 주의: 나사를 너무 세게 조이면 나사산이 망가집니다. 손으로 돌리다가 저항감이 느껴지면 그 정도면 충분해요.

    스팀덱 분해 과정 — 뒷면 커버 제거부터 M.2 2230 SSD 슬롯 접근까지의 단계별 모습입니다.

    4단계: SteamOS 재설치

    조립이 끝났으면 이제 OS를 설치할 차례입니다. 새 SSD는 당연히 비어있으니까요.

    1. 스팀덱에 복구 USB를 USB-C 허브로 연결
    2. 볼륨 다운(-) 버튼을 누른 채로 전원 버튼 누르기 → 부트 메뉴 진입
    3. USB 드라이브 선택해서 부팅
    4. 복구 화면에서 “Reimage Steam Deck” 선택
    5. 설치 완료까지 기다리기 (약 10~20분 소요)
    6. 재부팅 후 초기 설정 진행

    드디어 됐다! 싶은 순간이 여기서 오더라고요. 새 SSD에 깔끔하게 SteamOS가 올라오는 거 보면 진짜 뿌듯합니다 🎉

    5단계: 백업 데이터 복원

    OS 설치 후 Steam에 로그인하면 클라우드 저장 게임들은 자동으로 복원됩니다. 수동으로 백업해둔 저장 파일은 아래처럼 복원하면 돼요.

    # 데스크탑 모드 터미널에서 백업 파일 복원
    cp -r /run/media/mmcblk0p1/backup_userdata/ /home/deck/.local/share/Steam/userdata/
    
    # 권한 설정
    chown -R deck:deck /home/deck/.local/share/Steam/userdata/

    ⚠️ 실제로 겪은 트러블슈팅

    제가 처음 스팀덱 SSD 업그레이드할 때 몇 가지 삽질을 했습니다. 여러분은 같은 실수 반복하지 마시라고 공유드려요.

    문제 1: 뒷면 커버가 안 열려요

    처음에 픽을 너무 세게 밀어서 커버 클립 하나를 부러뜨렸습니다. 스팀덱 뒷면 커버는 클립으로 고정되어 있는데, 나사를 다 풀었다고 바로 확 열면 안 됩니다. 아랫부분(충전 포트 쪽)부터 천천히, 조금씩 틈을 벌려가며 진행해야 해요. 픽을 밀기보다 비틀어주는 느낌으로요.

    문제 2: 부팅이 안 돼요

    SSD 장착 후 전원을 켰는데 아무것도 안 뜨는 경우가 있습니다. 대부분 SSD가 완전히 슬롯에 안 꽂힌 경우예요. 다시 분해해서 SSD를 한 번 뺐다가 확실히 눌러서 다시 꽂아보세요. 저도 이 증상으로 한 번 더 분해했습니다 ㅎㅎ.

    문제 3: 복구 USB가 인식이 안 돼요

    USB 드라이브 포맷 문제일 수 있습니다. Rufus나 balenaEtcher로 다시 구워보세요. 또한 USB-C 허브의 호환성 문제도 있을 수 있으니 다른 허브나 어댑터를 시도해보는 것도 방법입니다.

    스팀덱 SSD 업그레이드 후 성능 향상 체감

    스팀덱 성능 향상 측면에서 솔직하게 말씀드리면, 게임 플레이 자체의 FPS가 극적으로 올라가지는 않습니다. GPU나 CPU가 바뀐 게 아니니까요. 하지만 체감되는 부분은 분명히 있습니다.

    • ✅ 게임 로딩 시간 단축: 특히 eMMC에서 NVMe로 바꾼 경우 확실히 빠릅니다
    • ✅ 저장 공간 여유: 더 많은 게임을 설치할 수 있는 건 당연하고, 삭제/재설치 반복 스트레스에서 해방
    • ✅ 셰이더 컴파일 시간 감소: 일부 게임에서 체감 가능
    • ✅ OS 반응성 향상: 데스크탑 모드에서 전반적으로 더 쾌적

    스팀덱 SSD 업그레이드 전후 로딩 시간 비교 — NVMe SSD로 교체 후 게임 로딩 속도가 개선되는 것을 확인할 수 있습니다.

    MicroSD 카드 vs SSD 업그레이드, 뭐가 나을까?

    사실 저장 공간만 늘리고 싶다면 MicroSD 카드로도 해결이 됩니다. 비용도 훨씬 저렴하고요. 그럼 굳이 스팀덱 SSD 업그레이드를 해야 할까요?

    구분 MicroSD 확장 SSD 업그레이드
    비용 상대적으로 저렴 상대적으로 고가
    난이도 매우 쉬움 (그냥 꽂으면 됨) 분해 필요, 중간 난이도
    속도 NVMe 대비 느림 빠름
    안정성 카드 분실/손상 위험 내장이라 안정적
    OS 설치 가능 불가 (게임 저장만) 가능
    보증 영향 없음 보증 영향 가능성 있음

    💡 제 추천은 이렇습니다: 저장 공간만 필요하면 MicroSD, 성능과 안정성까지 원하면 SSD 업그레이드. 저는 두 가지를 병행해서 SSD에는 자주 하는 게임, MicroSD에는 가끔 하는 게임을 넣어두는 방식으로 쓰고 있습니다.

    자주 묻는 질문 (FAQ)

    Q. 스팀덱 SSD 업그레이드하면 보증이 사라지나요?

    Valve는 공식적으로 사용자의 수리 및 업그레이드를 지지하는 입장이고, iFixit과 파트너십도 맺고 있습니다. 다만 업그레이드 과정에서 다른 부품이 손상되면 그 부분은 보증 처리가 어려울 수 있으니 신중하게 진행하세요.

    Q. 어떤 M.2 2230 SSD를 사야 하나요?

    시중에서 판매되는 M.2 2230 NVMe SSD 중 검증된 제품들을 선택하시면 됩니다. 구매 전 스팀덱 커뮤니티(Reddit r/SteamDeck 등)에서 호환성 확인 후 구매하시는 걸 추천합니다. 용량은 512GB 이상을 권장합니다.

    Q. 기존 SSD 데이터를 새 SSD로 그대로 복사할 수 있나요?

    가능은 합니다. USB-C 허브와 M.2 외장 케이스를 이용해 클론(Clone) 작업을 할 수 있어요. 다만 SteamOS를 새로 설치하는 게 더 깔끔하고 문제도 적더라고요. 저는 그냥 새로 설치하는 걸 선호합니다.

    Q. 분해 중 배터리 커넥터를 꼭 뽑아야 하나요?

    네, 꼭 뽑아야 합니다. 배터리가 연결된 상태에서 작업하면 쇼트 위험이 있습니다. 안전 제일이에요.

    스팀덱 SSD 업그레이드 가이드 요약 인포그래픽 — 준비물, 작업 단계, 주의사항을 한눈에 정리했습니다.

    마무리하며

    스팀덱 SSD 업그레이드, 처음엔 겁이 나는 게 사실입니다. 저도 그랬거든요. 근데 막상 해보면 생각보다 어렵지 않아요. 침착하게 단계별로 따라가면 충분히 할 수 있습니다.

    핵심만 다시 정리하면:

    1. 반드시 M.2 2230 NVMe 규격 확인
    2. 작업 전 데이터 백업과 복구 USB 준비는 필수
    3. 분해는 천천히, 플라스틱 도구로
    4. SSD 교체 후 SteamOS 복구 이미지로 재설치
    5. 저장 공간만 필요하면 MicroSD 병행도 좋은 선택

    다음 글에서는 스팀덱 데스크탑 모드 활용법과 외부 디스플레이 연결로 PC처럼 쓰는 방법을 다룰 예정이에요. 스팀덱을 더 잘 활용하고 싶으신 분들께 도움이 될 것 같습니다.

    궁금한 점 있으시면 댓글로 남겨주세요. 제가 경험한 범위 내에서 최대한 답변드릴게요 😊