13년차의 서버실

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

[작성자:] admin

  • [Proxmox] Proxmox LXC 컨테이너 vs VM: 홈랩 환경 최적화 비교 분석

    [Proxmox] Proxmox LXC 컨테이너 vs VM: 홈랩 환경 최적화 비교 분석

    [Proxmox] Proxmox LXC 컨테이너 vs VM: 홈랩 환경 최적화 비교 분석

    안녕하세요, 13년차의 서버실 주인장입니다. 홈랩을 운영하면서 가장 많이 고민하는 부분 중 하나가 바로 가상화 환경 최적화일 겁니다. 특히 Proxmox VE를 사용하시는 분들이라면, LXC 컨테이너 (Linux Container)를 써야 할지, 아니면 전통적인 가상머신 (VM, Virtual Machine)을 써야 할지 많이들 헷갈리실 텐데요. 저도 처음엔 Proxmox LXC 컨테이너가 뭔지 제대로 몰라서 이것저것 다 깔아보고 삽질 좀 했습니다. 😅

    이번 글에서는 제가 직접 써보고 경험했던 Proxmox LXC 컨테이너와 VM의 차이점, 장단점, 그리고 어떤 상황에서 무엇을 선택해야 할지 자세히 비교 분석해 드릴게요. 홈랩 자원을 효율적으로 사용하고 싶은 분들에게 멘토처럼 길잡이가 되어드리겠습니다!

    Proxmox VE 환경에서 LXC 컨테이너와 VM이 동작하는 방식을 시각적으로 나타낸 다이어그램입니다.

    Proxmox VE, VM, LXC 컨테이너: 기본 개념 잡기

    본격적인 비교에 앞서, 핵심 개념들을 간단하게 짚고 넘어갈게요. 이미 잘 아시는 분들도 있겠지만, 혹시나 헷갈리실 분들을 위해 쉽게 설명해 드리겠습니다.

    • Proxmox VE (Virtual Environment): 쉽게 말해 서버 한 대를 마치 여러 대의 컴퓨터처럼 쪼개서 쓸 수 있게 해주는 운영체제입니다. KVM(Kernel-based Virtual Machine)과 LXC(Linux Containers) 기술을 기반으로 Proxmox LXC 컨테이너와 가상화 환경을 통합 관리할 수 있게 도와주죠. 웹 인터페이스가 정말 편하더라고요!

    • 가상머신 (VM, Virtual Machine): 물리적인 컴퓨터 위에 완전히 독립적인 또 다른 가상 컴퓨터를 만드는 방식입니다. 운영체제(OS)부터 커널(Kernel)까지 모두 독립적으로 가집니다. 마치 서버 안에 또 다른 서버를 통째로 심는다고 생각하시면 됩니다. 오버헤드 (Overhead)가 좀 있지만, 완벽한 격리(Isolation)와 유연성을 제공합니다.

    • LXC 컨테이너 (Linux Container): VM과 달리 호스트 운영체제의 커널을 공유합니다. 운영체제를 통째로 가상화하는 것이 아니라, 애플리케이션 실행에 필요한 환경만 격리하여 제공하는 방식이죠. Proxmox LXC 컨테이너는 VM보다 훨씬 가볍고 빠르게 시작하며, 리소스 사용 효율이 뛰어나다는 장점이 있습니다. Docker 컨테이너와 비슷하지만, LXC는 좀 더 시스템 레벨의 가상화에 가깝습니다.

    LXC 컨테이너 vs VM: 핵심 차이점 비교

    이제 두 가상화 기술의 핵심 차이점을 표로 정리해서 한눈에 비교해볼까요? 제가 홈랩에서 Proxmox LXC 컨테이너와 VM을 직접 써보면서 느꼈던 점들을 바탕으로 정리해봤습니다.

    특징 LXC 컨테이너 (Linux Container) 가상머신 (VM, Virtual Machine)
    커널 공유 여부 호스트 OS 커널 공유 독립적인 커널 사용
    자원 오버헤드 매우 낮음 (경량) 상대적으로 높음 (무겁고 완전한 가상화)
    부팅 속도 매우 빠름 (초 단위) 느림 (OS 부팅 시간 필요)
    격리 수준 낮음 (호스트 커널 공유로 인한 잠재적 보안 이슈) 높음 (완전한 격리, 보안성 우수)
    운영체제 유연성 Linux 기반 OS만 가능 (호스트와 동일한 커널) Windows, macOS, Linux 등 모든 OS 가능
    스냅샷/백업 빠르고 가벼움 상대적으로 느리고 무거움
    하드웨어 패스스루 제한적 (GPU 등) 우수 (GPU, USB 등 다양한 장치)
    사용 사례 Docker 호스팅, 웹 서버, DB, 특정 서비스 (자원 효율 중시) Windows 게스트, 복잡한 네트워크, 보안 중요 서비스, GPU 활용

    실전 구현: Proxmox에서 LXC 컨테이너 만들기

    이제 실제로 Proxmox에서 LXC 컨테이너를 한번 만들어볼까요? 웹 UI에서도 쉽게 할 수 있지만, CLI (Command Line Interface)로 하는 것도 알아두면 좋습니다. 저는 개인적으로 CLI로 Proxmox LXC 컨테이너를 익숙해지는 걸 추천합니다. 자동화할 때 훨씬 편하거든요. 💡

    1. 템플릿 다운로드: LXC는 미리 만들어진 템플릿(Template)을 사용합니다. Ubuntu 22.04 LTS 템플릿을 받아볼게요.

      pveam update
      pveam available --section system
      pveam download local ubuntu-22.04-standard_22.04-1_amd64.tar.zst

      local은 저장소 이름입니다. 여러분의 Proxmox 저장소 이름에 맞게 변경해주세요.

    2. 컨테이너 생성: 이제 다운로드한 템플릿으로 Proxmox LXC 컨테이너를 생성합니다. CT ID는 고유한 번호입니다. 저는 101번으로 지정했어요.

      pct create 101 local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
        --hostname my-lxc-server \
        --rootfs local-lvm:8 \
        --memory 1024 --swap 512 \
        --cores 2 \
        --net0 name=eth0,bridge=vmbr0,ip=192.168.1.101/24,gw=192.168.1.1 \
        --unprivileged 1 --onboot 1 \
        --password your_secure_password
      • local-lvm:8: local-lvm 저장소에 8GB 디스크 할당
      • vmbr0: Proxmox 기본 브릿지 네트워크
      • --unprivileged 1: 비특권 컨테이너로 생성 (보안에 유리, 강력 추천!)
    3. 컨테이너 시작: 생성 후 바로 시작합니다.

      pct start 101
    4. 컨테이너 접속: SSH나 Proxmox 콘솔로 접속해서 설정하면 됩니다.

      ssh [email protected]

    Proxmox 웹 인터페이스에서 LXC 컨테이너가 성공적으로 생성되고 실행 중인 모습을 보여주는 화면입니다.

    실전 구현: Proxmox에서 가상머신 (VM) 만들기

    이번에는 VM을 만들어볼까요? VM은 OS 이미지 (ISO 파일)를 직접 설치해야 해서 LXC 컨테이너보다 손이 좀 더 갑니다. 그래도 그만큼 유연하죠.

    1. ISO 이미지 업로드: Ubuntu Server 22.04 LTS ISO 파일을 Proxmox ISO 저장소에 업로드합니다. 웹 UI의 데이터센터 > 저장소 > local > ISO 이미지에서 할 수 있습니다.

    2. VM 생성: CLI로도 가능하지만, VM은 웹 UI에서 생성하는 게 훨씬 직관적입니다. 생성 (Create VM) 버튼을 클릭해서 아래와 같이 설정해줍니다.

      • 일반 (General): 노드, VM ID (예: 201), 이름 (예: my-vm-server)
      • OS: 아까 업로드한 Ubuntu Server 22.04 LTS ISO 선택
      • 시스템 (System): 그래픽 카드 (기본값), SCSI 컨트롤러 (VirtIO SCSI 추천)
      • 하드 디스크 (Hard Disk): 저장소, 디스크 크기 (예: 32GB), 캐시 (Write-back 추천)
      • CPU: 코어 수 (예: 4), 소켓 수 (예: 1), 타입 (host 추천)
      • 메모리 (Memory): RAM (예: 4096MB)
      • 네트워크 (Network): 브릿지 (vmbr0), 모델 (VirtIO 추천)
    3. OS 설치: 생성된 VM을 시작하고, Proxmox 콘솔에 접속해서 일반적인 OS 설치 과정처럼 Ubuntu Server를 설치합니다. 이 과정은 일반적인 물리 서버에 OS를 설치하는 것과 동일합니다.

    ⚠️ 주의사항/트러블슈팅: 삽질 기록! (네트워크 설정, 자원 관리)

    제가 홈랩에서 가장 많이 겪었던 삽질 중 하나가 바로 네트워크 설정과 자원 관리였습니다. 특히 Proxmox LXC 컨테이너에서요.

    • LXC 컨테이너 내부 Docker 문제: 처음엔 Proxmox LXC 컨테이너 안에 Docker를 설치해서 사용하려고 했어요. 근데 이게 웬걸, systemctl start docker를 하면 자꾸 에러가 나는 겁니다. 찾아보니 비특권 컨테이너 (Unprivileged Container)에서 Docker를 제대로 사용하려면 nesting 옵션을 활성화해야 하더라고요. 아니면 cgroup v2 관련 문제일 수도 있고요. 이 부분에서 꽤 많은 시간을 보냈습니다. 해결책은 컨테이너 설정 파일(/etc/pve/lxc/101.conf)에 lxc.apparmor.profile: unconfined와 lxc.cgroup.devices.allow: a *:* rwm, 그리고 features: nesting=1을 추가하는 방법이 있었습니다. 물론 보안상 권장되는 방법은 아니니 신중하게 접근해야 합니다. ✅

      # /etc/pve/lxc/101.conf 예시
      arch: amd64
      cores: 2
      hostname: my-lxc-server
      memory: 1024
      net0: name=eth0,bridge=vmbr0,ip=192.168.1.101/24,gw=192.168.1.1,type=veth
      rootfs: local-lvm:8
      swap: 512
      mp0: /dev/sdb,mp=/mnt/data,size=10G # 추가적인 마운트 포인트 예시
      # Docker in LXC를 위한 설정 (주의해서 사용)
      features: nesting=1
      # lxc.apparmor.profile: unconfined # 비특권 컨테이너에는 보통 필요 없음. 특권 컨테이너에서 사용
      # lxc.cgroup.devices.allow: a *:* rwm # 특정 시나리오에서 필요
    • 네트워크 브릿지 오설정: Proxmox의 vmbr0 같은 네트워크 브릿지를 잘못 설정하면 외부 통신이 안 되거나, LXC 컨테이너나 VM끼리 통신이 안 되는 경우가 많습니다. 특히 홈랩에서 여러 VLAN을 사용하거나, 특정 네트워크 인터페이스를 VM에 직통으로 연결(패스스루)할 때 헷갈리곤 합니다. 항상 /etc/network/interfaces 파일을 꼼꼼히 확인하고, 변경 후에는 systemctl restart networking 또는 Proxmox 호스트 재부팅을 해줘야 합니다.

    • 자원 오버커밋 (Overcommit): Proxmox LXC 컨테이너는 자원을 유연하게 쓸 수 있어서 오버커밋하기 쉽습니다. 예를 들어, 물리 RAM이 16GB인데 LXC 컨테이너들에 총 20GB를 할당하는 식이죠. 짧게는 문제가 없지만, 모든 컨테이너가 동시에 많은 자원을 사용하면 Proxmox 호스트 전체가 느려지거나 멈출 수도 있습니다. 항상 실제 사용량을 모니터링하면서 적절히 할당하는 것이 중요합니다.

    성능 및 리소스 사용량 검증

    컨테이너와 VM을 만들었다면, 실제로 얼마나 리소스를 사용하는지 확인해봐야겠죠? 저는 주로 Proxmox 웹 UI의 그래프나 SSH로 접속해서 htop, free -h, df -h 같은 명령어로 확인합니다.

    제 경험상, 동일한 워크로드(예: 웹 서버 하나)를 Proxmox LXC 컨테이너와 VM에 올려보면, LXC 컨테이너가 훨씬 적은 RAM과 CPU를 사용하더라고요. 부팅 시간은 비교할 수 없을 정도로 LXC가 압도적이고요. 이 덕분에 저는 홈랩에서 대부분의 서비스를 LXC 컨테이너로 돌리고 있습니다. 자원 효율성 정말 최고예요! 🎉

    Proxmox VE 대시보드에서 LXC 컨테이너와 VM의 CPU 및 RAM 사용량을 비교하는 시각화된 그래프입니다.

    어떤 것을 선택해야 할까? (결론 및 제언)

    자, 그럼 이제 여러분의 홈랩 환경에 어떤 가상화 기술이 더 적합할지 정리해볼 시간입니다. 제가 13년 동안 삽질하며 내린 결론은 이렇습니다.

    • Proxmox LXC 컨테이너 (추천):

      • 자원 효율성이 최우선일 때: RAM, CPU가 제한적인 홈랩 환경에서 많은 서비스를 돌리고 싶다면 LXC 컨테이너가 정답입니다.
      • 리눅스 기반 서비스 위주: 웹 서버(Nginx, Apache), 데이터베이스(MySQL, PostgreSQL), Docker 호스팅, 파이썬 스크립트 실행 등 리눅스 기반의 애플리케이션을 돌릴 때 Proxmox LXC 컨테이너는 매우 효과적입니다.
      • 빠른 배포 및 테스트 환경: 새로운 서비스를 빠르게 띄우고 테스트하고 싶을 때 LXC 컨테이너만큼 좋은 게 없더라고요.
    • 가상머신 (VM) (추천):

      • 운영체제 유연성 필요: Windows나 다른 리눅스 배포판 (Proxmox 호스트와 다른 커널 버전)이 필요한 경우.
      • 높은 보안/격리 수준 요구: 중요 서비스나 외부와 직접 통신해야 하는 서비스처럼 완벽한 격리가 필요할 때 VM이 더 안전합니다.
      • 하드웨어 패스스루: GPU, USB 컨트롤러 등 특정 물리 하드웨어를 VM에 직접 연결해야 할 때 (예: 미디어 서버, 게임 서버).
      • 레거시 시스템: 오래된 OS나 특정 하드웨어에 의존하는 시스템을 돌려야 할 때 VM이 유일한 선택일 수 있습니다.

    제 홈랩에서는 대부분의 서비스는 Proxmox LXC 컨테이너로 돌리고, Windows나 특별한 하드웨어 패스스루가 필요한 경우에만 VM을 사용합니다. 예를 들어, 저는 Plex 미디어 서버는 VM으로 돌려서 GPU 트랜스코딩을 패스스루하고, Pi-hole이나 Home Assistant 같은 서비스는 LXC 컨테이너로 돌려서 자원을 아끼고 있습니다. 이렇게 섞어서 쓰는 게 가장 효율적이더라고요! 💡

    Proxmox 환경에서 LXC와 VM을 어떤 시나리오에서 선택하는 것이 좋은지 시각적으로 요약한 인포그래픽입니다.

    마무리: 배운 점 정리 및 다음 단계 제안

    오늘은 Proxmox VE 환경에서 LXC 컨테이너와 가상머신 (VM)을 비교 분석하고, 각각의 실전 구현 방법과 제가 겪었던 삽질 경험까지 솔직하게 공유해드렸습니다. 핵심은 각 기술의 장단점을 이해하고, 여러분의 홈랩 목적과 자원 상황에 맞춰 Proxmox LXC 컨테이너와 VM을 적절히 선택하는 것입니다.

    Proxmox LXC 컨테이너는 가볍고 빠르며 자원 효율성이 뛰어나 홈랩에 최적화된 선택지가 될 수 있습니다. 반면 VM은 높은 격리 수준과 운영체제 유연성을 제공하여 특정 목적에 더욱 강력한 대안이 됩니다. 여러분의 홈랩이 더욱 강력하고 효율적으로 운영되기를 바랍니다!

    다음 글에서는 Proxmox에서 ZFS 파일 시스템을 활용하여 스냅샷과 데이터 무결성을 어떻게 관리하는지 자세히 다뤄볼 예정입니다. 기대해주세요! 😄

    Proxmox VE 로고와 함께 LXC 컨테이너 및 VM 아이콘이 조화롭게 배치된 마무리 이미지입니다.

  • [Cloud] Terraform vs Pulumi: IaC 도구 비교 및 선택 가이드

    IaC 도구 선택, 생각보다 중요한 문제입니다

    인프라를 코드로 관리하기 시작한 게 벌써 7~8년 전 일인데요, 그때만 해도 Terraform(테라폼)이 사실상 IaC(Infrastructure as Code, 인프라를 코드로 관리하는 방식)의 표준처럼 여겨졌습니다. 그런데 최근 몇 년 사이에 Pulumi(풀루미)가 치고 올라오면서 팀 내에서도 “우리 이제 Pulumi로 갈아타야 하는 거 아니야?“라는 얘기가 슬슬 나오기 시작하더라고요.

    저도 처음엔 “또 새로운 도구 나왔네” 하고 넘겼는데, 실제로 홈랩에서 Terraform과 Pulumi를 나란히 써보면서 생각이 좀 바뀌었습니다. 단순히 어느 게 더 낫다는 게 아니라, 팀 상황과 사용 목적에 따라 선택이 완전히 달라지는 도구라는 걸 직접 느꼈거든요.

    이 글에서는 Terraform vs Pulumi를 실제 사용 경험을 바탕으로 비교해드리려고 합니다. IaC 도구 비교 글들이 많긴 한데, 대부분 공식 문서 요약 수준이라 아쉬웠거든요. 실무에서 어떤 차이가 나는지 한번 풀어볼게요.

    ▲ Terraform과 Pulumi — 둘 다 훌륭한 IaC 도구지만, 철학이 다릅니다

    Terraform과 Pulumi, 각각 어떤 도구인가요?

    Terraform — HCL로 선언하는 인프라

    Terraform은 HashiCorp(해시코프)가 만든 오픈소스 IaC 도구입니다. HCL(HashiCorp Configuration Language, 해시코프 설정 언어)이라는 자체 DSL(Domain-Specific Language, 도메인 특화 언어)을 사용하는데요. 쉽게 말해 “이런 인프라가 존재해야 해”라고 선언하면 Terraform이 현재 상태와 비교해서 필요한 작업을 자동으로 처리하는 방식입니다.

    2014년에 처음 나왔으니까 이미 10년이 넘었네요. 덕분에 Provider(프로바이더, 클라우드/서비스 연동 플러그인) 생태계가 정말 풍부합니다. AWS, GCP, Azure는 물론이고 GitHub, Datadog, PagerDuty까지 대부분의 주요 서비스를 지원해요.

    다만 2023년에 HashiCorp가 라이선스를 BSL(Business Source License)로 변경하면서 커뮤니티가 반발했습니다. 이 때문에 OpenTofu(오픈토푸)라는 포크 프로젝트도 생겼어요. 라이선스 정책은 도구 선택 시 꼭 고려해야 할 사항입니다.

    Pulumi — 진짜 프로그래밍 언어로 인프라를

    Pulumi는 2018년에 등장한 IaC 도구인데, Terraform과는 완전히 다른 접근을 취합니다. Python, TypeScript, Go, C#, Java 같은 범용 프로그래밍 언어로 인프라를 정의한다는 게 핵심이에요.

    처음 들었을 땐 “그게 뭐가 좋아?” 싶었는데, 직접 써보니 차이가 꽤 크더라고요. 반복문, 조건문, 함수, 클래스 같은 프로그래밍 언어의 모든 기능을 인프라 코드에 그대로 쓸 수 있거든요. 기존 패키지 생태계(npm, pip 등)도 활용 가능합니다.

    State(상태, 인프라의 현재 상태를 저장하는 파일) 관리는 Pulumi Cloud를 이용하거나, AWS S3나 Azure Blob 같은 스토리지에 직접 저장할 수 있어요.

    핵심 철학 차이: 선언형 vs 명령형

    Terraform과 Pulumi의 가장 근본적인 차이는 선언형(Declarative) vs 명령형(Imperative) 접근 방식입니다. 이 차이가 실제 개발 경험에 큰 영향을 미칩니다.

    항목 Terraform Pulumi
    언어 HCL (자체 DSL) Python, TypeScript, Go, C#, Java 등
    패러다임 선언형 (Declarative) 선언형 + 명령형 혼합
    State 관리 로컬 파일 또는 원격 Backend Pulumi Cloud 또는 자체 Backend
    라이선스 BSL 1.1 (2023년 변경) Apache 2.0
    Provider 생태계 매우 풍부 (수천 개) 풍부 (Terraform Provider 재활용 가능)
    학습 곡선 HCL 문법 별도 학습 필요 기존 언어 지식 활용 가능
    테스트 별도 도구 필요 (Terratest 등) 기존 테스트 프레임워크 활용
    IDE 지원 플러그인 필요 언어별 IDE 지원 그대로

    실제 코드로 보는 Terraform vs Pulumi 차이

    말로만 설명하면 와닿지 않으니까, 같은 작업을 두 도구로 작성한 코드를 비교해볼게요. AWS S3 버킷 3개를 만드는 간단한 예시입니다.

    Terraform 방식 — count와 for_each

    Terraform에서 여러 리소스를 만들려면 count나 for_each를 써야 합니다. 처음엔 문법이 좀 낯설 수 있어요.

    # variables.tf
    variable "bucket_names" {
      type    = list(string)
      default = ["my-app-logs", "my-app-backups", "my-app-temp"]
    }
    
    # main.tf
    resource "aws_s3_bucket" "app_buckets" {
      for_each = toset(var.bucket_names)
      bucket   = each.value
    }
    
    resource "aws_s3_bucket_versioning" "app_buckets" {
      for_each = aws_s3_bucket.app_buckets
      bucket   = each.value.id
    
      versioning_configuration {
        status = "Enabled"
      }
    }

    Pulumi 방식 — 프로그래밍 언어처럼

    Pulumi에서는 Python으로 같은 작업을 이렇게 씁니다. 훨씬 직관적이죠?

    import pulumi
    import pulumi_aws as aws
    
    bucket_names = ["my-app-logs", "my-app-backups", "my-app-temp"]
    
    for bucket_name in bucket_names:
        bucket = aws.s3.Bucket(
            bucket_name,
            bucket=bucket_name
        )
        
        versioning = aws.s3.BucketVersioning(
            f"{bucket_name}-versioning",
            bucket=bucket.id,
            versioning_configuration={
                "status": "Enabled"
            }
        )

    Pulumi 코드가 더 간결하고 읽기 쉽지 않나요? 이게 바로 범용 프로그래밍 언어를 쓰는 장점입니다. 변수, 함수, 클래스 등 익숙한 개념들을 그대로 활용할 수 있거든요.

  • [Nas] NAS 전력 소비 최적화: 전기세 절감 및 효율적인 운영 가이드

    [Nas] NAS 전력 소비 최적화: 전기세 절감 및 효율적인 운영 가이드

    NAS 전력 소비 최적화: 전기세 절감 및 효율적인 운영 가이드

    안녕하세요. 13년차 인프라 엔지니어, 여러분의 홈랩 멘토 ’13년차의 서버실’입니다. 오늘은 많은 분들이 궁금해하는 NAS(Network Attached Storage)의 전력 소비 최적화, 즉 NAS 전기세 절감 방법을 얘기해볼게요. 홈랩을 운영하다 보면 24시간 켜두는 장비들이 많아지는데, 이 녀석들이 생각보다 꽤 많은 전기를 잡아먹더라고요. 특히 NAS는 데이터를 항상 안전하게 보관해야 하니 켜두는 시간이 길어질 수밖에 없는데, 그렇다고 전기세 폭탄을 맞을 수는 없겠죠? 제가 13년간 쌓아온 경험과 홈랩에서의 직접적인 실험을 바탕으로, NAS 절전을 실현하는 현실적인 방법들을 공유해드릴게요. Synology, TrueNAS 등 어떤 NAS를 사용하시든 도움이 될 만한 내용들로 가득 채웠으니, 끝까지 함께 해주세요!

    NAS 전력 소비 최적화 개요

    NAS 전력 소비, 왜 신경 써야 할까?

    NAS는 개인 클라우드, 미디어 서버, 백업 스토리지 등 다양한 용도로 활용되면서 24시간 켜두는 경우가 많습니다. 장시간 운영되는 만큼, 전력 소비는 곧 전기세로 직결되죠. 단순히 몇 천 원 아끼는 수준을 넘어, 몇 년간 누적되면 상당한 금액이 될 수 있어요. 게다가 전력 소비를 줄이는 것은 곧 장비의 발열 감소로 이어져 부품 수명 연장에도 긍정적인 영향을 미칩니다. 환경적인 측면에서도 에너지 효율을 높이는 게 중요하고요. 특히 홈랩 환경에서는 전기 요금이 고정 지출로 꾸준히 발생하기 때문에, NAS 절전은 선택이 아닌 필수예요. 제가 처음 홈랩을 시작했을 때, 몇 대의 NAS와 서버를 24시간 돌리면서 전기 계량기가 쉴 새 없이 돌아가는 걸 보고 적잖이 당황했거든요. 그때부터 ‘어떻게 하면 이 녀석들의 전력 소비를 줄일 수 있을까?’ 고민하기 시작했습니다.

    NAS 전력 소비 최적화, 무엇부터 시작할까?

    NAS 전력 소비 최적화는 크게 두 가지 방향으로 접근할 수 있어요. 첫째는 NAS 하드웨어 자체의 전력 효율을 높이는 것이고, 둘째는 소프트웨어적인 설정을 통해 절전을 강화하는 것입니다. 물론, NAS를 어떤 용도로 사용하느냐에 따라 최적화 방법은 달라질 수 있어요. 예를 들어, 항상 데이터를 써야 하는 서비스(예: Plex 서버의 실시간 트랜스코딩)를 운영한다면 무작정 절전 모드로만 돌리기는 어렵겠죠. 하지만 대부분의 경우, 유휴 시간(Idle time)을 활용한 절전은 충분히 가능합니다.

    1. 하드웨어 레벨에서의 최적화

    가장 근본적인 방법은 전력 효율이 좋은 NAS 하드웨어를 선택하는 거예요. 이미 NAS를 가지고 계신 분들이라면, 기존 장비에서 할 수 있는 최적화에 집중해야겠죠.

    • HDD vs SSD: SSD는 HDD에 비해 전력 소비가 훨씬 적습니다. OS나 자주 접근하는 데이터를 SSD에 설치하고, 대용량 데이터 저장용으로는 HDD를 사용하는 하이브리드 구성도 고려해볼 만해요.
    • 저전력 CPU/칩셋: NAS 제조사들은 저전력 설계를 강조하는 모델들을 출시합니다. 인텔의 저전력 프로세서(예: Celeron, Atom)나 ARM 기반 칩셋을 사용한 모델들이 상대적으로 전력 소비가 낮아요.
    • RAM 용량: 과도한 RAM은 불필요한 전력 소비를 유발할 수 있습니다. NAS 운영체제와 사용할 서비스에 필요한 만큼의 RAM만 장착하는 게 좋아요.
    • 확장 장치 최소화: 불필요한 외장 하드나 USB 장치 연결은 전력 소비를 늘립니다. 꼭 필요한 장치만 연결하고, 사용하지 않을 때는 분리하는 습관을 들이세요.

    2. 소프트웨어 레벨에서의 절전 설정 (Synology & TrueNAS 중심)

    대부분의 NAS 운영체제(OS)는 다양한 절전 기능을 제공해요. 이를 잘 활용하면 NAS 전기세 절감의 핵심을 잡을 수 있습니다. 제가 주로 사용하는 Synology DSM과 TrueNAS CORE를 중심으로 설명드릴게요.

    Synology 절전 설정 가이드

    Synology NAS는 사용자 친화적인 인터페이스 덕분에 절전 설정을 비교적 쉽게 할 수 있어요. 제가 사용하는 DS218+ 모델을 기준으로 설명드리겠습니다. (모델별로 메뉴 위치나 옵션이 약간 다를 수 있습니다.)

    1. HDD 최대 절전 모드 (HDD Hibernation): 가장 효과적인 절전 기능 중 하나예요. 일정 시간 동안 NAS에 접근이 없으면 HDD를 회전시키지 않고 저전력 상태로 진입시킵니다.
      • 설정 경로: 제어판 > 하드웨어 및 전원 > HDD 최대 절전 모드
      • 설정 팁: 너무 짧은 시간으로 설정하면 잦은 HDD 회전으로 오히려 전력 소비가 늘거나 데이터 접근 시 딜레이가 발생할 수 있어요. 보통 15분~30분 정도를 권장합니다. 파일 서버처럼 자주 접근하는 환경이라면 이 옵션을 비활성화하거나 매우 길게 설정해야 할 수도 있어요.
    2. 예약된 작업 (Scheduled Task): NAS를 사용하지 않는 특정 시간에는 전원을 끄고, 필요할 때 자동으로 켜지도록 설정할 수 있습니다. Synology 절전의 핵심 기능이죠.
      • 설정 경로: 제어판 > 전원 > 전원 스케줄
      • 설정 팁: 예를 들어, 밤 12시부터 아침 7시까지는 NAS 전원을 끄고, 아침 7시에 자동으로 켜지도록 설정하면 밤새 낭비되는 전력을 크게 아낄 수 있어요. 물론, 밤중에 백업이나 외부 접속이 필요한 경우에는 이 설정을 조정해야 합니다.
    3. 저전력 모드/고성능 모드: 일부 모델에서는 CPU 성능과 전력 소비 간의 균형을 조절하는 옵션을 제공합니다. NAS 전력 소비 최적화를 위해 사용 빈도가 낮은 시간에는 저전력 모드로 설정하는 걸 고려해볼 만해요.
      • 설정 경로: 제어판 > 하드웨어 및 전원 > 일반 탭 (모델에 따라 다름)

    Synology DSM에서 HDD 최대 절전 모드 설정 화면 예시

    TrueNAS CORE 절전 설정 가이드

    TrueNAS 절전은 Synology에 비해 조금 더 수동 설정이 필요해요. TrueNAS CORE는 전문적인 사용자들을 위한 OS이기 때문에 직관적이지는 않지만, 강력한 커스터마이징을 통해 절전을 구현할 수 있습니다. TrueNAS는 ZFS 파일 시스템을 사용하기 때문에 HDD의 ‘Spin Down’ (회전 중지) 개념이 Synology와는 조금 다르게 접근될 수 있어요. ZFS는 데이터 무결성을 위해 HDD를 항상 활성 상태로 유지하려는 경향이 있기 때문입니다.

    1. Spin Down 설정: TrueNAS에서도 HDD의 Spin Down 기능을 설정할 수 있어요. 하지만 ZFS의 특성상 잦은 Spin Down/Spin Up은 오히려 HDD 수명에 좋지 않다는 의견도 있으므로 신중하게 접근해야 합니다.
      • 설정 경로: System Settings > Advanced (또는 Services > Shell 에서 직접 설정)
      • 설정 방법: sysctl 명령어나 loader.conf 파일을 통해 vfs.zfs.prefetch_disable 같은 ZFS 관련 커널 파라미터를 조정하여 Spin Down을 유도할 수 있어요. 하지만 이는 매우 고급 설정이며, 잘못 건드리면 데이터 손실 위험이 있으므로 매우 주의해야 합니다. 제 홈랩에서는 기본 설정을 유지하거나, 꼭 필요한 경우에만 아주 긴 시간(예: 24시간 이상)으로 설정해두는 편이에요.
    2. Cron Job을 이용한 예약 재부팅/종료: Synology의 예약된 작업처럼, TrueNAS에서도 Cron Job을 이용하여 특정 시간에 NAS를 재부팅하거나 종료하도록 스케줄링할 수 있어요.
      • 설정 방법: Shell (또는 SSH)에 접속하여 crontab -e 명령어를 사용하여 원하는 시간에 shutdown -p now (종료) 또는 reboot 명령어가 실행되도록 설정합니다.
      • 예시: 매일 새벽 3시에 NAS를 종료하고 싶다면, crontab -e 편집기에서 0 3 * * * /sbin/shutdown -p now 와 같이 추가하세요.
    3. 서비스 관리: 사용하지 않는 서비스(예: Plex, Docker 컨테이너 등)는 중지하거나 비활성화하여 불필요한 CPU 및 디스크 I/O를 줄이는 게 TrueNAS 절전에 도움이 돼요.

    TrueNAS CORE Shell에서 Cron Job 설정 예시 (명령어 기반)

    실제 경험 기반의 트러블슈팅 및 주의사항

    NAS 전력 소비 최적화를 진행하다 보면 예상치 못한 문제에 부딪히기도 합니다. 제가 겪었던 몇 가지 상황과 해결책을 공유해드릴게요.

    • ⚠️ HDD 최대 절전 모드 진입 실패: 분명히 설정 시간은 지났는데 HDD가 계속 돌고 있다면?
      • 원인: SMB/AFP/NFS 등의 네트워크 공유 폴더에 지속적인 접근이 있거나, Plex/Download Station 같은 패키지 서비스가 백그라운드에서 디스크 I/O를 발생시키고 있을 수 있어요. Plex의 경우 라이브러리 스캔이 백그라운드에서 실행되면 HDD가 깨어납니다.
      • 해결책: Synology DSM의 리소스 모니터 (Resource Monitor)나 iotop (SSH 접속 후) 명령어를 사용하여 어떤 프로세스가 디스크를 사용하고 있는지 확인하고 해당 서비스를 일시 중지하거나 설정을 조정해줘야 해요. Synology의 경우, 일부 패키지는 자체적인 절전 방해 설정을 가지고 있을 수 있습니다.
    • ⚠️ 잦은 HDD Spin Down/Up으로 인한 노이즈 및 수명 저하 우려: 너무 짧은 시간으로 절전 모드를 설정하면, 잦은 HDD의 기동/정지음으로 인한 스트레스와 실제 수명 저하가 걱정될 수 있어요.
      • 해결책: 앞서 언급했듯, HDD 절전 모드 시간은 넉넉하게 설정하는 게 좋아요. 개인적으로는 15분~30분 이상을 권장하며, 데이터 접근 빈도가 높다면 과감히 비활성화하는 것도 방법입니다. NAS 전기세 절감보다는 안정성과 편의성을 우선하는 게 현명할 때도 있거든요.
    • ⚠️ 예약 종료 후 부팅 실패: 예약 종료 후 다음 날 NAS가 켜지지 않는 경우가 간혹 발생합니다.
      • 원인: ACPI(Advanced Configuration and Power Interface) 관련 문제거나, 전원 공급 장치(PSU)의 Wake-on-LAN(WOL) 기능 문제일 수 있어요.
      • 해결책: BIOS/UEFI 설정에서 ACPI S3/S4 모드 관련 설정을 확인하고, NAS 자체의 WOL 설정을 확인해봐야 해요. Synology의 경우 ‘Power On After Power Loss’ 옵션을 활성화하는 게 도움이 될 수 있습니다.

    전력 소비량 측정 및 검증

    실제로 얼마나 전력을 절감했는지 확인하는 것은 매우 중요해요. 그래야 동기 부여도 되고, 어떤 설정이 효과적인지 알 수 있으니까요.

    1. 스마트 플러그 활용: 가장 간편하고 현실적인 방법이에요. NAS 전원 코드에 스마트 플러그를 연결하여 실시간 전력 소비량과 누적 사용량을 측정할 수 있습니다. 다양한 스마트 플러그 앱에서 그래프 형태로 제공해주기 때문에 추이를 파악하기 좋아요.
    2. NAS 자체 모니터링 기능: Synology DSM이나 TrueNAS CORE 자체적으로도 시스템 리소스 및 전력 소비량에 대한 모니터링 기능을 제공하는 경우가 있습니다. (모델 및 OS 버전에 따라 다름)
    3. 전기 계량기 확인: 홈랩 전체의 전력 소비량을 파악하고 싶다면, 집의 메인 전기 계량기나 분전함에 설치된 전력 측정 장치를 활용할 수 있어요.

    제가 스마트 플러그로 측정한 결과, Synology NAS의 HDD 최대 절전 모드와 예약된 작업 기능을 적극적으로 활용했을 때, 유휴 시간 기준 평균 10~20W 정도의 전력 소비를 줄일 수 있었습니다. 24시간 작동하는 NAS임을 감안하면, 하루에 240Wh~480Wh, 한 달이면 약 7.2kWh~14.4kWh를 절약하는 셈이죠. 현재 전기 요금 단가를 생각하면 무시할 수 없는 수준입니다! 🎉

    스마트 플러그로 측정한 NAS의 시간별 전력 소비량 그래프 (절전 설정 적용 후)

    마무리하며: 현명한 NAS 운영을 위한 제언

    오늘은 NAS 전력 소비 최적화를 통해 NAS 전기세를 절감하고 효율적인 운영을 하는 방법에 대해 알아봤어요. 핵심은 하드웨어 선택과 소프트웨어 설정, 그리고 꾸준한 모니터링입니다.

    가장 중요한 건 ‘나의 NAS 사용 패턴’을 이해하는 거예요. 항상 고성능을 요구하는 작업을 하지 않는다면, 적극적으로 절전 기능을 활용하는 게 좋습니다. Synology의 직관적인 설정과 TrueNAS의 강력한 커스터마이징 옵션을 잘 조합하면, 성능 저하를 최소화하면서도 상당한 NAS 절전 효과를 얻을 수 있어요.

    제가 오늘 공유해드린 정보들이 여러분의 홈랩 운영에 도움이 되기를 바랍니다. 혹시 더 궁금한 점이나 여러분만의 절전 팁이 있다면 언제든지 댓글로 공유해주세요! 다음 글에서는 NAS의 성능을 한층 더 끌어올릴 수 있는 네트워크 구성 팁에 대해 다룰 예정이니 많이 기대해주세요. 😉

    NAS 전력 소비 최적화 핵심 요약

  • [Cloud] Docker Compose 실전 가이드: 로컬 개발 환경 구축 및 관리

    “팀원 컴퓨터에서는 되는데 제 컴퓨터에서는 왜 안 되죠?”

    인프라 일을 13년 하면서 개발팀에서 가장 많이 들은 말 중 하나입니다. 그리고 솔직히 말씀드리면, 저도 초창기엔 이 문제로 꽤 많이 고생했거든요. 환경변수 하나 차이로 밤새 디버깅하고, OS 버전 달라서 라이브러리 충돌 나고… 생각만 해도 아찔하네요.

    그래서 오늘은 Docker Compose를 활용해서 로컬 개발 환경을 제대로 구축하는 방법을 공유하려고 합니다. “내 컴퓨터에서는 되는데”라는 말을 팀에서 영원히 추방할 수 있는 방법이에요. 실제로 제가 홈랩이랑 팀 프로젝트에서 직접 써보면서 정리한 내용이라 꽤 실용적일 거라 생각합니다.

    ▲ Docker Compose로 구성한 로컬 개발 환경의 전체 구조 — 웹 서버, 앱 서버, 데이터베이스가 하나의 네트워크로 묶이는 모습

    Docker Compose가 뭔지 먼저 짚고 넘어가요

    Docker 자체는 이미 알고 계신 분들이 많을 텐데, Docker Compose(도커 컴포즈)는 조금 다른 개념이에요. 쉽게 말해서, 여러 개의 컨테이너(Container)를 하나의 파일로 정의하고 한 번에 관리하는 도구거든요.

    예를 들어 웹 애플리케이션 하나를 띄우려면 보통 이런 것들이 필요하잖아요:

    • 프론트엔드 서버 (React, Vue 등)
    • 백엔드 API 서버 (Node.js, FastAPI 등)
    • 데이터베이스 (PostgreSQL, MySQL 등)
    • 캐시 서버 (Redis 등)

    이걸 Docker 명령어로 하나하나 실행하면… 솔직히 너무 번거롭더라고요. 컨테이너마다 네트워크 연결하고, 볼륨 설정하고, 환경변수 넣고… 저도 처음엔 그렇게 했었는데 한 달도 안 돼서 포기했어요 ㅎㅎ.

    그런데 Docker Compose를 쓰면 docker-compose.yml이라는 파일 하나에 이 모든 걸 정의하고, 명령어 한 줄로 전체를 올리고 내릴 수 있어요. 개발 생산성 측면에서 정말 게임 체인저였습니다.

    Docker Compose vs. 일반 Docker 명령어 비교

    항목 Docker 단독 사용 Docker Compose 사용
    서비스 시작 컨테이너마다 개별 명령어 실행 docker compose up 하나로 끝
    네트워크 설정 수동으로 네트워크 생성 및 연결 자동으로 네트워크 생성 및 연결
    환경 관리 각 명령어에 -e 옵션 반복 입력 yml 파일에 한 번에 정의
    팀 공유 실행 명령어 문서화 필요 yml 파일을 Git에 올리면 끝
    재현성 낮음 (사람마다 다르게 실행 가능) 높음 (동일한 환경 보장)

    시작 전 준비사항

    본격적으로 들어가기 전에 환경 세팅부터 확인해 봅시다. 요즘은 Docker Desktop을 설치하면 Docker Compose도 함께 딸려오거든요. 예전엔 따로 설치해야 했는데, 이 부분은 많이 편해졌어요.

    1. Docker Desktop 공식 사이트에서 OS에 맞는 버전 다운로드 및 설치
    2. 설치 완료 후 터미널에서 버전 확인
    # Docker 버전 확인
    docker --version
    
    # Docker Compose 버전 확인 (v2 기준)
    docker compose version

    💡 팁: 예전에는 docker-compose(하이픈 포함)로 실행했는데, 요즘 Compose V2부터는 docker compose(스페이스)로 바뀌었어요. 둘 다 동작하긴 하는데, 새 프로젝트라면 V2 방식으로 쓰는 게 좋습니다.

    실전: docker-compose.yml 파일 작성하기

    자, 이제 진짜 시작입니다. 실제 웹 애플리케이션 개발 환경을 예시로 만들어볼게요. Node.js 백엔드 + PostgreSQL 데이터베이스 + Redis 캐시 조합으로 가겠습니다. 제가 홈랩에서 사이드 프로젝트 할 때 자주 쓰는 스택이거든요.

    프로젝트 디렉토리 구조

    my-project/
    ├── docker-compose.yml       # 핵심 설정 파일
    ├── docker-compose.override.yml  # 로컬 개발용 오버라이드
    ├── .env                     # 환경변수 파일
    ├── backend/
    │   ├── Dockerfile
    │   └── src/
    └── frontend/
        ├── Dockerfile
        └── src/

    기본 docker-compose.yml 작성

    version: '3.8'
    
    services:
      # 백엔드 API 서버
      backend:
        build:
          context: ./backend
          dockerfile: Dockerfile
        container_name: myapp-backend
        ports:
          - "3000:3000"
        environment:
          - NODE_ENV=development
          - DATABASE_URL=postgresql://myuser:mypassword@db:5432/mydb
          - REDIS_URL=redis://cache:6379
        volumes:
          - ./backend:/app          # 소스 코드 마운트 (핫 리로드 가능)
          - /app/node_modules       # node_modules는 컨테이너 것 사용
        depends_on:
          db:
            condition: service_healthy  # DB 헬스체크 통과 후 시작
          cache:
            condition: service_started
        networks:
          - app-network
        restart: unless-stopped
    
      # PostgreSQL 데이터베이스
      db:
        image: postgres:15-alpine
        container_name: myapp-db
        environment:
          - POSTGRES_USER=myuser
          - POSTGRES_PASSWORD=mypassword
          - POSTGRES_DB=mydb
        volumes:
          - postgres-data:/var/lib/postgresql/data  # 데이터 영속성 보장
          - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql  # 초기화 스크립트
        ports:
          - "5432:5432"   # 로컬에서 DB 클라이언트로 직접 접속 가능
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
          interval: 10s
          timeout: 5s
          retries: 5
        networks:
          - app-network
    
      # Redis 캐시 서버
      cache:
        image: redis:7-alpine
        container_name: myapp-redis
        ports:
          - "6379:6379"
        volumes:
          - redis-data:/data
        networks:
          - app-network
    
    # 볼륨(Volume) 정의: 컨테이너가 삭제돼도 데이터 유지
    volumes:
      postgres-data:
      redis-data:
    
    # 네트워크 정의: 서비스 간 내부 통신
    networks:
      app-network:
        driver: bridge

    여기서 중요한 포인트! depends_on을 쓸 때 단순히 서비스 이름만 쓰면 컨테이너가 시작된 것만 확인하고 실제로 준비가 됐는지는 모릅니다. condition: service_healthy와 healthcheck를 함께 써야 PostgreSQL이 실제로 쿼리를 받을 준비가 됐을 때 백엔드가 시작돼요. 이거 몰라서 처음에 백엔드가 DB 연결 못 한다고 에러 뜨는 삽질을 꽤 했었더라고요 ㅎㅎ.

    환경변수 파일(.env) 관리

    민감한 정보는 절대 docker-compose.yml에 직접 넣으면 안 됩니다. .env 파일을 따로 만들고 Git에는 올리지 마세요.

    # .env 파일
    POSTGRES_USER=myuser
    POSTGRES_PASSWORD=super_secret_password
    POSTGRES_DB=mydb
    NODE_ENV=development
    APP_PORT=3000
    # docker-compose.yml에서 .env 변수 참조
    services:
      db:
        environment:
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - POSTGRES_DB=${POSTGRES_DB}
    # .gitignore에 반드시 추가
    .env
    .env.local
    .env.production

    ▲ docker-compose.yml로 정의된 서비스들이 내부 네트워크(app-network)로 연결되고, 필요한 포트만 호스트에 노출되는 구조

    개발 환경 전용 오버라이드 파일

    이건 좀 꿀팁인데요. docker-compose.override.yml을 만들면 docker compose up할 때 자동으로 합쳐져서 적용됩니다. 로컬 개발에서만 필요한 설정을 분리할 수 있어서 정말 편하더라고요.

    # docker-compose.override.yml (로컬 개발 전용)
    version: '3.8'
    
    services:
      backend:
        # 개발 중엔 빌드 없이 소스 코드 직접 마운트
        command: npm run dev   # nodemon 등 핫 리로드 명령어
        environment:
          - DEBUG=true
          - LOG_LEVEL=debug
    
      # 개발 환경에서만 DB 관리 UI 추가
      adminer:
        image: adminer
        container_name: myapp-adminer
        ports:
          - "8080:8080"
        networks:
          - app-network

    자주 쓰는 Docker Compose 명령어 모음

    이제 실제로 실행해 봅시다. 제가 매일 쓰는 명령어들 위주로 정리했어요.

    # 전체 서비스 시작 (백그라운드 실행)
    docker compose up -d
    
    # 빌드 포함해서 시작 (코드 변경 후)
    docker compose up -d --build
    
    # 특정 서비스만 시작
    docker compose up -d backend
    
    # 전체 서비스 중지
    docker compose down
    
    # 중지 + 볼륨까지 삭제 (DB 초기화할 때)
    docker compose down -v
    
    # 실행 중인 서비스 상태 확인
    docker compose ps
    
    # 특정 서비스 로그 보기 (실시간)
    docker compose logs -f backend
    
    # 실행 중인 컨테이너에 접속
    docker compose exec backend sh
    
    # 데이터베이스 컨테이너에서 psql 실행
    docker compose exec db psql -U myuser -d mydb
    
    # 서비스 재시작
    docker compose restart backend

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

    이론은 깔끔한데, 실제로 쓰다 보면 별별 문제가 다 생기더라고요. 제가 겪었던 것들 공유합니다.

    문제 1: 포트가 이미 사용 중이라는 에러

    # 에러 메시지
    Error response from daemon: Ports are not available: 
    exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp 0.0.0.0:5432: 
    bind: address already in use

    로컬에 PostgreSQL이 이미 설치돼서 실행 중인 경우 자주 발생해요. 해결법은 두 가지예요:

    # 방법 1: 로컬 PostgreSQL 서비스 중지
    sudo systemctl stop postgresql   # Linux
    brew services stop postgresql    # macOS
    
    # 방법 2: docker-compose.yml에서 포트 변경
    ports:
      - "5433:5432"   # 호스트 포트를 5433으로 변경

    문제 2: 볼륨 마운트 후 node_modules 사라짐

    이거 처음 겪으면 진짜 당황스러워요. 소스 코드 볼륨 마운트하면 로컬의 node_modules(없는 경우)가 컨테이너 안의 것을 덮어씌워버리는 현상이거든요.

    # 해결법: node_modules를 별도 볼륨으로 분리
    services:
      backend:
        volumes:
          - ./backend:/app
          - /app/node_modules   # 이 한 줄이 핵심!
                                # 익명 볼륨으로 컨테이너 내부 것을 보호

    문제 3: 컨테이너 간 통신이 안 될 때

    백엔드에서 DB 접속할 때 localhost로 접속하려다가 실패하는 경우가 많아요. 컨테이너 안에서 localhost는 그 컨테이너 자신을 가리키거든요.

    # ❌ 잘못된 방법 (백엔드 컨테이너 안에서)
    DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydb
    
    # ✅ 올바른 방법 (서비스 이름을 호스트로 사용)
    DATABASE_URL=postgresql://myuser:mypassword@db:5432/mydb
    # 'db'는 docker-compose.yml에서 정의한 서비스 이름

    같은 네트워크에 묶인 컨테이너끼리는 서비스 이름이 곧 호스트명이 됩니다. Docker의 내장 DNS가 자동으로 처리해줘요. 이거 알고 나면 진짜 편해집니다.

    문제 4: M1/M2 Mac에서 이미지 아키텍처 오류

    # 에러 메시지
    WARNING: The requested image's platform (linux/amd64) does not match 
    the detected host platform (linux/arm64/v8)
    
    # 해결법: platform 명시
    services:
      db:
        image: postgres:15-alpine
        platform: linux/amd64   # 또는 linux/arm64/v8

    요즘 Apple Silicon Mac 쓰시는 분들 많은데, arm64를 지원하는 이미지를 쓰거나 platform을 명시해주면 해결돼요. 대부분의 공식 이미지들은 멀티 아키텍처를 지원하니까 크게 걱정 안 하셔도 됩니다.

    ✅ 결과 확인: 제대로 떴는지 검증하기

    드디어 됐다! 이제 제대로 동작하는지 확인해봅시다.

    # 전체 서비스 상태 확인
    docker compose ps
    
    # 예상 출력
    NAME              IMAGE                COMMAND                  SERVICE    CREATED        STATUS                    PORTS
    myapp-backend     myapp-backend        "docker-entrypoint.s…"   backend    2 minutes ago  Up 2 minutes              0.0.0.0:3000->3000/tcp
    myapp-db          postgres:15-alpine   "docker-entrypoint.s…"   db         2 minutes ago  Up 2 minutes (healthy)    0.0.0.0:5432->5432/tcp
    myapp-redis       redis:7-alpine       "docker-entrypoint.s…"   cache      2 minutes ago  Up 2 minutes              0.0.0.0:6379->6379/tcp

    STATUS 컬럼에서 Up이면 실행 중, (healthy)면 헬스체크까지 통과한 것입니다. 🎉

    # 네트워크 확인
    docker network ls
    docker network inspect myproject_app-network
    
    # 컨테이너 간 통신 테스트
    docker compose exec backend ping db
    docker compose exec backend ping cache
    
    # 백엔드 API 응답 확인
    curl http://localhost:3000/health

    ▲ docker compose ps 명령어로 확인한 서비스 상태 — 모든 서비스가 Up 상태이고 DB는 healthy 헬스체크까지 통과한 모습

    🎉 팀 협업에서 빛나는 Docker Compose의 진짜 가치

    제가 Docker Compose를 팀 프로젝트에 도입하고 나서 가장 크게 달라진 점은 온보딩 시간이었어요. 예전엔 새 팀원이 오면 환경 세팅하는 데 하루 이상 걸리는 경우도 있었거든요. 근데 이제는 이렇게 끝납니다:

    # 새 팀원 온보딩 전체 과정
    git clone https://github.com/myteam/myproject.git
    cd myproject
    cp .env.example .env   # 환경변수 파일 복사 후 값 채우기
    docker compose up -d   # 끝!

    이 세 줄이면 끝이에요. 진짜로요. OS가 다르든, 로컬에 뭐가 설치돼 있든 상관없이 동일한 환경이 뜹니다. 개발 생산성 측면에서 이게 얼마나 큰 차이인지는 직접 경험해보시면 바로 느끼실 거예요.

    Docker Compose 활용의 주요 이점

    • ✅ 환경 일관성: “내 컴퓨터에서는 되는데” 문제 완전 해결
    • ✅ 빠른 온보딩: 새 팀원도 몇 분 안에 개발 시작 가능
    • ✅ 격리된 환경: 프로젝트별로 독립된 환경, 충돌 없음
    • ✅ 버전 관리: 인프라 설정도 코드로 관리 (Infrastructure as Code)
    • ✅ 프로덕션 근접: 로컬과 운영 환경의 차이 최소화

    ▲ Docker Compose 도입 전후 로컬 개발 환경 비교 — 온보딩 시간, 환경 일관성, 협업 효율성 측면에서의 개선 효과

    자주 묻는 질문 (FAQ)

    Q. Docker Desktop 없이 Docker Compose만 쓸 수 있나요?

    네, Linux 환경에서는 Docker Engine을 설치하고 Compose 플러그인을 별도로 설치하면 돼요. macOS나 Windows라면 Docker Desktop이 가장 간편한 방법이더라고요.

    Q. docker-compose.yml 파일을 Git에 올려도 되나요?

    네, 올려야 합니다! 이게 바로 팀 환경 공유의 핵심이거든요. 단, .env 파일은 절대 올리면 안 됩니다. .env.example 파일을 만들어서 어떤 변수가 필요한지만 공유하세요.

    Q. 프로덕션 배포에도 Docker Compose를 쓰나요?

    소규모 서비스라면 쓸 수 있어요. 하지만 스케일링이나 고가용성이 필요하다면 Kubernetes(쿠버네티스) 같은 오케스트레이션 도구를 고려해야 합니다. 이 부분은 다음 글에서 다룰 예정이에요.

    Q. 컨테이너를 내렸다 올리면 데이터가 사라지나요?

    docker compose down만 하면 볼륨은 유지돼요. 데이터까지 지우려면 docker compose down -v를 써야 하니까 주의하세요!

    마무리: 이제 로컬 개발 환경 걱정은 끝

    오늘 다룬 내용을 정리해볼게요:

    1. Docker Compose의 기본 개념과 일반 Docker 대비 장점
    2. 실전 docker-compose.yml 작성법 (서비스, 볼륨, 네트워크)
    3. 환경변수 분리와 오버라이드 파일 활용
    4. 자주 쓰는 명령어와 실제 트러블슈팅 사례

    처음 Docker Compose를 접하면 yml 파일 문법이 좀 낯설게 느껴질 수 있어요. 저도 들여쓰기 하나 틀려서 에러 뜨는 걸 수십 번은 겪었으니까요. 근데 한 번 손에 익으면 이것 없이 개발하는 게 상상이 안 될 정도로 편해집니다.

    다음 글에서는 Docker Compose로 구성한 환경을 기반으로 CI/CD 파이프라인과 연동하는 방법을 다뤄볼 예정이에요. 로컬에서 테스트한 환경을 그대로 자동화 배포에 활용하는 내용인데, 꽤 실용적인 내용이 될 것 같습니다.

    궁금한 점이나 삽질 경험 있으시면 댓글로 편하게 남겨주세요. 저도 비슷한 거 겪어봤을 확률이 높거든요 😄

  • [k8s] 쿠버네티스 Ingress Controller 비교: Nginx, Traefik, HAProxy 장단점 분석

    [k8s] 쿠버네티스 Ingress Controller 비교: Nginx, Traefik, HAProxy 장단점 분석

    [쿠버네티스] Ingress Controller 비교: Nginx, Traefik, HAProxy 장단점 분석

    안녕하세요, 13년차 인프라 엔지니어입니다. 쿠버네티스를 운영하면서 가장 자주 마주하는 고민 중 하나가 바로 외부 트래픽을 어떻게 효율적으로 서비스에 연결할까 하는 부분일 겁니다. 저도 처음엔 NodePort나 LoadBalancer 서비스만으로 충분하다고 생각했어요. 하지만 서비스가 많아지고, TLS(Transport Layer Security) 인증서 관리나 경로 기반 라우팅 같은 복잡한 요구사항들이 생기면서 Ingress(인그레스, 외부 트래픽 진입점)의 중요성을 절실히 깨달았습니다.

    특히 어떤 Ingress Controller를 사용해야 할지 결정하는 건 늘 어려운 선택이었어요. Nginx, Traefik, HAProxy… 저마다 장단점이 명확해서 어떤 상황에 어떤 걸 써야 좋을지 항상 고민하게 되더라고요. 제가 홈랩과 실제 프로덕션 환경에서 다양한 Ingress Controller들을 직접 써보고 겪었던 삽질 경험을 바탕으로, 오늘은 이 세 가지 주요 Ingress Controller들의 특징과 장단점을 꼼꼼하게 비교해 보려고 합니다. 혹시 어떤 Ingress Controller를 선택해야 할지 막막하셨다면, 이 글이 여러분의 고민을 덜어줄 수 있기를 바랍니다!

    그림 1: 쿠버네티스 Ingress Controller를 통한 외부 트래픽 라우팅 개요

    1. 쿠버네티스 Ingress Controller, 왜 필요한가?

    쿠버네티스 클러스터 내의 애플리케이션들은 기본적으로 클러스터 내부에서만 접근 가능합니다. 외부에서 이 서비스들에 접근하게 하려면 몇 가지 방법이 있죠. 대표적으로 NodePort나 LoadBalancer 타입의 Service를 사용하는 건데요.

    • NodePort: 모든 워커 노드의 특정 포트를 열어서 서비스에 접근하게 합니다. 간단하지만 포트 관리가 어렵고, 트래픽 분산 기능을 직접 구현해야 하는 단점이 있어요.
    • LoadBalancer: 클라우드 제공업체의 로드밸런서를 프로비저닝하여 외부 IP를 통해 서비스에 접근하게 합니다. 편리하지만, 서비스 하나당 로드밸런서가 하나씩 할당되어 비용 부담이 커질 수 있고, 복잡한 라우팅 규칙을 적용하기 어렵습니다.

    여기서 Ingress가 등장합니다. Ingress는 클러스터 외부에서 내부 서비스로 들어오는 HTTP/HTTPS 트래픽을 관리하는 API 오브젝트예요. 쉽게 말해, ‘외부 트래픽의 문지기’ 역할을 한다고 보시면 됩니다. 하나의 외부 IP와 포트를 통해 여러 서비스로 트래픽을 분산하고, 도메인 기반 라우팅, 경로 기반 라우팅, TLS 종료(Termination) 등을 처리할 수 있게 해줍니다.

    그리고 이 Ingress 리소스에 정의된 규칙들을 실제로 읽고 구현하여 트래픽을 라우팅해주는 것이 바로 Ingress Controller입니다. Ingress Controller는 클러스터 내부에서 Pod 형태로 동작하며, Ingress 리소스의 변경을 감지하고, 그 규칙에 따라 실제 로드밸런싱 설정을 동적으로 업데이트합니다. 마치 웹 서버나 리버스 프록시처럼 동작하는 셈이죠. 결국 Ingress는 ‘규칙’이고, Ingress Controller는 그 ‘규칙을 실행하는 엔진’이라고 이해하시면 편할 겁니다.

    2. 주요 Ingress Controller 심층 비교 분석

    자, 이제 본론으로 들어가서 우리가 주로 사용하는 세 가지 Ingress Controller인 Nginx, Traefik, HAProxy를 하나씩 파헤쳐 봅시다. 제가 직접 써보면서 느꼈던 장단점과 팁들을 솔직하게 공유해 드릴게요.

    2.1. Nginx Ingress Controller: 국룰에는 이유가 있죠

    Nginx Ingress Controller는 아마 쿠버네티스 환경에서 가장 널리 사용되는 Ingress Controller일 겁니다. 그만큼 안정성과 기능 면에서 검증된 솔루션이라고 할 수 있죠. 저도 처음 쿠버네티스를 도입했을 때 Nginx Ingress부터 시작했습니다.

    • ✅ 장점
      • 압도적인 안정성과 성능: Nginx 자체가 고성능 웹 서버이자 리버스 프록시로 유명하죠. Ingress Controller도 그 명성에 걸맞게 안정적이고 뛰어난 성능을 보여줍니다.
      • 풍부한 기능과 설정 옵션: HTTP/HTTPS 라우팅, URL 리라이트(Rewrite), 세션 어피니티(Session Affinity), WAF(Web Application Firewall) 연동 등 다양한 기능을 지원합니다. Nginx 설정 파일에 익숙하다면 복잡한 룰도 구현하기 쉬워요.
      • 넓은 사용자층과 커뮤니티: 워낙 많은 사람이 사용하다 보니, 문제가 생겼을 때 정보를 찾거나 도움을 받기 정말 쉽습니다. Stack Overflow나 GitHub 이슈 등 자료가 많아요.
      • 익숙함: 리눅스에서 Nginx 좀 다뤄봤다 하는 분들은 설정 방식이 익숙해서 빠르게 적응할 수 있습니다.
    • ⚠️ 단점
      • 설정의 복잡성: Nginx ConfigMap이나 Annotation을 통해 Nginx 설정을 직접 제어하는 방식이라, 처음에는 복잡하게 느껴질 수 있어요. 특히 고급 설정으로 가면 Nginx 문법을 알아야 하는 경우가 많습니다.
      • 동적 설정의 제약: Nginx의 특성상 설정 변경 시 리로드가 필요한 경우가 있는데, Ingress Controller가 내부적으로 처리하긴 하지만 완전히 실시간으로 모든 설정을 변경하기는 어렵습니다.
      • CRD(Custom Resource Definition) 미활용: 다른 Ingress Controller들이 CRD를 적극 활용하여 쿠버네티스 네이티브한 설정 경험을 제공하는 반면, Nginx는 Annotation 의존도가 높은 편입니다.

    제가 실제로 Nginx Ingress Controller를 사용하면서 느꼈던 건, “역시 국룰은 다르구나” 하는 점이었어요. 대규모 환경에서도 끄떡없이 잘 돌아갔고, 웬만한 라우팅 규칙은 다 구현할 수 있었거든요. 다만, 개발팀에서 새로운 경로를 자주 추가하거나 변경할 때마다 Ingress 리소스를 수정하고 적용하는 과정이 조금 번거롭다고 느낄 때가 있었습니다.

    2.2. Traefik Ingress Controller: 개발자를 위한 자동화 끝판왕

    Traefik Ingress Controller는 클라우드 네이티브 환경에 최적화된 HTTP 리버스 프록시 및 로드 밸런서예요. 특히 동적인 환경에서 그 진가를 발휘하는데, 저도 홈랩에서 간단한 서비스들을 올릴 때 Traefik을 정말 유용하게 쓰고 있습니다.

    • ✅ 장점
      • 뛰어난 동적 설정 기능: 쿠버네티스 Ingress 리소스뿐만 아니라 Service, Deployment 등 다양한 쿠버네티스 리소스를 감지하여 자동으로 라우팅 규칙을 생성합니다. CRD를 적극 활용해서 쿠버네티스 친화적인 설정 경험을 제공해요.
      • 자동 TLS 인증서 관리 (Let’s Encrypt): Traefik의 가장 강력한 기능 중 하나입니다. Let’s Encrypt와 연동하여 도메인에 대한 TLS 인증서를 자동으로 발급받고 갱신해줍니다. 💡 이거 진짜 편하더라고요! 제가 직접 인증서 갱신하느라 삽질했던 시간이 정말 아깝게 느껴질 정도였습니다.
      • 내장 대시보드: Traefik의 설정과 현재 라우팅되고 있는 서비스들의 상태를 한눈에 볼 수 있는 웹 대시보드를 제공해요. 디버깅이나 모니터링에 정말 유용하거든요.
      • 경량화 및 빠른 시작: Nginx 대비 가볍고 빠르게 시작할 수 있어 개발 환경이나 소규모 클러스터에 특히 적합합니다.
    • ⚠️ 단점
      • Nginx 대비 상대적으로 작은 커뮤니티: 물론 Traefik도 큰 커뮤니티를 가지고 있지만, Nginx만큼은 아닙니다. 아주 특수한 설정이나 문제 발생 시 정보 탐색이 조금 어려울 수 있어요.
      • 고급 설정 시 학습 곡선: 기본적인 설정은 쉽지만, Nginx에서 제공하는 복잡하고 미세한 튜닝 옵션들을 Traefik에서 구현하려면 Traefik의 설정 방식을 익혀야 합니다.
      • 성능: 대부분의 경우 충분하지만, 극단적인 고성능 트래픽 처리나 특정 벤치마크에서는 Nginx가 우위를 보일 수 있어요.

    저는 Traefik을 처음 써봤을 때, 자동 Let’s Encrypt 기능에 정말 감탄했습니다. 홈랩에 여러 서비스 올리면서 매번 인증서 발급받고 갱신하는 게 귀찮았거든요. Traefik은 이런 번거로움을 한 방에 해결해 줘서 개발자들이 정말 좋아할 만한 툴이라고 생각해요. 동적으로 서비스가 추가되거나 스케일 아웃될 때도 설정 변경 없이 알아서 라우팅 해주는 점도 매우 편리했습니다.

    2.3. HAProxy Ingress Controller: 성능과 유연성의 끝판왕

    HAProxy Ingress Controller는 고성능과 높은 유연성이 필요한 환경에서 빛을 발합니다. HAProxy는 이미 오랜 시간 동안 다양한 프로덕션 환경에서 검증된 강력한 로드 밸런서예요. L4(전송 계층) 및 L7(애플리케이션 계층) 로드 밸런싱 기능을 모두 지원하며, 매우 정교한 트래픽 제어가 가능하죠.

    • ✅ 장점
      • 극강의 성능과 안정성: HAProxy 자체의 강력한 성능을 그대로 가져옵니다. 대규모 트래픽 처리와 높은 동시 접속 처리에 매우 강해요.
      • 고급 로드 밸런싱 기능: 다양한 로드 밸런싱 알고리즘(Round Robin, Least Connections, Source IP Hashing 등), 세션 유지, 헬스 체크, 서버 가중치 부여 등 섬세한 제어가 가능합니다.
      • L4/L7 지원: 단순히 HTTP/HTTPS뿐만 아니라 TCP 트래픽에 대한 로드 밸런싱도 지원하여 더 넓은 범위의 애플리케이션에 적용할 수 있어요.
      • 매우 유연한 설정: HAProxy의 설정 문법을 통해 매우 복잡하고 정교한 트래픽 처리 룰을 구현할 수 있습니다.
    • ⚠️ 단점
      • 상대적으로 높은 복잡성: Nginx나 Traefik에 비해 설정 파일이 복잡하고, HAProxy 자체의 문법에 대한 이해가 필요해요. 학습 곡선이 좀 가파른 편입니다.
      • 동적 설정의 제약: Nginx와 유사하게, HAProxy의 설정을 동적으로 변경하는 데는 어느 정도 제약이 있습니다. 물론 Ingress Controller가 이를 최적화하지만, Traefik처럼 완전한 자동화를 기대하기는 어렵습니다.
      • 적은 사용자층: Nginx나 Traefik에 비해 쿠버네티스 Ingress Controller로서의 사용자층은 상대적으로 적은 편이에요.

    제가 HAProxy Ingress Controller를 써봤던 경험은, “이건 진짜 성능이 중요하거나, 표준적인 Ingress로는 부족한 복잡한 요구사항이 있을 때 쓰는 거구나” 하는 느낌이었습니다. 특히 특정 TCP 포트를 외부로 노출하면서 부하 분산을 해야 할 때 아주 유용하더라고요. 하지만 일반적인 웹 서비스 라우팅에는 Nginx나 Traefik이 더 적합하다고 느꼈어요. 굳이 HAProxy의 강력한 기능을 다 쓰지 않으면서 복잡한 설정을 감당할 필요는 없으니까요.

    그림 2: 주요 Ingress Controller들의 핵심 특징 비교

    3. 어떤 Ingress Controller를 선택해야 할까요? (선택 가이드)

    세 가지 Ingress Controller의 특징을 살펴봤으니, 이제 여러분의 환경과 요구사항에 맞춰 어떤 것을 선택해야 할지 가이드라인을 제시해 드릴게요. “정답은 없다”는 말이 식상하게 들릴 수도 있지만, 인프라 엔지니어의 세계에서는 정말 맞는 말입니다. 각자의 상황에 맞는 최적의 선택이 중요하거든요. 💡

    아래 표는 각 Ingress Controller의 주요 특성을 비교하여 선택에 도움을 주기 위한 것입니다.

    기준 Nginx Ingress Controller Traefik Ingress Controller HAProxy Ingress Controller
    성능 및 안정성 매우 우수 (검증됨) 우수 (대부분의 경우 충분) 최고 (고성능, L4/L7)
    설정 복잡도 중 (Annotation, ConfigMap 이해 필요) 하 (CRD 기반, 자동화 강점) 상 (HAProxy 문법 이해 필요)
    동적 설정 중 (리로드가 필요할 수 있음) 최상 (실시간, 자동 감지) 중 (Nginx와 유사)
    TLS 관리 수동 또는 cert-manager 연동 자동 (Let’s Encrypt 내장) 수동 또는 cert-manager 연동
    커뮤니티/자료 매우 풍부 풍부 상대적으로 적음
    주요 사용 시나리오 일반적인 웹 서비스, 레거시 시스템, 익숙함 중시 클라우드 네이티브, 개발 환경, 자동화, Let’s Encrypt 활용 극단적 고성능, 복잡한 L4/L7 규칙, 특정 TCP 서비스

    그림 3: 환경과 요구사항에 따른 Ingress Controller 선택 결정 가이드

    요약하자면:

    • 가장 보편적이고 안정적인 선택을 원한다면? ➡️ Nginx Ingress Controller. 특히 Nginx에 대한 경험이 많고, 대규모 서비스에서 검증된 안정성을 추구한다면 좋은 선택입니다.
    • 설정의 간결함과 자동화를 선호한다면? ➡️ Traefik Ingress Controller. 특히 Let’s Encrypt 자동화와 동적인 서비스 환경에 강점을 보여요. 개발팀이 빠르게 서비스를 배포하고 테스트하는 환경에 안성맞춤입니다.
    • 극단적인 성능이나 L4/L7 고급 기능이 필요하다면? ➡️ HAProxy Ingress Controller. 표준 Ingress로는 해결하기 어려운 복잡한 트래픽 제어나 특정 TCP 서비스 로드 밸런싱에 적합해요. 다만 학습 곡선과 설정 복잡도를 감수해야 합니다.

    4. ⚠️ 실제 겪은 삽질 경험과 트러블슈팅 팁

    제가 이 바닥에서 13년을 구르면서 느낀 건, 아무리 좋은 툴이라도 삽질은 피할 수 없다는 겁니다. 특히 Ingress Controller는 외부와 내부를 잇는 중요한 컴포넌트라 문제가 생기면 서비스 전체가 먹통이 될 수 있죠. 제가 겪었던 몇 가지 삽질 경험과 해결 팁을 공유해 드릴게요.

    1. Ingress Controller Pod가 Pending 상태? 권한 문제!
      처음 Ingress Controller를 배포했을 때 Pod가 계속 Pending 상태거나 CrashLoopBackOff에 빠지는 경우가 있었습니다. 확인해보니 대부분 RBAC(Role-Based Access Control) 권한 문제더라고요. Ingress Controller는 Ingress, Service, Endpoint 같은 쿠버네티스 리소스들을 읽고 변경해야 하므로, 충분한 권한을 가진 ServiceAccount, ClusterRole, ClusterRoleBinding이 제대로 설정되어 있어야 합니다. 공식 문서의 배포 YAML을 꼭 참고해서 필요한 권한들을 잘 설정해주세요.
    2. TLS 인증서 적용이 안 돼요! Secret 이름 확인 필수!
      HTTPS를 적용하려고 Ingress 리소스에 tls 섹션을 추가했는데, 브라우저에서 계속 “안전하지 않은 연결” 경고가 뜨는 겁니다. 며칠을 헤맸는데, 알고 보니 Ingress 리소스의 secretName 필드에 오타가 있었어요! 🤦‍♂️ 쿠버네티스에서 Secret은 대소문자를 구분하고, 이름 하나라도 틀리면 인식이 안 됩니다. Ingress 리소스의 tls.secretName과 실제 Secret 오브젝트의 metadata.name이 정확히 일치하는지 꼼꼼히 확인해야 합니다. cert-manager를 사용하면 이런 수동적인 오류를 많이 줄일 수 있어서 강력히 추천합니다!
    3. 외부에서 접근이 안 돼요! Service 타입이 문제?
      Ingress Controller 자체는 잘 동작하는데, 외부에서 Ingress IP로 접근이 안 되는 경우가 있었습니다. 이건 대부분 Ingress Controller Service의 타입 설정 문제였어요. 클라우드 환경에서는 보통 type: LoadBalancer를 사용해서 외부 IP를 할당받는데, 온프레미스 환경이나 특정 클러스터에서는 type: NodePort나 HostPort를 사용해야 할 수도 있습니다. 클러스터의 네트워크 구성과 환경에 맞는 Service 타입을 선택하는 것이 중요해요. MetalLB 같은 온프레미스 로드밸런서 솔루션도 고려해볼 만합니다.
    4. 동일 포트 충돌! 여러 Ingress Controller 사용 시 주의!
      간혹 하나의 클러스터에 여러 종류의 Ingress Controller를 배포하려는 경우가 있습니다. 예를 들어 Nginx와 Traefik을 같이 쓰는 거죠. 이때 주의해야 할 점은 각 Ingress Controller가 사용하는 외부 포트가 겹치지 않아야 한다는 겁니다. 예를 들어 Nginx가 80/443 포트를 NodePort로 사용하고 있는데, Traefik도 동일한 포트로 NodePort를 열려고 하면 충돌이 발생합니다. 각 Ingress Controller에 고유한 외부 포트나 별도의 LoadBalancer Service를 할당해야 합니다.

    5. Ingress Controller 동작 검증 및 결과 확인

    Ingress Controller와 Ingress 리소스를 배포하고 나면, 제대로 동작하는지 확인하는 과정이 필수입니다. 제가 주로 사용하는 몇 가지 방법을 알려드릴게요.

    1. Ingress 리소스 상태 확인
      가장 먼저 kubectl get ingress 명령어로 Ingress 리소스가 잘 생성되었는지 확인합니다. ADDRESS 컬럼에 Ingress Controller의 외부 IP 주소가 할당되었는지 봐야 해요.
    2. kubectl get ingress -n my-namespace
      # 출력 예시:
      # NAME             CLASS    HOSTS              ADDRESS          PORTS     AGE
      # my-app-ingress   nginx    myapp.example.com   192.168.1.100    80, 443   5m
      

      그리고 kubectl describe ingress <ingress-name> 명령어로 Ingress 리소스의 상세 정보를 확인합니다. Rules 섹션에 정의한 라우팅 규칙들이 제대로 표시되는지, Events 섹션에 오류는 없는지 확인해야 해요.

    3. Ingress Controller Pod 로그 확인
      Ingress Controller Pod의 로그를 확인하는 것은 문제 해결의 첫걸음입니다. kubectl logs -f <ingress-controller-pod-name> -n <ingress-controller-namespace> 명령어로 실시간 로그를 보면서 트래픽이 들어올 때 어떤 동작을 하는지, 오류 메시지는 없는지 파악할 수 있습니다.
    4. 외부에서 curl 테스트
      가장 확실한 방법은 Ingress Controller의 외부 IP(또는 도메인)로 직접 curl 명령어를 날려보는 겁니다.
    5. curl -v http://myapp.example.com/path
      curl -v https://myapp.example.com/secure-path
      

      HTTP 응답 코드(200 OK 등)와 실제 서비스의 응답이 제대로 오는지 확인하세요. 특히 HTTPS의 경우 인증서 정보가 올바르게 나오는지도 함께 확인해야 합니다.

    6. Traefik 대시보드 확인 (Traefik 사용 시)
      Traefik Ingress Controller를 사용한다면, 내장된 대시보드를 통해 현재 활성화된 라우터, 서비스, 미들웨어 등의 상태를 시각적으로 확인할 수 있어요. 대시보드 접근 설정은 Traefik 배포 시 함께 구성해야 합니다. 🎉

    6. 마무리하며: 13년차 엔지니어의 선택, 그리고 다음 단계

    오늘은 쿠버네티스 Ingress Controller의 핵심 플레이어인 Nginx, Traefik, HAProxy의 장단점을 비교하고, 어떤 상황에 어떤 컨트롤러가 적합한지 제 경험을 바탕으로 이야기해 봤습니다.

    다시 한번 정리해 보면:

    • Nginx Ingress Controller: 안정성, 성능, 범용성 측면에서 가장 검증된 선택이에요. 대부분의 웹 서비스 환경에 무난하게 적용할 수 있습니다.
    • Traefik Ingress Controller: 동적인 환경, 빠른 개발 주기, 그리고 Let’s Encrypt 자동화가 중요하다면 최고의 선택입니다. 홈랩이나 개발/테스트 환경에서 빛을 발하죠.
    • HAProxy Ingress Controller: 극강의 성능과 복잡한 L4/L7 로드 밸런싱 규칙이 필요할 때 고려해볼 만합니다. 하지만 학습 곡선이 높다는 점을 인지해야 해요.

    저 같은 13년차 엔지니어에게 “그래서 뭘 추천하냐?”고 물어보신다면… 사실 정답은 없습니다. 😅 하지만 저의 개인적인 경험으로는, 일반적인 웹 서비스라면 Nginx Ingress Controller로 시작해서 안정성을 확보하고, 개발팀의 빠른 배포와 Let’s Encrypt 자동화가 절실하다면 Traefik을 고려하는 편입니다. HAProxy는 정말 특수한 경우에만 꺼내 드는 비장의 무기 같은 느낌이랄까요?

    Ingress Controller는 쿠버네티스 클러스터의 ‘얼굴’과 같은 존재입니다. 여러분의 서비스 특성과 운영 환경을 충분히 고려해서 최적의 선택을 하시길 바랍니다. 다음 글에서는 특정 Ingress Controller를 Helm 차트를 이용해 실제로 배포하고 설정하는 과정을 좀 더 자세히 다뤄보도록 하겠습니다. 그때까지 즐거운 쿠버네티스 여정 되세요! 💪

    그림 4: Nginx, Traefik, HAProxy Ingress Controller 최종 요약 비교

  • [AI] Gemini Advanced 활용 가이드: 구글 AI 프리미엄 기능 완벽 분석

    [AI] Gemini Advanced 활용 가이드: 구글 AI 프리미엄 기능 완벽 분석

    [LLM 활용] Gemini Advanced 활용 가이드: 구글 AI 프리미엄 기능 완벽 분석

    안녕하세요, 13년차 서버실 지킴이, 13년차 인프라 엔지니어입니다. 홈랩에서 이것저것 만져보며 새로운 기술에 대한 감을 잃지 않으려 노력하는 게 제 일상인데요. 최근 들어 가장 뜨거운 감자는 역시 생성형 AI (Generative AI), 그중에서도 LLM (Large Language Model)이 아닐까 싶습니다.

    솔직히 처음엔 ‘이게 과연 업무에 얼마나 도움이 될까?’ 싶었어요. 간단한 스크립트나 문서 요약 정도는 괜찮겠지만, 복잡하고 민감한 인프라 환경에서 AI에 의존하는 건 좀 위험하지 않나 생각했었죠. 그런데 Gemini Advanced(제미니 어드밴스드)를 직접 써보니 생각이 많이 달라지더라고요. 특히 구글 AI 프리미엄 기능들을 경험하면서, ‘아, 이건 이제 선택이 아니라 필수겠구나’ 하는 확신이 들었어요.

    오늘은 13년차 인프라 엔지니어의 시각에서 Gemini Advanced가 왜 매력적인지, 그리고 이 구글 AI 프리미엄 기능을 완벽하게 활용해서 우리 업무에 어떻게 녹여낼 수 있을지 꼼꼼하게 알려드릴게요. 삽질 경험도 솔직하게 공유하면서 여러분의 시간을 아껴드릴 겁니다. 혹시 Gemini 사용법에 대해 궁금하셨다면, 이 글이 좋은 가이드가 될 거예요.

    Gemini Advanced의 사용자 인터페이스는 직관적이고 깔끔해서 처음 사용하는 분들도 쉽게 적응할 수 있습니다.

    ✅ Gemini Advanced, 무엇이 특별할까요?

    그럼 Gemini Advanced가 기존 무료 버전이나 다른 LLM들과 무엇이 다를까요? 인프라 엔지니어의 관점에서 핵심적인 차이점들을 짚어볼게요. 쉽게 말해, ‘더 똑똑하고, 더 길게 기억하고, 더 다양한 것을 이해한다’고 보시면 됩니다.

    • Longer Context Window (긴 컨텍스트 윈도우): 이게 정말 중요하거든요. 복잡한 시스템 아키텍처 문서, 장문의 로그 파일, 혹은 수많은 설정 파일들을 한 번에 넣고 분석해달라고 할 때, 무료 버전은 중간에 잘리거나 핵심을 놓치는 경우가 많았거든요. 하지만 Advanced 버전은 훨씬 더 긴 내용을 기억하고 추론할 수 있어서, 대규모 시스템 환경 분석에는 정말 압도적으로 유리하더라고요. 제가 홈랩에서 쿠버네티스(Kubernetes) 클러스터 설정을 통째로 던져주고 특정 문제점을 찾아달라고 했는데, 그 방대한 양을 척척 소화하는 걸 보고 깜짝 놀랐거든요.
    • Advanced Reasoning Capabilities (고도화된 추론 능력): 단순히 정보를 요약하는 걸 넘어, 복잡한 문제의 원인을 분석하고 여러 대안 중 최적의 솔루션을 제시하는 능력이 정말 뛰어나더라고요. 예를 들어, ‘이런 상황에서 네트워크 성능 병목이 생겼는데, 어떤 지표를 봐야 하고 해결책은 뭘까?’ 물어보면 꽤 구체적이고 논리적인 답이 돌아와요.
    • Multimodality (멀티모달): 텍스트뿐만 아니라 이미지, 오디오, 비디오 같은 다양한 형태의 정보를 이해하고 처리할 수 있는 능력이거든요. 아직 인프라 분야에서는 활용 범위가 제한적이겠지만, 서버 랙 구성 사진을 보고 개선점을 찾는다거나 네트워크 다이어그램을 해석하는 식의 미래 가능성을 충분히 엿볼 수 있어요.

    이런 기능들 덕분에 Gemini Advanced 활용은 단순한 검색을 넘어 경험 많은 시니어 엔지니어와 대화하는 느낌을 줘요.

    💡 인프라 엔지니어의 Gemini Advanced 활용법: 실전 가이드

    그럼 이제 13년차 인프라 엔지니어의 시각에서, Gemini Advanced를 어떻게 실전 업무에 적용할 수 있을지 구체적인 Gemini 사용법을 알려드릴게요. 저도 홈랩에서 다양한 시나리오로 테스트하며 얻은 노하우들입니다.

    1. 코드/스크립트 생성 및 디버깅

    반복적인 작업 자동화는 인프라 엔지니어의 숙명이죠. 파이썬(Python)이나 배시(Bash) 스크립트 작성에 Gemini Advanced가 큰 도움을 줍니다.

    1. 기본 스크립트 초안 생성: 특정 기능을 하는 스크립트가 필요할 때, 요구사항을 자세히 적어주면 초안을 빠르게 만들어주더라고요.
    2. 기존 스크립트 개선 및 최적화: 작성된 스크립트를 붙여넣고 ‘더 효율적으로 개선해줄래?’ 하거나 ‘에러 핸들링을 추가해주면 좋을 것 같은데’ 하고 요청하면 척척 처리해주거든요.
    3. 에러 디버깅: 에러 메시지와 관련 코드 스니펫을 주면, 문제의 원인을 분석하고 해결책을 척척 제시해줍니다.

    예시 프롬프트:

    "AWS EC2 인스턴스의 특정 태그(예: Environment: Production)를 가진 인스턴스들의 IP 주소를 가져와서 CSV 파일로 저장하는 Python 스크립트를 작성해줘. boto3 라이브러리를 사용하고, 에러 핸들링도 포함해줘."

    2. 복잡한 아키텍처 문서화 및 브레인스토밍

    새로운 시스템을 설계하거나 기존 시스템을 문서화할 때, 아이디어를 얻고 정돈하는 데 정말 유용하거든요.

    • 개념 설명 요청: ‘쿠버네티스 Ingress Controller(인그레스 컨트롤러, 외부 트래픽 진입점)의 작동 원리를 초보자도 이해하기 쉽게 설명해줄래?’ 하면 핵심 개념을 정말 잘 정리해주더라고요.
    • 설계 아이디어 제안: ‘대규모 웹 서비스를 위한 고가용성(High Availability) 아키텍처를 설계하려고 하는데, AWS 환경에서 뭘 고려해야 하고 어떤 서비스를 추천할까?’ 물으면 체계적인 제안이 나와요.
    • 문서 초안 작성: 특정 시스템의 운영 가이드나 장애 복구 절차(DRP, Disaster Recovery Plan) 문서를 만들어달라고 하면 초안을 작성해주는 식으로 활용할 수 있어요.

    성공적인 Gemini Advanced 활용은 효과적인 프롬프트 엔지니어링에서 시작됩니다.

    ⚠️ 삽질 경험: 프롬프트 엔지니어링의 중요성

    솔직히 처음에는 Gemini Advanced가 만능인 줄 알았습니다. ‘내 머릿속에 있는 걸 다 알아주겠지?’ 하는 막연한 기대를 했었죠. 하지만 막상 써보니, 프롬프트(Prompt)를 어떻게 던지느냐에 따라 결과물의 퀄리티가 천차만별이더라고요. 여기서 저의 ‘삽질’이 시작됐습니다. 😅

    제가 겪었던 흔한 실수들은 다음과 같습니다.

    • 모호한 요청: ‘서버 문제 해결해줘’ 같은 두루뭉술한 요청은 당연히 좋은 결과를 주지 못합니다.
    • 충분하지 않은 컨텍스트: 문제 상황을 설명할 때 관련 로그, 시스템 환경, 현재 상태 등을 충분히 제공하지 않아 AI가 오해하는 경우가 많았습니다.
    • 원하는 형식 미지정: ‘코드 짜줘’라고만 하고 어떤 언어로, 어떤 스타일로 원하는지 명시하지 않아 엉뚱한 결과가 나오기도 했죠.

    이런 시행착오를 겪으면서 ‘프롬프트 엔지니어링(Prompt Engineering)’의 중요성을 뼈저리게 느꼈습니다. Gemini Advanced 활용의 핵심은 바로 여기에 있어요. 몇 가지 팁을 드릴게요.

    1. 명확하고 구체적으로: 역할을 정해주고, 무엇을 해야 하는지, 어떻게 해야 하는지를 명확히 제시하세요.
    2. 충분한 컨텍스트 제공: 관련 정보(코드, 로그, 에러 메시지, 시스템 구성 등)를 최대한 많이 제공하세요.
    3. 예시 제공 (Few-shot prompting): 원하는 결과물의 예시를 몇 개 보여주면 AI가 훨씬 더 잘 이해하더라고요.
    4. 원하는 형식 명시: ‘JSON 형식으로’, ‘Python 코드로’, ‘마크다운 표로’ 등 결과물의 형식을 지정하세요.
    5. 제약 조건 명시: ‘Docker Compose(도커 컴포즈) 파일 생성 시, 특정 포트는 사용하지 말 것’과 같이 제약 조건을 알려주세요.

    🎉 실제 활용 사례 및 결과

    제가 Gemini Advanced에 ‘AWS Lambda(람다) 함수 배포를 위한 간단한 CI/CD(지속적 통합/지속적 배포) 파이프라인(Pipeline)을 GitHub Actions(깃허브 액션스)로 구현하는 YAML(야믈) 파일을 만들어줄래. Python 3.9 런타임 사용하고, S3(에스쓰리) 버킷에 배포 후 Lambda 함수를 업데이트하는 과정도 포함되어야 해.’ 라고 요청했거든요.

    name: Deploy Lambda Function
    
    on:
      push:
        branches:
          - main
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        permissions:
          id-token: write
          contents: read
    
        steps:
          - name: Checkout repository
            uses: actions/checkout@v3
    
          - name: Configure AWS credentials
            uses: aws-actions/configure-aws-credentials@v1
            with:
              role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole # IAM Role ARN
              aws-region: ap-northeast-2
    
          - name: Set up Python
            uses: actions/setup-python@v4
            with:
              python-version: '3.9'
    
          - name: Install dependencies
            run: pip install -r requirements.txt
    
          - name: Zip function code
            run: | 
              zip -r function.zip . -x "*.git*" "__pycache__/*"
    
          - name: Upload to S3
            run: aws s3 cp function.zip s3://your-lambda-code-bucket/function.zip
    
          - name: Update Lambda function
            run: aws lambda update-function-code --function-name YourLambdaFunctionName --s3-bucket your-lambda-code-bucket --s3-key function.zip
    
          - name: Clean up
            run: rm function.zip
    

    보시다시피 꽤 구체적이고 바로 활용 가능한 YAML 파일을 생성해줬어요. 물론 IAM Role ARN이나 S3 버킷 이름, Lambda 함수 이름은 제가 직접 넣어야 하지만, 기본 틀을 이렇게 빠르게 만들어주는 것만으로도 정말 시간 절약이 되더라고요. 이 LLM 활용 능력은 정말 감탄스러워요.

    Gemini Advanced는 인프라 엔지니어의 업무 효율을 혁신적으로 개선할 수 있는 잠재력을 가지고 있습니다.

    🤔 Gemini Advanced, 이런 점은 아쉽다?

    아무리 좋은 도구라도 완벽할 순 없겠죠. Gemini Advanced도 역시 아쉬운 점들이 있더라고요.

    • 할루시네이션 (Hallucination): 가끔 없는 사실을 만들어내거나 그럴듯해 보이지만 틀린 정보를 주곤 합니다. 특히 민감한 인프라 설정이나 보안 관련 조언에서는 반드시 교차 검증(Cross-verification)이 필요하거든요. ‘아, 이거 또 헛소리하네!’ 하면서 제가 직접 찾아본 적도 여러 번 있어요.
    • 최신 정보 부족: 학습 데이터 컷오프(Cut-off) 이후의 최신 기술이나 변경 사항에 대해서는 모르는 경우가 있거든요. 예를 들어, 최근에 업데이트된 소프트웨어의 새로운 기능이나 CVE(Common Vulnerabilities and Exposures) 정보는 직접 찾아봐야 하는 식이죠.
    • 복잡한 논리 오류: 복잡하고 다층적인 논리가 필요한 문제에서는 여전히 한계를 보이더라고요. 이때는 AI 답변을 맹신하기보다 아이디어 정도로 참고하고 스스로 검증해야 합니다.

    이런 한계들을 인지하고 사용하면, Gemini Advanced는 정말 강력한 도구가 될 수 있어요.

    🚀 마무리하며: 인프라 엔지니어의 새로운 동반자

    제가 Gemini Advanced 활용 가이드를 작성하면서 느낀 점은, 이 구글 AI 프리미엄 서비스가 인프라 엔지니어에게 정말 강력한 ‘동반자’가 될 수 있다는 거예요. 반복적인 작업을 자동화하고, 새로운 기술을 빠르게 학습하며, 복잡한 문제 해결의 실마리를 찾는 데 큰 도움을 주거든요.

    물론 프롬프트 엔지니어링 능력은 필수적이고, AI의 답변을 무비판적으로 받아들이면 안 됩니다. 하지만 이 도구를 잘 활용하면, 우리 인프라 엔지니어들은 더 본질적인 문제 해결과 혁신적인 아이디어에 집중할 수 있게 된다니까요. 저도 앞으로 홈랩에서 Gemini Advanced를 더 깊게 파고들면서 새로운 활용법들을 찾아낼 거고요. 다음 글에서는 특정 인프라 자동화 시나리오에 Gemini Advanced를 연동하는 방법을 다뤄볼 예정이니까요. 기대해주세요!

  • [Proxmox] Proxmox Backup Server (PBS) 완벽 가이드: 설치부터 백업/복구 전략까지

    [Proxmox] Proxmox Backup Server (PBS) 완벽 가이드: 설치부터 백업/복구 전략까지

    [Proxmox] Proxmox Backup Server (PBS) 완벽 가이드: 설치부터 백업/복구 전략까지

    13년차 인프라 엔지니어의 Proxmox Backup Server (PBS) 삽질 & 활용기

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘은 Proxmox Backup Server (PBS), 줄여서 PBS에 대한 이야기를 해보려고 합니다. 사실 인프라 엔지니어에게 백업(Backup)은 아무리 강조해도 지나치지 않은 핵심 업무 중 하나잖아요? 저도 수많은 시스템을 운영하면서 “아차!” 싶었던 순간이 한두 번이 아니었습니다. 특히 홈랩에서 Proxmox VE(Virtual Environment)를 쓰면서 가상 머신(VM)이나 컨테이너(Container) 백업이 늘 고민이었는데, 이 PBS를 만나고 나서 드디어 마음의 평화를 찾았지 뭐예요? 🎉

    Proxmox VE를 사용하시는 분들이라면 기본적으로 제공되는 백업 기능도 꽤 유용하다는 걸 아실 거예요. 근데 이게 스케일이 커지거나, 데이터 중복 제거(Deduplication)나 증분 백업(Incremental Backup) 같은 고급 기능이 필요해지면 한계에 부딪히거든요. 그때 PBS가 진가를 발휘합니다. 오늘은 제가 직접 PBS를 설치하고, Proxmox VE와 연동해서 백업/복구 전략까지 세워본 경험을 솔직하게 공유해 드릴게요. 삽질 과정과 해결 팁도 아낌없이 풀어놓을 테니, 끝까지 함께해 주시면 분명 큰 도움이 되실 겁니다!

    Proxmox Backup Server의 전체 아키텍처는 Proxmox VE에서 PBS로 데이터를 보내고, PBS가 중복 제거 및 압축하여 백업 스토리지에 저장하는 과정을 시각적으로 보여줍니다.

    Proxmox Backup Server (PBS)란 무엇인가요?

    Proxmox Backup Server (PBS)는 Proxmox VE 환경에 최적화된 엔터프라이즈급 백업 솔루션입니다. 쉽게 말해, Proxmox VE 위에 돌아가는 수많은 VM이나 컨테이너의 데이터를 효율적으로 저장하고 관리하기 위해 태어난 녀석이라고 보시면 됩니다. 단순히 데이터를 복사해서 저장하는 것을 넘어, 여러 가지 똑똑한 기능들을 제공하죠.

    • 데이터 중복 제거 (Deduplication): 이게 PBS의 가장 강력한 기능 중 하나인데요. 동일한 데이터 블록이 여러 백업 이미지에 존재하더라도, PBS는 딱 한 번만 저장하고 나머지는 참조만 합니다. 덕분에 저장 공간을 엄청나게 절약할 수 있어요. 제가 직접 써보니, 특히 비슷한 OS 이미지로 여러 VM을 돌릴 때 그 효과가 대단하더라고요!
    • 증분 백업 (Incremental Backup): 첫 백업 이후에는 변경된 데이터 블록만 백업합니다. 이는 백업 시간을 단축시키고, 다시 한 번 저장 공간 효율성을 높여줍니다.
    • 데이터 무결성 검증 (Data Integrity Verification): 백업된 데이터가 손상되지 않았는지 정기적으로 검사할 수 있습니다. 백업은 저장하는 것만큼 ‘제대로 저장되었는지’ 확인하는 게 중요하잖아요? 이 기능 덕분에 안심하고 데이터를 맡길 수 있습니다.
    • 클라이언트-사이드 암호화 (Client-side Encryption): 백업 데이터는 클라이언트(Proxmox VE)에서 암호화되어 PBS로 전송됩니다. 덕분에 민감한 데이터도 안전하게 보관할 수 있죠.
    • 원격 동기화 (Remote Sync): 백업 데이터를 다른 PBS 서버로 동기화할 수 있어, 재해 복구(Disaster Recovery) 전략을 수립하는 데 아주 유용합니다.

    처음엔 그냥 NAS에 백업하면 되지 않나 싶었는데, PBS의 이런 기능들을 경험하고 나니 왜 전용 백업 솔루션이 필요한지 절실히 깨달았네요. 특히 중복 제거는 진짜 혁명적입니다. 💡

    Proxmox Backup Server 설치하기

    자, 그럼 이제 본격적으로 PBS를 설치해 볼까요? 저는 별도의 물리 서버나 가상 머신에 Proxmox Backup Server ISO 파일을 이용해서 설치하는 방법을 선호합니다. 안정적이고 깔끔하거든요. 여기서는 ISO를 이용한 설치 과정을 간략하게 설명해 드릴게요. (Proxmox VE 위에 컨테이너로 설치하는 방법도 있지만, 안정성을 위해 전용 OS 설치를 추천합니다.)

    1. ISO 다운로드 및 부팅: Proxmox 공식 웹사이트에서 PBS ISO 이미지를 다운로드하고, USB에 굽거나 VM에 마운트하여 부팅합니다.
    2. 설치 마법사 진행: 부팅 후 나타나는 설치 마법사를 따라 진행합니다.
      • Target Harddisk (대상 하드디스크): PBS가 설치될 디스크를 선택합니다. 저는 보통 OS용으로 작은 SSD 하나, 백업 데이터 저장용으로 큰 HDD/SSD를 따로 구성합니다.
      • Country (국가), Time zone (시간대): 대한민국, 서울을 선택해 줍니다.
      • Root Password (루트 비밀번호) & Email address (이메일 주소): 관리자 비밀번호를 설정하고, 알림을 받을 이메일 주소를 입력합니다.
      • Management Network Configuration (네트워크 설정): IP 주소, 넷마스크, 게이트웨이, DNS 서버를 설정합니다. 나중에 Proxmox VE에서 접근해야 하니, 고정 IP로 설정하는 것이 좋습니다.
    3. 설치 완료 및 재부팅: 모든 설정이 끝나면 설치가 시작되고, 완료되면 재부팅하라는 메시지가 나옵니다. 재부팅 후에는 웹 인터페이스에 접속할 수 있습니다.

    웹 인터페이스는 https://[PBS 서버 IP]:8007로 접속할 수 있습니다. 사용자 이름은 root이고, 비밀번호는 설치 시 설정한 비밀번호를 사용하면 됩니다. 처음 접속하면 왠지 모르게 뿌듯하더라고요! 🎉

    Proxmox Backup Server 웹 인터페이스에 로그인한 후의 대시보드 화면입니다. 시스템 상태와 저장소 현황을 한눈에 확인할 수 있습니다.

    Proxmox VE와 PBS 연동하기

    PBS를 설치했으니, 이제 Proxmox VE에서 이 녀석을 백업 저장소로 추가해야겠죠? 이 과정도 정말 간단합니다.

    1. Proxmox VE 웹 인터페이스 접속: 평소처럼 Proxmox VE 웹 관리 화면에 로그인합니다.
    2. 데이터센터(Datacenter) > 스토리지(Storage) 이동: 왼쪽 메뉴에서 Datacenter를 클릭하고, 그 아래의 Storage 탭으로 이동합니다.
    3. ‘추가(Add)’ 버튼 클릭 > ‘Proxmox Backup Server’ 선택: ‘Add’ 드롭다운 메뉴에서 ‘Proxmox Backup Server’를 선택합니다.
    4. 정보 입력: 다음 정보를 입력해 줍니다.
      • ID: 이 저장소의 이름을 지정합니다. (예: pbs-backup-storage)
      • Server: PBS 서버의 IP 주소 또는 도메인 이름을 입력합니다.
      • Username: root@pam (PBS의 기본 관리자 계정)
      • Password: PBS 설치 시 설정한 root 비밀번호
      • Datastore: PBS에서 생성된 데이터스토어 이름을 입력합니다. 기본값은 datastore1입니다. (PBS 웹 인터페이스의 ‘Datastore’ 메뉴에서 확인할 수 있습니다.)
      • Fingerprint (지문): PBS 서버의 SSH 지문입니다. 처음 연결할 때 자동으로 채워지거나, PBS 웹 인터페이스에서 확인할 수 있습니다. 보안을 위해 꼭 확인해 주세요.
    5. ‘추가(Add)’ 버튼 클릭: 모든 정보를 입력하고 ‘Add’ 버튼을 누르면 끝!

    제대로 연결되었다면, Proxmox VE의 스토리지 목록에 PBS가 나타나고, ‘Status’가 ‘Active’로 표시될 거예요. 이제 Proxmox VE의 VM이나 컨테이너를 백업할 때, 대상 저장소로 PBS를 선택할 수 있게 됩니다. ✅

    Proxmox VE에 Proxmox Backup Server를 스토리지로 추가하는 설정 화면입니다. Server IP, Username, Datastore 등의 정보를 입력하는 창이 보입니다.

    백업 전략 수립 및 실행

    저장소를 연결했으니, 이제 어떤 VM을 언제, 어떻게 백업할지 전략을 세울 차례입니다. Proxmox VE에서는 백업 스케줄을 아주 유연하게 설정할 수 있습니다.

    1. Datacenter > Backup (백업) 메뉴 이동: Proxmox VE 웹 인터페이스에서 ‘Datacenter’를 클릭하고 ‘Backup’ 탭으로 이동합니다.
    2. ‘Add (추가)’ 버튼 클릭: 새로운 백업 작업을 생성합니다.
    3. 백업 작업 설정:
      • Storage (저장소): 방금 추가한 PBS 저장소를 선택합니다. (예: pbs-backup-storage)
      • Schedule (스케줄): 백업이 실행될 시간을 설정합니다. 매일 새벽 2시, 매주 일요일 자정 등 원하는 대로 설정할 수 있습니다. (예: daily, weekly)
      • VMs (VM 선택): 백업할 VM이나 컨테이너를 선택합니다. ‘All’을 선택하거나 특정 VM ID를 지정할 수 있습니다.
      • Mode (모드): Snapshot을 선택하는 것이 일반적입니다. (VM이 실행 중인 상태에서 일관성 있는 백업을 생성할 수 있습니다.)
      • Compression (압축): 백업 데이터의 압축 방식을 선택합니다. 저는 보통 Zstandard (ZSTD)를 사용합니다. 빠르고 효율적이거든요.
      • Retention (보존 정책): 백업본을 얼마나 오래 보관할지 설정합니다. 예를 들어, ‘Keep last 7’로 설정하면 최근 7개의 백업본만 유지하고 오래된 것은 자동으로 삭제됩니다. 이 정책은 데이터스토어 용량 관리에도 아주 중요합니다.
      • Email notification (이메일 알림): 백업 성공/실패 여부를 이메일로 받아볼 수 있습니다. 중요한 기능이니 꼭 설정해 두세요!
    4. ‘Create (생성)’ 버튼 클릭: 백업 작업이 생성됩니다.

    이렇게 설정해두면, 정해진 시간에 PBS로 자동 백업이 진행됩니다. PBS 웹 인터페이스의 ‘Tasks’ 메뉴나 Proxmox VE의 ‘Task Log’에서 백업 진행 상황을 확인할 수 있습니다. 처음 백업이 성공했을 때의 그 쾌감이란! 💪

    데이터 복구, 이젠 걱정 마세요!

    백업은 언제나 ‘만약의 사태’를 대비하는 것이죠. 가장 중요한 건 백업된 데이터를 성공적으로 복구(Restore)할 수 있느냐입니다. PBS는 복구 과정도 직관적이고 빠릅니다.

    1. Proxmox VE 웹 인터페이스 접속: 복구할 VM이 있던 Proxmox VE 노드에 접속합니다.
    2. VM 선택 및 ‘백업(Backup)’ 탭 이동: 복구할 VM을 선택한 다음, ‘Backup’ 탭으로 이동합니다.
    3. 복구할 백업본 선택: PBS에 저장된 백업 목록이 나타납니다. 복구하고자 하는 특정 날짜와 시간의 백업본을 선택합니다.
    4. ‘복원(Restore)’ 버튼 클릭: 복원 옵션 대화 상자가 나타납니다.
      • Storage (저장소): 복원될 VM의 디스크가 저장될 Proxmox VE 스토리지(예: local-lvm)를 선택합니다.
      • VM ID: 기존 VM ID로 복원하거나, 새로운 VM ID를 지정하여 복원할 수 있습니다. 기존 VM이 손상된 경우 같은 ID로 복원하고, 테스트 목적으로 복원할 경우 새로운 ID로 복원하는 것이 일반적입니다.
      • Overwrite (덮어쓰기): 기존 VM이 있을 경우 덮어쓸지 여부를 결정합니다. 주의해서 사용해야 합니다!
    5. ‘복원(Restore)’ 버튼 클릭: 복구가 시작됩니다.

    복구 작업이 완료되면, 해당 VM이 Proxmox VE 목록에 나타나고, 정상적으로 부팅되는 것을 확인할 수 있습니다. 제가 실제로 몇 번 복구 테스트를 해봤는데, 정말 빠르고 안정적이더라고요. 특히 중복 제거 덕분에 복구 시간도 단축되는 느낌이었습니다. 👏

    ⚠️ 삽질 경험 & 트러블슈팅 팁

    제가 PBS를 사용하면서 겪었던 몇 가지 삽질 경험과 그 해결 팁을 공유해 드릴게요. 여러분은 저처럼 고생하지 마시라고요! ㅎㅎ

    • 방화벽 문제: Proxmox VE와 PBS가 서로 통신하려면 8007번 포트가 열려있어야 합니다. PBS 서버에 UFW(Uncomplicated Firewall)나 다른 방화벽이 설치되어 있다면, 꼭 8007번 포트를 허용해 주세요.
      sudo ufw allow 8007/tcp
      sudo ufw enable
      sudo ufw status
      

      저는 처음에 포트 열어주는 걸 깜빡해서 “왜 연결이 안 되지?” 하고 한참 헤맸거든요. 😅

    • Datastore(데이터스토어) 설정 오류: PBS 설치 후 Datastore를 생성하지 않거나, Proxmox VE에서 입력하는 Datastore 이름이 PBS의 Datastore 이름과 다르면 연결이 안 됩니다. PBS 웹 인터페이스에서 ‘Datastore’ 메뉴를 확인하고 정확한 이름을 입력해야 합니다. 기본값은 datastore1이지만, 직접 이름을 바꿨다면 그 이름을 써야 해요.
    • 스토리지 용량 부족: 아무리 중복 제거가 뛰어나도 백업본이 쌓이면 결국 용량이 부족해집니다. PBS 웹 인터페이스에서 ‘Datastore’ > ‘Prune & GC’ 탭을 활용하여 가지치기(Prune)와 가비지 컬렉션(Garbage Collection) 스케줄을 설정해 주세요. Prune은 오래된 백업본을 삭제하는 정책이고, GC는 삭제된 데이터 블록을 실제로 정리해서 공간을 회수하는 작업입니다. 이걸 안 해주면 삭제된 백업본이 실제 공간을 계속 차지하고 있을 수 있습니다.
    • 네트워크 대역폭 문제: 동시에 여러 VM을 백업하거나, 대용량 VM을 백업할 경우 네트워크 대역폭이 충분하지 않으면 백업 시간이 엄청나게 길어질 수 있습니다. 1Gbps 네트워크 환경이라면 큰 문제가 없지만, 가능하다면 백업 전용 네트워크를 구성하거나 10Gbps 네트워크를 고려해볼 만합니다.

    Proxmox Backup Server의 주요 기능인 데이터 중복 제거, 압축, 암호화, 데이터 무결성 검증을 시각적으로 요약한 인포그래픽입니다.

    마무리하며: PBS, 인프라 엔지니어의 든든한 동반자

    오늘은 Proxmox Backup Server (PBS)에 대해 설치부터 Proxmox VE 연동, 백업/복구 전략, 그리고 제가 겪었던 삽질 경험까지 자세히 이야기해 드렸습니다. 13년차 인프라 엔지니어로서 여러 백업 솔루션을 경험해 봤지만, Proxmox 환경에서는 PBS만큼 효율적이고 안정적인 솔루션은 찾기 힘들다고 생각합니다.

    특히 데이터 중복 제거와 증분 백업 기능은 저장 공간을 아끼는 데 큰 도움이 되었고, 직관적인 웹 인터페이스 덕분에 관리도 정말 편했습니다. 여러분도 Proxmox VE를 사용하고 계시다면, PBS 도입을 적극적으로 고려해 보시길 강력히 추천합니다. 처음엔 좀 낯설게 느껴질 수도 있지만, 한 번 세팅해두면 든든한 백업 시스템이 될 거예요. 든든한 백업 시스템 구축으로 여러분의 소중한 데이터를 지켜내시길 바랍니다!

    다음번에는 PBS의 원격 동기화(Remote Sync) 기능을 활용한 재해 복구(DR) 전략에 대해 더 깊이 다뤄볼까 합니다. 기대해 주세요! 😉

  • [k8s] ArgoCD GitOps CI/CD 구축: 쿠버네티스 자동 배포 완벽 가이드

    배포가 두려운 분들께 — GitOps가 바꿔놓은 제 일상

    솔직히 말씀드리면, 저도 예전에는 배포가 제일 무서웠어요. 스테이징에서는 멀쩡하던 게 프로덕션에 올리면 왜인지 모르게 터지고, “누가 언제 뭘 바꿨지?” 하고 kubectl로 이것저것 뒤지다 보면 어느새 새벽 2시가 되어 있는 그런 날들이요. 쿠버네티스를 도입하고 나서도 한동안은 이 상황이 크게 달라지지 않았습니다. 오히려 배포 방법이 늘어나면서 혼란이 더 심해지기도 했고요.

    그러다가 ArgoCD를 알게 됐습니다. 처음엔 “또 새로운 툴이네” 하고 반신반의했는데, 막상 써보니까 진짜 다르더라고요. GitOps 방식으로 쿠버네티스 배포를 자동화하면, Git 저장소가 클러스터의 “진실의 원천(Source of Truth)”이 됩니다. 코드를 푸시하면 ArgoCD가 알아서 클러스터 상태를 맞춰주는 거예요. 오늘은 제가 홈랩과 실무에서 직접 구축하면서 겪은 경험을 바탕으로, ArgoCD를 활용한 CI/CD 파이프라인 구축 방법을 처음부터 끝까지 같이 살펴보겠습니다.

    ArgoCD GitOps 전체 아키텍처 — Git 저장소 변경이 쿠버네티스 클러스터에 자동 반영되는 흐름

    GitOps와 ArgoCD, 쉽게 이해하기

    GitOps란 뭔가요?

    GitOps를 한 문장으로 정리하면 이렇습니다. “인프라와 애플리케이션의 원하는 상태(Desired State)를 Git에 선언적으로 저장하고, 자동화 도구가 실제 상태를 그것에 맞게 유지하는 방식”이에요.

    쉽게 말해서, 예전에는 “지금 클러스터에 뭐가 떠 있지?”를 확인하려면 kubectl get 명령어를 직접 쳐봐야 했잖아요. GitOps를 쓰면 Git 저장소만 봐도 현재 클러스터 상태를 알 수 있어요. 변경 이력도 다 남고, 롤백도 git revert 한 방이면 되고요.

    기존 CI/CD 방식과 무엇이 다른가요?

    구분 기존 Push 방식 CI/CD GitOps (ArgoCD Pull 방식)
    배포 트리거 CI 파이프라인이 kubectl apply 직접 실행 ArgoCD가 Git 변경 감지 후 자동 동기화
    클러스터 접근 권한 CI 서버가 클러스터 자격증명 보유 ArgoCD만 클러스터 내부에서 관리
    상태 추적 파이프라인 로그 확인 필요 Git 커밋 히스토리 = 배포 이력
    드리프트(Drift) 감지 수동 확인 필요 ArgoCD가 실시간 감지 및 알림
    롤백 파이프라인 재실행 or 수동 Git revert + 자동 동기화

    특히 드리프트(Drift) 감지가 저한테는 정말 킬러 피처였어요. 누군가 실수로 kubectl로 직접 설정을 바꿔놔도, ArgoCD가 “어? Git이랑 다른데?” 하고 바로 잡아주거든요. 이게 얼마나 안심되는지 모릅니다.

    ArgoCD 설치 — 생각보다 간단합니다

    사전 준비

    • 쿠버네티스 클러스터 (v1.19 이상 권장)
    • kubectl 설치 및 클러스터 접근 설정 완료
    • Git 저장소 (GitHub, GitLab, Bitbucket 모두 가능)
    • ArgoCD CLI (선택사항이지만 있으면 편해요)

    1단계: ArgoCD 네임스페이스 및 설치

    ArgoCD 공식 설치 방법은 정말 간단합니다. 공식 매니페스트를 그대로 적용하면 되거든요.

    # ArgoCD 전용 네임스페이스 생성
    kubectl create namespace argocd
    
    # ArgoCD 공식 매니페스트 적용
    kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
    
    # 설치 완료 확인 (모든 Pod가 Running 상태가 될 때까지 대기)
    kubectl get pods -n argocd -w

    처음에 저도 이게 너무 간단해서 “이게 맞나?” 싶었는데, 맞습니다 ㅎㅎ. 잠시 기다리면 아래와 같이 Pod들이 뜨기 시작해요.

    NAME                                                READY   STATUS    RESTARTS   AGE
    argocd-application-controller-0                     1/1     Running   0          2m
    argocd-applicationset-controller-xxx                1/1     Running   0          2m
    argocd-dex-server-xxx                               1/1     Running   0          2m
    argocd-notifications-controller-xxx                 1/1     Running   0          2m
    argocd-redis-xxx                                    1/1     Running   0          2m
    argocd-repo-server-xxx                              1/1     Running   0          2m
    argocd-server-xxx                                   1/1     Running   0          2m

    2단계: ArgoCD UI 접근 설정

    기본적으로 ArgoCD 서버는 외부에 노출되어 있지 않아요. 로컬에서 테스트할 때는 포트 포워딩을 쓰고, 실제 운영 환경에서는 Ingress를 설정하는 게 좋습니다.

    # 로컬 테스트용 포트 포워딩
    kubectl port-forward svc/argocd-server -n argocd 8080:443
    
    # 초기 admin 비밀번호 확인
    kubectl -n argocd get secret argocd-initial-admin-secret \
      -o jsonpath="{.data.password}" | base64 -d; echo

    💡 팁: 초기 비밀번호는 반드시 첫 로그인 후 바꿔주세요. 그리고 argocd-initial-admin-secret은 비밀번호 변경 후 삭제하는 게 보안상 좋습니다.

    3단계: ArgoCD CLI 설치 (선택 권장)

    # macOS
    brew install argocd
    
    # Linux
    curl -sSL -o /usr/local/bin/argocd \
      https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
    chmod +x /usr/local/bin/argocd
    
    # CLI로 ArgoCD 서버에 로그인
    argocd login localhost:8080 --username admin --password <위에서-확인한-비밀번호> --insecure

    ArgoCD 웹 UI 대시보드 — 애플리케이션 동기화 상태와 헬스 체크 결과를 한눈에 확인

    첫 번째 Application 등록 — 실전 GitOps 시작

    Git 저장소 구조 준비

    ArgoCD를 쓸 때 저장소 구조를 어떻게 잡느냐가 은근히 중요하더라고요. 저는 앱 코드와 쿠버네티스 매니페스트를 분리하는 방식을 선호합니다.

    my-gitops-repo/
    ├── apps/
    │   ├── dev/
    │   │   ├── deployment.yaml
    │   │   ├── service.yaml
    │   │   └── kustomization.yaml
    │   └── prod/
    │       ├── deployment.yaml
    │       ├── service.yaml
    │       └── kustomization.yaml
    └── README.md

    예시로 사용할 간단한 Deployment와 Service 매니페스트입니다.

    # apps/dev/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sample-app
      namespace: default
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: sample-app
      template:
        metadata:
          labels:
            app: sample-app
        spec:
          containers:
          - name: sample-app
            image: nginx:1.25
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: 100m
                memory: 128Mi
              limits:
                cpu: 200m
                memory: 256Mi
    # apps/dev/service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: sample-app-svc
      namespace: default
    spec:
      selector:
        app: sample-app
      ports:
      - protocol: TCP
        port: 80
        targetPort: 80
      type: ClusterIP

    ArgoCD Application 생성

    이제 핵심입니다. ArgoCD에게 “이 Git 저장소의 이 경로를 이 클러스터에 배포해줘”라고 알려주는 Application 리소스를 만들어야 해요. YAML로 선언적으로 만드는 걸 추천합니다 — 이것 자체도 Git으로 관리하면 더 좋고요.

    # argocd-application.yaml
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: sample-app-dev
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: https://github.com/your-username/my-gitops-repo.git
        targetRevision: HEAD
        path: apps/dev
      destination:
        server: https://kubernetes.default.svc
        namespace: default
      syncPolicy:
        automated:
          prune: true        # Git에서 삭제된 리소스 자동 제거
          selfHeal: true     # 드리프트 감지 시 자동 복구
        syncOptions:
        - CreateNamespace=true
    # Application 생성
    kubectl apply -f argocd-application.yaml
    
    # 동기화 상태 확인
    argocd app get sample-app-dev
    
    # 수동 동기화 (처음 한 번)
    argocd app sync sample-app-dev

    여기서 selfHeal: true 옵션이 제가 아까 말씀드린 드리프트 자동 복구 기능이에요. 누군가 실수로 kubectl로 직접 replica 수를 바꿔도, ArgoCD가 Git에 선언된 값으로 되돌려줍니다. 처음에 이게 동작하는 걸 보고 “오오…” 했던 기억이 나네요.

    Private 저장소 연결

    실무에서는 당연히 Private 저장소를 쓰죠. SSH 키나 Personal Access Token으로 연결할 수 있어요.

    # HTTPS + Personal Access Token 방식
    argocd repo add https://github.com/your-username/my-gitops-repo.git \
      --username your-username \
      --password your-personal-access-token
    
    # SSH 키 방식
    argocd repo add [email protected]:your-username/my-gitops-repo.git \
      --ssh-private-key-path ~/.ssh/id_rsa

    CI 파이프라인과 연동 — 이미지 태그 자동 업데이트

    ArgoCD는 CD(Continuous Delivery) 도구입니다. CI(Continuous Integration)는 별도 도구를 써야 해요. 저는 GitHub Actions를 주로 쓰는데, 흐름은 이렇습니다.

    1. 개발자가 앱 코드를 main 브랜치에 push
    2. GitHub Actions가 Docker 이미지를 빌드하고 레지스트리에 push
    3. GitHub Actions가 GitOps 저장소의 이미지 태그를 새 버전으로 업데이트
    4. ArgoCD가 GitOps 저장소 변경을 감지하고 자동으로 클러스터에 배포
    # .github/workflows/deploy.yaml
    name: Build and Update GitOps Repo
    
    on:
      push:
        branches: [main]
    
    jobs:
      build-and-push:
        runs-on: ubuntu-latest
        steps:
        - name: Checkout app code
          uses: actions/checkout@v3
    
        - name: Set up Docker Buildx
          uses: docker/setup-buildx-action@v2
    
        - name: Login to Container Registry
          uses: docker/login-action@v2
          with:
            registry: ghcr.io
            username: ${{ github.actor }}
            password: ${{ secrets.GITHUB_TOKEN }}
    
        - name: Build and push
          uses: docker/build-push-action@v4
          with:
            push: true
            tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
    
        - name: Update GitOps repo image tag
          run: |
            git clone https://x-access-token:${{ secrets.GITOPS_TOKEN }}@github.com/your-username/my-gitops-repo.git
            cd my-gitops-repo
            # sed로 이미지 태그 업데이트
            sed -i "s|image: ghcr.io/your-username/sample-app:.*|image: ghcr.io/your-username/sample-app:${{ github.sha }}|"\
              apps/dev/deployment.yaml
            git config user.email "[email protected]"
            git config user.name "CI Bot"
            git add apps/dev/deployment.yaml
            git commit -m "chore: update image tag to ${{ github.sha }}"
            git push

    근데 여기서 주의할 점이 있어요. 앱 코드 저장소와 GitOps(매니페스트) 저장소를 분리하는 게 좋습니다. 같은 저장소에 두면 앱 코드 변경과 인프라 변경 이력이 섞여서 나중에 관리가 복잡해지더라고요. 처음에 같이 뒀다가 나중에 분리하는 삽질을 했었는데… 처음부터 분리하세요 ㅎㅎ.

    CI/CD 전체 파이프라인 흐름 — GitHub Actions가 이미지를 빌드하고 GitOps 저장소를 업데이트하면 ArgoCD가 자동 배포

    ⚠️ 삽질 모음 — 이것만 알면 시간 아낍니다

    1. OutOfSync 상태가 계속 유지되는 문제

    분명히 Git이랑 같은 내용인데 ArgoCD에서 계속 OutOfSync라고 뜨는 경우가 있어요. 대부분 리소스 정규화(normalization) 문제입니다. 쿠버네티스가 자동으로 추가하는 필드들(creationTimestamp, status 등)이 Git에 없는 거예요.

    # Application에 ignoreDifferences 추가로 해결
    spec:
      ignoreDifferences:
      - group: apps
        kind: Deployment
        jsonPointers:
        - /spec/replicas  # HPA가 관리하는 경우 replica 수 무시
      - group: ""
        kind: Service
        jsonPointers:
        - /spec/clusterIP

    2. Helm 차트 사용 시 values 파일 관리

    Helm을 ArgoCD와 함께 쓸 때 values 파일을 Git에 두면 됩니다.

    spec:
      source:
        repoURL: https://github.com/your-username/my-gitops-repo.git
        path: charts/my-app
        helm:
          valueFiles:
          - values-dev.yaml
          - values-secrets.yaml  # Sealed Secrets 등으로 암호화된 파일

    3. 시크릿(Secret) 관리 — 절대 Git에 평문으로 넣지 마세요

    이건 정말 중요해요. DB 비밀번호 같은 민감 정보를 실수로 Git에 넣는 사고가 생각보다 많이 일어납니다. 저는 Sealed Secrets나 External Secrets Operator를 씁니다.

    • Sealed Secrets: 공개키로 암호화된 SealedSecret 리소스를 Git에 저장, 클러스터 내 컨트롤러가 복호화
    • External Secrets Operator: AWS Secrets Manager, HashiCorp Vault 등 외부 시크릿 저장소와 연동

    4. ArgoCD 자체도 GitOps로 관리하기 — App of Apps 패턴

    ArgoCD Application 리소스가 많아지면 관리가 힘들어져요. 이럴 때 App of Apps 패턴을 씁니다. 루트 Application 하나가 다른 Application들을 관리하는 계층 구조예요.

    # root-application.yaml — 다른 Application들을 관리하는 루트
    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: root-app
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: https://github.com/your-username/my-gitops-repo.git
        targetRevision: HEAD
        path: argocd-apps  # 이 폴더 안에 다른 Application YAML들이 있음
      destination:
        server: https://kubernetes.default.svc
        namespace: argocd
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

    ✅ 배포 결과 확인 및 검증

    모든 설정이 끝났으면 이렇게 확인하시면 됩니다.

    # ArgoCD CLI로 앱 상태 확인
    argocd app list
    
    # 상세 상태 확인
    argocd app get sample-app-dev
    
    # 동기화 이력 확인
    argocd app history sample-app-dev
    
    # kubectl로 직접 확인
    kubectl get pods -n default
    kubectl get svc -n default

    ArgoCD UI에서 애플리케이션 상태가 Synced / Healthy로 표시되면 성공입니다. 🎉

    이제 Git 저장소에서 deployment.yaml의 이미지 태그만 바꿔서 커밋하면, 몇 분 안에 (기본 polling 주기는 3분) 클러스터에 자동으로 반영되는 걸 볼 수 있어요. 처음에 이게 자동으로 되는 걸 보고 “드디어 됐다!” 하고 혼자 좋아했던 기억이 납니다 ㅎㅎ.

    # 롤백도 이렇게 간단합니다
    argocd app rollback sample-app-dev 
    
    # 또는 Git에서 revert 후 push하면 ArgoCD가 자동으로 처리

    ArgoCD 애플리케이션 상세 화면 — Synced/Healthy 상태와 쿠버네티스 리소스 트리 시각화

    자주 묻는 질문 (FAQ)

    Q. ArgoCD는 무료인가요?

    네, ArgoCD는 오픈소스(Apache 2.0 라이선스)로 완전 무료입니다. CNCF(Cloud Native Computing Foundation) 졸업 프로젝트이기도 하고요.

    Q. Flux와 ArgoCD 중 어떤 걸 써야 하나요?

    둘 다 GitOps 도구이지만, ArgoCD는 UI가 풍부하고 직관적이라 팀에서 처음 GitOps를 도입할 때 진입 장벽이 낮습니다. Flux는 더 경량이고 CLI 친화적이에요. 저는 팀 협업 환경에서는 ArgoCD를, 단독 운영이나 자동화 중심이면 Flux를 추천합니다.

    Q. 여러 클러스터를 관리할 수 있나요?

    가능합니다. ArgoCD 하나로 여러 쿠버네티스 클러스터를 등록하고 관리할 수 있어요. argocd cluster add 명령어로 추가하면 됩니다.

    마무리 — GitOps, 한 번 맛보면 못 돌아갑니다

    ArgoCD와 GitOps를 도입하고 나서 제 일상이 꽤 달라졌어요. 배포가 무서운 이벤트에서 그냥 평범한 Git 커밋 하나로 바뀌었달까요. 팀원들도 “내가 뭘 배포했는지” Git 로그만 보면 바로 알 수 있으니 커뮤니케이션 비용도 줄었고요.

    물론 처음 셋업할 때 시크릿 관리나 멀티 클러스터 권한 설정 같은 부분에서 삽질이 좀 있긴 합니다. 근데 그 초기 투자를 하고 나면 이후에는 정말 편해요.

    오늘 다룬 내용을 정리하면 이렇습니다.

    • ✅ GitOps 개념과 기존 CI/CD 방식의 차이 이해
    • ✅ ArgoCD 설치 및 초기 설정
    • ✅ Application 리소스로 Git 저장소와 클러스터 연결
    • ✅ GitHub Actions와 연동한 완전 자동화 파이프라인 구축
    • ✅ 자주 겪는 문제와 해결법

    다음 글에서는 ArgoCD ApplicationSet을 활용해서 여러 환경(dev/staging/prod)을 템플릿 하나로 관리하는 방법을 다룰 예정입니다. App of Apps 패턴도 더 깊이 파볼 거고요. 이 글이 도움이 됐다면 댓글로 알려주세요! 궁금한 점도 편하게 물어봐 주시고요. 😊

  • [Cloud] Pulumi vs Terraform: 멀티 클라우드 IaC 선택 가이드 및 실전 활용

    [Cloud] Pulumi vs Terraform: 멀티 클라우드 IaC 선택 가이드 및 실전 활용

    IaC(Infrastructure as Code)는 왜 필요할까요?

    안녕하세요, 13년차 서버실 지킴이입니다. 오늘도 여전히 복잡한 인프라 구성에 머리 싸매고 계신가요? 요즘 같은 멀티 클라우드(Multi-Cloud) 시대에는 온프레미스(On-Premise)와 여러 클라우드 벤더(Cloud Vendor)를 넘나들며 인프라를 관리해야 하는 경우가 흔하죠. 저도 처음엔 수동으로 서버 올리고 네트워크 설정하고… 휴, 생각만 해도 아찔하네요. 사람이 일일이 하다 보니 휴먼 에러(Human Error)는 기본이고, 속도는 느려터지고, 무엇보다 재현성이 없어서 문제였습니다.

    그래서 등장한 개념이 바로 IaC(Infrastructure as Code, 코드형 인프라)예요. 쉽게 말해, 인프라를 코드로 정의하고 관리하는 방식이죠. Git 같은 버전 관리 시스템으로 관리할 수 있고, 자동화는 물론 팀원들과의 협업도 훨씬 수월해집니다. 제가 홈랩에서 이것저것 테스트해볼 때도, IaC 덕분에 환경을 순식간에 구축하고 파괴하면서 실험할 수 있었거든요. 시간 절약이 어마어마해요!

    멀티 클라우드 환경에서 IaC를 사용하는 인프라 프로비저닝 개념 다이어그램

    Terraform vs Pulumi: 핵심 개념 파헤치기

    IaC 도구는 정말 다양합니다만, 현재 시장에서 가장 강력한 양대 산맥을 꼽으라면 단연 Terraform(테라폼)과 Pulumi(풀루미)일 겁니다. 두 도구 모두 클라우드 인프라를 코드로 정의하고 배포할 수 있게 해주지만, 접근 방식에 큰 차이가 있어요. 저도 처음엔 뭐가 뭔지 헷갈려서 한참을 삽질했었죠.

    Terraform (테라폼)

    • 선언적 언어(Declarative Language): Terraform은 HCL(HashiCorp Configuration Language)이라는 자체 언어를 사용해요. "최종 상태가 이렇게 되어야 한다"라고 선언하면, Terraform이 현재 상태와 비교해서 필요한 변경 사항을 알아서 적용해줍니다. 예를 들어, aws_instance 리소스 블록을 정의하면, Terraform이 AWS에 해당 인스턴스를 생성하거나 업데이트하죠.
    • 상태 파일(State File) 관리: Terraform은 배포된 인프라의 현재 상태를 .tfstate 파일에 기록해요. 이 상태 파일을 통해 다음에 어떤 변경 사항을 적용할지 판단하는데, 이 파일 관리가 꽤 중요하고 때론 골치 아울 때도 있어요. S3 같은 원격 스토리지(Remote Storage)에 저장하고 잠금(Locking) 기능을 사용하는 게 일반적이에요.
    • 모듈(Modules): 재사용 가능한 인프라 구성 단위를 모듈로 만들 수 있어서, 복잡한 인프라도 효율적으로 관리할 수 있어요.

    Pulumi (풀루미)

    • 범용 프로그래밍 언어(General-Purpose Programming Language): Pulumi의 가장 큰 특징은 Python, TypeScript, Go, C# 등 여러분이 익숙한 프로그래밍 언어를 그대로 사용한다는 점이에요. 이게 진짜 매력적입니다! 일반 애플리케이션 개발하듯이 인프라 코드를 작성할 수 있어요. 조건문, 반복문, 함수 등 프로그래밍 언어의 모든 기능을 활용할 수 있다는 것이 큰 장점이죠.
    • 상태 관리(State Management): Pulumi도 인프라 상태를 관리하지만, 기본적으로 Pulumi 서비스에서 관리해주거나 S3, Azure Blob Storage 등 다양한 백엔드(Backend)를 지원해요. Terraform처럼 로컬 .tfstate 파일에 얽매이지 않아서 좀 더 유연하더라고요.
    • 테스트 용이성(Testability): 프로그래밍 언어의 장점을 살려 단위 테스트(Unit Test), 통합 테스트(Integration Test) 등을 적용하기가 훨씬 쉬워요. 저도 TypeScript로 Pulumi 코드를 작성하면서 Jest 같은 프레임워크로 테스트를 붙여보니, 안정성이 확 올라가더라고요.

    멀티 클라우드 환경에서 Pulumi와 Terraform 비교 분석

    자, 그럼 두 도구를 멀티 클라우드 관점에서 비교해볼까요? 제가 여러 프로젝트에 적용해보면서 느낀 점들을 솔직하게 말씀드릴게요.

    특징 Terraform Pulumi
    언어 HCL (HashiCorp Configuration Language) Python, TypeScript, Go, C#, Java 등 범용 프로그래밍 언어
    학습 곡선 HCL 학습 필요 (비교적 쉬움) 선택 언어에 익숙하다면 낮음
    추상화 수준 선언적, 모듈 기반 프로그래밍 언어의 강력한 추상화 및 로직 구현 가능
    상태 관리 .tfstate 파일 (로컬/원격), 잠금 기능 필수 Pulumi 서비스 또는 다양한 백엔드 지원, 더 유연함
    멀티 클라우드 지원 각 클라우드 프로바이더(Provider) 플러그인 각 클라우드 SDK 기반 라이브러리 (더 깊은 통합 가능)
    테스트 terraform plan, 외부 도구 활용 프로그래밍 언어의 테스트 프레임워크 활용 용이
    확장성 프로바이더 개발, 프로비저너(Provisioner) 프로그래밍 언어의 모든 기능 활용, SDK 개발
    커뮤니티/생태계 오래되고 매우 활발함, 방대한 자료 빠르게 성장 중, 비교적 최신

    Terraform은 꽤 오랫동안 IaC 시장을 지배해왔기 때문에 커뮤니티 자료나 레퍼런스가 정말 많아요. 저도 처음엔 Terraform으로 시작했고요. 반면 Pulumi는 비교적 최근에 떠오른 도구지만, 프로그래밍 언어의 유연성 때문에 개발자 친화적이라는 평이 많습니다. 특히 복잡한 로직이 필요한 인프라 구성이나 기존 개발 워크플로우(Workflow)와 통합하고 싶을 때 Pulumi가 빛을 발하더라고요.

    실전 활용: 간단한 웹 서버 배포 (Terraform vs Pulumi)

    백문이 불여일견이죠! AWS에 간단한 EC2 인스턴스(Instance)를 배포하는 예제를 통해 두 도구의 차이를 직접 느껴보시죠. 제 홈랩에서도 늘 이렇게 시작하곤 합니다.

    Terraform 예제

    main.tf 파일에 다음과 같이 작성해요.

    # main.tf
    
    provider "aws" {
      region = "ap-northeast-2" # 서울 리전
    }
    
    resource "aws_instance" "web_server" {
      ami           = "ami-0a0c4fdd9d45e4895" # Ubuntu 20.04 LTS (서울 리전 기준)
      instance_type = "t2.micro"
      tags = {
        Name = "MyWebServer-Terraform"
      }
    }
    

    명령어는 간단해요.

    terraform init
    terraform plan
    terraform apply --auto-approve
    

    terraform init으로 프로바이더를 초기화하고, terraform plan으로 어떤 변경 사항이 생길지 미리 확인합니다. 마지막으로 terraform apply로 인프라를 배포하죠. 정말 직관적이에요!

    Pulumi 예제 (TypeScript)

    index.ts 파일에 다음과 같이 작성해요.

    // index.ts
    
    import * as aws from "@pulumi/aws";
    
    const webServer = new aws.ec2.Instance("web-server-pulumi", {
        ami: "ami-0a0c4fdd9d45e4895", // Ubuntu 20.04 LTS (서울 리전 기준)
        instanceType: "t2.micro",
        tags: {
            Name: "MyWebServer-Pulumi",
        },
    });
    
    export const instanceId = webServer.id;
    export const publicIp = webServer.publicIp;
    

    명령어는 다음과 같아요.

    pulumi stack init dev # 스택 초기화 (환경 분리)
    pulumi up --yes # 인프라 배포
    

    Pulumi는 스택(Stack) 개념이 있어서 개발, 스테이징, 프로덕션 환경을 깔끔하게 분리할 수 있어요. pulumi up 명령어로 배포하고, --yes 옵션으로 확인 과정을 생략할 수 있습니다. 프로그래밍 언어의 문법을 그대로 따르기 때문에, 개발자라면 훨씬 친숙하게 느껴지실 거예요.

    Terraform과 Pulumi로 생성된 AWS EC2 인스턴스 목록

    ⚠️ 제가 겪었던 삽질과 트러블슈팅 경험

    13년차 엔지니어도 삽질은 피할 수 없죠! 저도 이 두 도구를 쓰면서 여러 번 멘붕에 빠졌어요. 몇 가지 기억에 남는 삽질 경험과 해결법을 공유할게요.

    Terraform: 상태 파일 관리의 늪

    제일 많이 겪었던 건 상태 파일(State File) 충돌이에요. 팀원 여럿이 동시에 같은 인프라를 건드리다 보면 .tfstate 파일이 꼬이는 경우가 생기더라고요. 특히 협업 툴(Collaboration Tool)이나 CI/CD 파이프라인(Pipeline) 없이 수동으로 작업할 때 심했습니다. 상태 파일이 꼬이면 terraform plan 결과가 이상하게 나오거나, 심지어 실제 인프라와 상태 파일 간의 불일치(Drift)가 발생해서 엉뚱한 리소스가 삭제될 뻔한 적도 있었죠. 😱

    • 해결법: 항상 원격 백엔드(Remote Backend) (예: AWS S3 + DynamoDB Lock)를 사용하고, 상태 잠금(State Locking)을 활성화해야 해요. 그리고 CI/CD 파이프라인을 구축해서 모든 변경 사항은 파이프라인을 통해서만 적용되도록 강제하는 것이 가장 안전합니다.

    Pulumi: 언어 버전 의존성

    Pulumi는 범용 프로그래밍 언어를 사용하다 보니, 언어 버전이나 패키지 의존성(Package Dependency) 문제로 삽질한 적도 있어요. 예를 들어, 특정 Pulumi AWS 라이브러리가 특정 Node.js 버전에서만 제대로 동작한다든지, npm install 과정에서 에러가 나는 경우요. 이게 진짜 별것 아닌 것 같아도, 디버깅(Debugging)하다 보면 시간을 꽤 잡아먹어요. 😅

    • 해결법: package.json(TypeScript/Node.js)이나 requirements.txt(Python)에 정확한 버전 정보를 명시하고, nvm(Node Version Manager)이나 pyenv(Python Version Manager) 같은 도구로 개발 환경을 일관되게 유지하는 것이 중요해요. 그리고 Pulumi 관련 라이브러리들도 최신 버전으로 꾸준히 업데이트해주는 게 좋아요.

    공통: 리프레시 명령어의 함정

    가끔 실제 인프라가 변경되었는데 상태 파일에 반영이 안 되는 불일치가 생기면 terraform refresh나 pulumi refresh 명령어를 사용하게 되죠. 그런데 이 명령어를 너무 맹신하면 안 돼요. 특히 중요한 리소스에 대해서는 리프레시 전에 항상 백업(Backup)을 해두거나, plan 명령어로 예상 변경 사항을 꼼꼼히 확인하는 습관을 들이세요. 예전에 리프레시 한 번 잘못했다가 스테이징 환경이 날아갈 뻔한 아찔한 경험도 있습니다. ⚠️

    그래서, 어떤 IaC 도구를 선택해야 할까요?

    결론부터 말씀드리자면, "정답은 없다"예요! (싱거운가요? ㅎㅎ) 하지만 여러분의 상황에 맞는 최적의 선택은 분명히 있습니다.

    Terraform을 선택해야 하는 경우

    • 인프라 전문 팀/운영 팀이 주도적으로 IaC를 도입할 때: HCL은 인프라 관리에 특화되어 있어 직관적이에요.
    • 방대한 기존 레퍼런스와 안정적인 커뮤니티 지원이 중요할 때: 오래된 만큼 자료가 정말 많습니다.
    • 비교적 단순하고 선언적인 인프라 구성이 많을 때: 복잡한 로직 없이 리소스 정의만으로 충분한 경우요.
    • GitOps(깃옵스) 워크플로우를 강력하게 따르고자 할 때: Terraform Cloud/Enterprise 같은 솔루션과 통합이 잘 되어 있어요.

    Pulumi를 선택해야 하는 경우

    • 개발 팀이 직접 인프라를 관리하거나, 개발 워크플로우에 IaC를 통합하고 싶을 때: 익숙한 프로그래밍 언어로 개발 생산성을 높일 수 있어요.
    • 복잡한 로직이나 조건부 인프라 구성이 필요할 때: 프로그래밍 언어의 모든 기능을 활용하여 동적인 인프라를 만들 수 있습니다.
    • 인프라 코드에 단위 테스트/통합 테스트를 적극적으로 적용하여 안정성을 높이고 싶을 때요.
    • 서버리스(Serverless) 아키텍처나 컨테이너 기반 환경(Containerized Environment)에 더 깊이 통합하고 싶을 때: Lambda 함수나 Kubernetes 리소스를 직접 코드로 제어하기가 편해요.

    Terraform과 Pulumi 선택 가이드 요약 인포그래픽

    마무리하며: 13년차 인프라 엔지니어의 조언

    오늘은 Pulumi(풀루미)와 Terraform(테라폼), 두 가지 강력한 IaC 도구에 대해 깊이 있게 다뤄봤어요. 멀티 클라우드 환경에서 인프라를 효율적으로 관리하고 자동화하는 것은 이제 선택이 아닌 필수가 되었죠. 저도 처음엔 "이걸 언제 다 배우지?" 했었는데, 막상 익숙해지니 정말 편하더라고요. 삽질 끝에 드디어 원하는 대로 인프라가 배포될 때의 그 희열은 경험해본 사람만 알 겁니다! 🎉

    두 도구 모두 강력한 장점을 가지고 있으니, 여러분의 팀 구성원들이 어떤 언어에 더 익숙한지, 어떤 유형의 인프라를 주로 다루는지를 고려해서 현명하게 선택하시길 바랍니다. 추가로 어떤 수준의 추상화와 유연성이 필요한지도 함께 생각하면서요. 가능하다면 작은 프로젝트에 두 가지를 모두 적용해보면서 장단점을 직접 느껴보는 것도 좋은 방법입니다.

    인프라 코드를 작성하는 것은 마치 소프트웨어 개발과 같아요. 지속적으로 리팩토링(Refactoring)하고, 버전 관리를 철저히 하며, 테스트를 통해 안정성을 확보하는 것이 중요해요. 이 글이 여러분의 IaC 여정에 조금이나마 도움이 되었기를 바랍니다. 다음번에는 더 유익한 주제로 찾아올게요. 감사합니다!

    홈랩에서 IaC 코드를 작성하는 13년차 인프라 엔지니어

  • [k8s] k3s와 MicroK8s 비교: 경량 쿠버네티스 환경 선택 가이드

    경량 쿠버네티스, 왜 지금 이 선택이 중요한가요?

    홈랩을 운영하다 보면 꼭 한 번씩 마주치는 고민이 있어요. “쿠버네티스(Kubernetes)는 써보고 싶은데, 풀스택 k8s를 올리기엔 서버가 너무 작다…” 저도 딱 그랬거든요. 라즈베리파이(Raspberry Pi) 클러스터 위에 뭔가 올려보려고 했는데, 일반 쿠버네티스는 메모리만 수 GB를 잡아먹으니 엄두가 안 나더라고요.

    그래서 찾게 된 게 경량 쿠버네티스(Lightweight Kubernetes)입니다. 그중에서도 현재 가장 많이 언급되는 두 가지가 바로 k3s와 MicroK8s예요. 이 둘, 뭐가 다른지 처음엔 저도 진짜 헷갈렸습니다. 이름도 비슷하고 목적도 비슷한 것 같고… 근데 실제로 써보면 꽤 다르거든요.

    이번 글에서는 제가 직접 두 솔루션을 홈랩에서 돌려보면서 느낀 점, 그리고 어떤 상황에서 어떤 걸 선택해야 하는지 정리해 드릴게요. 엣지 컴퓨팅(Edge Computing) 환경이나 라즈베리파이 쿠버네티스 구성을 고민 중이신 분들께 특히 도움이 될 거예요.

    k3s와 MicroK8s의 전체 아키텍처 구조를 한눈에 비교한 다이어그램. 각각의 구성 요소와 설계 철학의 차이를 보여줍니다.


    k3s와 MicroK8s, 각각 어떤 녀석인가요?

    k3s — “진짜 가볍게 만들어 버렸다”

    k3s는 Rancher Labs(현재 SUSE)에서 만든 경량 쿠버네티스 배포판입니다. 공식 CNCF(Cloud Native Computing Foundation) 인증 프로젝트이기도 해요. 핵심 철학은 딱 하나예요. “싱글 바이너리(single binary)로 모든 걸 해결하자.”

    쉽게 말해, etcd(이티시디, 쿠버네티스의 상태 저장소) 대신 기본적으로 SQLite를 쓰고, 불필요한 컴포넌트를 싹 쳐냈어요. 덕분에 바이너리 하나가 약 100MB 남짓이고, 메모리도 정말 적게 씁니다. 라즈베리파이 같은 저사양 ARM 기기에서도 잘 돌아가는 이유가 여기 있어요.

    • 단일 바이너리로 설치 및 실행
    • 기본 데이터스토어: SQLite (고가용성 구성 시 etcd 또는 외부 DB 사용 가능)
    • ARM 아키텍처 공식 지원 (라즈베리파이 최적)
    • Flannel(플란넬) CNI 기본 내장
    • Traefik(트래픽) Ingress Controller 기본 포함
    • CNCF 공식 인증 쿠버네티스

    MicroK8s — “Ubuntu 생태계에서 편하게”

    MicroK8s는 Canonical(캐노니컬, Ubuntu 만드는 회사)에서 만든 경량 쿠버네티스예요. 설치 방식이 좀 독특한데, Snap(스냅) 패키지 매니저를 통해 설치합니다. Ubuntu 환경이라면 진짜 설치가 간단해요.

    k3s와 달리 MicroK8s는 애드온(addon) 시스템이 핵심이에요. 기본 설치는 가볍게 하고, 필요한 기능(DNS, 대시보드, Ingress, 스토리지 등)을 명령어 하나로 활성화하는 방식이거든요. 개발 환경이나 Ubuntu 서버에서 빠르게 쿠버네티스를 시험해보고 싶을 때 특히 편합니다.

    • Snap 패키지로 설치 (Ubuntu/Linux 최적화)
    • 애드온 시스템으로 필요한 기능만 활성화
    • 단일 노드 개발 환경에 강점
    • Canonical의 지원 및 업스트림 쿠버네티스와 빠른 동기화
    • ARM 지원 (단, k3s 대비 리소스 사용량이 다소 높음)

    k3s vs MicroK8s 핵심 스펙 비교

    말로만 하면 헷갈리니까 표로 정리해 봤어요. 제가 직접 테스트하면서 확인한 내용 위주입니다.

    항목 k3s MicroK8s
    개발사 Rancher Labs / SUSE Canonical (Ubuntu)
    설치 방식 curl 스크립트 / 단일 바이너리 Snap 패키지
    기본 데이터스토어 SQLite (소규모) / etcd 선택 가능 dqlite (분산 SQLite)
    기본 CNI Flannel Calico (기본 활성화)
    Ingress 기본 포함 Traefik (기본 활성화) nginx (애드온으로 활성화)
    ARM 지원 매우 우수 (라즈베리파이 최적) 지원 (단, x86 최적화)
    멀티노드 클러스터 매우 간단 가능 (설정 다소 복잡)
    CNCF 인증 ✅ 인증 ✅ 인증
    주요 사용 환경 엣지, IoT, 라즈베리파이, 프로덕션 경량화 개발/테스트, Ubuntu 서버, 단일 노드
    OS 의존성 낮음 (대부분의 Linux 지원) 높음 (Snap 지원 OS 필요)

    💡 핵심 포인트: 둘 다 CNCF 공식 인증을 받은 쿠버네티스예요. 즉, 표준 kubectl 명령어와 YAML 매니페스트가 그대로 동작합니다. “이거 진짜 쿠버네티스 맞아?” 걱정 안 하셔도 돼요.


    k3s 설치: 진짜 이렇게 간단해도 되나?

    처음 k3s를 설치했을 때 솔직히 당황했어요. 너무 간단해서요. “이게 다야?” 싶었거든요. 라즈베리파이 OS나 Ubuntu 기준으로 설명드릴게요.

    마스터 노드(서버) 설치

    # k3s 서버(마스터 노드) 설치 — 딱 한 줄입니다
    curl -sfL https://get.k3s.io | sh -
    
    # 설치 완료 후 상태 확인
    sudo systemctl status k3s
    
    # 노드 상태 확인
    sudo kubectl get nodes

    이게 전부예요. 진짜로요. 스크립트가 k3s 바이너리를 받아서 systemd 서비스로 등록까지 해줍니다. 설치 후 1~2분 기다리면 노드가 Ready 상태가 돼요.

    워커 노드(에이전트) 추가

    # 마스터 노드에서 토큰 확인
    sudo cat /var/lib/rancher/k3s/server/node-token
    
    # 워커 노드에서 실행 (K3S_TOKEN과 서버 IP를 바꿔주세요)
    curl -sfL https://get.k3s.io | K3S_URL=https://마스터노드IP:6443 \
      K3S_TOKEN=여기에토큰값 sh -

    라즈베리파이 3대로 클러스터 구성할 때 이 명령어로 10분 만에 끝냈어요. 삽질 없이요. 😄

    kubeconfig 설정 (로컬 PC에서 접속)

    # 마스터 노드에서 kubeconfig 복사
    sudo cat /etc/rancher/k3s/k3s.yaml
    
    # 로컬 PC의 ~/.kube/config 에 붙여넣기
    # server: https://127.0.0.1:6443 부분을 실제 서버 IP로 변경
    # 예: server: https://192.168.1.100:6443

    ⚠️ 주의: k3s.yaml 파일의 server 주소가 기본적으로 127.0.0.1로 돼 있어요. 원격 접속할 때 반드시 실제 IP로 바꿔줘야 합니다. 이거 놓치면 “connection refused” 보면서 한참 헤맬 수 있어요. 저도 한 30분 고생했었습니다 ㅎㅎ


    MicroK8s 설치: Ubuntu라면 이게 편할 수도

    MicroK8s는 Ubuntu 환경이라면 진짜 편해요. Snap으로 설치하니까요. 다만 Snap이 없는 OS에서는 좀 번거로울 수 있습니다.

    설치 및 기본 설정

    # MicroK8s 설치 (Ubuntu 기준)
    sudo snap install microk8s --classic
    
    # 현재 사용자를 microk8s 그룹에 추가 (sudo 없이 사용하려면 필수)
    sudo usermod -aG microk8s $USER
    newgrp microk8s
    
    # 상태 확인
    microk8s status --wait-ready
    
    # kubectl 사용 (microk8s.kubectl 또는 alias 설정)
    microk8s kubectl get nodes
    
    # 편하게 쓰려면 alias 등록
    alias kubectl='microk8s kubectl'

    애드온 활성화 — 이게 MicroK8s의 핵심이에요

    # DNS 활성화 (거의 필수)
    microk8s enable dns
    
    # 대시보드 활성화
    microk8s enable dashboard
    
    # Ingress 컨트롤러 활성화
    microk8s enable ingress
    
    # 스토리지(hostpath) 활성화
    microk8s enable hostpath-storage
    
    # 여러 개 한 번에 활성화
    microk8s enable dns dashboard ingress hostpath-storage
    
    # 활성화된 애드온 확인
    microk8s status

    MicroK8s의 애드온 시스템과 k3s 멀티노드 클러스터 구성 화면. 각각의 설치 및 설정 방식의 차이를 보여줍니다.

    MicroK8s 멀티노드 클러스터 구성

    # 마스터 노드에서 조인 토큰 생성
    microk8s add-node
    
    # 출력된 명령어를 워커 노드에서 실행 (예시)
    # microk8s join 192.168.1.100:25000/토큰값/해시값

    k3s보다 조금 더 손이 가긴 하지만, 출력된 명령어를 그대로 복붙하면 돼서 어렵진 않아요.


    ⚠️ 실제로 써보면서 만난 문제들

    둘 다 써보면서 “아, 이거 주의해야 하는구나” 싶었던 것들 솔직하게 공유할게요.

    k3s에서 자주 만나는 문제들

    • 라즈베리파이 cgroup 설정: 라즈베리파이 OS에서 k3s 실행 시 cgroup(컨트롤 그룹, 리소스 제어 메커니즘) 설정이 안 돼 있으면 노드가 NotReady 상태로 뜹니다. /boot/cmdline.txt (또는 /boot/firmware/cmdline.txt)에 cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1를 추가하고 재부팅해야 해요.
    • Traefik vs 내 Ingress 충돌: k3s는 Traefik을 기본으로 깔아줘요. 근데 nginx Ingress를 따로 쓰고 싶다면 k3s 설치 시 --disable traefik 옵션을 줘야 합니다. 나중에 충돌 나면 진짜 원인 찾기 어렵거든요.
    • 방화벽 포트: 멀티노드 구성 시 6443(API 서버), 8472(Flannel VXLAN), 10250(kubelet) 포트가 열려있어야 해요. UFW 켜놓고 왜 에이전트가 안 붙나 한참 봤던 경험이 있어요.

    MicroK8s에서 자주 만나는 문제들

    • Snap 업데이트 자동 재시작: Snap 패키지 특성상 자동 업데이트가 되면서 MicroK8s가 재시작되는 경우가 있어요. 프로덕션에서 쓴다면 sudo snap refresh --hold microk8s로 자동 업데이트를 잠시 홀드해두는 게 좋습니다.
    • Snap 미지원 OS: CentOS나 일부 최소화 배포판에서는 Snap 자체가 없어서 설치가 번거로워요. 이런 환경에선 k3s가 훨씬 편합니다.
    • DNS 애드온 활성화 순서: 다른 애드온보다 DNS를 먼저 활성화해야 해요. 순서 안 지키면 파드 간 통신이 안 되는 경우가 있더라고요.

    💡 공통 팁: 두 솔루션 모두 kubectl 명령어는 동일하게 사용할 수 있어요. 한쪽에서 작성한 YAML 매니페스트를 다른 쪽에서 그대로 apply해도 됩니다. 그 점은 진짜 편하더라고요.


    간단한 애플리케이션 배포로 검증해보기

    설치만 하고 끝내면 아쉽죠. 간단한 nginx 파드를 배포해서 정상 동작을 확인해 봅시다. 두 솔루션 모두 동일한 YAML로 테스트할 수 있어요.

    # nginx-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-test
      labels:
        app: nginx-test
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx-test
      template:
        metadata:
          labels:
            app: nginx-test
        spec:
          containers:
          - name: nginx
            image: nginx:stable
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-test-svc
    spec:
      selector:
        app: nginx-test
      ports:
      - port: 80
        targetPort: 80
      type: NodePort
    # 배포
    kubectl apply -f nginx-test.yaml
    
    # 파드 상태 확인 (Running이 되어야 정상)
    kubectl get pods -o wide
    
    # 서비스 확인 (NodePort 번호 확인)
    kubectl get svc nginx-test-svc
    
    # 접속 테스트 (NodePort 번호는 위에서 확인한 번호로)
    curl http://노드IP:NodePort번호

    “Welcome to nginx!” 가 뜨면 성공입니다! 🎉 이 YAML은 k3s든 MicroK8s든 동일하게 동작해요.

    kubectl get nodes와 get pods 명령어로 확인한 클러스터 정상 동작 결과. 두 노드 모두 Ready 상태이며 파드가 Running 중인 것을 확인할 수 있습니다.


    결국 뭘 골라야 할까? — 상황별 선택 가이드

    “그래서 뭐 써요?”라는 질문을 제일 많이 받아요. 솔직히 말씀드리면, 상황에 따라 달라요. 제가 정리한 선택 기준 공유해 드릴게요.

    k3s를 선택해야 하는 경우

    • ✅ 라즈베리파이나 ARM 기기를 사용하는 경우 — k3s가 압도적으로 유리해요
    • ✅ 엣지 컴퓨팅, IoT 환경 — 리소스가 제한적인 환경에서의 프로덕션 배포
    • ✅ 멀티노드 클러스터를 빠르게 구성해야 할 때
    • ✅ Ubuntu 외 OS(CentOS, Debian, Alpine 등)를 사용하는 경우
    • ✅ CI/CD 파이프라인에 경량 쿠버네티스 환경이 필요할 때
    • ✅ Snap을 쓰기 싫거나 쓸 수 없는 환경

    MicroK8s를 선택해야 하는 경우

    • ✅ Ubuntu 서버/데스크탑이 주 환경인 경우 — 설치와 관리가 정말 편해요
    • ✅ 로컬 개발/테스트 환경 — 단일 노드에서 빠르게 시험해볼 때
    • ✅ 애드온 시스템이 매력적인 경우 — 필요한 기능을 명령어 하나로 켜고 끄고 싶을 때
    • ✅ Canonical 생태계와 통합이 필요한 경우 (Ubuntu Pro, Landscape 등)
    • ✅ 업스트림 쿠버네티스 최신 버전을 빠르게 따라가고 싶을 때

    제 개인적인 결론

    저는 홈랩에서 라즈베리파이 클러스터는 k3s, x86 Ubuntu 서버에서 빠른 테스트는 MicroK8s를 씁니다. 둘 다 훌륭한 도구예요. 어느 쪽을 선택하든 “진짜 쿠버네티스”를 배울 수 있고, 나중에 풀스택 k8s로 넘어가도 배운 게 그대로 써먹힙니다.

    k3s와 MicroK8s 상황별 선택 가이드 요약. 사용 환경, 목적, OS에 따른 최적의 선택을 한눈에 정리한 인포그래픽입니다.


    자주 묻는 질문 (FAQ)

    Q. k3s와 MicroK8s는 실제 쿠버네티스랑 호환되나요?

    네, 둘 다 CNCF 공식 인증을 받은 쿠버네티스입니다. 표준 kubectl 명령어와 YAML 매니페스트가 그대로 동작하고, Helm 차트도 사용할 수 있어요.

    Q. 라즈베리파이 4에서 어느 쪽이 더 잘 돌아가나요?

    k3s가 더 유리합니다. ARM 아키텍처 최적화가 잘 돼 있고, 메모리 사용량도 더 적어요. MicroK8s도 ARM을 지원하지만, 라즈베리파이 환경에서는 k3s가 훨씬 검증이 잘 돼 있습니다.

    Q. 나중에 풀스택 쿠버네티스로 마이그레이션하기 어렵나요?

    애플리케이션 레벨(YAML 매니페스트, Helm 차트)은 그대로 이전할 수 있어요. 다만 스토리지 클래스나 네트워크 플러그인 설정은 환경에 맞게 다시 잡아줘야 합니다. 어렵다기보다는 손이 좀 가는 작업이에요.

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

    k3s는 실제로 엣지 컴퓨팅, 리테일, 제조업 현장 등 다양한 프로덕션 환경에서 사용되고 있습니다. 고가용성(HA) 구성도 지원해요. MicroK8s도 프로덕션 사용이 가능하지만, 일반적으로 개발/테스트 환경에서 더 많이 쓰이는 경향이 있습니다.


    마무리: 일단 설치해 보세요

    k3s와 MicroK8s 비교, 어떠셨나요? 사실 이 글을 쓰면서 다시 한번 느낀 건데, 이 두 도구 모두 “쿠버네티스 진입 장벽을 낮추자”는 목표 하나는 정말 잘 달성했어요. 예전엔 쿠버네티스 클러스터 하나 올리는 데 반나절씩 걸렸는데, 지금은 30분이면 충분하니까요.

    제 추천은 간단해요. 라즈베리파이나 ARM 기기, 또는 멀티노드 엣지 환경이라면 k3s, Ubuntu 서버에서 빠르게 개발/테스트하고 싶다면 MicroK8s. 고민이 길어지면 일단 k3s로 시작해보세요. 단일 명령어 설치에 문서도 풍부하거든요.

    다음 글에서는 k3s 위에 Helm(헬름, 쿠버네티스 패키지 매니저)과 ArgoCD(아르고시디, GitOps 배포 도구)를 올려서 홈랩 GitOps 파이프라인을 구성하는 내용을 다뤄볼 예정입니다. 경량 쿠버네티스를 설치했으면, 이제 그 위에 뭔가를 올려야죠! 🚀

    혹시 설치하다가 막히는 부분이 있으시면 댓글로 남겨주세요. 제가 겪어본 삽질이라면 같이 풀어드릴 수 있을 것 같아요. 😄